Big Ball of Mud (1999)
laputan.org
laputan.org
Undertale has a single giant switch statement thousands of cases long for every line of dialog in the game. There are other stories of how infamously bad the code is. And none of that mattered one bit.
Banks are another example. The software is horrible. Everyone knows it. Yet all that’s required is minimally working software that fails rarely enough that the bank can maintain their lock in.
Believe it or not, being hired to work on a big ball of mud can be pretty chill. The key is for you to be in a stage in your life where you don’t really care about your work beyond meeting professional responsibilities. Big ball of mud codebases are the best for that, because everyone’s there for the same reasons, and the assignments are always easy drudgery. Neither Scottrade nor Thomson Reuters cared too much what I was up to as long as I was there at 9am.
It’s soul crushing for people who want to create nice things, or seek meaning in their work, which is partly why I left. But when you just need the money, there’s no substitute.
You'll still have to regularly get dirty, but the petunias you grew over the years form nice memories.
And then, because it generated no bug reports, I never looked at it again; and I spent the rest of my days there slapping dirt and water on the other mudballs.
Hard to know if that's true or not. Some code goes on for literally decades before being touched by another person. Often times, the parts of the code that are high touch end up justifying more gardening to make future touches less painful/faster.
Knowing when code will be cumbersome is really difficult when writing fresh.
I think a large part of what goes wrong is that code starts out too simple. When you look back at the history of the code, the original check-ins almost always look good. Good, but very “direct”. Here was the problem, and here we have solved it as bluntly as possible.
As the changes come, they often break concepts that were introduced in those first few check-ins. It’s understandable, the person coming after is just trying to add “that one thing” with as small a change as possible. These accumulate, and soon any semblance of a logical “model” has been lost. A bit of “build an example for others to follow” at the beginning, might have saved things down the track.
However, do too much “over-engineering”, and no one is checking in your code, and you might be wasting tons of effort.
Hence, experience is required to know the basic pitfalls that develop, and where you need to put in the extra for that initial check-in. Many code-bases, of course, are started by people without that experience, and balls of mud inevitably develop.
You can refactor them! It’s carve out chunks, partition them off, keep the two in parallel until the new is as stable as the old. Banks have actually done this; not all of them. The reality is that if you don’t, new features simply cost too much to be worth developing. You can eventually be completely paralysed by technical debt.
> could have been avoided
I complete agree with your sentiment. Too many of these commenters are unrealistic: In most cases you cannot avoid the BBoM. Usually, it is written by someone before you... or above you... so you have little power to change it, but you can make meaningful changes step by step.What does "clean up" mean? If you mean run a safe code formatter on some 20 year old PHP code that was written in vi, sure. But if you mean refactor, this sounds rather idealistic.
IMO, you are already outside of BBOM territory if your BBOM comes with a robust development environment where you can safely implement such changes without breaking prod in some insane and unforeseeable way.
It may have other issues, but is actually better than what this article is describing.
One hilarious case was at Scottrade. I was poking around their C++ codebase one day and to my amazed horror saw a file hundreds of lines long, and a big chunk of it was devoted to handling leap years. Like, every leap year, one at a time.
There are few enough leap years that it should in theory be difficult to write hundreds of lines of code to handle each of them, but some contractor managed to.
And so the ball of mud continued. What can you do but laugh and embrace the horror?
But I agree that in the case you described, that the programmer was being stupid. However they could have written it as a giant if-elseif block and that would also have been stupid, or a loop over a giant list of years, and that also would have been stupid. I think the problem was the programmer not thinking about the problem carefully, not with the control-flow construct they used to write the bad code.
laugh. embrace and share the fun with others: submit to https://thedailywtf.com
For the diametrical opposite, here's one time on an embedded system where I really didn't want to bring in a library dependency, so I wrote an inconspicuous-looking good-enough version:
y = (d - (d + 366 + (d >= 47847)) / 1461 + (d >= 47847)) / 365;
d = d - (d + 365 + (d >= 47848)) / 1461 + (d >= 47848) - y * 365;
y += 1970;int main() { long long d; std::cout << "Enter a Julian Day Number: "; std::cin >> d;
if (d < 0) {
std::cerr << "Error: Invalid Julian Day Number (must be non-negative)." << std::endl;
return 1; // Indicate an error to the system
}
const int DAYS_PER_YEAR = 365;
const int DAYS_PER_LEAP_YEAR = 366;
const int DAYS_PER_LEAP_CYCLE = 1461; // 4 years
const int JULIAN_TO_GREGORIAN_THRESHOLD = 2299161; // Oct 15, 1582
// Adjust for Julian-to-Gregorian transition
if (d >= JULIAN_TO_GREGORIAN_THRESHOLD) {
d += 10; // Account for dropped days
}
int a = d + 32044;
int b = (4 * a + 3) / DAYS_PER_LEAP_CYCLE;
int c = (4 * a + 3) % DAYS_PER_LEAP_CYCLE;
int y = (b / 1460) + 1970;
d = (c / 4) - 365;
if (d < 0) {
y--;
d += DAYS_PER_YEAR + (y % 4 == 0);
}
std::cout << "Gregorian Year: " << y << std::endl;
std::cout << "Day of Year: " << d + 1 << std::endl; // Add 1 as days are typically 1-indexed
return 0;
}Really begs the question of what the long-term outlook is for the non-top-quartile people. Maybe re-prompting LLMs is the new ball of mud?
Recently, my company acquired some engineers, and while I cannot evaluate their "percentile", I have been low-key flabbergasted at some of their suggestions for using LLMs in place of scripts. (For example, to modify or move nested data in a non-public JSON representation of a program.)
https://www.bbc.com/future/article/20240228-leap-year-the-im...
[0]: https://craftofcoding.wordpress.com/2020/02/12/the-world-of-...
But for case value
value can only be char or int, and must be unique
Really it is just sugar for if-else-if, but if you enforce explicit break in your code it is as close to a provable total function as you get in C.
Total functions are the ideal in any code.
As determining whether or not a function F is total is undecidable, switch is more reliable than if-else-if ladders.
Although, I suppose it doesn't matter all that much which is which, as long as they're not both written the same way.
It's implementing it two different ways and comparing the results. It's not a guarantee, since you could have implemented the wrong spec, but there's only so much you can do with internal consistency checks.
But it would be better to compare to a known good function. It might be easier to add a dependency to do that in a test than in production code.
int is_leap_year(int year) {
return 0;
}Had a customers app break when they used zips that contained over 65k separate files. Sent it to dev and they said "Oh use this other API we have". And yes, the file 'worked' but the api didn't do what the customer needed. Got back with the developer and saw
We had two api's that did almost but not quite the same thing. Ok, it happens, maybe there was a reason for it.
We also had two different zip libraries built in. At some point a dev ran into issues with legacy zip support not working on large files and added a new library. They converted about 10% of the API, enough to cover what they were working on and stopped.
This is an interesting problem. If you insist on maximizing consistency on a large code base, then nothing can ever change. If you allow too many small deviations / good ideas that are only ever partially completed, it results in chaos. I think it is a little like entropy: some (not too much) is needed for things to progress.
I think for most users it's made feature observability much better.
Case in point I've been at multiple places that have had multiple JSON and XML libraries in the same product at the same time.
All one file.
No subroutines.
No comments.
Three-letter variable names.
LOTS of GOTOs.
VT-100 300-Baud terminals.
Inspired me to never do that to anyone else[0].
You're giving me flashbacks to all the SAS code I inherited. The tables had three-letter names like "AAA" and "BBB", and all the columns had single-letter names. Wasn't long before I completely rewrote the entire thing (a couple times, because I wrote junk, too).
It’s like rewriting the code but by passing the ball from production code to test code and back to figure out who the individual players are.
Probably depends on how big the ball is and how messy the mud. If you’re not careful, you might find yourself drowning in a whole swamp instead: https://news.ycombinator.com/item?id=18442941
Once you have to dig through dozens of files full of hacks and bad abstractions just to make basic changes and even then the insufficient test suite prevents you from being confident in any positive outcome (the example above at least had good tests, often you don’t even get that much), maybe things aren’t going great.
That said, you can definitely write good monoliths and even codebases with technical debt can be pleasant, as long as things are kept as simple as possible.
I suspect that the perspective of "It sucks but it works for us; I'm not idealistic anymore" is really a rationalization of despair, but that's just me.
1. Engineers don't care about the health of the codebase and it becomes/stays a ball of mud, OR...
2. They do care, and end up refactoring/rewriting it in a way that just creates even MORE complexity.
But I think this is a false dichotomy. It just happens to be very difficult, and as much of an art as a science to keep huge codebases moving in the right direction.
I haven't worked at Google, but from what I've heard they have huge codebases, but they're not typically falling apart at the seams.
2. They absolutely care, but possibly about the wrong things, and this happens so often it's a cliche. Remember when a big chunk of the industry woke up one moring and decided RDBMs just had to be bullshit because my god look how old they are and collectively dove themselves, their projects, and their organizations off the cliff that was shoehorning mapreduce into a project NOT owned by Google?
Speaking of Google, I feel like there are few things less relevant to the industry writ large than whatever they happen to be up to at any given moment. From tech stack to hiring practices their needs are so totally orthogonal to what any other org requires they honestly may as well be operating in another dimension. Chasing after Google is like running around with a fork in your hand in search of a wall outlet.
Anyway, to finish up my thoughts on architecture as a concept, yeah having some structure to a codebase is something of a no-brainer, but dogma is as dogma does. There are very few unimpeachable capital T truths come from the software architecture intelligentsia. We could talk at some length about the decades of churn in this space as roughly every 5 years another crop of grad students gets unleashed into the industry dead-ass certain that they have found The Way.
Even for regular code organization. 100 small functions is ok but 100 switch cases is bad? It's the same amount of code, and switch cases aren't that "hard to read".
Edit: Evidently you can get O(1) from a Switch if the compiler converts it to jump statements. Just adding this for posterity, and to correct myself.
Just taking localisation strings out of the switch statement doesn’t fully fix this. You can swap out individual lines, but characters are still bound to say the same number of lines in the same order in every language, with player choice happening at the same point. This may work for simple conversations, but it will result in clunky localisations when languages differ in verbosity or sentence structure.
Changing a translation yaml triggers a webpack build in a lot of web setups but nobody seems to complain about that.
And if you wait a little while, what you need is new developers.
once you ship, you don't really need to maintain it the same way as other software. tech debt is free money if you ship before having to pay it back
and players often like complexity and interaction between systems, so there's less benefit to isolating them in code
> Sometimes a big ball of mud is exactly what’s needed...Banks are another example...It’s soul crushing...which is partly why I left.
Not a very convincing argument. ;-)
Often there's nothing to do. The patient is somewhat ok, and intervening would mean risking death due to the tumour being near some critical blood vessel.
At most you have some routine maintenance to do on a daily basis. Cut some things here and there, reroute a few small things, tell the patient they need this or that medicine.
You might even find it interesting to learn how the body of code works, the journal of previous surgeons, the little nooks and crannies where interesting decisions are made.
But you are never asked to rebuild the entire body.
Yeah, that's it, isn't it? I could probably make a career off of tiny incremental improvements to some terrible business app... or I could ... care. (I do realize the drip of sarcasm in your post, don't worry)
Anyway, hail Mammon, I suppose, innit? Unless...
Big Ball of Mud (1999) - https://news.ycombinator.com/item?id=35481309 - Apr 2023 (32 comments)
Big Ball of Mud (1999) - https://news.ycombinator.com/item?id=28915865 - Oct 2021 (23 comments)
Big Ball of Mud (1999) - https://news.ycombinator.com/item?id=22365496 - Feb 2020 (48 comments)
Big Ball of Mud - https://news.ycombinator.com/item?id=21650011 - Nov 2019 (1 comment)
Big Ball of Mud (1999) - https://news.ycombinator.com/item?id=21484045 - Nov 2019 (1 comment)
Big Ball of Mud (1999) - https://news.ycombinator.com/item?id=13716667 - Feb 2017 (6 comments)
Big Ball of Mud (1999) - https://news.ycombinator.com/item?id=9989424 - Aug 2015 (9 comments)
Big Ball of Mud - https://news.ycombinator.com/item?id=6745991 - Nov 2013 (21 comments)
Big Ball of Mud - https://news.ycombinator.com/item?id=911445 - Oct 2009 (2 comments)
The "Big Ball of Mud" Pattern - https://news.ycombinator.com/item?id=10259 - April 2007 (2 comments)
I actually even started enjoying it at some point - it felt like a mixture between a crossword puzzle and archaeology. There was also something nice about being good at something other people hated that was nonetheless very critical.
Somewhat ironically though, the better I got at it, the class of job I got the better the quality of the code I ended up working with.
Now my mud wrestling skills have atrophied a fair bit.
My career path has followed a similar trajectory but I do enjoy a good "mud wrestle" as you call it every now and then :)
Cue cave escape scene chased by huge rolling boulder.
The line was essentially a collection of:
restart instance_N &; restart instance_N+1&;
etcI always assumed that the way you got to 70+ was:
- write the first restart for instance N=1
- add another restart
- keep doing this till you get to about 5-8 restart commands
- AT THIS POINT someone should say "Hey, we should make this a script or something else" BUT CRUCIALLY that didn't happen
- you keep adding restarts till you get to 20+
- Now, doing anything to that giant line other than adding a new restart feels too dangerous so you decide to just keep adding restarts.
Moral of the story: the ball of mud usually doesn't just appear out of nowhere. It appears b/c there were multiple steps were someone didn't say "hey, maybe we should..." (or they said it and no one listened).
It was quite complete and very smart, with lots of OOP patterns and wrappers abound. But it was not only impossible to understand, it was almost impossible to debug too, because of the amount of indirection.
Big balls of mud often also appear because people actually say “hey maybe we should…” but but still manage to miss the mark.
As much as I would love to give some insightful comment here, I can’t. To paraphrase a post I saw here about Casey Muratori: sometimes the only advice you can give to someone is to “get good”. Putting in the 10000 hours and getting actual feedback rather than pretending that the bullshit you wrote is good because the previous one was understandable by a non-techie.
I've seen this SO MANY times too.
Nothing like having 8 files open to debug what turns out to be a one line change due to all of the object inheritance.
https://en.m.wikipedia.org/wiki/Dorodango
There's gotta be some analogy to the software big ball of mud though
Well that’s the idea anyway, but it always turns into a mess and then I have been using a new term to describe it: spaghetti over http
It's just implemented over YAML (what a great programming language!) and has crunchy microservices inside! (I'm not sure I want to know what the crunchy bits in a ball of mud are).
P.S. I love it and still re-read it sometimes.
https://www.ebay.com/sch/i.html?_from=R40&_trksid=p4432023.m...
I've seen some big balls of software mud that formed very nicely under pressure too.
[edit]
After doing the obvious thing and googling "john lennon shovel waiter" it is indeed him from Magical Mystery Tour
It is somewhat of a clichè but I think that (interactive) documentation and tooling can make a difference, but it is very difficult to design the process and the tooling to be as frictionless as possible. Tudor Girba and his team at feenk have been doing a lot of interesting work in that area that's worth a look [1, 2].
The software in question might be an entangled mess, a large part of it might be even inherent due to its requirements or technical constraints, but if that messy web can be readily augmented with background information and sign-posts I think the situation could be significantly improved.
On a related note, there has been a project at Xerox PARC called PIE (Personal Information Environment) [3] which has put forward the idea of organizing software and its artifacts (source code, various kinds of documentation) as a network. Although that particular concept has never been adopted in any major programming system as far as I know, I think that it has huge potential, especially if the software, as a network, can be collaboratively navigated and extended with additional information, where and when needed -- online.
Now that all does not change the fact that we are still dealing with a ball (or a web) of mud, but at least it is accessible and we might have a better chance to understand its evolution and the reasons that made it complicated in the first place.
[3] http://www.bitsavers.org/pdf/xerox/parc/techReports/CSL-81-3...
So you put a team on the APIs and issues keep cropping up again and again because every time one thing is changed it has knock-on effects causing other company-endangering incidents because you're making changes to to way billing and invoicing data is presented, or to how incoming metering data is stored. So you put some additional teams on the project and work everyone to the bone. Some senior developers burn out and leave the organisation. Likewise some project managers. Your best QA staff have their morale drop to rock bottom.
The project delivers on time but how do you measure these costs? How are you going to put a dollar figure on the burnout and lost staff? How much of the senior developers' decisions to leave can be attributed to the project and the big ball of mud? How do you measure the impact of your best tester losing his will to work and going dark?
Many of us have worked in organisations where things have gone down like this. We all know that impact is huge. But yeah you're right, I can't put together a business case that says it in clear numbers. On paper we had a one-year project, it probably went a bit over budget but it ultimately delivered so what's the big deal about the big ball of mud? Except that our competitors were able to produce the same APIs for a fraction of the cost without burning out half their staff.
Then it doesn’t have be that bad to have business impact. What does your customer say when the new feature that was promised in one month takes eight months to deliver, or your CFO say when it will take 15 years of licensing fees from that customer to pay those 24 man months to get the features working?
On the other hand, if you've got an old system with poor quality code and can't make changes, your customer(s) are willing to drop you, and you have competitors who can get out the desired features, you're screwed.
The moment that someone manages to crack the software visualization problem for the layperson, would be the (moment + delay) that considerable effort would actually be invested in software architecture.
> These patterns [BIG BALL OF MUD, THROWAWAY CODE, PIECEMEAL GROWTH, KEEP IT WORKING, SHEARING LAYERS, SWEEPING IT UNDER THE RUG, RECONSTRUCTION] explore the forces that encourage the emergence of a BIG BALL OF MUD, and the undeniable effectiveness of this approach to software architecture. What are the people who build them doing right? If more high-minded architectural approaches are to compete, we must understand what the forces that lead to a BIG BALL OF MUD are, and examine alternative ways to resolve them.
I think a lot of problems which reduce down to this are done by function-table lookups (as in, look up in a table the index of the next state, and call the function) but for the language I had, that wasn't an option.
Not that I'm saying don't rewrite. It will certainly be more fun and likely good for the resume.
Team size correlates with system complexity regardless of the problem domain.
What fraction of developers is on Team Rewrite?
I tend to be sceptical of “rewrite everyting” projects since they are often based on wishful thinking.
It's not spaghetti!
Few months later I heard a complaint from my direct manager that I called our code “big ball of crap” and it was a major software company