Type Classes

Type Classes

Share this post

Type Classes
Type Classes
Working with Legacy Haskell

Working with Legacy Haskell

A sort of book review: Working Effectively with Legacy Code from a Haskeller’s perspective.

Chris Martin's avatar
Chris Martin
Apr 10, 2023
∙ Paid
3

Share this post

Type Classes
Type Classes
Working with Legacy Haskell
Share

In 2010 I picked up Michael Feathers’ Working Effectively with Legacy Code1 from the company book shelf because I felt the title described something I had been having trouble with. Most of my software experience at that time was from class projects, and I found that what I had learned so far in school wasn’t sufficient for corporate work. I was reminded of it again while thinking about some commentary from grumpy Haskell advocate Deech:

I've found very few tech tutorials which teach you to get out from under a mess. It's all golden path scenarios, maybe that's why there's such a massive gap between learning and practice.

Too much writing focuses on school-style stuff but not corporate wisdom, and so I got to wondering how much of Feathers I could translate into Haskell. What follows is a sort of book review: Working Effectively with Legacy Code from a Haskeller’s perspective. This article covers my thoughts on chapters one through four.

What is legacy code?

Our legacy is what we pass down for others to inherit. A legacy can be valuable, but in any inheritance one is likely to find something disturbing.

Screenshot from Pulp Fiction (1994). A man is holding a watch that has been hidden for several years inside the rectums of two men in a prisoner of war camp; the watch is now being handed down to the son of one of the men.
“Now… Little man, I give the watch to you.”

My favorite quote from this book comes from the preface:

To me, legacy code is simply code without tests.

I think this definition is spot on. When we’re using “legacy” in the pejorative sense, it’s code that we’re stuck with because it’s hard to change. When we say code is hard to change, we mean it’s hard to be confident that the changes will work and not break something. The book, then, is about how to regain lost confidence.

Specifically, by tests Feathers is talking about unit tests: checks that are very fast and have no dependencies on a database, network, file system, or any other kind of environment that isn’t fast and easy to set up. These tests are what really matters because they allow a tight feedback loop that lets us continually work with confidence.2

Main bullet point of the book: To work with legacy code, first we have to make it not legacy code anymore, and we do that by introducing testing. To introduce testing, careful refactors are often needed first. So we first do conservative refactoring code to make it testable, then write tests, and finally then we can begin the work we set out to do.

Working with Feedback

Feathers gives examples using Java and C++ with UML diagrams — all things I recall from school but haven’t worked with in a long while — and they are at times difficult for me to follow. But the gist of the example in chapter two is that shows two types of refactor to break problematic dependencies:

  1. Changing a function’s domain to something more specific so a test doesn’t have to instantiate values that are not really needed.

  2. Changing a function’s domain to something less specific by, in a language like Java, changing a parameter’s type from a concrete class to an interface.

These are really two ways of accomplishing the same thing, which I will illustrate in Haskell.

Keep reading with a 7-day free trial

Subscribe to Type Classes to keep reading this post and get 7 days of free access to the full post archives.

Already a paid subscriber? Sign in
© 2025 Mission Valley Software LLC
Privacy ∙ Terms ∙ Collection notice
Start writingGet the app
Substack is the home for great culture

Share