January 31, 2026
What Ultramarathons Taught Me About Building Software
Running 62 miles through the desert teaches you things about pacing and ignoring small problems. Turns out those lessons apply to code too.
I didn’t start running ultras to become a better engineer. I started because I like being outside and I’m stubborn in a way that responds well to training plans.
But somewhere around hour six of my first 100K, shuffling through the Arizona desert at 2am, I realized that the way these races punish bad decisions feels a lot like the way long software projects do. You make a choice early on, think you got away with it, and then it catches up to you at mile 45.
Going Out Too Fast
Every new ultrarunner learns this the hard way. You feel great at mile 10, so you run faster than your plan says. You’re borrowing energy you don’t have yet, and the interest rate is brutal.
I’ve done the same thing on software projects. Built abstractions before there were users. Solved problems that didn’t exist yet. Over-engineered things because I was “thinking ahead.” It feels responsible in the moment. But you’re just running too hard at mile three, and you pay for it later when the real work shows up.
Now I try to ship something small first. Learn from it. Resist the urge to sprint just because I can.
Small Problems That Become Big Problems
Most ultras don’t end with someone collapsing at the finish. They end quietly. A blister that got ignored. A tight achilles that turned into real pain. Something small that was easy to dismiss until it wasn’t.
Software fails the same way. A confusing interaction that nobody fixes. Tech debt that’s “not urgent.” A missing test that seems harmless. These things compound. By the time they demand attention, they’re expensive.
I’ve gotten better at noticing small signals early. In my legs and in a codebase. Fixing problems when they’re minor is almost always cheaper than waiting.
Systems Over Motivation
Nobody finishes an ultra on motivation alone. That fades somewhere around mile 40. What gets you through is boring stuff: a fueling plan, salt tablets every hour, drinking before you’re thirsty. You don’t negotiate with the plan mid-race. You just follow it.
I think about tests, code reviews, and CI pipelines the same way now. They’re not exciting. They’re the equivalent of eating a gel when you don’t feel like it. But they keep the system functioning when things get hard. Discipline beats inspiration every time.
Feeling Bad Doesn’t Mean Failing
One of the hardest things to learn in ultrarunning is that feeling terrible doesn’t mean you’re doing something wrong. Some of the most productive miles feel awful. You’re tired and uncomfortable but still moving forward.
The messy middle of a software project feels the same way. Refactors feel like regressions. Platform work feels invisible. Long migrations make it seem like nothing is shipping. Early in my career I took that discomfort as a sign something was broken. Now I just recognize it as part of the work.
Knowing When to Stop
There’s a version of endurance culture that glorifies never quitting. Push through everything. Finish at all costs.
That mindset breaks people.
Experience teaches you that stopping is sometimes the right call. Long-term health matters more than one finish line. The same is true with software. Killing a project, pausing a launch, or saying no to a feature can be the responsible choice. I used to think toughness meant never backing down. Now I think the real skill is judgment.
The Long Game
Running ultras didn’t make me a better engineer overnight. But it trained the same muscles: patience, restraint, respect for long timelines. I don’t sprint through projects anymore. I pace them. I pay attention to small problems. I build boring systems that keep working when things get uncomfortable.
Finishing strong matters more than starting fast. That’s true whether you’re 50 miles into a race or six months into a codebase.