SJ cartoon avatar

Embedded Hardware's Single Responsibility Principle

If you’ve been in software for more than a few months, you’ve inevitably come across the SOLID acronym - which means, you’ve probably heard of the single responsibility rule.

As Uncle Bob says it:

A class should have only one reason to change

Broadly speaking, this is a pretty solid rule… Ha… Get it?

Sigh… Anyways. Followed very precisely, this can lead to an explosion of incredibly small classes - maybe this is good, maybe this is bad, but it definitely makes for good unit testing.

Sort of an example

Here is a simple example of SRP in action.

That link is just to highlight the concept of taking an existing class that does many things and changing that into many classes that each do a single thing.

Disclaimer: Other than illustrating the concept of SRP, I wouldn’t use that example for much else - as I think during that re-factoring, a few other code smells were introduced in terms of strange dependencies, tight coupling, lack of interfaces, lack of dependency injection, etc…

Sucks to be me

I think SRP can/should also be applied at a method level (within reason). To prove a point during a code review, I re-named a colleague’s function to be a bit more descriptive of what it actually did:

  • Original: bool save(Message message)
  • New: bool decryptReadParseAndPersistMessage(Message message)

If ‘save’ had been an aggregator of 4 separate method calls, I could probably get onboard, but the ‘save’ method actually performed those 4 operations (200ish lines of code).

The worst violation of SRP (or any other decent coding principle) I have ever seen was a ‘Draw()’ method which was 1000 lines of code, had 100-150 if statements, early returns, nested switches, and everything else hideous you could imagine. It had about 30-40 responsibilities.

Worse still, there was another call ‘DrawNow’, which was a near copy/paste of Draw, and it was REALLY important that the two weren’t mixed up.

A can of spaghetti code

It’s not just software

I’d love to give hardware designers a pass on this post, given that I’ve mentioned very specific software development principles.

Well… No dice homeslice.

The single responsibility principle can’t really exist in the hardware world, otherwise we’d have single ICs for each purpose on a board, and boards would become huge and expensive.

However, we CAN have a single ‘intention’ principle.

What I mean by this is that (as a hardware designer) when you’re designing and building a PCB, you need to know what the primary intention of that specific board release is. You can have multiple secondary intentions, but you need a primary one that is the goal of your release.

The following stems from conversations I’ve had with many clients for the past several years when developing firmware (but not designing the hardware). Inevitably, they want EVERY PCB we produce to be the ‘production’ board. And even more inevitably, all progress slows down as a result of this primary intention.

The reason being? Well, how am I supposed to make meaningful progress on firmware development for a production-grade and style of PCB?

Typically, when releasing a production board (especially in IoT and wearables), it’s been compacted to fit a small form factor, many test points/jumpers/hooks have been removed for space savings, the programming connectors are removed in favour of a bed of nails, passives are shrunk to 0402 (or worse, 0201), and the ICs are QFN/BGA. In the worst case, it’s also been environmentally coated…

So, after my firmware is loaded, when something goes wrong on the I2C lines, where am I going to hook up my logic analyzer? And, if it’s been coated, how am I even going to check the voltage lines?

Red flag warning: If day 1 of firmware development begins with a microscope and fly wires - it’s going to be a bad few weeks/months.

Heads up though. What I’ve just mentioned doesn’t mean that you should be releasing ‘production’ boards with all those debug test hooks. In addition to adding size and cost to a board, they also provide a (simple) way for your designs to be reverse engineered or otherwise exploited.

So, what now?

Well, here’s the deal. I typically come across 5 reasons why a client wants a PCB revision to be built, so for each one of them, I have some recommendations. Let’s try these out for a while, and maybe, just maybe, we’ll all live happily ever after.

By the way, these are all paraphrased comments I’ve actually received:

  1. “I need to test out if some of this circuitry works as I expect it, so we may as well do a PCB rev.” Is it complex analog circuitry? Have you tried Spice? Has it been bread-boarded? Have you bought that IC’s eval kits? If these 3 cases haven’t been explored, no board for you.

  2. “This IC doesn’t have a breakout board, eval kit, or DIP packaging - so we need to layout a board so that we can test out this chip.” Buy a (PACKAGE)-to-DIP breakout, solder it down, and let’s move on.

  3. “We need a board that we can develop firmware for.” You’re my best friend. Follow these handy instructions and shine on you crazy diamond. Bonus points - make the dev board twice the size you think it should be.

  4. “We need a board to finalize our injection moulding.” For sure. Is your schematic and layout 100% final? No? Oh, then no, no boards. Stick with CAD and use 3d-printers to get a feel for what your industrial design will look like. For IoT and Wearables, depending on how creative and crafty you’re getting, moulds need board tolerances of sub-mm and even your PCB panelization can mess with them (much worse with PCB layout changes). Wait until the PCBs are finalized because PCB revs are hella fast and cheap compared to injection moulding changes.

  5. “We need a new production board rev because we goofed [e.g. flipped the UART RX and TX lines].” Good reason, but… Hmm… Wait… How did that mistake get past your development board into your production board? Ohhhh… You crafty jackrabbit… You skipped the dev board part, right? RIGHT? Admit it! To paraphrase Anchorman… “80% of the time, it happens every time”

In summary, if you’re doing development - support development. If you’re in production, support production. Don’t mix and match, because the risk/reward profiles don’t line up, and you’ll usually end up taking way more time and spending way more money than doing it the right way.

My favourite dev board

By the way, my feature photo image is of REDLINE from Neutron Controls, which is a development platform for Infineon’s Aurix series of MCUs.

I think REDLINE is THE benchmark of what a good development PCB looks like - clearly labeled, all useful pins exposed, colour-coded test points, status LEDs for everything, plug-and-play components, fully extensible, and just works as soon as you apply power.