On architecture

Complexity should be earned

Architecture should fit the actual problem - and the honest version of that sentence means most projects deserve less architecture than they get.

Every technical decision carries follow-on cost. Frameworks need updating, build pipelines can fail, dependencies bring new security risks, and abstractions never behave as cleanly as planned in every case. That is not an argument against sophisticated tools. It only means extra complexity has to be maintained, continuously.

Even so, it is often not chosen deliberately. A simple marketing site then starts with a server-side framework, a state-management library and a full CI pipeline - before anyone has asked how often the content will actually change. The technical foundation does not come from the real need. It is taken from the last project, or from whichever architecture trend is current.

The result is systems that are expensive to change and, paradoxically, are therefore rarely changed.

So I try to start with the simplest architecture that can reliably carry a project. Each extra layer should solve a concrete problem that exists today - not one that might appear later. And certainly not one that mainly looks good on a CV.

This site is the simplest example. The portfolio is HTML5, CSS and vanilla JavaScript. There is no framework, no build process and no backend. Any file can be opened, edited and reloaded in the browser. Deployment is essentially putting files in place.

Of course the site could also have been built with Next.js. The better question is: what would that improve?

The content changes a few times a month. Interaction is limited to navigation and a few quiet scroll effects. A framework would bring a node_modules directory, extra configuration and regular dependency updates - in exchange for capabilities this site does not need. For a static publication, React would not be an improvement. It would be extra work.

That is not a criticism of React. It is a criticism of making a technical decision before the problem has even been described.

The deliberate constraint also had an effect I had not fully counted on: it forces clarity. Without a component library, you have to decide how typography, spacing and hierarchy work. Without a build process, there are fewer technical layers for a bug to hide behind. You work closer to the thing itself.

On commercial decision infrastructure, the same question carried more weight. The company needed reliable margin and pricing analysis from real purchasing documents, plus a revenue and cash-flow forecast.

The obvious answer would have been a bundle of SaaS products: one for document recognition, one for BI dashboards, another for forecasting. Then those tools would have to be kept wired together, permanently, so their data and assumptions still lined up.

Instead, two small, locally run applications were built.

Margin & Pricing Intelligence processes around 1,000 real PDF invoices in 74 seconds and makes visible what the company actually pays for its products, and what margin that produces.

Revenue & Cash-Flow Intelligence supports revenue planning, seasonal expectations and scenario analysis. Across the full year, the forecast sat only 2.1 percent away from the net revenue later actually achieved. If someone had promised me that result in advance, I would probably have been skeptical.

By conventional engineering standards these are not spectacular applications. Their value is how closely they fit the problem. Both do a clearly defined job with data the company owns. There are no per-user fees, no feature requests sitting in an external vendor’s backlog, and no painful export of your own data from someone else’s system. The wider context is described under Commercial Intelligence.

That does not mean internal applications are always the right answer. They have weaknesses too. They can depend too heavily on the people who built them, and over time become hard-to-maintain legacy systems without anyone quite noticing.

So the decision is not, in principle, “build it” or “rent software.” Both options should have to make the same case: why does this solution fit the actual problem better?

Sometimes the problem does justify a more demanding architecture. Google Performance Intelligence uses MCP with OAuth, several specialist agents and an orchestrator. That is substantially more architecture than most of the other systems I run.

In this case, though, each extra layer has a clear job. The agents need authenticated, scoped access to three different Google platforms. Orchestration is required because the real value only appears when several sources are analysed together. The permission model matters because it states, unambiguously, what an agent may do on its own - and what it may not.

Just as important are the cases where I deliberately refused that kind of architecture. Several neighbouring workflows could technically have been attached to the same orchestration. Some of them already ran reliably with a scheduled script and a spreadsheet. An extra integration would not have created real value there. It would have been architecture in search of a problem.

Technical restraint does not show itself in the absence of sophisticated options. It shows itself in declining them when they are available and interesting.

Before any extra layer, I therefore try to answer a simple question:

What concrete problem does it solve that the simpler version cannot?

“We need scalability” is not yet a concrete problem.

“We process a thousand invoices, and the current process takes eleven minutes” is.

If the answer can only be put vaguely, the need is probably still vague. Extra architecture then quickly becomes technical debt that has merely been sold better.

Complexity should come from the problem - not from the tool you happen to want to use.

This is not a case for primitive systems. It is a case for proportionate ones: architecture whose ambition can be explained by pointing at the problem, not at the ecosystem in use.

The best architectures I have shipped were usually almost invisible to the people using them. The worst often looked especially impressive on a diagram.