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:

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