In his foreword to Working Effectively with Legacy Code by Michael C. Feathers, Robert C. Martin says:
Legacy code. The phrase strikes disgust in the hearts of programmers. It conjures images of slogging through a murky swamp of tangled undergrowth with leaches beneath and stinging flies above. It conjures odors of murk, slime, stagnancy, and offal. Although our first joy of programming may have been intense, the misery of dealing with legacy code is often sufficient to extinguish that flame.
Besides serving as inspiration for poetic descriptions of wetlands and humorous sequences of drawings, legacy code is also something you don’t want in your Emacs. But how can you prevent it from getting there? At what point does code turn from “perfectly good” or at least “I guess it’s OK” into “legacy crap”? We need to define what “legacy code” is.
Many people will characterize legacy code as simply old, but that’s not a very practical definition. Good code doesn’t turn into legacy code on a rainy Tuesday afternoon at 2:17pm. A better definition gives us some clues on how to prevent code from becoming legacy code. You can’t stop time.
Perhaps legacy code is a feeling. It’s the feeling that the code is too hard to approach, risky to change, and difficult to understand. This makes for a slightly better definition, because it suggests some things to avoid (don’t write crappy code, duh!). However, basing a definition like this on feelings is a bit… scary.
In the book, Feathers gives a very simple definition:
To me, legacy code is simply code without tests.
This is a pretty good definition. Tests make the code simpler to approach, less risky to modify, and easier to understand. Tests protect against the very things that make legacy code legacy.
With this definition, we arrive at a shocking realization: someone in your team could be writing legacy code right now.
Do you write legacy code?