Wednesday, June 6, 2012

Refactoring legacy systems

Working on a greenfield project once in a while is nice and liberating. More often though, maintenance of legacy systems is the reality. People define the term "legacy system" differently. A naive - and common - definition is legacy = old. Since the industry evolves so quickly, old must be bad as a consequence. I think there is more to it than that. There are new systems - most of them actually - that can be considered legacy even before they're made.

Systems are built to satisfy requirements. Requirements have the tendency to change often. Ideally a system can be feasibly adapted to these changes. My definition of legacy is simple: when such adapting is not feasible. This can happen for various different reasons: bad internal quality, badly chosen or obsolete technology, compatibility constraints, and a lot more.

The pace systems turning into legacy can be controlled and some improvements can be made even when the damage is already done. Compatibility constraints (like APIs) can be tough to challenge, changing certain technologies may be difficult. Improving internal quality through continuous refactoring is usually available as a viable option. In refactoring, the technical todo is usually the easy part. The hard part is how to do it in the context of development process, especially if new functionality needs to be continuously delivered. In such a scenario, several ideas can come into mind.

One is to make small changes at a time. This approach can be problematic if the development team is not disciplined enough. Bad code is viral and tends to reinfect the already healed parts. Also there are certain types of changes that can't be reasonably split into several smaller changes. A bit more elaborate strategy is called for. An enticing option is to create bubbles: carefully separate a part of the system from the others, refactor the bubble to it's "ideal" state. Eventually bubbles grow, merge and take over the system. This is a most useful approach, and can result in success.

These bubbles have interesting pitfalls though. The anti corruption layer that protects a bubble has its cost. If the bubble is left alone, not nurtured actively, the additional complexity it introduces becomes a burden to the system. In some cases it's worse to live with it than with the problems of original system. Fragmented pieces of hanging refactorings can be expensive.

1 comment:

  1. "If the bubble is left alone, not nurtured actively, the additional complexity it introduces becomes a burden to the system."


    My word, the codebases that I maintain, have had to survive "whirlwind programmers" who love to do these kinds of refactorings. They come in and have grand ideas as to what will make the codebase better, do half the work, then wander off to the next shiny thing. Meanwhile, I spend twice as much time dealing with their added complexity than I would have had they never touched the code to begin with.