Is there an anti pattern that describes a historically grown software system where multiple developers just added new features to the system but no one really kept an eye on the overall architecture nor were refactorings ever done?

I think this happens when management/customer asks for new feature constantly and no one ever refactors anything but just adds on to what other developers haven done before. 

A reason could also be that the developer is just overwhelmed with the software system and does not really understand how it currently works and then just adds/glues his code at the very end (instead of refactoring the code and changing it.)

So over time it's getting harder and harder to maintain the system.

(I wonder if there are pictures for these kind of anti pattern to make this more clear to none programming folks - like a car that was built by just adding more and more features without thinking of the overall design. Like someone has the need to tow trailers while riding backwards and then an engineer just welds a tow bar to the front of the car. Job done. But now the cowl doesn't open anymore.)

You refer to technical debt.

We all accrue technical debt in the products we develop over time; refactoring is one of the very common and effective ways of reducing this technical debt, though many companies never pay down their technical debt. These companies tend to find their software extremely unstable years down the road, and the technical debt becomes so gruesome that you can't pay it down incrementally, because it would take too long to pay it down that way.

Technical debt has the term, because it follows the same behaviours of debt. You get the debt, and as long as you continue spending (creating features) and not paying down that debt, it'll only grow. Much like debt, when it get's too large you get to points where you may wish to shed it entirely with dangerous tasks like full-out rewrites. Also like real debt, as it accrues to a certain point, it hinders your ability to spend (creating features) altogether.

Just to throw another term in the mix, cohesion refers to how well a system, micro to the line level, or macro to the system level, fits together. A highly cohesive system will have all of its pieces fit together very well and look like one engineer wrote all of it. Your reference above to somebody just gluing their code to the end would be violating the cohesion of that system.



Managing Technical Debt

There are a lot of ways to manage technical debt, though like real debt the best approach is to pay it down frequently. Unfortunately like real debt it's occasionally a better idea to accrue more for a short period, where for instance time to market for a feature may double or triple your revenue. The tricky part is weighing these competing priorities as well as identifying when the debts ROI isn't worth it for the given feature vs. when it is.

So sometimes it is worth it to accrue the debt for a short period, but that's rarely the case, and as with all debt, the shorter the period the better. So eventually (preferably quickly) after you accrue technical debt, you have to pay it down, these are common approaches:


Refactoring

This allows you to take bits of code that were only realized to be misplaced partway through or after implementation was complete, and put them in their correct place (or a more correct one anyway).

Rewrite

This is like a bankruptcy. It wipes the slate clean, but you start with nothing and have every opportunity to make the same mistakes, or even bigger ones. High risk high reward approach to technical debt, but sometimes it's your only option. Though that's more rarely the case than many will tell you.

Architecture Overview

This is more of an active technical debt pay-down approach. This is done by having someone with authority over the technical details to halt an implementation regardless of project plans and schedules to ensure it accrues less technical debt.

Code Freeze

Freezing the code of changes can allow you breathing room where your debt doesn't go up or down. This gives you time to plan your approach to reducing the technical debt with hopes of having the highest ROI on your approach.

Modularization

This is like a tier-2 approach only available when you employ either Architecture Overview to have a modular system already, or Refactoring to move towards one. When you have a modular system, you can then pay down debt in whole pieces of the system in an isolated way. This allows you to do partial re-writes, partial refactoring, as well as minimizing the rate technical debt accrues because the isolation keeps the debt only in those areas where the features went in, as opposed to spread around the system.

Automated Tests

Automated testing can aid in managing your technical debt, because they can help you identify trouble spots in the system, hopefully before the debt in those areas has grown very large, but even after the fact they can still make engineers aware of those dangerous areas they may not have already realized. Furthermore, once you've got automated tests, you can more freely refactor things without concern for breaking too much. Not because developers won't break things, but because they'll find out when they do break things, relying on manual testers in highly indebted systems tends to have a poor track record for finding issues.


