Shipping Fast Without Cutting Corners

· 3 min read

The phrase “move fast and break things” did real damage to how people think about software quality. It set up a false choice: you can either ship quickly or you can build it right, pick one.

The engineers I respect most have figured out that this framing is wrong. Fast is a quality. An application that deploys in thirty seconds has a real advantage over one that takes thirty minutes — not just in developer experience, but in how tightly you can iterate on feedback. The goal isn’t to choose between speed and quality. It’s to figure out which corners actually matter.

Corners That Don’t Matter (Much)

Some things feel important while you’re building them but have almost no impact on users:

  • Perfect test coverage — 80% with the right 80% is worth more than 100% that tests implementation details instead of behavior
  • Pristine code architecture — a slightly awkward module boundary that you might refactor later is fine. An abstraction built for requirements you don’t have yet is expensive maintenance now
  • Zero tech debt — some tech debt is interest you’ll never pay because the code isn’t worth revisiting

The common thread: these are things that matter to engineers more than they matter to the people actually using what you build.

Corners That Do Matter

Some shortcuts look cheap now and are catastrophically expensive later:

  • Unclear error handling — undefined behavior under failure conditions is a time bomb
  • No observability — shipping without knowing what’s happening in production is flying blind
  • Data model assumptions that bake in wrong constraints — I once added a userId foreign key to a table that, six months later, needed to support records without users. The migration was painful

The pattern: anything that forces you to make assumptions about the future that turn out to be wrong.

A Concrete Example: PR Discipline

Here’s a place where I’ve seen teams buy a lot of speed cheaply: pull request discipline.

A team that ships fast doesn’t necessarily ship with giant PRs. In fact, the opposite is often true. Small, focused PRs ship faster because they’re easier to review, easier to test, and easier to revert when something goes wrong. The overhead of a hundred small PRs is lower than the overhead of ten massive ones.

Here’s a pattern that pays dividends: write the commit message before you write the code.

git commit -m "feat: add rate limiting to /api/auth/login

Limit: 10 requests per minute per IP.
Returns 429 with Retry-After header.
Resets on successful login."

Writing the message first forces you to articulate what you’re actually doing and why. If you can’t write the commit message, you don’t understand the change. If the message would be too long, the change is too big.

”Fast” as Feedback Loop Tightness

The real reason to care about shipping quickly is feedback. Every day between “we shipped this” and “users told us this is wrong” is a day you’re building on an untested assumption.

Speed isn’t about skipping the hard parts. It’s about minimizing the gap between a decision and evidence that the decision was right.

That reframe changes what you optimize for. Instead of “how do I write this faster?”, the question becomes “what’s the smallest thing I can ship that would tell me whether this approach works?” Sometimes the answer is a prototype. Sometimes it’s a feature flag that exposes a new behavior to 1% of users. Sometimes it’s a type signature or an interface before the implementation.

The corner you should never cut is the one that would prevent you from learning. Everything else is negotiable.