Why even consider switching from C++ for embedded UI SW development?
History
In the past, when the hardware was much more limited than today, the software for that hardware was a monolithic binary containing everything. The (embedded) OS, the drivers and the application itself.
The embedded operating systems evolved and introduced things like multi threading or something in the middle of threads and processes.
At that stage hardware resources were the biggest constraint so that switching from C to C++ was considered a crazy step. All those virtual tables that eat up RAM and ROM!
At that time the applications were rather simple. No complex UI flows or things like content that can be downloaded by the user.
Today
Fast forward to today.
We now have Linux as an operating system.
We have multiple processes running on that hardware.
We have downloadable content.
We have OTA updates.
We have much more complex UI software (Features, UX, Animations, states)
Of course we have much more resources than in the old days.
The switch to Linux is key here. This - at least in theory - allows us to use all kinds of technologies because Linux is a common target that is supported by a very high number of technology stacks.
The software got much more complex over the years. The requirements what a UI software in an household appliance should look like and what features it has to support raised dramatically.
The question we have to ask now is:
Do we still use the right tool for the problems we solve?
C++ has been chosen basically as the only possible step away from C towards a more modern way of developing applications. There were no real other options to that language at that time given the constraints.
But considering the new context we have to question the status quo (which can be quite uncomfortable)
C++
C++ is a powerful language. No doubt. It has a couple of upsides:
Upsides (list is not complete)
1. Resource usage
You will have a hard time to find an alternative that uses less resources (besides C). C++ is fast and even when we don’t optimize every copy operation out of our codebase the result is in a range where it doesn’t matter for us.
We don’t have to tweak on a language usage level in order to get sufficient performance.
2. Status Quo
C++ is currently used and is also used in a whole bunch of products that are field-proven
3. Knowledge
Our SW developers do C++ for years now. There is plenty of knowledge available. If you have a problem just ask the colleagues. There will probably be a colleague that can help you.
But there are also a couple of downsides:
Downsides (list is not complete)
1. Native
This is also true for some of the alternatives.
C++ compiles natively.
You have binary dependencies to the system you compile for. This means if you have to support a number of target configurations you end up most likely to release for every target configuration (and do all the build steps over and over)
The level of dependency management that you have to do for a native compiled artifact is much higher than for a platform independent artifact.
2. Features
More modern programming languages and frameworks have a huge set of features that encapsulate much of the complexity. There are many examples but for instance watching a directory / file to get notified about changes is a breeze in Python / .Net / JS / you name it and is really hard using C++ and the standard library. Even if there are features available in the standard library or in boost the interface is often times more complex and error prone than with more modern languages.
3. Modernity
C++ is not the youngest language. It has some constructs that hint at its age.
Headers are one such thing. This idea is derived from C:
You have to create a cpp file containing your code. If other places in your code want to use that (which is the case in most situations) you have to declare your class and its members in an header file (redundant).
Or lets take interfaces. An interface in C++ is a pure virtual class. This is because interfaces were slapped onto the already available concept of classes instead of making them a 1st class citizen.
C++ is full of such weird things. Let’s take smart pointers. Those can be used (and you really should 😁) to have an reference count based memory management. Those smart pointers work great but are not 1st class citizens. This is - for example - why you can’t use a smart pointer to this
in a constructor. The smart pointer gets created after your class gets created so you can’t access the smart pointer (it’s simply not yet there).
I think those are all indications of the fact that C++ has gotten old. All the new standards and improvements in the Boost library are awesome: I really appreciate the amount of work and thought that went into it but in the end it is only another layer slapped onto C++.
4. Compilation time
Compiling C++ is very resource intensive. This leads to very long change - build - test - repeat cycles. If you factor running unit tests in then doing something like “live testing” is simply not possible. You thought your Android app takes long to compile because of that Kotlin-Java-DEX madness going on? This is nothing compared to a similar sized C++ program.
One could think this is also an upside:
5. Complexity
C++ operates on an abstraction layer that is far below the abstraction layer of other languages or frameworks. This is a big “+” (haha) when you need control over behavior at that abstraction level but is a big “-“ when you don’t need that. The amount of ways a developer can do wrong is very high in C++. Often those errors even are of a very nasty kind that doesn’t happen near the root cause of the problem but much later in the control flow.
We don’t need that performance
The most resource intensive thing our software does is the rendering of the UI. This is not in control by us but by the rendering framework we use (Qt).
So in fact it wouldn’t matter if the business logic is a little bit slower than today as this is not the critical path. We don’t do complex calculations that require optimizing the business logic code.
The performance might get even better if some cycle based logic (there are still a few) could be more easily transformed into an event based approach using a modern language.
The only thing that is currently holding back a technology shift (technology wise) is the ROM size of our lowest end hardware. But this is something that will change.
We are heading into the right direction
We are currently heading into a direction where different parts of the software are more isolated. This will lead to more independent processes that can switch technology without affecting other parts of the system.
In such an environment it will be possible to be brave and test a new technology in a small project (that is able to react to risks without loosing much) without affecting anything else.
The groundwork for this will be to evaluate different technologies to get a first idea for what the problems might be to use it in our context.
For example I consider it crucial to have a working Qt/QML binding. The transition has to be as smooth as possible. The amount of resistance against such a change will be high enough. No need to even extend it.
The social factor
The technological aspect is one thing. It is clear and easy to tackle. Even getting a clear yes/no answer is only a matter of time invested.
The much bigger problem (at least for someone like me) is the social aspect of this.
Of course: change is always something that makes you feel uncertain. The amount of uncertainty is different between people. I think this is mostly a personality and age thing. Your personality lays the ground and the older you get the less open to change you will be. So the effective openness to change is a combination of that.
There are most likely other factors that also influence this:
- Current status: Maybe the status you currently have in the company and / or the team is tied to the current technology stack (“Hero C++ dev”) and you fear to loose that?
- History: Maybe you had to fight very hard some time ago to make the transition from C to C++ happen and you see a change away from C++ as loosing that battle in the long run?
- Religion: What? We shall move to something that Microsoft / Google / whatever invented? Won’t happen!
- Environment: Working in a big company vs a small startup is also a factor. Getting change through in a big company involves many discussions, many decision makers that want to get asked and last but sadly not least politics. It might happen that an idea or a proposal is ignored or countered only because there are political conflicts between different areas in the company.
Communication
The key here will be to encourage the people that change can also be something good. This is why the technical aspect is so important. Having something to show and demo some advantages that affect peoples everyday work will (hopefully) make them more open to that change.
Also a clear talking about the risks and benefits is crucial. Change has always risks tied to it but also can bring benefits. A clear plan for how to encounter each risk and what to do if the risks will happen is needed to get trust and also reduce the uncertainty for the people that have to decide.