“Big ball of mud” is one of the more common pejoratives thrown at “legacy” code. Systems suffering from a wide variety of different problems get tarred with the brush of “mud,” but generally the overall experience of a developer facing a big ball of mud is one of constant low-grade terror. A sense that everything makes a little sense, but not nearly as much as it should. And so you’ll feel like you’re fighting against the edges of architectural choices that were never made, or were made by then ignored, or were intentionally subverted.
The authors argue that the big ball of mud isn’t just the absence of architecture in a software system, but rather its own architectural pattern that has merits and trade-offs.
The idea of a “big ball of mud” long predates it, but the paper from Brian Foote and Joseph Yoder, entitled simply “Big Ball of Mud” is thus clearly worth some attention. Among its many values, perhaps my favorite is that the authors argue that the big ball of mud isn’t just the absence of architecture in a software system, but rather its own architectural pattern that has merits and trade-offs and it’s own backwards-seeming wisdom. Not only that, but they argue that it is not just any pattern, but the “most frequently deployed of software architectures.” You might scoff but given how frequently developers complain about the “legacy” system they work with and its problems it’s pretty easy to believe.
In the paper, this description of a big ball of mud — which one could parse at length and learn a great deal from — is offered:
Data structures may be haphazardly constructed, or even next to non-existent. Everything talks to everything else. Every shred of important state data may be global. … Variable and function names might be uninformative, or even misleading. Functions themselves may make extensive use of global variables, as well as long lists of poorly defined parameters. The function themselves are lengthy and convoluted, and perform several unrelated tasks. Code is duplicated. The flow of control is hard to understand, and difficult to follow. The programmer’s intent is next to impossible to discern. The code is simply unreadable, and borders on indecipherable.
In short, the nightmare many many developers in the world deal with regularly. Noting the problem, the paper discusses not only the factors that contribute to software collecting these problems, but the solutions to them (which, at least for now, I’ll leave you to read from the source itself). Below is a list of the patterns that Foote & Yoder identify as the contributing factors to a system having qualities of a big ball of mud. The ideas are theirs, but the explanations are my own.
One of the “patterns” beyond the big ball of mud that Foote & Yoder call out is the frequency with which software is full of “patch fixes,” “quick hacks,” and other variations on the theme of “I didn’t mean that to be the final solution to the problem, just a solution.” Whether “throwaway” code gets into production because a boss-type overrules a coder-type about how temporary your prototype should be or because its a necessary hot-fix to a hemorrhaging problem, the basic problem is that “throwaway” solutions of which no one is proud regularly and with reason makes it into production. Once in production, code quickly harden in place and becomes the “legacy software” that a new developer then finds space to describe as “a big ball of mud.”
Financial and Time Pressure
Corners are cut, luxuries like code-reviews are sacrificed, and generally a working system gets prioritized over a good system.
Less a pattern than an implacable force in the business world in which most software operates, one of the most important drivers of throwaway code hitting production is that time costs money and people want to spend the least possible amount of money to get a software artifact that fulfills their goals. So corners are cut, luxuries like code-reviews are sacrificed, and generally a working system gets prioritized over a good system.
Unskilled or Inexperienced Developers
This travels sanely along with the ideas of financial or time pressures, but feels quite distinct: sometimes people are trying to make smart architectural choices, but just don’t know nearly enough about actual trade-offs they’re making. Buzzword bingo, and other such obvious bugaboos fit into this cause, broadly, as less experienced developers are likely to trade in favor of apparent popularity and early productivity regardless of its impact of long-term maintainability and intelligent optionality. Nothing can substitute for the battle-won wisdom of someone who will make hard choice against hot technologies or simply bone-headed ideas that are currently sweeping up the inexperienced in a fit of fervor.
Software Architecture is Invisible
A civilian buyer who can easily go into a building and notice the wide crack in the foundation cannot do the same when evaluating software artifacts.
This contributing factor is really obvious but rarely talked about. The people who actually see the architecture and condition of a software system and have informed opinions on the soundness of the choices that have been made are only those who are regularly in contact with that system. This means that a boss or civilian buyer who can easily go into a building and notice the water that has collected on the floor from a hole in the roof, or note and be worried the wide crack in the foundation cannot do the same when evaluating software artifacts. This leads to uninformed choices, and much resistance when money or time is requested for the sake of repairing a system that from the outside seems to be functioning fine.
This is the second of Foote & Yoder’s “patterns” which I feel falls into the category of causative factors. The broad topic of how you can and should grow software and build architecture that doesn’t feel quickly like “legacy” is far beyond our scope here. But what typically happens is that software artifacts — whether there was a large upfront planning phase as the start of a “waterfall” or not — is that slowly people want new features and they’re added. That isn’t itself a problem, but unmanaged grafting-on of new features onto systems — regardless of their initial quality — tends to make for the sprawling messes that get labeled as “big balls of mud.”
Change to Project Domain or Scale
Sometimes an experiment becomes a heavily trafficked site that fail-whales a lot. Sometimes a business that started by building a tool to evaluate the attractiveness of other college students become the most important social network in the world. When these things happen, big shifts are likely to be needed in the underlying code-base. But because architecture is invisible and business always want to spend as little time and money as it can, this can lead to a huge amount of piecemeal growth and one-off throwaway code quickly merging into production. And, as we’ve said, that can easily have corrosive effects on the quality of the architecture of the application.
It’s likely that the complexity of your problem will end up interacting problematically with the complexity of your solution, and then you’ll have a real production software artifact on your hands!
Finally, though hardly the least of the causes for software becoming an unmanageable ball of mud is that sometimes software is given a complicated and hard-to-manage domain. Taxes are the canonical example of a hard and complex problem that software may be tasked with. Then, if you’re lucky, the only complexity in your software will be all that inherent complexity of the tax law itself. But if we’re honest, it’s likely that the complexity of your problem will end up interacting problematically with the complexity of your solution, and then you’ll have a real production software artifact on your hands! (I’ve written a good deal more about the difference between incidental and inherent complexity.)
And all the other stuff…
This list is my best attempt to concisely summarize the idea of Foote and Yoder, and I’m certain I’ve done an injustice to some of their points or forgotten things they mentioned. It’s also quite likely that their list could leave a reader feeling left out or that a crucial idea went unmentioned. Any list of why human endeavors — which, like it or not, software is — go wrong is going to feel inadequate to some audience.
But the core fact is, software goes wrong for lots of reasons. Making good reliable, extensible, and usable software is something we’re all still struggling to do well. Most of the problems that have made this list are essentially and permanently intractable, because that’s what making software is: a series of trade-offs made with insufficient knowledge, wisdom, and/or humility. But it sure can be fun to make those choices and have an impact on the world as a result. Happy hacking!
Image Credits: Steven Buyanasky