Four architectural choices that made sense when they were made and are now generating technical debt at scale.
Software architecture is a set of bets about the future — about what the system will need to do, at what scale, under what constraints, and with what team.
Some of those bets age well. Others do not.
The following four architectural decisions were each, in their time, defensible — often enthusiastically adopted as best practices. They are now generating significant operational cost for the organisations that made them, and the organisations that can identify and address them early are recovering delivery velocity that has been silently consumed for years.
1. Microservices at the Wrong Scale
The microservices movement produced genuine improvements for organisations operating at the scale where distributed, independently deployable services addressed real operational constraints. For large organisations with hundreds of engineers and complex, heterogeneous technical requirements, the microservices architecture enabled independent team scaling, isolated deployment, and technology diversity that genuinely mattered.
For smaller organisations — and for larger organisations in their earlier stages — many microservices adoptions were premature optimisations. The distributed systems complexity, the inter-service communication overhead, the operational burden of running dozens of independently deployed services, and the latency introduced by network calls that replaced function calls all imposed costs that only justified themselves at scales the organisation had not yet reached.
The consequence, now visible across the industry, is a significant cohort of engineering teams operating distributed monoliths — systems that have the operational complexity of microservices without the team scale or technology heterogeneity that would make that complexity worthwhile.
The decision now facing these teams is not simple. The architecture is in place, the services have accumulated operational history, and the dependencies between them make consolidation non-trivial. But the teams that are honestly evaluating their microservices architecture against their actual scale and operational reality are finding, consistently, that consolidation of closely-coupled services reduces operational overhead without meaningful reduction in the flexibility that the architecture was supposed to provide.
2. MongoDB for Everything
The NoSQL enthusiasm of the early 2010s produced a generation of applications built on document databases — particularly MongoDB — that were selected for their flexibility and developer friendliness at a stage of product development when schema fluidity genuinely mattered.
A decade later, many of these applications have evolved to the point where the schema is effectively fixed, the data relationships are complex and well-understood, and the document model's flexibility is no longer the primary concern. What the applications now require is the transactional integrity, complex query capability, and relational data model that document databases were specifically designed not to provide.
The migration cost is real — not because document databases are technically inferior to relational ones, but because years of accumulated data in a document model does not translate cleanly to a relational schema, and the application logic that was built around document semantics requires rework.
The teams that are addressing this most effectively are not attempting wholesale database migration. They are introducing relational stores incrementally for the parts of the data model where relational semantics are most needed, while maintaining document storage for the parts where flexibility remains genuinely valuable.
3. JWT Tokens Everywhere
JSON Web Tokens became the default authentication mechanism for a wide range of applications in the mid-2010s, and for good reasons: stateless authentication scaled well, reduced database load, and fit naturally with the API-first architectures that were becoming dominant.
The design trade-off that was not fully reckoned with at the time — and that is generating significant operational cost now — is that JWTs cannot be revoked before they expire.
For long-lived tokens, this creates an operational reality where a compromised credential remains valid until its expiry, a user who logs out is not actually logged out in the traditional sense, and permission changes for a user do not take effect until their current token expires. In applications where security posture matters — and the list of applications where it genuinely does not is shorter than many teams assume — this trade-off is increasingly difficult to justify.
The retrofit is unglamorous: token allowlists or short-lived tokens with refresh mechanisms, both of which reintroduce the stateful server-side lookups that JWTs were adopted to avoid. But it is the honest response to an architectural choice that traded long-term security posture for short-term scaling convenience.
4. Configuration in Environment Variables, Arbitrarily
Twelve-factor app methodology made environment variables the canonical mechanism for application configuration, and the principle was sound: externalise configuration from code, and manage it consistently across environments.
What the principle did not address was the operational reality of managing hundreds of environment variables across dozens of services, multiple deployment environments, and teams that were not all operating with the same level of operational discipline.
The consequence is a configuration management landscape that, in many organisations, has grown beyond the point where anyone has a complete picture of what is configured where. Secrets are mixed with non-sensitive configuration. Configuration values are duplicated across services with no single source of truth. Changes require coordination across multiple deployment configurations. Auditing what configuration existed at a specific point in time is difficult or impossible.
The responses that are gaining adoption — dedicated secrets management tooling, centralised configuration services, explicit separation of secrets from configuration — are not architectural novelties. They are the operational maturity that the environment variable approach was always going to require at scale, and that many teams deferred until the cost of the deferral became unavoidable.
The Common Thread
These four decisions share a common characteristic: they were each the right choice at a specific stage, for specific reasons, and became technical debt not because they were wrong when they were made but because they were not revisited as the context that justified them changed.
The architectural decision that was appropriate for a ten-person team building to product-market fit is often the wrong architecture for a hundred-person team optimising for reliability and delivery velocity. The question is not whether a decision was correct at the time. The question is whether the conditions that made it correct still apply.
Regular, honest architectural review — evaluating current decisions against current context rather than against the context in which they were made — is the practice that keeps accumulating technical debt visible and manageable.
WiseAccelerate brings architectural review discipline to every engagement — helping teams see clearly what is working, what has aged poorly, and what the highest-leverage improvements are.
→ Which of these four architectural decisions has your team encountered — and what was the remediation approach that worked?
Top comments (0)