This is an HTML rendering of a working paper draft that led to a publication. The publication should always be cited in preference to this draft using the following reference:
  • Diomidis Spinellis. Book review: Working effectively with legacy code. ACM Computing Reviews, 47(11), November 2006. Green Open Access

The document's metadata is available in BibTeX format.

Find the publication on Google Scholar

This material is presented to ensure timely dissemination of scholarly and technical work. Copyright and all rights therein are retained by authors or by other copyright holders. All persons copying this information are expected to adhere to the terms and constraints invoked by each author's copyright. In most cases, these works may not be reposted without the explicit permission of the copyright holder.

Diomidis Spinellis Publications

Copyright © 2006 by the Association for Computing Machinery, Inc. Permission to make digital or hard copies of part or all of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. Copyrights for components of this work owned by others than ACM must be honored. Abstracting with credit is permitted. To copy otherwise, to republish, to post on servers, or to redistribute to lists, requires prior specific permission and/or a fee. Request permissions from Publications Dept, ACM Inc., fax +1 (212) 869-0481, or

Book Review: Working Effectively with Legacy Code

Diomidis Spinellis
Athens University of Economics and Business

Michael C. Feathers
Working Effectively with Legacy Code
Prentice Hall, Upper Saddle River, NJ. 2005
434 pp.

In the 1980s Lehman and Belady observed that programs used in real-world environments must continuously evolve to remain useful, and, more importantly, as evolving programs change, their structure becomes more complex unless active efforts are made to avoid this decay. Valuable code that one generation of developers inherits to the next is often termed legacy code, and, more often than not, this code through its evolution suffers from a complex structure, outdated development methods, and useless documentation. Feathers's book "Working Effectively with Legacy Code" tackles the problem head on, providing valuable practical advice for bringing such code under control.

Feathers idiosyncratically defines as legacy code, code that is lacking tests, and by tests he typically means unit tests that developers can swiftly execute after a change to ensure that they didn't break anything. While this definition does provide a clarity of purpose, it steers the subject's treatment toward directions that are neither widely accepted, nor universally practical. For example, a large part of the book deals with object-oriented programs and techniques, whereas most legacy code is likely to be in procedural languages like Cobol, Fortran, and C. Furthermore, although many modern development approaches espousing unit testing have demonstrated encouraging results, we currently lack empirical evidence regarding the risks and practicality of retrofitting unit tests onto legacy code.

The book is divided into three parts: an introductory part discussing the high-level mechanics of program change, a sequence of chapters offering answers to commonly-encountered maintenance challenges (for example, "How Do I Add A Feature" or "I Need to Make a Change, but I Don't Know What Tests to Write"), and a final part detailing 24 different refactorings that developers can use for breaking dependencies. All material is extensively cross-referenced, however the organization of the book's chapters could be improved by adopting a more consistent narrative structure. The book ends with a small glossary and an index, but lacks a separate bibliography or list of references.

The technical advice contained in the book is excellent. Feathers obviously has a deep understanding of object-oriented design and development techniques, and a rich experience in applying them in practice. The advice spans both design and coding techniques, and, where appropriate, references how changes can be automated by using refactoring tools. The writing is clear, although, unsurprisingly, many examples of supposedly legacy code require significant effort to comprehend. Clear UML diagrams are extensively used to illustrate the code's structure.

In summary, Feathers is to be commended for addressing the vitally important subject of legacy code maintenance. As object-oriented code ages and becomes legacy the book will become increasingly relevant to the practitioners working with it.