A presentation at Bulgaria PHP in in Sofia, Bulgaria by Adam Culp
Refactoring Legacy Code By: Adam Culp Twitter: @adamculp https://joind.in/talk/a3ecc
Refactoring Legacy Code ● 2 About me – PHP 5.3 Certified – Consultant at Zend Technologies – Zend Certification Advisory Board – Organizer SoFloPHP (South Florida) – Organized SunshinePHP (Miami) – Long distance (ultra) runner – Judo Black Belt Instructor
Refactoring Legacy Code ● Fan of iteration – 3 Pretty much everything requires iteration to do well: ● Long distance running ● Judo ● Development ● Evading project managers ● Refactoring!
Refactoring Legacy Code ● 6 Modernizing – “Modernizing Legacy Applications in PHP” on LeanPub – by Paul M. Jones – http://mlaphp.com
Refactoring Legacy Code ● What is “Legacy Code” – 7 Is there a coding standard for your project?
Refactoring Legacy Code ● 8 What is “Legacy Code” – Is there a coding standard for your project? – Is code using OOP?
Refactoring Legacy Code ● 9 What is “Legacy Code” – Is there a coding standard for your project? – Is code using OOP? – Is Composer used in your project?
Refactoring Legacy Code ● 10 What is “Legacy Code” – Is there a coding standard for your project? – Is code using OOP? – Is Composer used in your project? – Is the project using a framework?
Refactoring Legacy Code ● 11 What is “Legacy Code” – Is there a coding standard for your project? – Is code using OOP? – Is Composer used in your project? – Is the project using a framework? – Are you unit testing?
Refactoring Legacy Code ● 12 What is “Legacy Code” – Is there a coding standard for your project? – Is code using OOP? – Is Composer used in your project? – Is the project using a framework? – Are you unit testing? – Does your project avoid NIH?
Refactoring Legacy Code ● What is “Legacy Code” – Is there a coding standard for your project? – Is code using OOP? – Is Composer used in your project? – Is the project using a framework? – Are you unit testing? – Does your project avoid NIH? If you can answer “No” to any of these, you may be creating “Legacy Code”!!! 13
Refactoring Legacy Code ● 14 What is “refactoring”? – “…process of changing a computer program’s source code without modifying its external functional behavior…” en.wikipedia.org/wiki/Refactoring – No functionality added – Code quality
Refactoring Legacy Code ● 15 Two hats – Adding Functionality Hat – Refactoring Hat – We add functionality, then refactor, then add more functionality …
Refactoring Legacy Code ● 16 Then optimize – Do not optimize while refactoring. – Separate step. – Refactoring is NOT optimizing.
Refactoring Legacy Code ● 17 Source Control – Refactor in branch – Allows rollback
Refactoring Legacy Code ● 18 Editor/IDE – Makes searching easier – Search within project
Refactoring Legacy Code ● Style Guide – 19 Framework Interop Group ● http://php-fig.org ● PSR – Faster reading – United team
Refactoring Legacy Code ● 20 Testing – Consistent results – Prevents breaks – Speeds up development
Refactoring Legacy Code ● 21 Modernizing Steps – Autoloading – Consolidate Classes – Cleanup Globals – Replace “new” (instantiation) – Create Tests – Extract SQL – Extract Logic – Replace Remaining “Includes”
Refactoring Legacy Code ● Autoloading – Namespaces – PSR-0 ● Legacy code typically used long class names Usage = My_Long_Class_Name – Translates to “/My/Long/Class/Name.php” – Class = My_Long_Class_Name If not, then PSR-4 – ● – – – 22 Use My\Great\Namespace\Name Translates to /My/Great/Namespace/Name.php Class = Name
Refactoring Legacy Code ● Autoloading Approaches – – 23 Approaches ● Global function ● Closure ● Static or Instance Method (preferred, if possible) ● __autoload() - PHP v 5.0 Need a central place for classes
Refactoring Legacy Code ● Consolidate Classes – Move to one location ● 24 Could be named “includes”, “classes”, “src”, “lib”, etc.
Refactoring Legacy Code ● Consolidate Classes Step 1 – Search for include statements ● 25 (include, include_once, require, require_once)
Refactoring Legacy Code ● 26 Consolidate Classes Step 2
Refactoring Legacy Code ● Consolidate Classes Step 3 – 27 User class is now autoloaded, no more require_once.
Refactoring Legacy Code ● Consolidate Classes Repeat – 28 Search for more instances
Refactoring Legacy Code ● 29 Cleanup “Global” Dependencies Steps 1 Search for global reference 2 Move global calls to constructor 3 Convert global call to a constructor parameter 4 Update global call to a class 5 Instantiate new class and pass as parameter (DI) 6 Repeat
Refactoring Legacy Code ● Global Cleanup Step 1 – 30 Search for global reference
Refactoring Legacy Code ● 31 Global Cleanup Step 2 & 3 – Move global call to constructor – Pass values as properties
Refactoring Legacy Code ● Global Cleanup Step 4 – 32 Convert call to a constructor parameter
Refactoring Legacy Code ● 33 Global Cleanup Step 5 – Instantiate new class – Inject as parameter (DI)
Refactoring Legacy Code ● Global Cleanup Repeat – 34 Look for more instances to clean up
Refactoring Legacy Code ● Steps to Replacing “new” 1 Search for “new” 2 Extract instantiation to constructor parameter. (if one time) ● 35 Or extract block of creation code to new Factory class. (if repeated) 3 Update instantiation calls 4 Repeat
Refactoring Legacy Code ● Replacing “new” Step 1 (Single) – 36 Before
Refactoring Legacy Code ● 37 Replacing “new” Step 2 (Single) – Inject Db object into class constructor. (DI) – No longer instantiating within class
Refactoring Legacy Code ● 38 Replacing “new” (Multiple)
Refactoring Legacy Code ● 39 Replacing “new” Step 3 (Multiple) – Create factory – Extract “new” call to new factory
Refactoring Legacy Code ● Replacing “new” Step 4 (Multiple) – 40 Update instantiation calls
Refactoring Legacy Code ● Replacing “new” Step 4 (Multiple) – 41 Call to factory
Refactoring Legacy Code ● 42 Replacing “new” Repeat
Refactoring Legacy Code ● 43 Write Tests – Code is fairly clean – Write tests for entire application – If not testable, refactor ● Extract method ● Replace temp with query ● Etc.
Refactoring Legacy Code ● 44 Extract SQL 1 Search for SQL 2 Move statement and relevant logic to Gateway class 3 Create test for new class 4 Alter code to use new method 5 Repeat
Refactoring Legacy Code ● 45 Extract Logic 1 Search for uses of Gateway class outside of Transaction classes 2 Extract logic to Transaction classes 3 Test 4 Write new tests where needed 5 Repeat
Refactoring Legacy Code ● Replace “includes” – Search for left over includes – If in current class – 46 1 Copy contents into file directly 2 Refactor for: no globals, no ‘new’, DI, return instead of output, no includes More often 1 Copy contents of include as-is to new class method 2 Replace with in-line instantiation 3 Search for other uses of same, and update them as well 4 Delete original include file, regression test – Test, create new tests if needed – Repeat
Refactoring Legacy Code ● 47 Additional Possibilities – Can now implement framework – Leverage services – Leverage events – Use Composer
Refactoring Legacy Code ● 48 Why refactor – Less bugs – Faster development – More stable – Easier onboarding – Save $$$
Refactoring Legacy Code ● 49 When/How to refactor – Ask boss for time – “Leave it cleaner than you found it” – Do it on your own, it makes YOUR life easier
Refactoring Legacy Code ● 50 Challenges – Manager Buy In – Technical Challenge – Social Challenge
Refactoring Legacy Code ● Convince the boss – 51 Three kinds of managers: ● Tech Savvy ● Quality Centric ● Time Driven Right…
Refactoring Legacy Code ● 52 Tech Savvy boss – Lower cyclomatic complexity – SOLID – Separation of concerns – MVC/Framework – Less bugs – Easier onboarding
Refactoring Legacy Code ● 53 Quality Centric boss – Code quality – Tests – Happier customers – Less bugs
Refactoring Legacy Code ● 54 Time driven boss – Faster feature delivery – Higher productivity - less time reading – Faster onboarding – Less testing time – Less debugging
Refactoring Legacy Code ● 55 Concluding Thoughts – Do not refactor a broken application – Have tests in place prior to refactor ● Unit tests or ● Functional tests or ● Manual tests – Do things in small steps – Love iteration!
● Thank you! – Please rate at: https://joind.in/talk/a3ecc Adam Culp http://www.geekyboy.com http://RunGeekRadio.com Twitter @adamculp Questions?
Faced with legacy PHP code many decided to rewrite, thinking it easier, but for many reasons, this can be very wrong. It can lead to angry developers and managers, never-ending projects due to scope creep, resulting in more bad code.
Follow along as we refactor a legacy PHP codebase. We begin with assessment and why, cover planning how and when, discuss execution and testing, providing step-by-step examples. Attendees will gain tips on how to handle their own pile of code and refactor happily.