Search
Close this search box.
Search
Close this search box.
Search
Close this search box.

Legacy Code: Extract-FirstUT-Cover-Refactor-TDD

Facebook
Twitter
LinkedIn
Pinterest
WhatsApp

Recently, I had the opportunity to work on legacy code with several teams from various organizations. I would like to share my experience.

We usually start by choosing a piece of code that is “painful”: changing frequently and “scary” to touch because of its complexity. We explain that our purpose is to make the code simpler, readable, and easy to change. Establishing the motivation for what we do is important!

In essence, the steps we take are:

  1.       Use extract method/rename to make the code more readable (specifically applicable for very long methods).
  2.       Write and execute the first unit test (that’s usually the toughest part) as described by Michael Feathers.
  3.       Add more unit tests until the area you want to refactor is satisfactorily covered.
  4.       Refactor to make the code more maintainable (working in very small steps, as described by Joshua Kerievsky).
  5.       Make the required change using TDD.

The purpose of (1) is to see the forest, not the trees. Long methods tend to be unreadable. Using the “extract method” helps you see clearly what’s going on. Once you gain vision, you can start to rename. Arlo Belshee talks about this.

As an example, look at these two statements:

At the first, if statement, we have extracted the condition to a method. Remember that what you do most of the time with code is read it. You need to make it readable.

Item (2), as mentioned above, is the difficult part. You need both to master the technique and have the resolution to do it. I usually do it with the entire team and so, together, we have the required courage.

For instance, take a look at this behemoth method.

Pure fun, eh? This is something I call an amusement park method. We usually start by trying to call it null. Sometimes it actually works and we have a first-unit test. Then we start to slowly fill in the parameters. Maybe instead of a null send an empty dictionary. Maybe instead of an empty dictionary send a dictionary with two entries. And if there’s no choice sometimes we run the actual application and serialize the parameters, to be deserialized in the unit test later.

Sometimes we change a method from private to public, sometimes we add a method to better control a member, and there are more vicious things we do. Sometimes it can take a whole morning to do this. However, once you understand this, it becomes very simple.

Then you start looking at coverage.

Once you have the first test, things start to move faster (3). You start adding more and more tests. You start looking at coverage reports to see which lines of code are covered and which aren’t. If something is not covered, you can add another unit test to cover it.

Now (4) we can start to make bigger changes. Once you have the unit tests in place you feel free. You make a small change, you run the test. Another small step and the tests run again. Some IDEs have plug-ins that run the tests every time something is changed.

This is the time to get better familiar with the automatic refactoring tools of your IDE. Make sure you are familiar with introducing parameters, fields, and variables. Extract class is a very nice one and so is the ability to convert a method to static and move a method. The trick here is to make as fewer manual changes as possible and move the code around fluently.

Many times by this point, there is a small disappointment. The code you feared in the morning now looks quite simple. The real challenge is making the code simple and solving the puzzle.

Now we reached the point when we can quite easily add some code to fulfill a new requirement (5). We can add a new test, see it fail, make the required change, see it pass, and maybe do a little refactoring. Nothing like the joy of seeing unit tests turn from red to green.

(the above are unit tests from a very nice exercise called Gilded Rose)

And that’s it.

Subscribe for Email Updates:

Categories:

Tags:

Achieve Business Agility
Tips
Change Management
Business Agility
Agile and DevOps Journey
speed at scale
PI Objectives
Lean Agile Basics
RTE
Agile Risk Management
SA
Portfolio for Jira
Agile Product Development
LPM
Tools
Software Development Estimation
Principles of Lean-Agile Leadership
Lean Agile
Advanced Roadmaps
Agile Community
Quality Assurance
ART Success
Development Value Streams
Risk Management on Agile Projects
Legacy Enterprise
Continuous Planning
Spotify
Pomodoro Technique
predictability
Story Slicing
Entrepreneurial Operating System®
TDD
RTE Role
Scrum
Value Streams
Release Train Engineer
Professional Scrum with Kanban
The Agile Coach
SAFe
Agile Basics
Agile Mindset
Games and Exercises
Professional Scrum Product Owner
Agile Games and Exercises
Nexus Integration Team
Operational Value Stream
Nexus and Kanban
Risk Management in Kanban
Reading List
Atlaassian
Managing Risk on Agile Projects
Elastic Leadership
Lean-Agile Budgeting
Applying Agile Methodology
Enterprise DevOps
Nexus vs SAFe
Agile Delivery
Product Management
ALM Tools
Continuous Deployment
Lean and Agile Principles and Practices
Agile Project
LeSS
Lean Budgeting
Rapid RTC
Scrum With Kanban
A Kanban System for Software Engineering
Agile for Embedded Systems
Presentation
EOS®
Sprint Planning
Implementing SAFe
Agile Assembly Architecture
Kaizen Workshop
Agile Games
An Appreciative Retrospective
Program Increment
Agile Contracts Best Practices
SPC
Lean Agile Organization
speed @ scale
Agile Release Management
ARTs
Accelerate Value Delivery At Scale
Kanban
Slides
Code
Lean Software Development
Agile Israel
Certification
Agile Techniques
Sprint Retrospectives
Daily Scrum
Lean and Agile Techniques
Agile Marketing
Self-organization
Software Development
NIT
Nexus
Product Ownership
Legacy Code
Agile
Agile Israel Events
Agile Product Ownership
Kaizen
PI Planning
Agile Program
QA
Scaled Agile Framework
Scrum Primer
Scrum Guide
AgileSparks
Lean Risk Management
System Archetypes
Effective Agile Retrospectives
Covid19
Artificial Intelligence
Kanban Kickstart Example
Kanban Game
Agile India
Planning
Implementation of Lean and Agile
Jira Cloud
WIP
System Team
IT Operations
Introduction to Test Driven Development
Scrum.org
Agile in the Enterprise
Webinar
Releases Using Lean
Engineering Practices
Risk-aware Product Development
Agile Development
Certified SAFe
Process Improvement
Acceptance Test-Driven Development
Atlassian
Professional Scrum Master
ROI
Scrum Values
Iterative Incremental Development
The Kanban Method
Sprint Iteration
DevOps
Kanban 101
SAFe DevOps
Agility
Agile Project Management
chatgpt
Lean Startup
POPM
Limiting Work in Progress
agileisrael
ATDD
Kanban Basics
AI
Agile Outsourcing
Agile Release Planning
Scrum Master
Agile Testing Practices
lean agile change management
Lean Agile Management
Jira admin
Systems Thinking
Perfection Game
Video
AI Artificial Intelligence
Introduction to ATDD
SAFe Release Planning
LAB
Scrum Master Role
Coaching Agile Teams
Manage Budget Creation
What Is Kanban
Amdocs
Continuous Integration
Continuous Delivery
Lean Agile Leadership
Large Scale Scrum
System Integration Environments
Frameworks
Agile Exercises
ATDD vs. BDD
ScrumMaster Tales
Jira
RSA
Test Driven Development
Lean-Agile Software Development
BDD
Managing Projects
Continuous Improvement
Hybrid Work
Built-In Quality
Jira Plans
User stories
Scrum and XP
Nexus and SAFe
AgileSparks
Logo
Enable registration in settings - general

Contact Us

Request for additional information and prices

AgileSparks Newsletter

Subscribe to our newsletter, and stay updated on the latest Agile news and events

This website uses Cookies to provide a better experience
Shopping cart