Skip to content

Engineering · 4 min read

We default to boring technology, and we can tell you exactly when we stop

Postgres before Kafka, monolith before microservices — and the specific signals that make us change our minds.

Why boring wins in year two

Boring technology is software that has been in wide production use long enough that its failure modes are known. Postgres is boring. A single deployable service is boring. Running a background job from a database table is boring. We reach for these first, and we do it on purpose.

The reason shows up in year two, not year one. In the first months, almost any stack can carry a demo. The bill comes later: when a new engineer has to understand the system in a week, when something breaks at 2am and someone has to diagnose it, when you need to hire three more people who already know the tools. Boring technology is cheap exactly here. The error messages are searchable, the operational playbook already exists, and the people who can run it are not rare.

Novel technology front-loads excitement and back-loads cost. Sometimes that trade is worth it. Usually it is not, and the honest default is the one that keeps the system cheap to operate and cheap to staff for years, not the one that looks sharpest in a kickoff slide.

Postgres before Kafka

Most teams who ask for a streaming platform on day one do not yet have a streaming problem. They have a queue of work to process and a worry that the database will not keep up.

Postgres handles far more than people expect. It will run your relational data, a job queue, full-text search, and a pub/sub channel, all with one system to back up, monitor and reason about. That is a real saving: every additional piece of infrastructure is another thing to secure, patch, and wake someone up for. Starting with one well-understood database means fewer moving parts while you are still learning what the product actually needs.

So we start there, and we measure. If the numbers later say the database is the wrong tool for a genuine stream, we move that part, with data to back the decision.

Want this math run against your actual project? The estimator returns a written range.

Get my cost range

Monolith before microservices

The same logic applies to how the code is split. We start with a single, well-organized deployable, with clear module boundaries inside it, rather than a set of independent services.

Microservices solve a specific set of problems: teams that need to deploy independently, components with genuinely different scaling needs, and blast-radius isolation for critical paths. They also add a tax that is easy to underestimate. A call that was a function in one process becomes a network request that can time out, retry, or half-succeed. A change that touched one codebase now touches three, each with its own deploy and its own version. For a small team still finding the shape of the product, that tax buys very little and slows everything down.

Clear module boundaries inside a monolith give you most of the design discipline of services with none of the distributed-systems cost. When a boundary later proves it needs to scale or deploy on its own, you lift it out along a line that is already drawn. You pay for the complexity when you have the problem it solves, not before.

The signals that make us switch

Defaulting to boring is not the same as refusing to change. We change when the evidence is there, and we try to name the signal in advance so the decision is not a matter of taste.

  • A measured limit, not a guessed one. When profiling shows a component is genuinely constrained, and tuning the boring option has run out, we move that component. The trigger is a number, not a hunch.
  • A real team boundary. When two teams are blocking each other on the same deploy often enough to slow both down, independent deployment starts to pay for itself, and we split along that line.
  • Diverging scaling needs. When one part of the system needs very different resources from the rest, isolating it stops the cheap parts from paying for the expensive one.
  • A failure that must be contained. When one path is critical enough that its outage cannot be allowed to take down the rest, we isolate it on purpose.

Notice what is missing from that list: that the new thing is interesting, that a competitor uses it, or that it would look good in an architecture diagram. Those are not signals. They are reasons people adopt technology they later regret.

Our commitment is not to boring for its own sake. It is to being able to tell you, in plain terms, why we chose what we chose, and exactly what would make us choose differently. That is the version of a technical decision you can actually hold us to.

Reading is research

Got a project that needs this kind of thinking?

Send two sentences. The engineer who replies may be the one who wrote the article.

ContactCost rangeSend brief