Post-Mortems

Retrospectives & Lessons

Most of what I know came from the work that didn't go well. These are a few of those moments — the ones I think about when I'm about to make the same mistake again.

012022
Context:An early greenfield project, six weeks in.

I shipped the wrong abstraction.

I built a beautifully generic table component before I knew what the second use case actually needed. It had props for everything — sorting, grouping, virtualization, inline edit, column permissions. None of which we used.

When the second team finally adopted it, their needs didn't fit the shape I'd guessed at. We forked it within a sprint.

The Core Lesson

Wait for the second instance before you abstract. The cost of a small duplication is almost always lower than the cost of the wrong shared shape.

022023
Context:A dashboard rewrite I led for two months.

I optimized for the wrong metric.

I obsessed over Lighthouse scores. We hit 99 across the board and I was proud of it. The team using the dashboard told me — politely — that the new version felt slower.

Time to interactive looked great on a cold load, but the things they actually did all day — filtering, jumping between tabs — were a few hundred milliseconds slower than before.

The Core Lesson

Pick the metric the user actually feels. A score is a proxy. The proxy is not the thing.

032023
Context:A redesign with a tight deadline.

I didn't push back when I should have.

We knew the navigation pattern was going to confuse users. We had the research. I raised it once, got a polite nod, and let it ship.

Three weeks after launch, support tickets told the story everyone in the room had already been told.

The Core Lesson

Saying it once is not the same as making sure it landed. Quiet engineers are a liability the team is paying for, even if they don't know it yet.

042024
Context:A content tool used by editors every day.

I underestimated empty states.

The happy paths were polished. Loading states were thoughtful. The first real user opened the tool with no content yet and stared at a blank page with no instruction at all.

I'd treated empty states as a thing to do later. Later never came in time.

The Core Lesson

Empty, loading, and error states are not edge cases — they are the first thing every new user sees. Design them first, not last.

052024
Context:A pricing page A/B test.

I trusted my taste over the data.

I was sure the cleaner, more typographic variant would win. It looked better to me. Six weeks of traffic later, the noisier, busier version converted noticeably better. I'd been protecting my own aesthetic at the expense of the people the page was for.

I still believe the quiet version is the better design. But it wasn't the better page for that audience, and it wasn't my call to make alone.

The Core Lesson

Your taste is one input, not the answer. The page belongs to the people using it, not the person who made it.

062025
Context:A legacy admin tool nobody wanted to touch.

I rewrote what I should have refactored.

I convinced myself the codebase was past saving. I scoped a rewrite, sold it, and started fresh. Eight months later we had a beautiful new app that was missing half the quiet features the old one had grown over five years.

A patient refactor would have been slower week to week and faster overall. I learned that the hard way.

The Core Lesson

A rewrite is a bet that you understand the old system better than the people who built it. Most of the time, you don't.

The way I work

If any of this resonates, the way I work now grew out of these moments