Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Rewriting 15-Year-Old Code
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Anna Filina
November 15, 2017
Programming
430
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Rewriting 15-Year-Old Code
Anna Filina
November 15, 2017
More Decks by Anna Filina
See All by Anna Filina
Surviving a Symfony Upgrade
afilina
1
190
Upgrading Legacy to the Latest PHP Version
afilina
1
210
Better Code Design in PHP
afilina
0
320
Semi-Automated Refactoring and Upgrades with Rector
afilina
0
210
Better Code Design in PHP
afilina
1
470
Better Code Design in PHP
afilina
0
630
Adding Tests to Untestable Legacy Code
afilina
0
420
Upgrading Legacy to the Latest PHP Version
afilina
0
440
Semi-Automated Refactoring and Upgrades with Rector
afilina
0
340
Other Decks in Programming
See All in Programming
Contextとはなにか
chiroruxx
1
390
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
0
310
Javaの型とAI時代に型が大事な理由 / java types and type in AI era
kishida
2
160
dRuby over BLE
makicamel
2
400
その問い、本当に正しいですか?AI時代のエンジニアに必要な哲学と認知科学 / ai-philosophy-cognitive-science
minodriven
14
6.5k
symfony/aiとlaravel/boost
77web
0
110
act1-costs.pdf
sumedhbala
0
140
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
230
ADKを使って簡単にAIエージェントを作ってみよう
k1mu21
0
290
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
280
Strategic Design in the Frontend: Moduliths & Micro Frontends @DDDEurope
manfredsteyer
PRO
0
140
AI駆動開発を妨げる技術的負債の解消アプローチ / ai-refactoring-approach
minodriven
16
8.3k
Featured
See All Featured
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
380
WCS-LA-2024
lcolladotor
0
670
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.3k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.3k
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
220
Designing for Timeless Needs
cassininazir
1
270
Context Engineering - Making Every Token Count
addyosmani
9
1k
We Have a Design System, Now What?
morganepeng
55
8.2k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.2k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
340
Transcript
@afilina Rewriting 15-Year-Old Code BuildStuff, Vilnius - November 15, 2017
Anna Filina • Project rescue • Legacy code • Development
• Conferences • Private workshops • Canada
You inherited a 17-year-old codebase Code doesn't age like wine.
The Web Was 600px Wide
Feeling Old Yet? • Y2K bug. • Internet Explorer 5.
• ICQ was starting to be cool. • Rounded corners = status symbol.
Code smells
Mixed Concerns <?php mysql_query('...'); $total = 0; foreach ($products as
$p) { $total += $p['qty'] * $p['price']; } ?> <p>Total: <?= $total ?></p>
Poorly Named Variables $a = //... $array = //... $item3
= //... $tempItem = //...
Global Functions & Constants include("functions.php"); MyClass::myMethod(); // namespaced function? myMethod(DEV_MODE);
Inexplicable Conditions if ($order_id > 20117) { // use this
sql } else { // use that sql } // weakness = time to refactor
Long Methods public function importCsv($path, $googleApiKey, $databaseDsn, $databaseUser, $databasePassword) {
// Convert CSV to array of conferences $lines = file($path); $csv = array_map('str_getcsv', $lines); $conferences = []; foreach ($csv as $line) { $conference = new Conference(); $conference->name = $line[0]; $conference->location = $line[1]; $conferences[] = $conference; // Get coordinates for location $location = urlencode($conference->location); $url = 'https://maps.googleapis.com/maps/api/geocode/json?address='.$location.'&key='.$googleApiKey; $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $response = curl_exec($curl); curl_close($curl); $json = json_decode($response); if (count($json->results) == 0) { continue; } $latitude = $json->results[0]->geometry->location->lat; $longitude = $json->results[0]->geometry->location->lng; $coordinates = $latitude.','.$longitude; $conference->coordinates = $coordinates; // Save conference to database $pdo = new PDO($databaseDsn, $databaseUser, $databasePassword); $statement = $pdo->prepare('REPLACE INTO conference (name, location, coordinates) VALUES (?, ?, ?)'); $statement->execute([ $conference->name, $conference->location, $conference->coordinates, ]);
Average Legacy Code File • 3000-6000 lines of code. •
Half of it is commented "in case we need it later". • Method length of 800 lines. • Abuse of helper classes. • Sometimes no classes at all.
Codebase • 5,000 classes. • 20,000 methods. • 1,500,000 lines
of code.
Before you code
Strategy • Make a strategy based on constraints. • Full
rewrite vs progressive: ◦By class. ◦By feature/module. ◦By HTTP call. • How to run code side-by-side: ◦DB/Session sharing. ◦mod_rewrite.
Data Can Be Lost, Stuff Can Break • Backup: test
restore. • Nullify sensitive data. • Staging: simulate deployments/ upgrades/batch processes. • Automate tests before code changes. • Make a risk assessment: ◦ Don't be too optimistic. ◦ Account for side-effects.
Build With Real Legacy Data
(Failed) rewrite example
PHP 3 to PHP 5.6 • HTML + PHP +
SQL in same file. • Includes all over the place. • IFs that concatenate SQL. • Previous rewrite attempt: ◦ Failed, made things worse. ◦ Folders of dead code. ◦ Classes with static functions (no instances).
Solution • Rewrite complex forms in Symfony: ◦ mod_rewrite for
concerned pages. • Rewrite biggest module as OOP: ◦ Design extraction. ◦ Flexible architecture. ◦ Automated tests.
New feature should not take longer than a sprint.
Design extraction
Avoid Code Bias • Old code → design docs. •
Validate design docs: ◦Clarify business rules. • Improve design: ◦Reduce technical debt. ◦More flexible. • Design docs → new code.
Fixing bugs
Code Duplication • Sometimes, the bug is repeated 80+ times.
• Remove duplications ASAP.
Fix Long Methods • Extract broken part into its own
method. • Write unit tests for it. • Fix it. • Call it from the mega-method.
Spot Logical Groups Code block Comment Code block Comment Convert
CSV to array of conferences. Get coordinates for conference location. Save conference to database. Code block Comment
Extract & Test Code block Comment Code block Method Code
block Comment Call method
Name Code block Method Code block Method Call method Call
method Code block Method Call method getConferencesFromCsv getLocationCoordinates saveConference
Rewrite example #2
ASP Classic to PHP 5.6 • 15+ spaghetti and hacks.
• Language no longer supported. • Huge ERP with lots of code.
Solution • Rewrite page by page to Symfony. • mod_rewrite
for concerned pages. • DB session adapter in both apps. • Page in any language = HTTP request. ◦ Guzzle tests FTW!
Guzzle Tests
On Testing Before you code You better test So that
on weekends You may rest. -- Anna Filina
Testing Static Methods $mock = Mockery::mock('alias:SomeClass'); $mock->shouldReceive('staticMethod')->andReturn(42);
Stuck?
Try Something New • Bounce ideas. ◦ New people to
avoid tunnel vision. • Has this been done before? • Can I try another approach?
Takeaways • Make a strategy. • You touch it, you
refactor it. • Use known tools & methodologies. • Get inspiration from others. • Refactoring gets easier. • Every problem has a solution.
Refactoring: Improving the Design of Existing Code Martin Fowler
@afilina afilina.com