return 42;

by Jan Wedel

Refactoring Legacy Code

I am currently working on a an old Java projects that contains of hundreds of classes with almost no test cases. And I had to fix some bugs. Now, what you could do is just attempting to fix the bug and hope that you actually fixed it and - even more important - that you didn't break something else. That is actually the reason why I was horrified and didn't want to touch that thing.

The code was unreadable, untestable and contained loads of concrete-class dependencies and dependencies to external components and middleware. However, after a trying to understand the dependencies a bit, I chose a few important classes and picked the one with the least dependencies to other classes or external systems and started to write test cases. Then I picked the next class that was depending on the previous one, inserted an interface (Thanks to IDE based refactoring) and wrote a small mock object that I could inject to the class during testing. The class had a lot more dependencies so I also introduced interfaces wherever I could. Some classes contained static methods, mostly as a factory method without a factory. So I moved the code from that method to the constructor, created a factory for that class and replaced all calls to static method by calls to the factory which I could replace during testing.

The more I refactored, the more everything converged to one static class that holds a few factory implementations. Moreover, the more I inserted dependencies, the more methods turned out to be just superfluous which then could be removed. IntelliJ IDEA helped a lot by pointing out even public methods that weren't used all over the project.

By writing unit test cases, the code got more readable, shorter and concise at the same time allowed regression testing and much faster and confident bug fixing for the future.

So, don't fear the dragon! It pays off.