foolab.ca | @foolabca
Rewriting
12-Year-Old Code
ConFoo, Montreal - February 25, 2016
Slide 2
Slide 2 text
Anna Filina
• Developer
• Problem solver
• Trainer
• Advisor
• FooLab + ConFoo
2
Slide 3
Slide 3 text
You Inherited a
10-Year-Old Codebase
Slide 4
Slide 4 text
You Inherited a
12-Year-Old Codebase
Slide 5
Slide 5 text
You Inherited a
15-Year-Old Codebase
Slide 6
Slide 6 text
You Inherited a
15-Year-Old Codebase
Code Doesn't Age Like Wine
Slide 7
Slide 7 text
The web was 600 pixels wide
7
Slide 8
Slide 8 text
Feeling old yet?
• Y2K bug
• Google launched AdWords
• There was no Twitter, no Facebook, no iTunes
• Internet Explorer 5
• ICQ was starting to be cool
• Rounded corners = status symbol
8
Global functions
include("functions.php");
MyClass::myMethod(); // namespaced function?
11
Slide 12
Slide 12 text
False security
$clean = htmlentities($_POST['input_field']);
// use filter functions or a framework
// use prepared statements
12
Slide 13
Slide 13 text
What happened at order 20117?
if ($order_id > 20117) {
// use this sql
} else {
// use that sql
}
// weakness = time to refactor
13
Slide 14
Slide 14 text
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.
14
Slide 15
Slide 15 text
Complex call graph
$instance = Model::getInstanceByCode($code);
class Model
{
public static function getInstanceByCode($code)
{
//...
$instances = Cache::getCache($cacheIndex);
}
}
class Cache
{
public static function getCache($cacheIndex)
{
//...
$cache = File::getFileContent($filePath);
}
}
15
Strategy
• Make a strategy based on
contraints
• Full rewrite vs progressive
◦ By class
◦ By module
◦ By HTTP call
• How to run code side-by-side
◦ Session sharing
17
Slide 18
Slide 18 text
Before You Code
Slide 19
Slide 19 text
Data can be lost, stuff can break
• Backup: test restore
• Staging environment: app versions, configs
• Simulate deployments/upgrades
• Automate tests before code changes
• Make a risk assessment
◦ Don't be too optimistic
◦ Account for side-effects
19
Slide 20
Slide 20 text
Refactoring Example
Slide 21
Slide 21 text
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)
21
Slide 22
Slide 22 text
Solution
• Rewrite complex forms in Symfony
◦ mod_rewrite for concerned pages
• Rewrite biggest module as OOP
◦ Design extraction
◦ Automated tests
◦ Flexible architecture
22
Slide 23
Slide 23 text
Design Extraction
Slide 24
Slide 24 text
Avoid code bias
• Old code → design docs
• Validate design docs
◦ Clarify business rules
• Improve design
◦ Reduce tech. debt
◦ More flexible
• Design docs → new code
24
Slide 25
Slide 25 text
Code-Level Advice
Slide 26
Slide 26 text
Infrastructure
• Set up logging
◦ Monolog if PHP version allows
◦ file_put_contents if really old version
• Set up testing
◦ Mocking static methods: Patchwork or equivalent
◦ Cache API call output
26
Slide 27
Slide 27 text
Code duplication
• Sometimes, the bug is repeated 80+ times
• Remove duplications ASAP
27
Slide 28
Slide 28 text
Fix long methods
• Extract broken part into its own method
• Write unit tests for it
• Fix it
• Call it from the mega-method
28
Slide 29
Slide 29 text
More Stories
Slide 30
Slide 30 text
ASP Classic to PHP 5.6
• 15+ spaghetti and hacks
• Language no longer supported
• Huge ERP with lots of code
30
Slide 31
Slide 31 text
Solution
• Symfony to rewrite page by page
• mod_rewrite for concerned pages
• DB session adapter in both apps
• Page in any language = HTTP request
◦ Guzzle tests FTW!
31
Slide 32
Slide 32 text
Guzzle tests
32
Slide 33
Slide 33 text
PHP 5.3 to PHP 5.6
• 12+ spaghetti and hacks
• Uses deprecated functions
• Can't run on PHP 5.6
33
Slide 34
Slide 34 text
Solution
• Split servers into 5.3 and 5.6 for fresh start
• REST and modern design patterns
• AngularJS frontend
34
Slide 35
Slide 35 text
Splitting the app
35
Slide 36
Slide 36 text
Alias is your friend (5.3 server)
Alias "/module-name" "/var/www/project/angular"
RewriteBase /module-name/
36
Slide 37
Slide 37 text
Stuck?
Slide 38
Slide 38 text
Try something new
• Bounce ideas
◦ New people to avoid tunnel vision
• Has this been done before?
• Can I try another approach?
38
Slide 39
Slide 39 text
Ask refactoring experts
• Pick their brain
• Read their blog
• Hire one for a day
◦ Refactoring strategy
◦ Remove roadblocks
◦ Guidance (one day per week to steer in right direction)
39
Slide 40
Slide 40 text
Takeaways
• Plan before you act
• Use known tools & methodologies
• Get inspiration from others
• Refactoring gets easier
• Every problem has a solution
40
Slide 41
Slide 41 text
Anna Filina
• Development.
• Fix bugs & performance issues.
• Workshops on testing, Symfony & API.
• Advisor on testing strategy, legacy code.
41