Slide 1

Slide 1 text

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

Slide 9

Slide 9 text

Objectives • Reduce mistakes • Increase dev. speed • Reduce tech. debt • Avoid getting stuck • Increase confidence 9

Slide 10

Slide 10 text

Code Smells

Slide 11

Slide 11 text

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

Slide 16

Slide 16 text

Codebase • 5,000 classes. • 20,000 methods. • 1,500,000 lines of code. 16

Slide 17

Slide 17 text

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

Slide 42

Slide 42 text

@afilina afilina.com