Refactoring PHP

Adam Culp
Web Engineer/Consultant at Rogue Wave
Jul. 17, 2012

More Related Content


Refactoring PHP

  1. Refactoring Presentation for: South Florida PHP Users Group By: Adam Culp Twitter: @adamculp
  2. Refactoring  Based on popular “Refactoring” Improving The Design of Existing Code book, by Martin Fowler.  We will start in the code with an example.  Tips and descriptions will be handled during the example.  In the example we are tasked with creating an HTML representation of the customer statement for a movie rental.
  3. Refactoring  Movie class  With a new project we take a look at the current application a customer has requested to be changed.  We start with the Movie class.
  4. Refactoring  Rental class  Next we look at the Rental class.
  5. Refactoring  Customer class p1  With a new project we take a look at the current app that is about to be changed.  Next we look at part 1 of the Customer class.
  6. Refactoring  Customer class p2  With a new project we take a look at the current app that is about to be changed.  Next we look at part 2 of the Customer class.
  7. Refactoring  Not terrible for a small quick and dirty application, but if part of a larger application we have problems.  Customer class doing far too much, and statement method is too long.  Impossible to reuse the statement for an HTML representation.  The customer also wants to be able to change how they classify movies.  As experienced developers we know that customers will always come back six months from now and want it changed in some way.
  8. Refactoring  Rewrite vs Refactor  Budget constraint  Time constraint  Rewrite is an excuse to NOT dig in someone's code  Refactor is the best teacher
  9. Refactoring  First step  Build tests based on current “working” application, so we can verify if we break something.  Pre-load database with data or create fixtures needed for tests, to ensure we have a constant to compare test results.  If we are not starting with a working application you must first get the application working prior to refactoring. Do not try to refactor a broken application or you risk breaking it further, and end up with a total rewrite.
  10. Refactoring  Step 1  Extract Method to move switch statement to its own method.
  11. Refactoring  Step 2  Variable names should make sense. (each > rental, thisAmount > result)
  12. Refactoring  Step 3  Extract Method amountFor() to Rental class. It uses information from Rental, but no information from Customer. We rename it to more meaningful getCharge().
  13. Refactoring  Step 4  Call getCharge() directly from statement() instead of using amountFor() as a middle man method.
  14. Refactoring  Step 5  Replace Temp with Query - Cleanup of call to getCharge(). Eliminate temp variables by calling method direct. Less maintenance.
  15. Refactoring  Step 6  Extract Method and move frequentRenterPoints to its own method in Rental class where it logically belongs.
  16. Refactoring  Step 7  We do Replace Temp with Query for totalAmount. Temp variables can be a problem and really only serve a purpose within their own routine and encourage long, complex routines.
  17. Refactoring  Step 8  Also do Replace Temp with Query on frequentRentalPoints to eliminate more temp variables.
  18. Refactoring  Step 9  We are now able to create the HTML version of the statement, and we rename the original to represent a Text version.
  19. Refactoring  Recap  Most refactoring reduces code, while we increased it for this example.  We also duplicated a loop to make it happen 4 times instead of once. (getFrequentRenterPoints, getTotalCharge, getTotalFrequentRenterPoints)  Optimizing and refactoring are different actions. Refactor first, then optimize later if needed.  More refactoring could further clean up Text and HTML statements to DRY it up. (split out header/footer, etc.)  Still need more refactoring to allow classification changes by the customer.
  20. Refactoring  Step 10  Move Method on getCharge() because it uses data in Movie, so should be in the same class as the data.
  21. Refactoring  Step 11  Replace Conditional with Polymorphism on getCharge() because it uses data in Movie, so should be in the same class as the data.
  22. Refactoring  Two hats  Adding Function Hat  Refactoring Hat First we add functionality, they we refactor it, then add more functionality, ...
  23. Refactoring  Why Refactor?  Without refactoring code decays  As code is changed it loses structure, making it harder to see design  Regular refactoring preserves design  Poorly designed = more code due to duplication  Reduced code = easier to maintain  Reduced code = easier to understand  Helps find bugs  Helps us program faster
  24. Refactoring  When to Refactor?  Should not set aside time to refactor, it is just something we do in short bursts  Refactor because you want to do something, and refactoring helps you do it  Often a quick refactor can help developing new functionalities move faster  Rule of Three → see next slide
  25. Refactoring  Rule of Three  When you add function  Helps to learn code you need to modify  Changes code that prevents the addition  When you need to fix a bug  Make code more understandable  Usually highlights the bug  During code review  Code looks good to developer, but maybe not to the team.  More concrete results
  26. Refactoring  What do I tell my manager?  For a tech saavy manager it may not be hard to explain the benefits  Quality centric manager stress quality aspects  Perhaps introduce it as a review process  There are many resources on Google about value of reviews, inspections, or software development process  Schedule driven … Don't tell (controversial?)  Find a way to work it into scheduling.  Overall it saves time, but some will never “see” it
  27. Refactoring  Code “smells” as indicators  Bad code “smells” and is a great way of indicating it is time for a refactor.  Duplicate Code  Long Method  Large Class  Long Parameter (argument) List  Divergent Change - if change is needed in multiple areas to accommodate a change  Shotgun Surgery – change causes ripple of other needed changes  Feature Envy – a method seems to use another class instead of the one it is in
  28. Refactoring  Code “smells” as indicators  More “smells”  Data Clumps – if data items tend to accompany one another  Primitive Obsession  Switch statements  Parallel Inheritance Hierarchies – caused when you need to create a subclass of one object because you created a subclass of another  Lazy Class – classes that do not do much and do not pay for their extra weight  Speculative Generality – constructs built for the sake of possibility later
  29. Refactoring  Code “smells” as indicators  More “smells”  Temporary Field  Message Chains – object asking for object that asks for another object...  Middle Man – directors in place but serving no real purpose  Inappropriate Intimacy – classes should not deal too much with each others private parts  Data Class – getters and setters, but nothing else  Comments – where comments are used as deodorant to cover a bad smell
  30. Refactoring  Tests and Refactoring  You cannot properly refactor without tests in place.  Writing tests is the first step of refactoring, and should happen as you write the code in the first place. (or before, as with TDD)
  31. Refactoring  Thank you Adam Culp Twitter @adamculp