Jack recommends some interesting reading for embedded systems engineers.
Today, a search of “embedded systems” in the books section of Amazon.com turns up 1,600 hits. How many would have turned up two decades ago when this magazine was in its infancy? Well, Amazon.com didn't even exist back then. And neither did the web. There were no books on embedded systems, either.
Surveys show the average software developer reads but one technical book a year. Yet the quantity and quality of books on embedded systems and related subjects is impressive. It's rare that I run into one that doesn't inform or challenge my thinking. Recently a couple of new books came out that are very worthwhile.
Some months ago James Grenning and I had a point/counterpoint in these pages about test-driven development (TDD). He's has been writing a book on the subject for some time, and it should be available shortly after this column goes to press. He generously sent me a PDF of the nearly final version.
Test Driven Development for Embedded C (I think there should have been a hyphen in the adjectival phrase) is hands down the best book on the subject. This is an amiable, readable book with an easy style that is fairly code-centric, taking the reader from the essence of TDD through mastery using detailed examples. It's a welcome addition to the genre as the book is completely C-focused, unlike so many others, and is specifically for those of us writing firmware.
James skips no steps and leads one through the gritty details, but always keeps the discussion grounded so one is not left confused by the particulars. The discussion is laced with homey advice and great insight. He's not reluctant to draw on the wisdom of others, which gives the book a sense of completeness.
The early phases of a TDD project are mundane to the point of seeming pointlessness. One writes tests to ensure that the most elemental of things work correctly. Why bother checking to see that what is essentially a simple write works correctly? I've tossed a couple of books on the floor in disgust at this seeming waste of time, but James warns the gentle reader to adopt patience, with a promise, later fulfilled, that he'll show how the process is a gestalt that yields great code.
TDD does mean one is buried in the details of a particular method, a particular test, and the path ahead can be obscured by the tests at hand. If you're a TDD cynic or novice be sure to read the entire book before forming any judgments so you can see how the details morph into a complete system accompanied by a stable of tests.
Better than any book I've read on the subject, Test Driven Development for Embedded C lays out the essential contrast between TDD and conventional write-a-lot-of-code-and-start-debugging. With the latter technique, we're feeding chili dogs to our ulcers as the bugs stem from work we did long ago, and are correspondingly hard-to-find. TDD, on the other hand, means today's bug is a result of work one did 10 minutes ago. They're exposed, like ecdysiast Gypsy Rose Lee's, uh, assets. A test fails? Well, the bug must be in the last thing you did.
One of TDD's core strengths is the testing of boundary conditions. My file of embedded disasters reeks of expensive failures caused by code that failed due to overflows, off-by-one errors and the like. TDD—or, at least James' approach to it—means getting the “happy” path (his word—the basic functionality) working and tested, and then writing tests to ensure each and every boundary condition is also tested. Conventional unit testing is rarely so extensive and effective.
The problem with early testing is that the target system will not be available. In TDD, stubs replace the hardware, the stubs exactly mirroring the operation of the I/O. Examples show, for instance, stubbed-LEDs and other components, but one would imagine a complex device could require quite a bit of simulation code. The book is less clear about how one eventually merges the target hardware with the stubbed-out code. The stubs are a hugely valuable asset in terms of starting testing very early, but of course they are merely facsimiles of reality. NASA's mantra “Test what you fly, fly what you test” may pose problems for TDD.
Embedded TDD revolves around creating a test harness, which is a software package that allows a programmer to express how production code should behave. James delves into both Unity and CppUTest in detail. Although the latter is targeted to C++ applications it does support C. Each test invokes creation and teardown routines to setup and remove the proper environment, like, for instance, initializing a buffer and then checking for buffer overflows. I found that very cool.
The book goes much further than showing how to evolve code in concert with the tests. For instance, it shows design patterns based on Bob Martin's SOLID principles (read the book for the details!) that illustrate design techniques that lead to innately testable and reliable code.
It would have been interesting to see more on design, which feels relegated to a minor role. And I wished for some comments on TDD in a regulated environment, like avionics.
But Test Driven Development for Embedded C is an active-voice work packed with practical advice and useful aphorisms, like “refactor on green” (in other words, get the code working first, and when the tests pass you can improve it if necessary). I was also fascinated to find the book had been in beta for some time, and a wide range of developers had made critiques and suggestions for improvement. Rather agile-like.
Above all the book stresses having fun while doing development. And that's why most of us got into this field in the first place.
Phil Koopman has a new book out as well, titled Better Embedded System Software. I don't know Phil personally but we have been corresponding for years. His work includes a lot of research into dependable embedded systems, and I recommend his papers on the subject at www.ece.cmu.edu/~koopman/.
Better Embedded System Software is a broad work covering firmware development from soup to nuts. Some might view it as an anti-agile tome as Phil goes on at length about paperwork and other associated work products that are often scorned by some in the agile community. Yet he's right. In the decades I've worked with developers, I've seen that one of the biggest causes of failed projects is a lack of planning, a dearth of forethought, and the complete abandonment of documentation. Is this anti-agile? I don't think so; in my opinion there's a balance that needs to be struck between a total focus on the code and one that is more plan-driven. And that balance will vary somewhat depending on the nature of the product.
Better Embedded System Software includes five chapters about requirements, a subject that is universally neglected in most firmware books (including mine). Yet if you don't know what you're trying to build—in some detail—you can't build it.
The chapters on engineering a real-time system are worth the price of admission. One succinctly discusses a number of difference scheduling approaches, and unusually for an embedded book, shows how to do the math to understand schedulability issues. And although everyone knows it's costly to build systems with few spare resources, Phil gives a number of graphs that put numbers to the anecdotes. His thoughts on globals, mutexes, and data concurrency are essential reading for anyone who has not (yet) run into the nearly-impossible-to-find challenges that result from poor use of shared resources.
The book delves into the important and oft-neglected math behind reliability, MTBF (mean time between failures), and redundancy. He doesn't mention Nancy Leveson's work on redundancy. She found that having multiple systems built by independent teams may not offer much of an advantage, since so many problems stem from errors in requirements.
The chapters are short, pithy, and full of specific recommendations, the highlights of which are displayed as take-aways in boxes that jump from the page. Alas, it's not a pretty book; the publisher should have enshrined such great content in a more attractive volume.
I advise reading James Grenning's book in concert with Phil's. The two advocate somewhat different, though not incompatible, approaches to development. Which is right? Both and neither. Each team has their own needs. Wise engineers will be familiar with many approaches and will pick the best practices for their needs from the firehose of ideas.
Engineering for fun
A number of readers have written recommending The Existential Pleasures of Engineering by Samuel Florman.
Normally one doesn't hear the words “existential” and “engineering” in the same paragraph, or even the same book!
This is an old book first released in 1976 and updated in 1994, so it's a bit dated and is very much a reaction to the anti-establishment '60s where a distrust in technology burned. (Today I'd argue that rather than distrust there's a complete lack of understanding about technology and science, which is arguably worse.) And a lot of the context is in terms of the new (at the time) rise of the environmental movement, heralded by Rachel Carson's Silent Spring and President Nixon's creation of the Environmental Protection Agency.
Samuel Florman paraphrases philosophers of technology who “reserve some of their disdain for the activity [engineering] itself, and for the men who make it their life's work. As seen by the antitechnologists, engineers and scientists are half-men whose analysis and manipulation of the world deprives them of the emotional experience that are the essence of the good life.” Hmm. I've yet to meet Mr. Spock despite nearly four decades as an engineer. But that sure does make for a fun sound bite.
Mr. Florman discusses the golden age of engineering, which he pegs from 1850 to 1950. Certainly in the 19th century engineers were the rock stars of the age, their glories trumpeted widely and their ambitions admired by all. He worries that the field has been in decline since then. I'm not so sure; 1950 signaled, roughly, the birth of digital computing which has accomplished marvels that could not have been even dreamed of. Even civil engineering, which one would think had reached a stable maturity, has blossomed with creations like the stunning Puente de la Unidad bridge that offers a slender and functional beauty unknown a century ago.
I found his railing against other peoples' perceptions somewhat tiresome, while agreeing completely with him. But some of the writing is nearly poetic: “My proposition is that the nature of engineering has been misconceived. Analysis, rationality, materialism, and practical creativity do not preclude emotional fulfillment; they are pathways to such fulfillment. They do not reduce experience, as is so often claimed, they expand it. Engineering is superficial only to those who view it superficially. At the heart of engineering lies existential joy.”
I suspect a lot of engineers won't care for this book. After all, who cares what people think about us? But underneath Mr. Florman's concerns is a paean to engineers and to the work we do. And for that I enjoyed the book and recommend it to those who find the history and philosophy of this field compelling.
Jack Ganssle () is a lecturer and consultant specializing in embedded systems' development issues. He has been a columnist with Embedded Systems Design and Embedded.com for over 20 years. For more information at Jack, click here.