What this is. Opinion + Experience + Fact (45% opinion · 45% experience · 10% fact). Written in collaboration with AI — I discuss, I do not outsource.
The first time a new board prints "hello" over serial, it feels like the finish line. It is the starting line. Here is why the milestone that is easy to reach is rarely the one that matters — and what actually stands between a board that boots and a product that works.
There is a moment every embedded engineer knows: a fresh board, a fresh toolchain, and then "hello" scrolls up the serial terminal for the first time. It feels like arrival. It is one of the most satisfying feedback loops in all of engineering.
It is also, quietly, a trap. Because "it boots" and "it works" are not the same claim, and the distance between them is where most of the real work lives. Let me walk through why booting is the easy part, why "works" only reveals itself in conditions a bench cannot stage, and how I treat a first boot as the beginning of the questions rather than the end.
1. Booting is the easy part
Powering up, reaching main(), blinking an LED, printing a banner — that is the part of embedded with the fastest feedback and the biggest hit of progress. You change one line, you flash, you see it. It is deeply motivating, and that is exactly what makes it deceptive.
The reason it is easy is that it behaves the same way, on your bench, every single time. A clean power supply, a stable temperature, a debugger attached, one known input. Under those conditions almost anything looks like it works. First boot proves the board is alive and the toolchain is sane. It proves very little about whether the thing will survive contact with the real world.
▸ First principle. The milestone that is easy to reach is rarely the one that matters.
2. "Works" lives where the bench can't follow
A device that boots still has to survive the conditions you cannot conveniently reproduce at your desk. Power can sag or drop in the middle of a flash write, and the device has to come back with its storage intact rather than half-written. A network link fails at the worst possible moment, and the firmware has to retry, back off, and reconnect instead of wedging. A peripheral stops responding, and something has to notice and recover rather than hang forever.
Then there are the slow ones. A sensor that lies — returns a plausible but wrong value — and the code has to sanity-check its inputs rather than trust them. Weeks of continuous uptime, where a small heap fragmentation or a counter that rolls over finally catches up with you. And the input nobody imagined, the sequence of events no test case covered, which is where a surprising share of field failures actually live.
None of this shows up at first boot, and most of it never shows up on the bench at all. That is not a gap in your diligence; it is the nature of the environment. "Works" is a claim about behaviour under conditions you do not fully control, and you can only earn it by designing for them on purpose.
▸ First principle. "It works" is proven in the field, under conditions no bench fully reproduces.
3. Treat first boot as question one, not answer one
So when a board finally boots, I try not to read it as a finish line. I read it as permission to start asking the questions that actually decide whether this becomes a product. What happens on power loss during a write? What happens when the flash is full? What happens when a peripheral hangs, when the network disappears for an hour, when the device has been running for weeks? What is the worst input someone could hand this, on purpose or by accident?
Booting earns you the right to ask those questions well. It does not earn you the right to stop asking them. The teams that ship things that last are the ones who treat "hello" as the moment the interesting work begins, and who budget real time for the distance between a board that powers on and a product that holds up in someone else's hands.
▸ First principle. Booting earns you the right to ask the real questions, not the right to stop asking.
4. The questions I run at a fresh boot
Concretely, here is the short list I start working through the moment a new board is alive. It is not exhaustive, and every product adds its own — but it turns "it boots" into a plan instead of a celebration:
| What I ask | What it protects against |
|---|---|
| What happens if power drops mid-write? | Corrupted storage, bricked devices in the field |
| What happens when the network goes away? | Wedged connections, no reconnect, silent devices |
| What happens when a peripheral stops responding? | Hangs with no recovery; a watchdog nobody added |
| Do I trust every input, or validate it? | Acting on a sensor that lies |
| Will it still be healthy after weeks of uptime? | Fragmentation, leaks, counter rollover |
| What is the input I did not plan for? | The edge case that only happens at the customer |
▸ First principle. A first boot is a to-do list of failure modes to design against, written in the order you will meet them.
The distance between "it boots" and "it works" is most of the job. Budget for that distance — design for power loss, for lost links, for hung peripherals, for lying sensors, for long uptime, for the input nobody imagined — and you ship something that lasts. Skip it, and the field measures it for you, on its own schedule, in front of your customer.
Sources
This is a craft piece drawn from twenty years of embedded work rather than a study, so it carries no statistics. The failure classes named — power loss during a flash write, connection loss and reconnect, peripheral hangs, input validation, long-uptime issues like heap fragmentation and counter rollover, and unhandled edge cases — are standard, well-documented embedded reliability concerns. "Weeks of uptime" is used as an illustrative archetype of long-running failures, not a measured figure.
FAQ
What does "'it boots' is not 'it works'" mean?
It means reaching first boot — power-on, main(), a serial banner — proves the board is alive and the toolchain is sane, but it does not prove the device is reliable. "Works" is a claim about behaviour under real-world conditions a bench cannot stage, and closing the gap between the two is where most of the engineering lives.
Why is getting a board to boot the "easy part"?
Because booting has fast feedback and behaves the same on the bench every time: clean power, stable temperature, a debugger attached, one known input. Those conditions flatter almost any code. The hard part is everything that only appears once conditions vary.
What kinds of things break after a device boots fine?
Power dropping mid-write and corrupting storage; a network link failing and never reconnecting; a peripheral hanging with no recovery; a sensor returning plausible-but-wrong data; slow issues after weeks of uptime like heap fragmentation or counter rollover; and unhandled edge cases — inputs or event sequences no test covered.
How do you close the gap between "boots" and "works"?
Treat first boot as the start of the questions, not the end. Design explicitly for power loss, connection loss, peripheral hangs, input validation, long uptime, and unexpected inputs — and budget real schedule time for that work rather than assuming a booting board is nearly done.
Does this mean bring-up doesn't matter?
No — bring-up is necessary and often genuinely hard. The point is that it is necessary, not sufficient: a board has to boot before it can do anything, but booting is the floor, not the ceiling. The reliability work that comes after is what turns a booting board into a product.
The short version of this is on my LinkedIn. These are field notes from twenty years below the OS — the longer story lives on my profile.
Stay in the loop
New essays on embedded systems, firmware quality, and engineering craft. No noise.
Discussion
No comments yet. Be the first to share your thoughts.
Leave a comment