Cover of Working Effectively with Legacy Code by Michael Feathers, depicting techniques for safely changing untested software

Pages

457

Published

2004

Programming ✨ New

Working Effectively with Legacy Code

Proven techniques for understanding, testing, and safely changing code you did not write

Learn to make targeted changes in any legacy codebase without breaking what already works.

Most working programmers spend the majority of their time in existing code, not greenfield projects. Working Effectively with Legacy Code gives you a toolkit of concrete techniques for adding tests to untested code, breaking apart tightly coupled modules, and making changes safely. Michael Feathers defines legacy code as code without tests, then systematically shows you how to fix that.

About this book

Most software projects are not new. You inherit a codebase someone else wrote, under constraints you did not choose, without tests, and with a deadline. The question is not whether you will work in legacy code. The question is how quickly you can move in it without breaking things.

Michael Feathers gives that skill a name: seams. A seam is a place in the code where you can change behavior without editing that spot directly. The book teaches you to find seams, exploit them to get code under test, and then refactor with confidence. The result is a codebase that gets better over time instead of worse.

The techniques here are language-agnostic in principle and illustrated with concrete examples in C++, Java, and C#. Feathers walks through real problems: a class that is impossible to instantiate in a test, a method that calls a database directly, a global variable that contaminates every function that touches it. For each, he shows a safe, step-by-step way out.

This is not a book about ideal design. It is a book about the code you actually have. You will learn to recognize the patterns that make code hard to change, apply targeted dependency-breaking techniques to get a test harness in place, and make changes you can actually trust. The book covers:

  • How to identify and exploit object, interface, and preprocessor seams
  • Dependency-breaking techniques including Extract and Override, Subclass and Override, and Parameterize Constructor
  • How to characterize existing behavior with tests before you change anything
  • Strategies for working in large classes, monster methods, and deeply nested logic
  • How to add features to untested code without making the problem worse
  • When and how to break dependencies across layers, packages, and compilation units

After four hundred pages of specific, actionable guidance, you will approach legacy code as a set of solvable problems rather than a source of dread. The codebase you leave behind will be easier to change than the one you found.

🎯 What you'll learn

  • Identify seams in any codebase and use them to break dependencies without changing observable behavior
  • Write characterization tests that pin down what existing code actually does before you touch it
  • Apply over twenty dependency-breaking techniques to code that was never designed for testability
  • Refactor long methods and bloated classes into units small enough to reason about
  • Add new features to legacy code without making the existing mess worse
  • Recognize the specific structural patterns that make code resistant to change and address them one at a time
  • Build a working test harness around code that was never written with tests in mind

πŸ‘€ Who is this book for?

  • Backend and systems engineers who maintain production codebases they did not author and need to add features or fix bugs safely
  • Software developers who want to introduce unit tests to a project that currently has none
  • Tech leads responsible for improving code quality incrementally without stopping feature delivery
  • Consultants and contractors who regularly parachute into unfamiliar codebases and need to move fast without causing regressions
  • Computer science graduates joining their first industry team and encountering real-world code for the first time

Table of contents

  1. 01

    Changing Software

    Feathers frames four reasons you change code and explains why only one of them, behavior-preserving restructuring, lets you move fast long-term. Sets up the central problem the rest of the book solves.

  2. 02

    Working with Feedback

    Introduces the edit-and-pray versus cover-and-modify distinction. You learn why a test harness is not optional and what a safe change cycle looks like in practice.

  3. 03

    Sensing and Separation

    Explains the two reasons you break dependencies in tests: to sense what a piece of code does and to separate it from the rest of the system so it can run in isolation.

  4. 04

    The Seam Model

    Defines the concept of a seam and its enabling point. You learn to identify object seams, link seams, and preprocessor seams across different language ecosystems.

  5. 05

    Tools

    Surveys the automated refactoring and testing tools available for C++, Java, and C#, and explains how to use them safely when the code has no existing test coverage.

  6. 06

    I Don't Have Much Time and I Have to Change It

    Covers four quick techniques for making a targeted change with minimal risk when you cannot stop to add comprehensive tests first.

  7. 07

    It Takes Forever to Make a Change

    Diagnoses the build-time and coupling problems that make change slow, and shows techniques for breaking physical and logical dependencies to speed up the feedback loop.

  8. 08

    How Do I Add a Feature?

    Presents test-driven development as the safest way to add new behavior to legacy code, and introduces the Sprout Method and Sprout Class techniques for doing so without touching existing untested code.

  9. 09

    I Can't Get This Class into a Test Harness

    Works through the most common obstacles to instantiating a class in a test: irritating parameters, hidden dependencies, and singleton globals, with a safe workaround for each.

  10. 10

    I Need to Make a Change. What Methods Should I Test?

    Teaches you to reason about effect propagation: given a change to one method, you learn to trace which callers and collaborators could be affected and write tests that cover the blast radius.

Frequently asked questions

Do I need to know C++ to benefit from this book?

The code examples are in C++, Java, and C#, but the underlying techniques apply to any object-oriented language. Readers working in Python, Ruby, or similar languages will find the concepts directly transferable even if the syntax differs.

Is this book still relevant given it was published in 2004?

The core problems it addresses, untested code, tight coupling, and unsafe change, have not changed. The dependency-breaking techniques and the seam model remain the clearest treatment of this subject available. Specific tool names have evolved, but the reasoning is timeless.

What level of programming experience do I need?

You should be comfortable reading and writing object-oriented code in at least one language. The book does not teach programming fundamentals; it assumes you are already working on real projects and struggling with a specific class of problems.

Does the book cover functional or procedural codebases, or only object-oriented ones?

The primary focus is object-oriented code. Some techniques adapt to procedural C, which Feathers addresses briefly, but if your codebase is purely functional the book will be less directly applicable.

Is there a companion repository or code download?

The book does not include a separate companion codebase. The examples are self-contained within the text and are short enough to follow on the page without running them.

Who is this book not for?

If you are building a brand-new project from scratch and have full freedom to design it with testability in mind from day one, this book addresses problems you do not yet have. Start with a design or TDD book and return here when the codebase grows.

You might also like

πŸ“¬ Weekly Newsletter

Stay ahead of the curve

Get the best programming tutorials, data analytics tips, and tool reviews delivered to your inbox every week.

No spam. Unsubscribe anytime.