Thursday, June 10, 2010

The Joy of Legacy Code

Michael Feathers

Legacy systems are not "sexy" but they are still doing useful/interesting work

Code is biological
A kudzu vine that grows and grows, takes over an ecosystem over time
The aesthetic is different in a large system: our standards may need to change

We align with the things that are easier over time
adding code to an existing function is easier
therefore functions will get longer
classes will get bigger
extra work to create a new class/function: think of a new name, more keystrokes, etc

Morale: how are we going to make progress on this code that isn't always pretty
attainable goals: hard to feel like you're making progress
Code coverage as a metric: you could spend your entire career trying to get to 100%
Adding automated tests to code that is already working can be futile
Add tests to code you are about to change, as a feedback mechanism
Some areas are changed much more frequently than others
Hotspots will gain test coverage sooner than you think, you may be pleasantly surprised

Useful metrics:
Change coverage: find the areas where you have the most commits
Count all commits in a file towards this metric once that file has tests

The hardest part of adding tests to legacy code is breaking the dependencies to attain isolation for unit tests

Method Object
Martin Fowler's Refactoring Catalog
Take a method and turn it into a new class with all the code in a run() method
Allows you to move forward in interesting ways

There is a one time cost for testability
Hardest part of creating tests is breaking dependencies
Once you have broken the dependencies adding more tests will be much easier

Isolate Sections
Higher levels of testing are also valuable
Easy to have changes propagate far away from the actual change
It's easy with singletons to modify states from any place: so people do modify it from any place
Componentize large sections are consolidate the globals: totally eliminating them might be too difficult in a large existing system

Exploit Natural Encapsulation
The main problem with legacy code is understandability: use Understand tool to examine the structure of your code and create new classes that are already naturally encapsulated

Name the Thorny Areas
"Quince's Quagmire"
Wall Map with your visualization of the system "here be dragons"
Dismisses the fear associated with particularly nasty code
Some gallows humor...

Wounded Giant Metaphor
Approach it like a doctor: the existing code is not an enemy, you're trying to make it better

Heroic Stories
Sharing war stories. Develop a folklore about the code you're working on

Other metaphors: Code as a garden, code as a playground

Explain your system as simply as possible, ideally 4 elements or less, as a way to start owning/exploring the code. A way to get a foothold of understanding

Scratch Refactoring
You have a big piece of code and no idea where to start refactoring
Refactor it to hell, dont test it, dont even compile it, and then throw it away
Not a waste of time because you will understand more about what's there

Viking Laws
-be brave & aggressive
-be direct
-be versatile and agile
-attack one thing at a time
-be prepared
attitude is everything
You *can* apply creativity to a legacy code

No comments:

Post a Comment