Every once in a while, it is a good idea to take stock of the environment and the market around us to determine if what we are doing is what we should be doing. I’m a developer, not a prognosticator, so these observations are simply based on my experience in the development world, along with a frank assessment of what’s changing, to try and offer some advice to my fellow developers. This week I’ll talk about embedded, but we’ll hit a bunch of application targets over the coming weeks.
Embedded development is, generally speaking, more low-level than most other modern programming practices. Considering the goal of embedded is to interface with the hardware, this is no surprise.
And that brings us to the king(s) of the embedded hill. C, and to a lesser extent, C++ rule this roost. You will see a lot of talk about Python, and we’ll get to that in a minute, but for historical and performance reasons, C is still your best bet. If your DevOps tools support your Make variant – Ant, Maven, or whatever – it can be plugged directly into the DevOps process. Testing will still take extra steps. Since deployment is most often handled directly, that does not generally need extra steps, but, in some cases, it might. A lot of general guides claim C/C++ is “easy” to learn. I disagree with this assessment; newer languages tend to be more intuitive while retaining some of C’s better features, but it is, at this time, necessary to embedded development.
There’s a Reason (or Many) for That …
There are a lot of conflicting factors going into where embedded is headed in the future, so we’ll try to address them here.
Historically speaking, C/C++ have had better performance and smaller footprints than interpreted (even bytecode) languages. They are easier to code in than Assembly and supported by a ton of libraries to get work done; they struck the right balance for embedded. The weight of these developers and the legacy source code they created are part of the reason C/C++ are still on top.
But three things have caused a shift that will open up room for other languages to make headway into this space. Embedded devices are getting faster, and storage is getting both smaller and cheaper. That means that a less-efficient means is more viable. Arduino and other hobbyist embedded platforms have also come of age. It is now viable to pick up an embedded board and start prototyping over the weekend. These embedded environments are well-supported by newer languages, and, historically speaking, today’s hobby builders are tomorrow’s startups. This is pulling other languages into the mix far more frequently, particularly our next entry.
Python is popular in almost every category of programming. It has been around long enough to lose the mantle of “language du jour,” and should be considered based on its strengths and weaknesses. Given that the newer wave of prototype systems is well-supported by Python, it is easy to maintain, and has a broad selection of libraries (often, ironically, written in C), it has gained clout in the embedded space. It doesn’t perform as well as C/C++, but modern embedded devices are of a class that this may not be as important (early embedded devices were high-performance tools, while IoT often has devices that don’t require anything like near-real-time), and hardware improvements make this less of a concern. Python’s popularity makes it relatively easy to work in to your DevOps toolchain, with targeting of embedded devices making deploy and test require extra steps … but that’s true for all of these languages, as it is a targeting feature, not a language issue.
In the end, we need machine code. Even bytecode (or p-code, if you prefer) interpreted languages execute their instructions in hardware, eventually. Because performance and space have long been issues in embedded development, assembly language has been a preferred tool for pieces of the development pie. While few developers use assembly language for everything, most embedded developers use it, at some point, to modify libraries or create targeted subroutines. Certainly not a “popular” language among developers, most of us buckle down and just do what we need to. Like C, assembly is normally built using a Make variant. These are easily integrated into DevOps toolchains to get reporting and results up to those dashboards that run a company’s agile efforts.
There are a wealth of other languages in use on embedded platforms, most notably C#, but also newer languages like Rust. The environment is changing, and as the ramifications of terabyte SD cards and multi-core embedded boards start to sink in, they are worth watching. We are not that far off from having a desktop-quality computer in a board only a little larger than a credit card. That changes a lot of things. More room for data storage and processing, and the need for tools that are easier to use in these contexts.
All languages use libraries to make development easier. We are past the days when coders wrote all of the functionality of their project. The tools that bring libraries into a project need to be incorporated into the DevOps toolchain. For C/C++, the mechanism is largely manual, and can be automated with scripts or with the build tool. For newer languages, tools like NPM will need to be hooked into the toolchain. The ease of library dependency management is one of the appealing aspects of newer languages, and making it easier for a developer to hook in libraries also makes it easier for DevOps tools to make use of library management functionality.
Whatever your language of choice, in the end it will likely be your build tool that links it to DevOps. Maybe we should do a series on those, too; comparing when to use Gradle versus Ant, for example. Until then, keep rocking it. All development depends upon embedded in the end, so you’re holding up the foundation.