LonghornPHP 2025 - So You Just Inherited a Legacy Application... .pdf

svpernova09 7 views 69 slides Oct 24, 2025
Slide 1
Slide 1 of 69
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40
Slide 41
41
Slide 42
42
Slide 43
43
Slide 44
44
Slide 45
45
Slide 46
46
Slide 47
47
Slide 48
48
Slide 49
49
Slide 50
50
Slide 51
51
Slide 52
52
Slide 53
53
Slide 54
54
Slide 55
55
Slide 56
56
Slide 57
57
Slide 58
58
Slide 59
59
Slide 60
60
Slide 61
61
Slide 62
62
Slide 63
63
Slide 64
64
Slide 65
65
Slide 66
66
Slide 67
67
Slide 68
68
Slide 69
69

About This Presentation

Given at Longhorn PHP 2025 in Austin, TX


Slide Content

So You Just Inherited a $Legacy
Application...
Joe Ferguson

leanpub.com/minimumviabletests leanpub.com/mlaphp
For Further Reading

Legacy
Applications

First:
A Warning

“There are no
solutions, only
trade offs”
- Thomas Sowell

What is a "Legacy" application
“The Princess Bride”

Legacy is often used for an older
production application that was
written before, or without regard
for modern technologies or
practices.

If you ask Wikipedia…
"... no-longer supported …"
"... maintained by an administrator that did not develop the code …"
"... supporting older file formats ..."
https://en.wikipedia.org/wiki/Legacy_code

Modern Interpretation
"... source code inherited from someone else …"
"... source code inherited from an older version of the software ..."

Some people say…
"Any code in production is not legacy”
"Any code written X years ago is legacy"

Legacy is all these things
"... no-longer supported …"
"... maintained by an administrator that did not develop the code …"
"... supporting older file formats ..."
"... source code inherited from someone else …"
"... source code inherited from an older version of the software ..."
"Any code in production is not legacy”
"Any code written X years ago is legacy"

This process is
not Legacy
Specific…

Inheriting a Legacy App
Precontemplation or Shock/Disbelief
Contemplation and/or Anger
Determination and Bargaining
Action and Reconstruction
Maintenance and Acceptance

Precontemplation
or Shock/Disbelief

Precontemplation
or Shock/Disbelief
This is the initial "what is this?!"

That’s now how this works!

Precontemplation
Not ready for change (project, code base, etc)
Usually you don’t know the depths of issues
Can sometimes lead to assuming the worst
Usually this is the shortest phase due to business needs

Shock/Disbelief
This is where the WTFs and the WTHs should be left
Try to work through any negativity here
Be positive about the previous developer’s intentions

Contemplation and/or Anger
This is the planning phase
Try to get all of your ager at the code base out during this phase, it will
help you see the path forward.
Taking stock of what we’re working with

Initial Project Overview
Is there a framework?
Is there a coding standard?
Is there any autoloading?
How are dependencies being handled?
Is there an ORM or how is the database being utilized?
Is there a development environment?

Is there a
framework?
Is it modern? Is it upgradeable?

Is there a
coding
standard?

No Standard? No problem! Use PSR-12

Is there any
autoloading?
In 2025 I would hope so, but not always!

There is a PSR for that…

How are
dependencies
behind
handled?
In 2025 I would hope via Composer, but not always!

Is there an
ORM?
How is the database being utilized?

Is there a
development
environment?
If not, start here

Tools to help with Code Standards
https://cs.symfony.com/

Tools to help with Code Standards
php-cs-fixer fix app --dry-run

PHPStan
https://phpstan.org/

PHPStan
https://phpstan.org/

Warning about
Automating
Code Changes

Composer
https://getcomposer.org/doc/01-basic-usage.md

Doctrine
http://www.doctrine-project.org

Propel ORM
http://propelorm.org
●Migrations
●Reverse Engineer your
existing DB
●Fast

Local Dev Environments
Physical Hardware (Somewhat uncommon outside
Academia)
Vagrant (Virtual Machines) (What year is it?!)
Docker (Containers)
K8s / K3s / Rancher (Containers)

Docker
Containerised your application where each part runs in isolation
App servers, DB servers, Cache Servers all isolated but interconnected
Can be orchestrated across many nodes or a single node

Docker For Developers 2nd Edition
https://www.phparch.com/books/docker-for-developers/

Determination
and Bargaining
Decision making and triage time

Triage
Address any critical things found in Contemplation phase
PHP version issues
Fixing critical vulnerabilities

You have a
plan
… now you need to estimate this plan.

I hate estimating; some tips:
Estimates must be based in reality of what you and the team can accomplish
Don’t short estimates to force budget constraints, cut features instead
Don’t be afraid to push back, but be reasonable
Don’t be afraid to follow minimum viable product and iterate from there

No Question Left Behind!
The application has no framework, We’re going to use a micro framework as
we refactor.
The application has no autoloading, But we’re using Composer
Dependencies are checked into version control, But we’re using Composer
There is no ORM, but we’re going to use Propel
We have no dev environment but we’re going to use Docker

Proof of Concept
Any new things introduced should be tested to ensure functionality
Build out a small example of an area you or the team doesn't fully
comprehend so you can address any questions that may arise

Bargaining
Getting stakeholders on board with your estimates
Do the decisions made thus far make business sense?
Are there any doubts in the plan?

“We should
just rewrite the
app”

"This would be
so much easier
in framework X”

Why not rewrite?
Progress halts entirely
Business logic is rarely reused
Most of the time is getting back to
current functionality

Why you should refactor
Progress continues
Business logic reused
Modernizing functionality instead
of recreating

What we’ve done so far
Made Decisions
Build Proof of Concept(s)
Ensure stakeholder buy in
Avoid the allure of green fields**
** in some cases a rewrite is warranted

Action and
Reconstruction

Existing Tests
This is great!
Review the tests to get an idea of coverage
Passing tests become your control for any upcoming changes
Confidence++

No Existing Tests
Not the end of the world!
Inspect the code base, was it written to be easily testable?
Could you easily mock dependencies?

Untestable Code
Not all code is testable
If you can’t easily unit test the code base, consider alternatives
Functional testing and Acceptance testing are valid options

Acceptance Testing
NOT a replacement for Unit Testing
Test large parts of your application at a time
Can be harder to pinpoint error location
Gives large code coverage in short amount of time

Digging into the Code
Code Consolidation

Digging into the Code
Code Consolidation
Replace globals with DI

Digging into the Code
Code Consolidation
Replace globals with DI
Write tests
Extract SQL (to ORM or other)

Digging into the Code
Code Consolidation
Replace globals with DI
Write tests
Extract SQL (to ORM or other)
Extract Business Logic (To domain logic)

Digging into the Code
Code Consolidation
Replace globals with DI
Write tests
Extract SQL (to ORM or other)
Extract Business Logic (To domain logic)
Extract Presentation Logic to Views (Twig, Blade, etc)

Digging into the Code
Code Consolidation
Replace globals with DI
Write tests
Extract SQL (to ORM or other)
Extract Business Logic (To domain logic)
Extract Presentation Logic to Views (Twig, Blade, etc)
Extract Action Logic (To Controllers)

Digging into the Code
Code Consolidation
Replace globals with DI
Write tests
Extract SQL (to ORM or other)
Extract Business Logic (To domain logic)
Extract Presentation Logic to Views (Twig, Blade, etc)
Extract Action Logic (To Controllers)
Write (more) tests

Maintenance and
Acceptance

Maintenance and Acceptance
Code Consolidation
Replace globals with DI
Write tests
Extract SQL (to ORM or other)
Extract Business Logic (To domain logic)
Extract Presentation Logic to Views (Twig, Blade, etc)
Extract Action Logic (To Controllers)
Write (more) tests

Maintenance and Acceptance
Adding Features
More New Code
Less Refactoring
Maintain your processes

Continuous
Integration

Revisit
Acceptance
Tests

Resources / Q & A
●Modernizing Legacy Applications In PHP - Paul M. Jones
○https://leanpub.com/mlaphp
●Minimum Viable Tests - Chris Hartjes
○https://leanpub.com/minimumviabletests
●Code Style
○https://github.com/FriendsOfPHP/PHP-CS-Fixer
○http://editorconfig.org
●Autoloading PSR-4
○https://getcomposer.org/doc/01-basic-usage.md
●ORMs
○http://www.doctrine-project.org
○http://propelorm.org
●Docker
○https://www.phparch.com/books/docker-for-developers/
○https://lando.dev/
Tags