Skip to main content

About

I started out building applications. Not architecting platforms, not designing distributed systems — just writing features, fixing bugs, and shipping things people actually used. Most of that was Java, and I spent enough years in it to develop the habits that come from operating long-lived services: watching memory behaviour, reasoning about concurrency, and reading thread dumps at unhelpful hours. That’s still the part I enjoy most, and I think it quietly shaped everything that came after. When your first instinct is “what does this do for the person using it,” you end up asking different questions later, when the systems get bigger and the answers get less obvious.

How I got here
#

The move from application work into cloud and distributed systems wasn’t a career plan. It was the natural consequence of applications getting harder to run. One service became several. Deployments stopped being a thing you did on a Friday afternoon and became something that needed to be boring and repeatable. State moved out of the process and into somewhere you had to reason about carefully. Each of those shifts was a problem I had to understand to keep doing the job I already had, and somewhere along the way, understanding them became the job.

Data followed the same path. Applications generate data, and eventually somebody wants to do something useful with it — reporting, analytics, and now models. I got pulled into data platforms because the systems I was building were producing the inputs, and the seams between “the app” and “the pipeline” were where things broke. Working on both sides of that seam taught me something I still believe: most production incidents that look like application problems are data problems wearing a costume. A schema changed. A field that was never supposed to be null was null. A batch ran twice.

AI-enabled software is the current version of that same story. The interesting engineering problem isn’t the model — it’s everything around it. Where does the context come from, and is it fresh? How do you know the output got worse? What happens when it fails in a way that isn’t an exception, just a quietly wrong answer? Those are data and reliability questions, which is probably why the work feels familiar rather than foreign.

What I’ve come to believe
#

A few opinions I’ve arrived at the hard way, and hold loosely enough to argue about:

Simple systems win on a long enough timeline. Not simple to build — simple to understand six months later, at 3am, by someone who wasn’t there when it was written. Clever code is a loan taken out against your future self’s patience.

If it’s hard to debug, that’s a design bug. Observability isn’t something you bolt on after an incident. Whether a system can be understood while it’s running is a property you decide at design time, and it’s much cheaper to decide it early. I’d rather ship something small and observable than something ambitious and opaque.

Maintainability is a feature with no ticket. Nobody ever files a request for “code that’s pleasant to change,” which is exactly why it gets sacrificed first. It’s also the thing that determines whether a team is still moving quickly two years in.

Developer productivity is not a soft concern. Slow feedback loops don’t just waste time — they change behavior. When a test suite takes forever, people stop running it. When deploys are scary, they get batched, which makes them scarier. A lot of what looks like a discipline problem is actually a tooling problem.

What I’m working through now
#

I’m currently spending time on evaluation — specifically, how you tell whether an AI-enabled feature is working when there’s no clean ground truth to compare against. It’s an unsatisfying problem in a way I find genuinely interesting: the honest answer usually involves proxy metrics and human review, and every option has a failure mode you have to be upfront about.

I’m also thinking a lot about the cost side of observability. It’s easy to instrument everything and end up with a bill and a dashboard nobody reads. Deciding what not to measure turns out to be the harder skill.

Beyond that, I read a lot and try things. Learning new technology has never felt like a chore to me — though I’ve become more skeptical with time about adopting things quickly. The good ideas tend to still be good in two years.

Away from the keyboard
#

I ride a lot. Cycling is the closest thing I have to a reset button — it’s one of the few activities where the problem in front of me is entirely physical and completely solvable by pedaling.

The rest of my spare time tends to end up in the garage or somewhere in the house with the trim off. I like cars, and I like working on them, which are two separate hobbies that occasionally overlap. Same with DIY and home improvement projects — furniture, repairs, the ambitious weekend plan that becomes a three-weekend plan.

I’ve stopped pretending this is unrelated to the day job. Taking something apart to understand why it stopped working is the same instinct either way, and physical projects are usefully humbling. A brake job doesn’t care how confident you feel. There’s no rolling back a cut you’ve already made, which makes you measure properly the first time — a habit I wish transferred more cleanly to production changes than it does.

Getting in touch
#

I’m always up for a conversation about interesting engineering problems, speaking opportunities, or open source. The contact page has the details, or you can find me on GitHub and LinkedIn.

Related