As part of investing in myself I decided to read four different programming/management books in 2017 to improve myself. For the first quarter, I read Working Effectively with Legacy Code by Michael Feathers (even though I’m not getting this writeup out until the second quarter I swear I read it in Q1). This article is my way of keeping myself accountable for the actual reading. :-)
Main Take Away
The book’s main thesis is that having your code under test (with unit tests) is the most important metric of your code. Even if getting the code under test causes you to make some less than optimal solutions in the short term. I’m a perfectionist at heart and at first this seemed like a horrible idea but then I started thinking about some of the legacy code we have and how hard it would be to rewrite completely it so it could be tested “right”. As I’ve applied some of the techniques in the book on my own work I’ve really seen how this is better.
I also like that his definition of legacy is code without tests. Even though we have new code in our projects because it’s not unit tested it’s still legacy and could still be really hard to test (and it has been).
I think the hardest part of reading this book was that I kept thinking about how it could impact my work and I kept getting distracted instead of focusing on the page. :-)
This book is full of little snippets of helpful information. I though I would share a couple of the better quotes I pulled out of the book as I was reading.
Behavior is the most important thing about software. It is what users depend on. Users like it when we add behavior (provided it is what they really wanted), but if we change or remove behavior they depend on (introduce bugs), they stop trusting us.
I think this really speaks for itself.
A unit test that takes 1/10th of a second to run is a slow unit test.
After reading this I ran a check on our Unit Tests and this doesn’t always hold true. It’s something I know we need to work on and I’m hoping to find a way to add this as part of our unit tests.
When you need to add a feature to a system and it can be formulated completely as new code, write the code in a new method. Call it from the places where the new functionality needs to be. You might not be able to get those call points under test easily, but at the very least, you can write tests for the new code.
This is an example of just getting it under test but it works really well in practice.
The best way to see if you will have trouble instantiating a class in a test harness is to just try to do it. Write a test case and attempt to create an object in it. The compiler will tell you what you need to make it really work.
I tried creating an instance of one of the more difficult classes I’ve inherited (and made worse) and this was really difficult. Ripping out huge sections of the code was the only way around it.
Long methods are a pain, but monster methods are worse. A monster method is a method that is so long and so complex that you really don’t feel comfortable touching it. Monster methods can be hundreds or thousands of lines long, with enough scattered indentation to make navigation nearly impossible. When you have monster methods you’re tempted to print them on a couple of yards of continuous-feed paper and lay them out in a hallway so that you and your coworkers can figure them out.
There are a couple bad parts about this book.
The first is only a grip because we primarily work with PHP at my day job. Some of the chapters (the one on non-OOP languages especially) are less helpful because we can’t rely on the compiler to catch places where we change signatures and the signature change cause breaks (however we’ve added more unit tests this has been less of a problem).
As my co-workers and I have been discussing this book we keep talking about how it would be nice to have any examples that work in PHP moved over. This might have to be something I look into later once I get a better grasp of the content. :-)
The second is that the last chapter is a real slog. It comprises a bunch of sections that explain recipes on how to refactor your code. I don’t know of a better way to present the material but I think I just kept waiting for the chapter to end and it never did. :-) I also think it would be nice to have a cheat sheet with these because it’s hard to wrap my mind around it all at once.
I would highly recommend this book to others and it’s actually going to be added to the required reading for new employees that I on board. I’m actually planning on re-reading it soon because there was so much information to digest. It, plus some additional articles have really improved my ability to write good unit tests. The project I’m working on at work is almost completely TDD.