We Know Better. So Why Do We Keep Building the Same Broken Architectures?

We Know Better. So Why Do We Keep Building the Same Broken Architectures?

Tight coupling, god objects, premature abstraction, we’ve documented every architectural sin. Here’s why teams keep repeating them, and what AI changes about the equation.

We Know Better. So Why Do We Keep Building the Same Broken Architectures?

There’s a special kind of frustration that comes from walking into a codebase and finding a God Object that’s been there since 2014. You know it’s wrong. Everyone who’s touched it knows it’s wrong. There’s probably a ticket somewhere titled “Refactor UserManager” that’s been reprioritized into oblivion for four consecutive quarters.

The industry has spent decades documenting these failures. Anti-pattern books, conference talks, blog posts, linters, architecture decision records, we’ve built an entire ecosystem dedicated to preventing the same mistakes. And yet, every new project, every startup, every “greenfield opportunity” ends up with the same spaghetti code, the same tight coupling, the same premature abstraction that we swore we’d never build again.

This isn’t a knowledge problem. It’s a behavioral one.

The “Technical Debt” Cop-Out

Let’s start by calling out the elephant in the room: most of what teams call technical debt isn’t debt at all. It’s mess.

In a recent essay, software consultant Nat Bennett made this distinction painfully clear. Financial debt has terms. You know exactly how much you borrowed, what the interest rate is, and when the payment is due. Most technical decisions don’t work that way. When a team chooses to skip writing tests because management is breathing down their neck, that’s not taking on debt, that’s just leaving a mess for future-you to clean up.

The “debt” metaphor is actively harmful because it implies intentionality and predictability. Teams tell themselves they’re making a strategic trade-off when they’re really just deferring the inevitable. The problem with calling it debt is that businesses understand debt. They know how to manage it, amortize it, and eventually pay it off. Mess doesn’t work that way. Mess compounds unpredictably and collects interest at rates no one disclosed.

As Bennett puts it, the classic example of “that’s not technical debt, that’s just mess” is slow or insufficient tests. Writing fast, reliable tests is a matter of craft. If you know the techniques, it’s not actually harder than writing untested code. Calling it “debt” lets teams pretend they made a conscious trade-off when they really just didn’t know how to do the job properly.

The Seven Sins, Revisited

The anti-pattern canon is well-established. We’ve known about these failures for decades:

Anti-Pattern The Problem Why It Persists
Spaghetti Code Deeply nested, tangled control flow that’s impossible to trace It “works” until it doesn’t, and refactoring it feels riskier than living with it
God Object One class that does everything: users, orders, emails, database operations It’s the path of least resistance when deadlines hit
Copy-Paste Programming Duplicated code that breaks in one place but not another Faster than refactoring, until a spec change requires touching 47 locations
Magic Numbers Unexplained literals scattered through the codebase “I’ll comment it later”, you won’t
God Functions Hundreds of lines doing a dozen things “It’s only this one function, it’s fine”, it’s not
Database Over-Access Chatty queries that could be batched or cached Premature optimization feels harder than just doing the query
Swallowed Exceptions Errors ignored because handling them properly is “too much work” The bug you can’t find is always worse than the one you know about

If this table reads like a checklist you’ve encountered in every codebase you’ve ever worked on, that’s exactly the point. We’ve known about these anti-patterns for decades. There are books, courses, and linters dedicated to them. And yet, they persist because they’re the path of least resistance when you’re under pressure to ship something that works today.

Why Knowing Better Isn’t Enough

Here’s what makes architectural anti-patterns so persistent: they’re a rational response to misaligned incentives.

The person making the architectural decision is rarely the person who pays for its consequences. The developer who ships a tightly coupled mess gets praised for velocity. The maintenance burden lands on someone else, usually months later, when the original author has moved on to another project.

This isn’t a moral failing. It’s just how the economics of software tend to work out when organizations:

  • Reward shipping features over maintaining systems
  • Measure velocity in story points, not system health
  • Treat refactoring as “non-delivery work” that gets cut when schedules tighten
  • Fail to distinguish between intentional trade-offs and unconscious mess

One of the most pernicious versions of this is the team that builds an event-driven system because they’ve read about how well it scales, only to discover that no one on the team actually knows how to instrument it properly. The system handles half an event per second. The event-driven architecture added tremendous complexity without solving any actual scaling problem. That wasn’t technical debt, that was a decision made on the edge of the team’s experience, with consequences they couldn’t have predicted.

The Abstraction Paradox

Premature abstraction deserves special attention because it’s the anti-pattern that the best-intentioned teams fall into. You’re building a simple CRUD app. Someone suggests adding a service layer, an interface for every repository, and a generic base class for all your entities. It feels like good architecture. It feels like you’re being responsible.

It’s not. It’s speculative generality, and it’s a trap.

The “architectural purity” debate plays out in countless teams. A developer building medical software with Java and Spring Boot faces this exact dilemma: they’ve embraced Clean Architecture principles, their domain layer is supposed to be independent of any framework, and now they’re wondering whether Spring annotations in use cases violate that principle. The answer, of course, is “it depends.” But the tension between architectural purity and production reality is real, and the teams that resolve it by defaulting to maximum abstraction often end up with code that’s harder to maintain, not easier.

The irony is that abstraction is supposed to reduce complexity. When it’s premature, it does the opposite. You end up with layers of indirection that make it harder to trace what’s actually happening, not easier. The AI coding assistants that are supposed to help developers navigate these systems are often just as confused as we are, they lack the architectural context to understand what a given abstraction is actually doing.

The Role of Culture

The persistence of anti-patterns isn’t just an individual problem. It’s a cultural one. Organizations that tolerate mediocrity in their engineering practices create environments where anti-patterns thrive.

Research on the topic has identified several preventive measures, including:

  1. Code reviews, Multiple people reviewing code catches design issues early
  2. Responsibility separation, Classes and functions should have clear, single responsibilities
  3. Common process consolidation, Extract shared logic into reusable functions
  4. Continuous refactoring, Keep improving readable code even when it works

These all sound simple. They’re not. Each one requires organizational commitment and psychological safety. A code review that’s actually going to catch a God Object requires reviewers who feel empowered to push back on a senior developer’s code. A team that’s consistently shipping features on impossible deadlines doesn’t have time for continuous refactoring, so the mess compounds.

AI Is Making This Worse, Faster

Here’s what’s changed in the last few years: AI has become the repo man for architectural debt.

We’re already seeing the impact in cybersecurity. As Katie Moussouris, founder and CEO of Luta Security, told ISMG at Black Hat 2026: “Everything that they left in the technical debt pile has come for collection.” AI-generated vulnerability reports are flooding organizations, exposing years of deferred patching and accepted risks that previously flew under the radar.

The Sysdig Threat Research Team has documented how AI has become the collector on tech debt. The marimo case is particularly revealing: an AI agent gained entry through an ordinary CVE, then composed an entire post-exploitation chain in under 10 hours. The vulnerability categories haven’t changed. What changed is the cost of exploitation. Finding and weaponizing a bug used to require scarce human attention and hard-to-acquire skills. Now it costs the price of API tokens.

That’s the thing about architectural anti-patterns: they accumulate quietly. The team that chose not to fix that fragile webhook implementation because “it’s not a priority right now” becomes the team that gets breached through that same implementation two years later.

AI Is Also Creating New Debt

The problem isn’t just that AI is exposing old debt in security contexts. AI is creating its own technical debt at an alarming rate.

Anthropic recently cut the Claude Code system prompt by more than 80%, from roughly 800 tokens to 164. This is the second migration its customers have absorbed in a single summer. Sonnet 5, released June 30, removed support for non-default sampling parameters and manual thinking budgets. The new tokenizer maps the same text to roughly 1.0 to 1.35 times more tokens, effectively shrinking every context window.

As Futurum Group analyst Mitch Ashley points out, the mechanism is “configuration thrash”: vendors revise how their models should be prompted, configured, and governed faster than customers can rebuild the assets that depend on them. Teams spend months tuning CLAUDE.md files and prompt strategies, only to have the rug pulled out from under them with each release.

This is a new kind of architectural anti-pattern, but it follows the same logic. The AI coding assistants that were supposed to make teams more productive are generating their own wake of technical debt, and customers are carrying the balance.

The lesson is uncomfortable: the same behavioral incentives that produce God Objects and spaghetti code are now producing prompt drift and configuration thrash. We’re building new systems in new domains, but we’re making the same mistakes.

What Actually Changes the Pattern

The honest answer is: not much, without structural changes.

Individual teams can do a lot. Treat the “tech debt” metaphor with suspicion, if you can’t articulate the terms of the “loan” you’re taking out, you’re not making a strategic trade-off, you’re just making a mess. Invest in code reviews that actually catch design issues, not just syntax errors. Build time for refactoring into your sprint cadence. Question whether that abstraction layer is solving a real problem you have today or a hypothetical problem you might face next year.

But the biggest lever is organizational. Teams need to be measured on system health, not just feature velocity. The reward structure needs to change so that maintaining a clean architecture is as valued as shipping new functionality. That’s hard. It requires leadership willing to say “we’re slowing down on features this quarter to fix our architectural problems” and meaning it.

The AI question adds urgency. Scaling AI agent architectures is exposing flaws in cloud-first designs that ignored system boundaries. The same patterns that made monoliths hard to maintain are making AI systems hard to secure. The debts that were deferred are coming due, and AI is the collector.

The Bottom Line

We keep repeating the same architectural mistakes because knowing better isn’t the same as doing better. The incentives that produce anti-patterns are structural. The teams that escape them are the ones that change those incentives, not just the ones that have better documentation about what not to do.

The next time someone calls a mess “technical debt”, ask them what the interest rate is. Ask them when the payment is due. Ask them what happens when the collector shows up, because in 2026, the collector has AI on its side.

The tools for building good architecture have always existed. What’s been missing is the organizational will to use them consistently. That’s not a technical problem. It never was.

Share: