Skip to content

Big Ball of Mud – Architecture Under Real-World Conditions

There is no shortage of books and articles about software architecture.

We know what a clean architecture can look like. We know layers, ports and adapters, domain boundaries, modular monoliths, microservices, event-driven architecture, domain-driven design, and an almost unmanageable number of other patterns and principles.

On paper, software architecture surprisingly often begins with a blank sheet.

In reality, it often begins with a repository.

And that repository is ten years old.

It has seen several generations of developers. Different architectural styles. Different frameworks. Time pressure. Reorganizations. Changes in strategy. Discontinued products. Deadlines that mattered more than the next round of maintenance. Temporary solutions that were never touched again. And, of course, that one transitional solution that has been running in production for seven years.

This series is about systems like these.

Not about what architecture should look like.

But about what happens when it no longer does.

The architecture we talk surprisingly little about

Section titled “The architecture we talk surprisingly little about”

Brian Foote and Joseph Yoder described the Big Ball of Mud as early as 1997. Their observation was remarkably sober: while software architecture spends a great deal of time on well-ordered architectural styles, one of the forms commonly found in practice is precisely the one without a clearly recognizable structure.

A Big Ball of Mud is not simply old software.

Nor is it automatically a monolith.

A large monolith can be exceptionally well structured. It can have clear domain boundaries, consistent dependencies, and recurring solution patterns.

A Big Ball of Mud loses something else:

a recognizable internal structure.

Boundaries blur. Responsibilities overlap. Decisions that were originally local begin to spread. Dependencies emerge where none existed before. Shared services become increasingly shared. Exceptions become rules. Eventually, knowledge about what can be changed safely resides less in the architecture than in the heads of individual people.

This rarely happens in one dramatic moment.

A Big Ball of Mud usually emerges gradually.

And that is precisely what makes it so dangerous.

Most of my professional work did not begin on a greenfield project.

Looking back very roughly, probably 90 percent of the systems I worked with intensively had already eroded architecturally in one way or another.

That figure is obviously not a statistic. It is my personal sample — and it is probably heavily biased. Especially in recent years, I was often brought into projects once problems already existed. Anyone who is called in as a firefighter should not be surprised to see an above-average number of fires.

Even so, I find it increasingly difficult to dismiss my experience as a collection of personal outliers.

Research provides at least some interesting indications that the problem is broader.

Besker, Martini, and Bosch investigated how much development time is lost because of technical debt. In their empirical study, developers reported losing around 23 percent of their working time to technical debt on average. A significant amount of the additional work came from activities such as extra testing and additional analysis of the existing code.

A follow-up study by Besker, Ghanbari, Martini, and Bosch explicitly examined the human aspect. Technical debt was associated with lack of progress and wasted time; the results indicate that it can negatively affect developer morale, while active technical-debt management can have the opposite effect.

That is remarkable.

Because when we talk about technical debt, we usually talk about money.

Or story points.

Or lead time.

Far less often do we talk about what it does to the people who have to work in these systems every day.

The problem is not limited to a single industry

Section titled “The problem is not limited to a single industry”

I have encountered particularly problematic systems in the medical domain and in the public sector. Conversations and reports can quickly create the impression that certain industries are especially prone to legacy problems.

I have not, however, found a serious ranking of the “worst industries.”

And I see little value in upgrading an interesting anecdote into an invented statistic.

What can be substantiated is already striking enough.

An empirical study of three real automotive systems found substantial interconnection between their features. Fewer than twelve percent of the architectural components were responsible for more than ninety percent of the feature dependencies. At the same time, developers were unaware of a large proportion of those dependencies.

In the public sector, the problem is documented even more directly.

In 2025, the UK government estimated that around 28 percent of central government systems were legacy technology. Across individual NHS organizations and police forces, the reported proportions varied by organization from roughly ten percent to sixty or seventy percent.

The U.S. Government Accountability Office examined 69 legacy systems operated by federal agencies in 2025. The eleven most critical were approximately 23 to 60 years old and together cost around 754 million U.S. dollars per year to operate and maintain. Several relied on outdated programming languages, unsupported hardware or software, or known security vulnerabilities.

That does not mean every legacy system is a Big Ball of Mud.

That distinction matters.

But it does show that we are not talking about an exotic edge case in software development.

We build new systems.

And at the same time, a significant part of our industry spends its time keeping existing systems alive.

The following graph comes from a real frontend I worked on.

For publication, the names have been fully anonymized and transferred into the fictional domain of an ACME Factory. The structure itself, however, has not been changed: nodes, dependencies, sizes, and topology correspond to the system that was analyzed.

Do not try to understand it at first.

Just grab any node and move it.

Open interactive dependency graph ↗

Grab any node and move it. Watch not only what moves, but also how long the system keeps reacting after you let go.

What interests me most about this visualization by now is not even its size.

It is the movement.

It makes almost no difference which node you grab. The movement propagates through the entire system. When you let go, the graph does not immediately settle down again. It keeps oscillating for a long time.

Of course, at first this is simply the physics of a D3 force simulation. D3 is trying to rearrange a large number of interconnected nodes.

But as a metaphor for working in a tightly coupled system, I can hardly imagine a better visualization.

A local change is locally complete.

Its consequences do not have to be.

You change a service today.

The code compiles. The tests pass. The feature works.

Days later, something breaks in a completely different place.

The person who finds the defect may not know about the original change. The person who made the change may no longer make the connection. Cause and effect are separated not only structurally, but now also in time.

The system keeps reverberating.

Eventually, technical coupling becomes a human problem

Section titled “Eventually, technical coupling becomes a human problem”

At this point, talking only about clean code is no longer enough for me.

In a heavily eroded system, maintenance costs are not the only thing that increases.

The amount of mental context required grows as well.

A change requires knowledge of increasingly large parts of the system. Developers spend more time on analysis. Changes become more cautious. Reviews become harder. Tests become more extensive. Defects become more difficult to trace.

At the same time, knowledge becomes concentrated.

A few people still understand certain areas.

So those are exactly the people who get asked more and more often.

They support colleagues. Analyze side effects. Repair production issues. Review changes. Explain historical decisions. And on top of all that, they are expected to fix the structural problems that made them indispensable in the first place.

A cycle begins:

The more problematic the architecture becomes, the more dependent the organization becomes on individual knowledge holders.

The more dependent it becomes on those people, the less time those people have to solve the underlying problem.

And when one of them leaves, the organization does not merely lose development capacity.

It loses architectural knowledge.

I have seen what systems like this can do to people.

In one project, I experienced twelve resignations within two years. Two heads of development left. Three developers I worked with directly went on leave with burnout.

I have seen people despair because of systems like these.

And I failed in that project myself.

Not because I could not find a better technical design.

But because of organization, understanding, priorities, and resistance.

At some point, being technically right is no longer enough.

A Big Ball of Mud is not a refactoring ticket

Section titled “A Big Ball of Mud is not a refactoring ticket”

That is exactly why I do not want this series to pretend that a Big Ball of Mud can be repaired with a handful of architectural rules.

Of course we will talk about technical options.

In great detail.

We will look at how boundaries can become visible again. How dependencies can be analyzed. Where useful cuts might exist. When a strangler approach makes sense. When a system should be stabilized before it is restructured. How risks can be limited and how changes can become local again at all.

But that comes later.

Because first we have to deal with a more uncomfortable truth:

A Big Ball of Mud is not a purely technical problem.

Its architecture has evolved together with its organization over many years.

It contains prioritization decisions, team structures, budget decisions, time pressure, staff turnover, release processes, missing knowledge, responsibility boundaries, and political decisions.

Anyone who only changes the code is therefore often changing only one part of the system.

And sometimes the smaller one.

Technical debt is called debt for a reason.

Debt is not inherently irrational.

It can be entirely reasonable to choose a pragmatic solution today and accept higher costs later in return.

The problem begins when nobody knows how much debt exists anymore.

When nobody knows who took it on.

When no repayment is planned.

And when new loans are constantly taken out merely to pay the interest on the old ones.

The economic consequences often appear first as a development problem:

Features take longer.

Testing becomes more expensive.

Defect analysis takes longer.

Releases become riskier.

But eventually these become business problems.

Modernization becomes so expensive that it is postponed again and again. New products have to remain compatible with old structures. Security risks can no longer be eliminated locally. Domain changes require major technical projects.

The system begins making decisions about the company.

Not the other way around.

That is why I am at least as interested in what happens on the other side of the repository.

What happens to a team when nobody can reliably estimate the consequences of a change anymore?

What happens to responsibility when defects can hardly be assigned clearly to one area?

What happens to new developers when they need months just to understand where they can work safely?

What happens to experienced developers when experience gradually turns into permanent responsibility?

What happens to an organization when the people who warn most clearly about structural problems simultaneously appear to be the people making change slower and more expensive?

And what happens when everyone involved knows that something is fundamentally wrong, but nobody can see a realistic way out anymore?

These are not questions about Angular.

They are questions about organizations.

That, too, is part of an honest discussion.

There are always options.

But not every option is:

We fix the system.

You can try to change it.

You can learn to work with it and limit its risks.

You can replace individual areas.

You can rebuild.

You can accept that certain structures will remain.

And as a developer, you can eventually decide that you no longer want to be part of that system yourself.

Which decision makes sense depends on more than code quality.

It depends on costs, risks, people, time, product strategy, and above all on whether an organization actually enables change.

A technical analysis can show where the problem is.

It cannot force an organization to want to solve it.

This series will therefore not be a collection of horror stories.

Nor will it be a catalog of twelve simple steps from a Big Ball of Mud to perfect architecture.

We will first examine what a Big Ball of Mud actually is.

How it emerges.

How to recognize one.

Why a monolith is by no means automatically a Big Ball of Mud.

Why systems like these can continue to work for a surprisingly long time.

What technical, economic, and human risks arise.

Why organizations often fail to respond even when the problems are obvious.

And what options remain when you are right in the middle of such a system yourself.

There will be technical tools.

Architectural patterns.

Analysis methods.

Migration strategies.

But they do not come first.

Something else does:

taking the problem seriously.

Not only for the code.

But for the people who have to change it every day.


Brian Foote, Joseph W. Yoder: Big Ball of Mud. Pattern Languages of Program Design 4, originally published in 1997.

Terese Besker, Antonio Martini, Jan Bosch: Software Developer Productivity Loss Due to Technical Debt – A Replication and Extension Study Examining Developers’ Development Work. Journal of Systems and Software 156, 2019, pp. 41–61. DOI: 10.1016/j.jss.2019.06.004.

Terese Besker, Hadi Ghanbari, Antonio Martini, Jan Bosch: The Influence of Technical Debt on Software Developer Morale. Journal of Systems and Software 167, 2020, 110586. DOI: 10.1016/j.jss.2020.110586.

Jesper Olsson, Erik Risfelt, Terese Besker, Antonio Martini, Richard Torkar: Measuring Affective States from Technical Debt: A Psychoempirical Software Engineering Experiment. 2020.

Andreas Vogelsang: Feature Dependencies in Automotive Software Systems: Extent, Awareness, and Refactoring. Journal of Systems and Software, 2019. DOI: 10.1016/j.jss.2019.110458.

UK Department for Science, Innovation and Technology / Government Digital Service: State of Digital Government Review. 2025.

U.S. Government Accountability Office: Information Technology: Agencies Need to Plan for Modernizing Critical Decades-Old Legacy Systems. GAO-25-107795, July 2025.