Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Rewriting 15-Year-Old Code
Search
Anna Filina
November 15, 2017
Programming
450
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
220
Upgrading Legacy to the Latest PHP Version
afilina
1
240
Better Code Design in PHP
afilina
0
330
Semi-Automated Refactoring and Upgrades with Rector
afilina
0
240
Better Code Design in PHP
afilina
1
500
Better Code Design in PHP
afilina
0
670
Adding Tests to Untestable Legacy Code
afilina
0
450
Upgrading Legacy to the Latest PHP Version
afilina
0
460
Semi-Automated Refactoring and Upgrades with Rector
afilina
0
360
Other Decks in Programming
See All in Programming
設計次第でAIコードの読む量は減らせる / designing-for-code-reading
minodriven
35
17k
R8 の設定見直しでアプリサイズ削減
andpad
0
220
UPDATE をやめる — EF Core でマスタをバージョン管理する
panda728
PRO
0
1.2k
Compiling a real-world CLI tool to native with Static Hermes
tmikov2023
0
120
機械に任せるテスト、人が見るテスト ⽣成AIで引き直した、運⽤保守フェーズの線引き
dske104
0
190
當我們開始不讀 Code - AI Agent 時代,Code Review 與 Clean Code 還剩下什麼?
jame2408
1
190
AIで開発が速くなった先で、開発チームは何を目指すか
shihochan
0
880
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
1.1k
iOS 27でニュースアプリはどう変わる!? 〜日経電子版の新機能対応と、開発事例から〜
lynnswap
7
13k
Agentic Software Factoryに、すごく賢いIF文を。 / super smart IF statement into the Agentic Software Factory.
rkaga
8
2.2k
JIS keyboard support in Omarchy
lef237
0
110
Unity6 URPによる海底をテーマにしたVJシステムの解説 | Unity Shader 完全に理解した 勉強会
gam0022
0
370
Featured
See All Featured
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
5
820
Designing Powerful Visuals for Engaging Learning
tmiket
1
610
How STYLIGHT went responsive
nonsquared
100
6.3k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.4k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.6k
A better future with KSS
kneath
240
18k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.5k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
800
The Curious Case for Waylosing
cassininazir
1
570
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
600
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
33
5.2k
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