[2021-03-14] Learning Golang For Embedded Linux Development
The need for a robust update solution
As part of my day job I was tasked with investigating a robust update system we could implement for an core piece of our product's hardware. The hardware was running a custom embedded Linux image. A significant number of the devices were already being used in the field at this point, but they were only just starting to come "online" with LTE connectivity. An update mechanism already existed for the device, but it was basic. By using the the regular ol' debian style APT package manager it was possible to update software remotely from a private server.
However, as the product is vehicle mounted the APT update mechanism wasn't considered a feasible solution for anything but the most minor/high level of device software. Considering modification at the kernel level or to aspects relating to the LTE connectivity itself caused every engineer on my team to simultaneously grit their teeth and take a sharp intake of breath.
The current system wasn't necessarily unreliable, but even those behind it's design knew that a power cycle at the wrong time whilst updating the wrong piece of software could result in a bricked device. Hence we needed a better solution.
Picking the right tool for the job
As per my task, I set about performing the evaluation on available Linux remote update tools and solutions. At this point my team were heavy users and advocates of the Yocto Project, a powerful tool used to create custom embedded Linux distributions, with a focus on minimalism and reproducibility. Their wiki contained the following evaluation of the most popular remote update systems with this fantastic table. Some poor (lucky?) sod had done most of the work already.
Based on the needs and limitations of our device we narrowed down the possible solutions to the following:
-
SWUpdate - The classic and simple "vanilla flavour" robust update system.
-
Mender - The modern robust update system offering a full-package-style solution.
I found advocates for both solutions online and through in-person contacts. Both tools could certainly do the job. But there could only be one.
After a prototyping phase with live Raspberry Pi demos, the decision was made to go with the Mender solution.
Mainly it was because we liked the cut of their jib. The Mender team was quick to respond to any queries we had, and generally positive whisperings had been heard about the skilled developers working at Northern.Tech (creators of Mender). The Mender solution met all of our requirements and critically offered both a dedicated client and server solution. SWUpdate on the other hand requires that you either build your own server-side management application from scratch, or integrate their client with another server-side tool called Hawkbit.
Golang for Embedded Systems?
I was particularly interested in the fact that Golang (The Go Programming Language) had been used for Mender's development. Although I'm a relative novice when it comes to Embedded Software Engineering, this fact came as a surprise. I had been conditioned to expect low-level, close to the hardware, highly efficient languages to be used for embedded systems (C, C++, and Rust come to mind). Much less a language with a garbage collector!
As both SWUpdate and Mender are open-source projects hosted on GitHub, their language makeup is easy found. The former of the tools fits the expected narrative.
Over the years the Mender team has frequented Software Engineering conferences to talk about (and sell) their solution. At one such event Marcin Pasinsk of the Mender team led an interesting talk titled:
Develop Your Embedded Applications Faster: Comparing C and Golang. Which can be found here.
As the title of the talk alludes, Marcin discusses and justifies the decision for Mender to use Go as its primary programming language. You can watch the video for the full story, but below I will summarise my main takeaways from the talk:
- Go can perform admirably in terms of efficiency. Quantifiably, on most metrics that matter on modern embedded systems. But it isn't a replacement for C.
- Released in 2009, Go is sufficiently mature programming language to be used for production systems.
- Go's primary aim is to combine the trio of: efficient compilation, efficient execution, and ease of programming.
- Go is a really productive language, the learning curve from C to Golang is very low, and it has lots of core language features and libraries that allows much faster development of applications.
- As it is a compiled language Go runs natively on embedded devices.
- Go applications are statically linked into a single binary. Which is similar in size to static C binaries, Go binaries will continue to get smaller as their compilers are optimized.
Learning Golang
As the deployment of the Mender solution progressed I became increasingly interested in contributing to the open-source Mender project. There were a number of specific issues I bumped into, in which additional features to the Mender project would solve my problems in an elegant way.
The classic software engineering book The Pragmatic Programmer states the following:
"Learn at least one new language every year. Different languages solve the same problems in different ways. By learning several different approaches, you can help broaden your thinking and avoid getting stuck in a rut. Additionally, learning many languages is far easier now, thanks to the wealth of freely available software on the Internet."
Having never used Golang before, but feeling inspired by the usage of the language in the Mender project and the possibility of contributing to an open-source project for the first time. I plan to commit myself to learning Golang in 2021.