← Back to posts

Shipping at the Speed of Thought

I used to spend weeks planning architecture before writing a single line of code. Diagrams, documents, meetings about the diagrams, meetings about the meetings. By the time I shipped, the requirements had changed.

Then something clicked.

The cost of premature abstraction

The biggest lie in software engineering is that you need to get the architecture right from the start. You don’t. You need to get it right enough to learn from real usage.

Every abstraction you introduce before you have data is a bet. And most of those bets are wrong.

// What I used to write
class AbstractRepositoryFactoryProvider {
  // 200 lines of "flexibility" nobody needed
}

// What I write now
async function getUser(id) {
  return db.users.find(id);
}

The new stack mentality

Modern tools have fundamentally changed the economics of building software:

  1. Deployment is instant — push to main, it’s live in seconds
  2. Rollback is trivial — bad deploy? One click to undo
  3. Iteration is cheap — change anything, see results immediately
  4. AI assists the boring parts — boilerplate writes itself

This means the cost of trying something has collapsed. The rational strategy shifted from “plan extensively” to “ship and learn.”

What I actually do now

My process looks like this:

  1. Identify the core interaction — what’s the one thing users need to do?
  2. Build the simplest version — no auth, no edge cases, no settings
  3. Put it in front of people — even if it’s embarrassing
  4. Listen to what breaks — real bugs tell you what matters
  5. Iterate ruthlessly — add complexity only when earned

This isn’t “move fast and break things.” It’s move deliberately and learn faster than you break things.

The architecture emerges

Here’s the counterintuitive part: the codebases I’m proudest of weren’t designed upfront. They emerged from constraints discovered through shipping.

Good architecture is extracted, not invented.

When you let patterns emerge from real usage, you end up with systems that are simpler, more focused, and easier to change than anything you’d design in a vacuum.

Practical advice

If you’re starting a new project today:

  • Skip the monorepo until you have a reason for one
  • Skip the microservices until a single service can’t handle the load
  • Skip the design system until you’ve built the same component three times
  • Skip the abstraction until duplication actually hurts

Start concrete. Let the codebase tell you what it wants to become. You’ll be surprised how often the simple thing is the right thing.