TDD & Refactoring in Legacy Systems
Test Driven Development (TDD) is one of those very rare software engineering practices that can make a real difference to the quality of your code.?
Although the easiest place to start with TDD is at the start of any new project, most software development is working with existing, or “legacy” code. And that's a bit more complicated...
In this article, I set out my advice for TDD and Refactoring in Legacy Systems, with some links to other helpful resources.
Where To Start?
I recommend that all new code added to existing will be done with TDD, and then gradually introduce tests for existing code where you are changing it. Always leave the codebase in a better state after every commit.
1. Begin new pieces of work by first creating a test that expresses some need in the software. Test for what you would like your software to do.
2. Next, write some code to make the test pass.
3. Then, refactor the code and the test to make them simpler, more readable, more concise, more general and easier to maintain.
I refer to these 3 distinct phases as:
The Three Mindsets of TDD
The simple organising principle, of “Red, Green, Refactor” is the driving force behind TDD.
RED - Write a test, run it and see it fail.
When writing the test, your goal is to clearly express the outcome that your code needs to achieve. Do this without worrying about the implementation detail - focus on designing the outside view of your code: how people will see and use it.
GREEN - You are now in an unstable state. Write the simplest code that will make the test pass.
Your aim is to get the code back to a safe, passing state as quickly and simply as you can. Make the minimum changes to your code to make the test pass.?
Don’t aim for the perfect solution at this point, the goal is only to make the test pass: Small Steps, one at a time.
REFACTOR - This is where we focus on perfecting the design our implementation. Rework code and test to make them clearer, more expressive, more general and better designed overall.
Focus primarily on the design of the implementation detail and tidying your tests to make them more readable. Your tests are passing at this point, so it is safe to make changes as long as the tests continue to pass after each change. You can safely make small changes, using the tests to reassure you that everything still works.
领英推荐
Refactoring for Legacy Systems
Refactoring means - Behaviour-Preserving Change, if you refactor and it changes what your code does, it isn’t refactoring!
Refactoring is an important tool for anyone working with legacy code. It helps us to keep our code as a habitable space, somewhere that we can do useful work.
To learn more about refactoring code towards something that you can more easily test, check out my Free Refactoring Tutorial at CD.Training.
Introducing TDD to Legacy Systems
Add tests only for code that you are changing. Use Approval Tests or Acceptance Tests to defend the code that you want to change.
When making changes, prefer design choices that enhance modularity and cohesion. Reduce coupling through separation of concerns and abstraction.
Do Not ‘retrofit’ TDD-style Unit Tests to legacy code. TDD encourages us to make our code Testable. Testable code nearly always looks different, better designed, than untestable code. So retrofitting TDD style test can be very disruptive to your existing code, so you need to approach the introduction of tests with some care.
Focusing on the areas of code that you are changing, and adopting TDD for any new code, is the best way to manage this.
Changing Your Design
Test Driven Development is really more about Design, than testing! If you would like to learn how to use these techniques to improve the design of your software, I have a comprehensive on-line course where you can study and practise at your own pace.
Even if you have been using TDD to design better software, over time your understanding of the problem will inevitably change. You will face new problems and may think of better ways to solve old ones. So you will want to be able to re-visit your design choices.
If you have used TDD to develop modular code, with loose coupling and good separation of concerns, this will be easier, but it can still be a trial! At this point, break the restructuring of tests and code into small steps, using refactoring techniques. Steer the code and tests in small steps toward your new model. Work to keep your tests passing for as long as possible while doing this.
Treat the ability to safely change your code, at any point in its life, as a good measure of its quality.
Practise
TDD improves the skills of the developer and the quality of the code that they write. It is worth investing the time and effort to learn these techniques.
I have a free TDD Top Tips guide you can sign up for.
?And a free Introduction to TDD Tutorial at CD.Training to help get you started.
Solutions Architect / Aspirante Divulgatore
2 年The right way to become an hero??♂?