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:

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