Untestable Architecture in Legacy Code
Michael Feathers said: "To me, legacy code is simply code without tests." But is it possible to add tests?
🔒Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders & Senior Software Developers apply TDD in Legacy Code. This article is part of the TDD in Legacy Code series. To get these articles in your inbox every week, subscribe:
Legacy Code = Code without tests
Michael Feathers defined Legacy Code in Working Effectively with Legacy Code:
To me, legacy code is simply code without tests.
In his book Working Effectively with Legacy Code, he clarified this definition, most importantly why tests are critical, and where even the most clean code is bad code if it’s not covered by tests. Changes to that code are risky, we don’t have a safety net:
I’ve gotten some grief for this definition. What do tests have to do with whether code is bad? To me, the answer is straightforward, and it is a point that I elaborate throughout the book:
Code without tests is bad code. It doesn’t matter how well written it is; it doesn’t matter how pretty or object-oriented or well-encapsulated it is. With tests, we can change the behavior of our code quickly and verifiably. Without them, we really don’t know if our code is getting better or worse.
You might think that this is severe. What about clean code? If a code base is very clean and well structured, isn’t that enough? Well, make no mistake. I love clean code. I love it more than most people I know, but while clean code is good, it’s not enough. Teams take serious chances when they try to make large changes without tests. It is like doing aerial gymnastics without a net… If they don’t have supporting tests, their code changes still appear to be slower than those of teams that do.
Yes, teams do get better and start to write clearer code, but it takes a long time for older code to get clearer. In many cases, it will never happen completely. Because of this, I have no problem defining legacy code as code without tests. It is a good working definition, and it points to a solution.
Legacy Code at different levels
Now I’m going to breakdown what Legacy Code looks like at different levels:
Michael Feathers mainly focused on testability at the unit level, but in reality it exists at different levels: ⬇️⬇️⬇️