Escaping the Complexity Trap

12 Feb 2021

The trap closes in stages. We obviously need X - which, as it turns out, requires Y, which means Z1 and Z2, and before anyone knows what’s going on, we’re weeks deep in a “simple feature”.

When that starts to happen, it’s worth revisiting X to see if there’s another way. Software development is like a depth-first traversal of a maze - after all, you’re generally interested in reaching the exit as quickly as possible, not in the overall shortest path - but if a path starts getting longer, a bit more breadth-first time can be worthwhile.

A worked example

The user (me) requires a device that indicates whether or not it’s after 5am, without conveying any other information[1], or disturbing sleep.

Additional requirement: it must be reliable and fail-safe. If I don’t trust it, I’ll go back to checking the time.

First pass

Use a phone, ideally a webapp. Doesn’t work; the phone will lock overnight. If we switch to native code and use a scheduled notification to wake it up, then even on silent mode the screen will glow and wake me up. If we use a webapp but configure the phone to never sleep (eg with a silent, looping, 1px movie), the screen backlight is still too bright. Also, phones are complex, fragile systems and won’t be reliable enough.

Second pass

Use a raspberry pi. Massive overkill, but sure. A ruby script polls every minute or so and controls the onboard indicator LED. The LED flashes slowly overnight (to confirm that it’s working), and goes steady at 5am, and it’s dim enough to not be visible unless you’re awake and looking for it.

Problem: After brief experimentation, the Pi doesn’t have a backup battery for its realtime clock. Further consultation with the user reveals that part of the “reliable” constraint is “Don’t require any action other than plugging into power, and don’t assume that power is present during the day”. The Pi won’t know when it’s 5am.

The trap closes

Options now include “solder on a battery-backed RTC to the GPIO pins”. But I’d much rather solve problems with software than hardware.

We’ll connect the Pi to wifi, and it’ll get the time via NTP on startup.

This “simple” task turns complex; though it’s a Pi Zero W, it can’t see my router on its default frequency. I do end up getting it working (via reconfiguring the router), but it’s a ludicrously overcomplicated and fragile solution and it took longer than it should have.

It also requires a full 5W of power, meaning a full-size USB adapter (not a tiny phone charger). And it’s dependent on my local wifi network, so it won’t work when travelling, once that’s a thing again.

Worse, with an initial solution in place, the user starts coming up with enhancements. Since we’re running a full computer now, we could create a web interface, accessible from a phone, to allow configuring the alert time. If I go to bed late, perhaps that shouldn’t be until 05:30.

Totally doable, but… seems awkward, and triggers my “this is harder than I think it should be” alarm. Time to revisit the design.

Going back to the beginning

If the user requirement is actually “toggle the LED in 6.5 hours”, not “toggle the LED at 5am”, none of this is necessary.

The third pass uses a Raspberry Pico microcontroller, and uses the lack-of-power-during-the-day as a feature. 6.5 hours after you plug it in, it toggles the LED. Though there’s an onboard button (and plenty of pins to solder on more), it’s not even needed.

It’s a much neater solution, and working well in production.


[1]: Being able to repeatedly check the actual time during the night makes insomnia worse. But giving up at 4am makes for a bad day. A reasonable compromise is “after 5am, you may (rather than must, which is how normal alarm clocks work) get up”.