The best architecture I have ever shipped is the kind nobody noticed. No launch post, no clever diagram passed around the office, no war story. It simply worked, kept working, and stayed out of the way. I learned to value that the slow way, by failing in both directions at once: building far too much, and building far too little.
Early on, I shipped beautiful solutions to problems that did not exist yet. Abstractions for requirements that never arrived. Flexibility nobody had asked for, paid for in complexity everybody then had to carry. Later, trying not to repeat that, I made the opposite mistake. I built services so narrow, so tightly fitted to the one application that needed them, that the day a second consumer showed up they simply shattered. Two failures that look like opposites. They turned out to be the same failure wearing different clothes: a misread of what the moment actually needed.
Good architecture lives in that judgment, and most of it comes down to two sentences an architect has to learn to say at the right time. "Not now" to the complexity that has not been earned yet. And "yes, properly" to the few foundations that are ruinous to add later. Knowing which sentence the moment calls for is, more than any pattern or any stack, the actual job.
Saying Not Now Is Harder Than Saying Yes
Overengineering is real, and it rarely arrives looking like a mistake. It arrives looking like ambition. Saying yes to a great idea feels generous and forward-thinking; saying "not now" feels like you are the person standing in the way of progress. That asymmetry is exactly why overbuilding is the more seductive failure. Nobody writes a retrospective praising the abstraction they did not build.
So I have had to make my own definition of pragmatism concrete enough to act on, and it is deliberately unglamorous. It means building for today without blocking tomorrow. Solving real, validated problems rather than imagined ones. Being genuinely at peace with a version one, as long as it works and is honest about what it is. And keeping the whole thing understandable for the teams that have to depend on it, because cleverness they cannot follow is not a gift, it is a tax. You can write your own version of that list. The point is to have one, and to hold your designs against it before you fall in love with them.
"Not now" is not the same as "no, never." It is a deferral with a trigger attached: we will build this the day a real problem actually asks for it, and not one sprint before. The harder cousin of this question, when to keep optimising the engine you have versus build a different machine entirely, I have written about separately in five stepping stones to systems that last. This piece is about the smaller, daily decision that keeps you out of that corner in the first place.
Build a Platform, Not a Project
Restraint, though, is not an excuse to build too small, and that is the second failure I had to learn the hard way. It was the early days of adopting microservices, back when the books were few, battle-tested strategies were rare, and most blog posts left you more confused than before. We had a handful of inspirational design guides, mostly from Martin Fowler and Chris Richardson, and otherwise we were figuring it out as we went. Our strategy was not copied from a playbook. It was trial, error, and the occasional "what were we thinking" retrospective.
Through those years, and through a lot of conversations at community events and knowledge-sharing evenings, I kept noticing the same trap that many teams, mine included, fell into. We built services like projects. Each one custom-fit to a specific use case, tightly coupled to the single application that needed it. And it worked, right up until it did not. The moment we tried to scale or reuse one of those services for a different consumer, the cracks showed: contracts that would not flex, assumptions nobody had written down, logic too rigid to stretch beyond the context it was born in.
That was when it landed. Building services like one-off projects gets you exactly as far as the first use case and no further. Building them like platform capabilities is what sets you up to scale. The difference is a handful of habits: services designed for reuse and autonomy, clear domain-driven boundaries, contracts defined well enough to stay stable for years, and a product mindset applied even to internal tools that no outside customer will ever see. The mechanics of getting there, the readiness it takes and the contracts that hold, I have written about in are you ready for microservices and your API's users are developers. The shift itself is smaller and harder than any of it: stop shipping a project, start growing a capability. The result was fewer rebuilds, more stability, and happier teams.
The Line Between Too Much and Too Little
Here is where the two sentences look like they contradict each other. "Not now" says do not build for the future. "Platform, not project" says build for the future. Both are right, and the whole craft is in the line between them, because they are aimed at different things. You say "not now" to speculative features and abstractions. You say "yes, now" to foundations. The first is cheap to add later and expensive to carry early. The second is cheap to get right early and ruinous to retrofit.
- An abstraction for a requirement that has not arrived
- Configurability nobody has asked for
- A second datastore before the first is full
- Generalising from a single example
- Flexibility added because it is interesting, not needed
- Clear domain boundaries
- The contract between two teams
- Who owns which data
- The seams where you genuinely expect change
- The observability that tells you when you were wrong
Five stepping stones calls those investments seams: deliberate boundaries placed where the most uncertainty lives, so that decisions you have not made yet land somewhere designed to absorb them. What I want to add here is the test for telling a seam apart from overengineering wearing a respectable coat. A foundation earns its place now when two things are true at once: it would be genuinely expensive to retrofit, and you have at least one real, present reason to believe the second use case is coming. If only the first is true, you are guessing. If neither is, you are decorating. Everything else can wait for the problem to introduce itself.
Design With Humility, Ship With Intent
This is the one value system I have carried unchanged across search and checkout and payments and banking: think long-term, design with merit and intent, but without dragging in overhead, and always leave room for the decisions that have not been made yet. The companies changed, the domains changed, the scale changed. The discipline did not.
Humility and intent are the two halves of it, and they pull in opposite directions on purpose. Humility is the admission that you cannot see the future clearly, so you refuse to overbuild for your own guesses about it. Intent is the recognition that a few things genuinely must be right from the start, so you build those deliberately and well. Hold only humility and you ship timid, short-sighted projects. Hold only intent and you ship cathedrals to your own cleverness that nobody can afford to change. Hold both and you get architecture that carries exactly enough.
Which brings me back to the invisible architecture I started with. It is invisible precisely because it carries exactly enough. No monument to the architect who built it, and no debt left by the architect who rushed it. Just a system that does its job today and has quiet room to do tomorrow's, whenever tomorrow decides to show up.
Build for the future. Just not all of it today.