Developing BikeOtter on the go thanks to Shorebird
Most of what BikeOtter does can only be tested outside, on a bike, with a head unit on the bars. With Shorebird that's no longer a problem. It's how I work now.
My test lab is a bike
BikeOtter is a Flutter app that talks to your bike computer (why I built it). A lot of it is normal app work that I can test at my desk. The important parts I can't.
A radar warning is about a car coming up behind you on a real road. Live tracking is about a phone losing signal in a valley and catching up again. Sending a route to a head unit is about a device that is busy recording a ride. I write tests for all of that, but to know if it really works, I have to ride with it.
For a long time that meant a slow loop: notice something on a ride, fix it in the evening at my desk, install the new build on my phone, and test it on the next ride.
The ideas come on the bike
Riding is also where I get most of my ideas. I'm an hour into a ride without a route loaded and think: the app knows I saved this loop, why doesn't it offer it to me? Or a car passes closer than I expected, and I think I should have heard it coming.
I don't wait until I'm home for that anymore. At the next stop I open T3 Code on my phone and describe the change to a coding agent (Claude Code) running on my Mac at home. It builds the change and runs the tests while I keep riding.
Soon I'd like to just speak to my Pebble smartwatch and tell it the ideas.
Shorebird closes the loop
This is the part that makes it work. BikeOtter ships with Shorebird, so a change to the Dart code goes out as an over-the-air patch. No laptop, no cable, no new build to install. At the next stop I push the patch, restart the app, and keep riding with the new version. So I can try an idea on the same ride I had it.
Three features went out exactly like that, tested on the same ride they were built on:
- Radar alerts: the tone in your headphones when a car comes up behind you. It didn't work at first. I sent my AI agent the logs, it was fixed within minutes, and afterwards I could fine tune it on real roads with real cars behind me.
- Your usual route: you start a ride without a route, the app notices which of your saved routes you're riding and offers to put it on the head unit.
- A fix for sending routes during a ride: a route didn't make it to a head unit while it was recording. That's a bug you only find outside, because at my desk nothing is recording.
None of these would be as good if every try had meant waiting until I'm back home at my desk.
Sending myself the logs
When something goes wrong on a ride, "it didn't work" isn't a bug report. Not even when it's my own. BikeOtter has a support chat in the app, and every message can include the app's diagnostic log. Riders use it to tell me what went wrong, and I use exactly the same button for myself.
So when something is off at kilometre 40, I send the log from the side of the road. When I stop for coffee, it's already on my Mac, and the agent that's going to fix it can read the same log I would. Bonus: the logging gets better every week. Whenever I can't figure out what happened from my own log, a rider's log wouldn't have helped me either.
Every restart is a test
One thing I didn't plan for: applying a patch means restarting the app. In the middle of a ride, with a route on the head unit, a live link open and a group watching my dot on the map.
The head unit keeps recording on its own. The app has to come back and continue exactly where it was: same ride, same live link, same route, same group. It should do that anyway, because phones kill apps in the background all the time. But that's easy to get wrong, and patching mid-ride tests it much harder than I ever would on purpose. If a restart loses something, I find the bug before a rider does.
What it can't do
Shorebird patches Dart code. If a change needs a new native plugin (a new audio library, a different Bluetooth setting), it still needs a full store release. Those go into planned releases instead of roadside patches. Honestly that's fine: most features are pure Dart, and the ones that aren't are worth planning anyway.
For everything else the loop is now one ride long. I have an idea on the bike, it gets built while I ride, and I test it on the road it's meant for. For an app like this that makes a huge difference.
Finish
builds BikeOtter. Want something on your rides? Put it on the wishlist, or read the other posts.