Chapter 8: How Do I Add a Feature?

  • Do TDD

TDD and Legacy Code

One of the most valuable things about TDD is that it lets us concentrate on one thing at a time. We are either writing code or refactoring; we are never doing both at once.

That separation is particularly valuable in legacy code because it lets us write new code independently of new code.

After we have written some new code, we can refactor to remove any duplication between it and the old code.

For legacy code, the usual TDD flow should look more like this:

0. Get the class you want to change under test.

  1. Write a failing test case.

  2. Get it to compile.

  3. Make it pass. (Try not to change existing code as you do this.)

  4. Remove duplication.

  5. Repeat.

Programming by difference

Programming by difference is a method of building new features in legacy OO code. It involves using inheritance to handle new requirements. This helps with the testing because it can limit the scope of the new tests.

It’s important when applying this method to be cognisant of when the inheritance is getting out of hand. If features are always implemented using inheritance, you will not easily be able to use multiple of those features in a single flow.

In these cases, we can begin to refactor towards a composition-based solution.

See the example beginning around figure 8.2

Avoiding Liskov Substitution Violations When Using Inheritance

  1. Whenever possible, avoid overriding concrete methods.

  2. If you do, see if you can call the method you are overriding in the overriding method.

When overriding concrete methods, there is nothing forcing the override to preserve the intent of the original method. Callers may then mistakenly use the subclass thinking it’s doing something similar to the base, when it’s not.

If you really want to keep the inheritance around, you can apply an idea called normalised hierarchy: no class overrides a concrete method (overrides only ever implement abstract methods), and there’s only one level of inheritance, so there’s no ambiguity about how a given class implements method X.

Source

Working Effectively with Legacy Code, Michael Feathers — Chapter 8, How Do I Add a Feature?