Refactoring Legacy

Turning monsters into friends

Barry O'Sullivan

@barryosull

DDDEU 2021

About me

  • Web Developer/Architect
  • Contractor
  • Specialise in Legacy Web Apps
  • Massive Soulsborne fan
     
  • Worked in legacy php/js codebases for 7+ years

@barryosull

Barry O'Sullivan

Session Structure

  1. Talk (30mins)
  2. Exercise 1 (25mins)
  3. Exercise 2 (25mins)
  4. Exercise 3 (25mins)
  5. Closing (5 mins)

What is Legacy

  • Long lived code
  • Outdated design/tech
  • High turnover of dev team
  • Little to no documentation
  • Hard to understand
  • Profitable

"Kill the Monster!"

How we discuss legacy

REWRITE IT!

BURN IT!

SWITCH TO TYPESCRIPT!

OLD DEVS WERE LAZY/RUBBISH!

WOOF!

1

2

3

Why Legacy Scares Us

NO POWER FANTASY FOR YOU!

Software: Prepare to die edition

I'M THE BEST

Dev

Legacy

Facing Legacy

1. Ego

2. Ignorance

The two main blockers

Ego as a Mental Model

"All models are wrong but some are useful"

Accepting Ignorance

"True ignorance is not the absence of knowledge, but the refusal to acquire it"

Gaining Understanding

Exploring and gaining context

Explore

Iterate/Refactor

Build a model

Q

Letting Patterns Emerge

Iteration leads to discovery

The Legacy Mindset

 

Explore instead of conquer

 

Let designs/patterns emerge

 

Don't force it, be patient

Iterative approach

 

Respect the legacy code

 

Build a mental map

The Benefits

What you gain

  • Better code: Faster development
  • Better devs: Learn to spot useful patterns
  • Confidence: Lose the fear, keep the respect
  • Compounding gains: Gets better over time

Refactoring safely

Working with care

Dealing with Estimates

"I'll have it done at half past never"

Q&A Intermission

The Hands-on Session

The Truth

Refactoring hands-on sessions are typically:

  • Contrived (to say the least)
  • Too short 
  • Too simple
  • Poor at demonstrating value

The goal is to try out the techniques and ideas safely, not to get value straight away

"The truth may be out there,

but the lies are inside your head."

The Techniques

A good place to start

  1. Extract and name conditionals
  2. Isolate and extract implementation concepts
  3. Use git history for context

- Not definitive or proscriptive

- Allow you to try out these ideas safely

- You'll discover your own techniques

The Code

Java

Library: Hibernate

https://github.com/hibernate/hibernate-orm

Javascript

Library: Sequelize

https://github.com/sequelize/sequelize/

Technique A:

Extract and name conditionals

  1. Find a conditional statement
  2. Extract it into a variable
  3. Give the variable a name
  4. Iterate on the name to express intent, not implementation
  5. Move onto the next conditional

Steps:

Name the system rules

Technique A Example


if ( typeof selector !== "string" || !selector ||
    nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {

    return results;
}

var isInvalidSelector = (typeof selector !== "string" || !selector);
var isValidType = (nodeType !== 1 && nodeType !== 9 && nodeType !== 11);

if (isInvalidSelector || isValidType) {
    
	return results;
}

Before

After

Technique A Session

  • 20 minutes session
  • Pair up or work alone
  • Work on a function
  1. Find a conditional statement
  2. Extract it into a variable
  3. Give the variable a name
  4. Iterate on the name to express intent, not implementation
  5. Move onto the next conditonal

Steps:

Session

main/lib/dialects/abstract/query-generator.js#L728

Discover and express system rules in your own language

Goal

Javascript:

hibernate-core/src/main/java/org/hibernate/boot/model/

source/internal/hbm/ModelBinder.java#L388

Java:

Technique B:

Separating noise from signal

Extract and name implementation details

  1. Find use of infrastructure
  2. Move like with like (if needed)
  3. Extract into private method
    (use auto-refactoring tools)
  4. Iterate on the name to express intent, not implementation
  5. Move onto the next piece

Steps:

Technique B Example


let connection = mysql.createConnection(config);

let title = 'Refactor this mess';
let completed = 'false';
let sql = `INSERT INTO todos (title, completed) VALUES('${title}', ${completed})`;

connection.query(sql);

function saveNewTodo(title, completed)
{
    let connection = mysql.createConnection(config);
    let sql = `INSERT INTO todos (title, completed) VALUES('${title}', ${completed})`;
    connection.query(sql);
}

let title = 'Refactor this mess';
let completed = 'false';

saveNewTodo(title, completed);

Before

After

Technique B Session

  • 20 minutes session
  • Pair up or work alone
  • Work on a function
  1. Find use of infrastructure
  2. Move like with like (if needed)
  3. Extract into private method
    (use auto-refactoring tools)
  4. Iterate on the name to express intent, not implementation
  5. Move onto the next piece

Steps:

Session

Explore & describe the behaviour of the system, not the implementation

Goal

main/lib/dialects/abstract/query-generator.js#L728

Javascript:

hibernate-core/src/main/java/org/hibernate/boot/model/

source/internal/hbm/ModelBinder.java#L388

Java:

Technique C:

Use git history to gain context

  1. Find a confusing piece of code
  2. Open up the file on github using git blame
  3. Look for who last changed the code
  4. See what other changes they made
  5. Move onto the next piece you find confising

Steps:

Understand the context of the developers

Technique C Example

Technique C Session

  • 20 minutes session
  • Pair up or work alone
  • Work on a function
  1. Find a confusing piece of code
  2. Open git blame view of the file
  3. Look at history of changes
  4. Who made the changes?
    When? Why?
  5. Take notes
  6. Repeat

Steps:

Session

Explore the lifecycle of the code and understand its history

Goal

main/lib/dialects/abstract/query-generator.js#L728

Javascript:

hibernate-core/src/main/java/org/hibernate/boot/model/

source/internal/hbm/ModelBinder.java#L388

Java:

Synopsis

Working with legacy is about:

  • Patience
  • Humility
  • Iteration
  • Exploration

Legacy will teach you more about writing software then any green field project.

Improving something existing is harder and more rewarding than making something new. Embrace the challenge.

More Techniques

Thank you

Refactoring legacy: Turning monsters into friends

By Barry O' Sullivan

Refactoring legacy: Turning monsters into friends

Slides from my DDDEU 2021 hands on lab on working with legacy code. When people talk about legacy they tend to use aggressive language, they view it as a nightmare that everyone should just ignore and forget. This is entirely the wrong attitude to take and it guarantees failure. Legacy can be a friend that will teach you more about programming than any green field project ever will, it’s all about changing your mindset. This session will take you through the approach you need to succeed with refactoring legacy. You’ll learn how to shift your perspective and how to deal with the uncertainty that’s ever present when working in legacy. You’ll learn how to make changes safely, gain understanding and uncover suitable patterns to apply. This is a hands-on session were you’ll tackle a messy piece of code and apply three simple techniques to gain clarity. At the end you’ll be much more comfortable dealing with legacy code and will have both the techniques and the mindset required to improve your existing system. Code samples will be available in several languages, so you just need to bring your favourite IDE and an environment that can run the code. Prerequisites: A laptop that can edit and run Java, C# or JavaScript.

  • 956