According to Michael Feathers, legacy code is any code that is not currently under test. This is often the code I end up working with.
To make matters worse, dependencies within a code base often make it difficult to get that code under test. In order to write an automated test, one must recreate all those dependencies within the test systems - a daunting task if those dependencies are external systems, such as databases or web services.
In "Working Effectively with Legacy Code", Feathers describes ways to attack "untestable" code.
He suggests using "sensing variables" to determine what the code is doing within a method and writing an automated test specifically to document the current behavior of a method.
He also recommends some ways to refactor code to break dependencies or replace them with fake objects inside your test. One effective technique is to identify a problem method you want to test; make it protected; subclass the class; override the problem method, replacing the dependencies with fake objects; then call the subclass from your test.
The book focuses mostly on object-oriented languages, such as C++, Java, Visual Basic, and C#; but there are a few examples in procedural languages, such as C. The examples are simple enough that I was able to follow them and mentally translate the concepts to C# (my language of choice), despite having no practical experience with the other languages.
Feathers ends the "Working Effectively with Legacy Code" with a set of refactoring patterns designed to apply the principles of the book. In each case, he identifies the specific challenge the pattern addresses and some of the tradeoffs you will encounter when implementing this pattern.
"Working Effectively with Legacy Code" provides an excellent foundation for anyone who finds themselves maintaining someone else's code (or their own code from years before). I have used it as a model on my current project - a mass of spaghetti code with database calls within the UI layer.
I recommend it for anyone who finds themselves maintaining a legacy code base.