A blank page can be very intimidating, even for a Test-driven developer. Where do we start? Write a test, right? Not always.more...
Embedded Systems Consultant at Embedded Artistry LLC
I took a remote TDD training course hosted by James in September 2018. I published a detailed review of what I learned from James's TDD course on my website.
Here, I will focus on how I applied the lessons after the training.
We need our tests to be fast and easily runnable if we're going to stick with TDD. I spent a few hours getting my text editor (Sublime Text) to run my unit tests with a keystroke. Now, I press ctrl+B to have my editor save all open files, compile code, and run the unit tests. Results are presented to me within 1 second.
The feedback cycle is so short that I run the tests almost compulsively: ctrl+B has become the new ctrl+S.
Since every module I write now has an associated suite of tests, I can refactor and improve the code without fear of messing anything up. The tests have boosted my refactoring confidence so much that I don't hesitate to rewrite a function if I review a file and find something that's not up to snuff.
Quite often, my changes will inadvertently make a test fail. In the past, these problems would not have been caught until later in the development cycle, and usually by another developer or tester who is trying to use the program. The frequency with which my tests break due to seemingly innocuous changes has been eye-opening - it's so easy to make an innocent mistake.
Improved Designs & Architecture
One of the common problems in embedded systems software is tight coupling between firmware and the underlying hardware, RTOS, and vendor SDKs. Many teams do not spend any time creating abstractions to keep their systems flexible. As a result, designs can quickly become a tightly-coupled house of cards, and the move to a new processor can trigger a total rewrite of software.
TDD has largely improved the design of my systems. Testing also helps us notice coupling problems, especially when a module requires us to pull in the rest of the project in order to test it. By requiring myself to write modules and tests that run on my host machine, I am forced to utilize abstraction layers and prevented from becoming dependent on vendor SDKs. These considerations keep our software flexible and reduce future costs of change.
Driver Development on My Host Machine
Another benefit of creating abstractions which run on our host machine is that we can develop and test our device drivers on our host machines. TDD forces us to write our drivers using generic interfaces instead of chip- and vendor-specific APIs. Mocking allows us to provide data to our device drivers such that we can test the behavior with a given input. Spies and fakes allow us to ensure that other drivers and libraries are being used correctly by our drivers.
Since we've built our drivers with tested interfaces, we will be able to validate the software much more quickly when the target hardware is finally available. Alternatively, with a debug adapter (such as an Aardvark I2C/SPI adapter) and a development board, you can even test your driver on real hardware from the comfort of your host machine.
We've been using TDD to write drivers ahead of hardware deliveries and have drastically reduced bring-up and debugging time as a result.
Breaking the Target Hardware Bottleneck
The perpetual problem for embedded systems developers is the dependency on target hardware. This manifests in a variety of ways: waiting on hardware before beginning development in earnest, inefficient workflows due to slow flashing times, difficulty debugging problems, and not having enough hardware to go around.
The TDD approach enables us to begin developing our firmware before hardware is ready, and can keep teams moving forward even if hardware is scarce. We can get a jump start on development and write code that can be quickly and confidently ported to the target platform once we are able to work with hardware. To me, this is the greatest benefit of the TDD approach.
I didn't expect that James's TDD course would have such a large impact on the way I develop code. The hands-on exercises got me comfortable with the process, and once I configured my environment to make it easy to running tests, I never stopped.
We invite you to submit your own story about TDD or Agile for Embedded System Development.
Here is a short interview with James about TDD and embedded software from the deliver:Agile conference last spring.more...
James participated on these social media platforms.more...
Do you have some time to do a simple programming problem in C or C++ for my research?more...
My long-time good friend (Uncle) Bob Martin and I have fun programming together firing tracer bullets for distributed water pressure measurement system.more...
Here are a couple reviews of our TDD for Embedded C training.more...