Working Effectively with Legacy Code – Part 1

This week we covered the preface & introduction, and the first two chapters (Changing Software and Working with Feedback) of Working Effectively with Legacy Code by Michael Feathers.

Preface & Introduction

  • I had a similar experience getting into writing code when I was younger; I’ve always enjoyed seeing how things work (physical objects, software, processes, teams).
  • “To me, legacy code is simply code without tests.” Jameson agrees, but only because the author thoroughly defines why this is the case. Without tests, you don’t know the impact of a change.
  • “This book is about being able to confidently make changes in any code base.”
  • Jared: Be cognizant of what you do today, because you or others will have to maintain it. Jared recalled a story of how a “legacy” project got put on his plate where it would take one day to make the change, and another several days to make sure it didn’t break other things because there were no tests.
  • We discussed the idea of getting something with no tests and having a policy of adding tests for any new functionality (with the intent to come back and add coverage to other areas). You still can’t ensure existing functionality won’t break.
  • This book was recommended to Houston several jobs ago, where he was working on projects with no tests. He wants to learn how he would have done things differently.

Chapter 1: Changing Software

  • Four reasons to change software: add a feature, fix a bug, improve the design, optimize resource usage.
  • “Sadly, though, in many organizations, bug fixes and features have to be tracked and accounted for separately because of contracts or quality initiatives.” Sadly??? Jameson took this to mean that we can’t agree to disagree and move on because we have to adhere to steadfast definitions of bug vs. feature for the sake of metrics. Jared said one change could end up being tracked in two different ways, which adds for more overhead.
  • Interesting concept of considering system behavioral change instead of arguing the semantics of bugs vs. features. What are you adding? What are removing?
  • Without tests, it’s too easy to try to improve the design of a system while inadvertently losing desired behavior or creating bad behavior in the process.
  • Refactor = change the structure without changing the behavior
  • “The big deal is that we often know how much of that behavior is at risk when we make our changes.”
  • “It’s tempting to think that we can minimize software problems by avoiding them, but, unfortunately, it always catches up with us.”
  • This chapter allowed Jared to really grasp the concepts of unit, functional, and end-to-end tests. It’s an investment in the future.
  • “If they’d just stop changing their minds, we’d be done” — Jameson has heard this so many times. This is another example of “is this a bug” and “is this a new feature.” The example in the book (i.e., moving a logo from one side of the page to the other) was ultimately a communication issue (i.e., unclear requirements).

Chapter 2: Working with Feedback

  • “Changes in a system can be made in two primary ways. I like to call them Edit and Pray and Cover and Modify.” Jameson has found “edit and pray” is a more traditional approach.
  • The distinction between testing to show correctness vs. testing to detect change is huge.
  • Unit tests have the advantage of being small, localized, and able to give fast feedback of pass/fail. His point about error localization is spot-on; you want to quickly determine what a failure means without having to untangle a web of dependencies.
  • Houston: Unit tests fill the gaps that larger tests can’t, but you still need bigger tests to see how those fit together. Jameson said this is the test pyramid.
  • What about the opinion of unit testing not being as important because they’re too low level? Jamie said end-to-end (E2E) tests get you more coverage, but you trade that for slower feedback (i.e., longer test suite runtime, debugging is harder, run less frequently). Integration tests don’t talk to real things (e.g., you use an in-memory database instead of a real database). The State of DevOps Report states that unit testing does have a positive impact on quality.
  • Jamie shared this resource from Microsoft: Shift Left to Make Testing Fast and Reliable
  • “Dependency is one of the most critical problems in software development.” I’d say that’s true of any process, not just software. The theory of constraints (ToC) is built on this premise.