“Legacy Code is code without tests”
That's pretty much the premise of the whole book.
Thanks for reading...
Just kidding, there's a lot more to this.
Testing is one of those things that I've ignored for a good portion of my career but recently have sworn upon the practice.
It's just that I've experienced the pain of how fast business requirements change and how small changes lead to unexpected bugs.
The good thing is that I'm not alone in this. Lots of developers before me and definitely after me will suffer from this problem.
What's the problem?
Legacy code is one of those inevitable things in life.
So instead of avoiding it, we have to learn how to manage it.
This is the main premise of the book "Working Effectively with Legacy Code". It was written in 2004 but its content isn't outdated.
I would love everyone to read this book, especially my future colleagues...
Unfortunately, it's around 500 pages long and most people are just lazy.
*Imagine a nice transition to the next paragraph...*
In this series, we summarise the book Working Effectively with Legacy Code by Michael Feathers.
You can support the blog by buying the book from the following link:
PS. If you want any other book recommendations, you can check out my favourite books on Goodreads.
What is legacy code?
Let's start off by defining legacy code.
In the industry, legacy code is often used as a slang term for difficult-to-change code that we don’t understand.
But as the author helped software teams past their coding problems he arrived on a different definition:
Legacy code is simply code without tests.
Code without tests is bad code. It doesn’t matter how well written it is; it doesn’t matter how pretty or object-oriented or well-encapsulated it is. With tests, we can change the behavior of our code quickly and verifiably. Without them, we really don’t know if our code is getting better or worse. – Michael Feathers
An extra note on my part:
If there is one constant in life then it must be that everything changes.
Business requirements change a lot and it's up to programmers to make changes as easy as possible.
This is where tests come, how can you confidently make changes without tests?
Your refactor might break some other code.
Tests are the first thing that you should do.
Now with introductions over, let's go over the reason why code changes.
Making changes is essentially what we do for a living but there are different types of changes.
Some are straightforward to do, others aren't.
Let's look at the different kinds of changes that software has.
Kinds of Change
The four primary reasons why code changes are:
- Adding a feature
- Fixing a bug
- Improving design
- Optimizing resource usage
Adding Features and Fixing Bugs
Adding a feature seems like the most straightforward type of change to make. The software behaves one way, and users say that the system needs to do something else also.
But there's a fine line between adding a new feature and fixing a bug.
For example let's say that we are working on a web-based application, and a manager tells us that she wants the company logo moved from the left side of a page to the right side. We talk to her about it and discover it isn’t quite so simple. She wants to move the logo, but she wants other changes, too. She’d like to make it animated for the next release. Is this fixing a bug or adding a new feature?
It depends on how you look at it. From the point of view of the customer, she is definitely asking us to fix a problem. On the other hand, the developer will see this as a new feature.
We can talk all day about the difference between the two but in general it comes down to whether you are adding new behaviour or changing old behavior.
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. – Michael Feather
Design improvement is a different kind of software change. We want to alter software structure to make it more maintainble and keep the same behavior. When there are unexpected behavioural changes, then it's called a bug.
This is one of the main reasons why developers don’t attempt to improve design often is because it is relatively easy to lose behavior or create bad behavior in the process of doing it.
This form of change is also called refactoring.
Optimizations is like refactoring but has a different goal.
When we refactor, we want to keep the same behavior while improving code structure.
In optimizations we want to improve some resource used by the program, usually time or memory.
Putting it all together
In summary, three different things can change when we do work in a system:
- Resource Usage.
Sometimes when changing these we can change behavior which leads to bugs and that's why:
Preserving existing behavior is one of the largest challenges in software development. Even when we are changing primary features, we often have very large areas of behavior that we have to preserve. – Michael Feather
T0 mitigate this risk we have to ask three questions:
- What changes do we have to make?
- How will we know that we’ve done them correctly?
- How will we know that we haven’t broken anything?
Some teams simply ignore this and follow the mantra:
- "If it’s not broke, don’t fix it."
- "Let's not change any existing code and simply add new code instead."
This has serious consequences such as:
- When we avoid creating new classes and methods, the existing ones grow larger and harder to understand.
- When people don’t make changes often they get rusty at it.
- The last consequence of avoiding change is fear. Unfortunately, many teams live with incredible fear of change and it gets worse every day.
But what's the solution here?
Do we try harder?
Hire more people?
This is what we will cover in this book.
Next article we will cover the second chapter of the book that deals with working with feedback.
Thanks for reading.