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.