Why We Ship Fast (Without Cutting Corners)
Most people think speed and quality are opposites. I disagree. Here's how a small team stays fast while still sweating the details.
There’s a myth in software development: you can have it fast, or you can have it good. Pick one.
I’ve never bought into that.
At ZADIE, we ship fast and we obsess over details. Not because we’re superhuman, but because we’ve learned some hard lessons about what actually matters.
I learned this the hard way
A few years ago, I decided to rewrite Tattoo Studio Pro from scratch. The existing codebase had grown unwieldy. I had a vision for something cleaner, more powerful, better in every way.
So I went into hiding.
For two years.
I told myself I was building something great. And I was, technically. But while I was heads-down perfecting my grand vision, I wasn’t shipping. I wasn’t learning from users. I wasn’t iterating on feedback in real time the way I did in the early days.
When I finally emerged, I had a beautiful product. But I’d also spent two years not improving the thing my customers were actually using. Two years of features I could have shipped. Two years of lessons I could have learned.
Never again.
Ship small, ship often
The lesson wasn’t “move faster.” The lesson was “don’t ship huge.”
Big releases are seductive. They feel important. You get to unveil something dramatic, make a splash, impress people with how much you’ve done.
But big releases are also risky. You’re betting months of work on assumptions you haven’t validated. You’re accumulating changes that interact in ways you can’t predict. You’re delaying feedback that could have changed your direction.
Now we ship small. A feature here, an improvement there. Each release is focused, testable, and reversible if something goes wrong.
This doesn’t mean we lack ambition. We still build big things. We just build them in small pieces, learning as we go.
Speed is a feature
When you move fast, you learn fast. Every week something sits in development is a week you’re not learning from real users.
I’ve watched teams spend months perfecting features that users didn’t want. That’s not quality. That’s waste.
Real quality comes from iteration. Ship something good, watch how people use it, make it better. Repeat. The product that’s been through ten iterations will always beat the product that was “perfected” in isolation.
Choosing the right tool for the job
Speed isn’t just about working faster. It’s about not creating unnecessary work in the first place.
Every technology choice has trade-offs. The hot new framework might have a great developer experience, but also a steep learning curve and immature ecosystem. The boring old technology might feel less exciting, but you know exactly how it behaves and where to find help when things go wrong.
I pick tools based on the job, not the hype. Sometimes that means using the latest thing. Sometimes it means reaching for something battle-tested. The goal is always the same: get to a working product with the least friction possible.
This applies to architecture too. I don’t build elaborate systems for problems we don’t have yet. I don’t add abstraction layers “in case we need them later.” We build what we need now and trust ourselves to adapt when requirements change.
Saying no to what doesn’t matter
Every feature has a cost. Not just the time to build it, but the time to maintain it, document it, support it, and work around it when building other features.
Most features aren’t worth that cost.
I say no a lot. Not because I don’t care about our users, but because I care about all of them. Every feature request comes from someone with a real need. But adding that feature means adding complexity for everyone, including the people who don’t need it.
The best products aren’t the ones with the most features. They’re the ones that do a few things exceptionally well. Every feature we add makes it harder to maintain that focus.
So I ask: does this help most users do the core thing better? If not, it’s probably a no.
The 80/20 rule for features
When we do decide to build something, I think carefully about scope.
Most features have a core that delivers 80% of the value with 20% of the effort. Then there’s the long tail of edge cases, customization options, and nice-to-haves that consume the remaining 80% of effort for 20% of the value.
We ship the core first.
Sometimes that’s enough. Users get the value they need, and we move on to the next thing. Sometimes users ask for more, and we iterate. But we never build the complete, fully-featured version upfront.
This isn’t about shipping incomplete work. The core should be polished, well-designed, and genuinely useful. It’s about recognizing that “complete” is a moving target and that shipping something valuable today beats shipping something perfect someday.
Where we spend time
Not everything deserves the same attention. I’ve learned to identify the work that matters most:
- First impressions. Loading states, empty states, error messages. The moments when users form opinions about your product. These should feel intentional, not like an afterthought.
- Core loops. The thing users do most often. If your app is for scheduling appointments, the scheduling flow better be seamless. Everything else is secondary.
- The details that compound. Small touches that make the product feel crafted. Thoughtful animations, smart defaults, helpful microcopy. Individually they’re minor. Together they’re the difference between software that feels good and software that just works.
We obsess over these things. Everything else gets good enough and moves on.
Small teams move faster
We don’t have layers of approval. No design committee. No stakeholder alignment meetings.
Someone has an idea, we talk about it, we build it. Sometimes that conversation takes five minutes.
This isn’t chaos. It’s trust. Everyone on the team understands what we’re building and why. We can make decisions quickly because we share the same context.
Big organizations need process to stay coordinated. We stay coordinated by staying small and staying in sync.
The real trade-off
Fast vs. good is the wrong frame. The real trade-off is between shipping something that works today or perfecting something that might never ship.
I’ll take the first one every time.
Not because I don’t care about quality. Because I’ve learned that quality comes from iteration, not isolation. Because I’ve felt the pain of building in the dark for too long. Because our users are better served by steady improvements than by waiting for the perfect release that’s always six months away.
Ship small. Ship often. Make each small thing as good as it can be.
That’s how we work. That’s why we ship fast.