Several years ago I started at a job where the team had had reached the point where even simple requests become arduous to implement. We are well aware of the traps that our predecessors fell into, one being that they gave up on unit testing under schedule pressure. All that technical debt built up to the point that we felt like we would need to declare technical bankruptcy.
So what could we do? The original code wasn’t built to be unit tested even though the original programmers wanted to do testing and even started to try. But classes were highly coupled which made testing arduous. And, unfortunately, instead of recognizing this as a smell, they pushed onward, declaring unit testing too complicated and time consuming.
We couldn’t pause the product for the time it would take to write everything. This was a large product that many customers depended on. Trying to do that can be the death of a product or even a whole company. Fortunately the code was built in a way that we were able to build a new “shell” around the existing product and once that was in place, replace the individual parts as needed. It worked great and allowed us to start producing a steady stream of reliable, maintainable and unit tested code.