Dealing with an ageing code base is one of the hardest challenges that software development teams face. Legacy code bases can slow teams to a crawl, and therefore it is critical to solve this on the road to agility. Software rewrites fail at alarming rates! Refactoring – a safer approach – has emerged as the de-facto technique to tackle this challenge.
This session we will equip attendees with techniques and lessons to help them refactor more effectively. We will share our experience gained while working with various software teams, from startups to mid-sized organisations, that attempted to rescue their legacy from impending doom.
You will learn how to justify the investment in refactoring legacy code to product owners; when and how to apply different refactoring workflows on legacy code; and practical tips to avoid common pitfalls when refactoring code.
7. Credits
• Kent Beck on Small, Safe Steps and TDD
• Robert C. Martin on Clean Code
• Martin Fowler on Refactoring Techniques
• Ward Cunningham on Technical Debt
• Michael Feathers on Starting with a Mess
• J.B. Rainsberger relating it to Accidental Complication
8. What is legacy code?
What is the value in fixing legacy code?
How do we speak to Product Owners about it?
Should you rewrite?
What is refactoring?
When should we refactor?
53. Code that we’re afraid to change.
Invest in making change easier and less risky.
Talk to Product Owners about return on investment.
Avoid rewrites, favour refactoring.
Many, small improvements without changing behaviour.
Keep it clean and escalate when crisis is imminent.
54. HOW ARE YOU GOING
TO MAKE IT HAPPEN?
martin.cronje@myob.com
@martincronje
jacques@nreality.com
@jacdevos
Notes de l'éditeur
Come and chat to us and let even code together
We really what you to get some ideas on: how to make it happen!
Beck, Kent (2003). Test-Driven Development by Example, Addison Wesley - Vaseem.
Beck, Kent (2001). Extreme Programming Explained: Embrace Change 2nd. ed. Addison-Wesley.
Fowler, Martin (1999). Refactoring: Improving the design of existing code. Addison Wesley.
Feathers, Michael C (2004). Working Effectivelywith Legacy Code. Prentice Hall.
Martin, Robert Cecil (2009). Clean code: a handbook of agile software craftsmanship. Upper Saddle River, NJ: Prentice Hall.
Cunningham, Ward (2011). Ward Explains Debt Metaphor http://c2.com/cgi/wiki?WardExplainsDebtMetaphor
Rainsberger, J.B. Fundamental Theorem of Agile Software Development
https://vimeo.com/79106557
To speaker:
- Remember the trade-off between cleaning up and ROI
- Let’s have a beer together
Example:
Spaghetti code that breaks all over the place
when you make a change in one area
Is very scary to change
So, now that we know what legacy code is.
Why would we bother to improve it?
If it ain't broken, don't fix it
But that approach, and not improving, got is into trouble the first place
Make it easier to work with or even
For our future happiness
I think that is a great reason, but who would pay for your future happiness?
Good craftsmanship
That brings me to 3 main reasons we found
To fix legacy code.
We found that there are
3 main reasons
To fix legacy code.
The first reason is that:
It is our PROFESSIONAL DUTY
To TAKE GOOD CARE of our system
This is almost like the
Hippocratic Oath that doctors take
“First do no harm … to code ”
Following this oath,
We always build well crafted software.
Although professionalism is a great value
, it has it’s limits:
If we follow it blindly
We might forget what we are paid for.
We might starting building things
that don’t benefit our customer.
A second, related line of reasoning is that:
our primary goal is
to deliver a quality product
to our customer.
With this mindset,
We will not compromise on quality
And always go the extra mile to
Although this is also a great mindset:
it may cause over-engineering
But over-engineering
, by definition,
does not add value
in the customer’s terms.
This brings us to the third and ultimate reason:
The effort we expend on improving the system is an investment
And this investment should have a value
….A monetary value In Dollars
Reasoning in terms of investment is the only way
to know
how much fixing we should do.
For example:
Fixing
an unimportant system
that does not change all that often,
will NOT pay off.
But thinking in terms of investment is hard
How do we actually go about
determining the balance between:
short term investments of adding NEW features and
long term investments in making the system less expensive to work with
Cost of delay
Example: A special “Moonlight” project
where a senior dev has to quickly hack in changes
So get access to a new market
Will slow us to a grind
When that system starts getting used and need changes
Cost of delay
Example: A special “Moonlight” project
where a senior dev has to quickly hack in changes
So get access to a new market
Will slow us to a grind
When that system starts getting used and need changes
They think refactoring fails?
They think developers play?
They don’t understand the impact of bad design?
Example:
I talked to some product owners and their response was:
Nobody spoke to me about this,
Nobody told me what the implication of this is,
Nobody explained to me what was happening.
Example:
OneLaw document generation
Example:
If we work on a mission critical system,
Like a trading system,
And we know the system is messy – changing one part will impact other.
Any change can easily make products stop working.
Causing revenue and reputation damage.
Even thought no related changes are made.
HARDER AND HAEDER TO GET SOMETHING OUT
Example:
If we try to make a change to messy system,
It might have adverse effects on other, unrelated parts,
The time getting to grips with all the permutations,
And making sure these permutations cause no harm,
Is something that cannot be estimated, especially by an analyst.
So,
Now that we understand the problem
and have time to fix it. What do we do?
Why do we even bother with the crappy old system?
Why don’t we just rewrite and start with a clean slate?
No. Rather the devil you know: fine, but we have to do something, this devil is causing havoc
No. It’s too expensive: yes, but development on the legacy system is also becoming increasingly expensive
Yes. Use latest technologies + Learnt from mistakes!
Thinking that:
We learnt from mistakes in the old system.
And we want to use the latest technologies anyway.
This this line of reasoning is extremely tempting.
But. Let me tell you about a project.
I’m sure most of you know this story
from your own experiences;)
I joined a rewrite
of a mission critical system
6 months after it began.
…although it was supposed to be finished by the time I started.
We were completely stuck!
For months we were in a kind of “Whack a Mole” state,
dealing with the one unexpected problem after the other.
And despite the best effort of the analysts,
The complexity of the old system
Over years
was completely underestimated,
To make matters worse,
the Maintenance team was churning out functionality on the old system.
It was a nightmare trying to merge changes regularly from an incompatible system.
This clearly taught me that:
it is nearly impossible to predict
the difficulty to rewrite
an old complex system.
We finally pushed through and released to production.
But the week after release was one big crises:
Parts of the system stopped working
, for unexpected reasons.
To make matters worse,
Some business departments could not function at all,
Since they started to rely on idiosyncrasies of the old system.
I remember getting a call from one department manager.
He shouted in my ear that:
Our mess will get him fired!
and he is only weeks from retirement!
The lesson I got from this was that:
rewrites can bring a business to its knees
They are extremely risky. Especially on mission critical systems.
We finally pushed through and released.
But the week after release was one big crises:
Parts of the system stopped working
, for unexpected reasons.
Further,
Some business departments could not function at all,
Since they started to rely on idiosyncrasies of the old system.
I remember getting a call from one department manager.
He shouted in my ear that:
Our mess will get him fired!
and he is only weeks from retirement!
This taught me that:
rewrites can bring a business to its knees
They are extremely risky.
We should think twice before we rewrite a system.
And resist the fallacy that
“we will do it better this time round”
But we still need to do something about our legacy.
This makes it pretty clear that:
Refactoring the current system
is often a safer bet
than a rewrite.
But what is this thing we call refactoring?
The word “Refactoring” does not even appear in the English dictionary!?
Simply put, refactoring:
Is a disciplined, step by step process
That gradually improves
The internal quality
Of our system
Refactoring is never
a quick fix.
Refactoring does not change behavior:
That includes things like bug fixes
and performance improvements.
And when we refactor
We have 2 goals:
Firstly,
we want to
make it easier
to change the system.
In other words,
we want to make it less expensive
to get new valuable features
out the door.
Secondly,
we want to reduce the risk
in making changes to the system.
We want to get to the point
Where we can deploy changes regularly
without loosing sleep over it.
Reducing the risk of change
is especially relevant to mission critical legacy systems
Refactoring
achieves these goals,
Through a process of,
Divide and Conquer:
We want to:
make many, small
seemingly insignificant
Improvements to the system.
We want to avoid big, commits like the pest.
Since big changes are inherently risky.
In the words of Kent Beck
We must get into the habit of:
Taking “Small, Safe steps”
Following this approach, we can make HUGE improvements in a much safer way.
The next thing to remember is that
Refactoring puts Safety First.
This is done by
Capturing the
current behavior of the system
with tests.
And you want to run these tests on every change.
TO get quick feedback.
If you have broken a major feature.
(even thought this is not bullet proof)
A lot is written on the topic of testing, but that is outside the scope of this talk.
I recommend Michael Feather’s “Working effectively with legacy code” is a good start
Lastly, we have to realize with refactoring,
Is that there are usually
many things you can do
To improve the the code base
Without rocking the boat
So we find that a good rule of thumb is to:
start with the lowest risk
readability improvements.
Like the naming standard
Refactoring legacy code is a process of managing risk in changes.
Starting with the lowest risk improvements. will make the rest of the refactoring process much easier.
But Martin will talk more about When we refactor.
In summary,
refactoring is a process
that makes change less risky and expensive
By making many, small, safe improvements
To the internal structure of your code
For example:
Fixing a bug: is a behavior change
Fixing performance: is a behavior change
Splitting the system into separate services: a refactoring change.
Example: when making a change in someone else’s code:
break long method into clearly named sub-methods,
to make it clear to others what you figured out
Example: we can see that spaghetti-code in our trading system is fragile and dependent.
If we change things in one part we can see that the system will keep crashing down in other important areas.
We need to create awareness that modules need to be broken up, into subsystems.
Example: We are in a dangerous minefield of important code,
trying to figure out how current code works,
and where we want to take it.
use a detached head, to start making throwaway changes
for the purpose of learning.
once we learnt, we start with a clean checkout, knowing where we will go.
In this talk we saw that:
Legacy is code that we’re afraid to change
And that we should invest in making it easier and less risky to work with.
---
We should also clearly communicate to our PO
What the impact of legacy is and the value in improving it.
---
We saw the dangers of rewrites and the benefits of refactoring,
in terms of risk and cost.
And we saw that refactoring avoids risk by making lots of little improvements,
Without changing any observable behavior.
---
Finally,
We should always quietly improve our system,
but that should make it clearly heard
when there are big underlying problems
To speaker:
- Remember the trade-off between cleaning up and ROI
- Let’s have a beer together