There's a strong temptation, when you know what you want to build, to just start building it. Open an editor, create a file, write the first function. You'll figure out the rest as you go.
I’ve done that plenty of times. It works until it doesn’t. The problems tend to arrive around the third or fourth decision that depends on an earlier one you didn’t think through. By then you’re committed and the cost of changing direction is no longer zero.
With islet, I decided to try something different.
The problem
islet is a glucose intelligence platform for Type 1 diabetes. The core job is straightforward: take continuous glucose monitor (CGM) readings from a sensor, store them locally and build analytics on top. No cloud services and no third-party dependencies for the critical path. Everything runs on a Raspberry Pi under my own control.
But “straightforward” hides a lot of decisions. How should the data be stored? What deduplication strategy handles re-ingested records? How does authentication work against the upstream API? What happens when the network drops at 3am? What does the schema look like and what happens when it needs to change?
Each of these questions has multiple reasonable answers and the wrong combination creates problems that only surface later.
Seven documents before one line of code
Before writing any implementation code, I wrote seven specification documents:
This took real effort. Writing a spec is not the fun part. But something useful happened during the process: decisions that would have been made under time pressure during implementation were instead made calmly, with full context, before any code existed to defend.
For example, the deduplication strategy. Nightscout assigns each record an _id. Using INSERT OR IGNORE on that field means re-ingesting the same data is a no-op. Simple, but only if you decide it during schema design. If you discover you need it after you’ve already built an insert pipeline that assumes every record is new, the fix is much more invasive.
One session
With the spec complete, Phase 1 implementation was a single session: a Nightscout client, SQLite storage layer, daemon with backfill, CLI with five commands, a systemd service and install scripts.
There were no design decisions to make during implementation. Every module had a defined interface and every error path had specified behaviour. The only surprises were small environmental ones. The default database path did not work on Windows and bearer auth was not accepted by my Nightscout instance. Both were resolved quickly because the architecture did not need to change.
The deployment went the same way. Clone, install, start. The daemon backfilled 3,808 historical records on first run. Within minutes it was polling live data, and it hasn’t stopped since.
What the spec-first approach actually gives you
It’s not about having perfect documentation. Several of those documents have been updated since. The schema is now on version 6. The pipeline has changed significantly.
What it gives you is decisions made in the right order.
When you’re writing a spec, you can hold the whole system in your head because nothing exists yet. You can change your mind about the schema without rewriting code. You can spot that your dedup strategy conflicts with your auth model before either one is built.
Once implementation starts, your degrees of freedom shrink with every file you create. The spec-first approach means you’ve already used that freedom well.
The pattern since
Every subsequent phase of islet has followed the same approach. Phase 2 (the glucore analytics engine) was specced, reviewed and then implemented in waves. Phase 3 (replacing the Nightscout dependency) was planned against the existing spec rather than retrofitted.
At the time of writing, the project is in active development, runs 24/7 on a Raspberry Pi and handles live CGM data with a large automated test suite and staged operational hardening. Most major design decisions trace back to a document that existed before the code it describes.
I’m not claiming this approach works for everything. For exploratory work, for prototypes, for things where you don’t know what you’re building yet, start coding. But when you do know what you want and the system needs to be reliable, writing the spec first is high-leverage work you can do.
It’s not the fun part. But it’s the part that makes everything after it go smoothly.
Safety note: islet is a personal project and is not medical advice. It does not make dosing decisions.