Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHP For Grown Ups

linden3
April 14, 2015

PHP For Grown Ups

Slides of the talk as given at the PHPAmersfoort Meetup on April 14, 2015

linden3

April 14, 2015
Tweet

Other Decks in Programming

Transcript

  1. PHP
    FOR
    GROWN-UPS

    View Slide

  2. ANDREAS
    PHP DEVELOPER @ MIJNDOMEIN.NL

    View Slide

  3. PHP HAS A
    BAD RAP
    (WHICH IT PARTLY DESERVES)

    View Slide

  4. BUT
    YOU CAN STILL USE IT TO BUILD SOLID STUFF
    (IF YOU KNOW HOW)

    View Slide

  5. SO LET’S TALK ABOUT
    THE HOW

    View Slide

  6. QUALITIES OF
    GOOD CODE

    View Slide

  7. EASY TO CHANGE
    EASY TO UNDERSTAND
    EASY TO (RE)USE
    ~
    HARD TO BREAK

    View Slide

  8. “Always code as if the guy who ends up maintaining your code will be a
    violent psychopath who knows where you live”
    - probably John Woods

    View Slide

  9. SHY CODE

    View Slide

  10. “Shy code - modules that don’t reveal anything unnecessary to other
    modules and that don’t rely on other modules’ implementations”
    - The Pragmatic Programmer

    View Slide

  11. ENCAPSULATION
    “MODULES THAT DON’T REVEAL ANYTHING
    UNNECESSARY TO OTHER MODULES”

    View Slide

  12. $totalPrice = 0;
    foreach ($order->getItems() as $item) {
    $amount = $item->getAmount();
    $price = $item->getPrice();
    $totalPrice += $amount * $price;
    }
    $totalPrice += $order->getShippingCosts();

    View Slide

  13. $totalPrice = $order->getTotalPrice();

    View Slide

  14. TELL, DON’T ASK

    View Slide

  15. $order->applyDiscount($discountPercentage);

    View Slide

  16. “[...] modules that don’t rely on other modules’ implementations”

    View Slide

  17. interface EventDispatcher
    {
    public function dispatch(Event $event);
    }

    View Slide

  18. public function __construct(EventDispatcher $eventDispatcher)
    {
    $this->eventDispatcher = $eventDispatcher
    }

    View Slide

  19. class SymfonyEventDispatcher implements EventDispatcher
    {
    public function dispatch(Event $event) {
    // Symfony implementation here
    }
    }

    View Slide

  20. public function __construct(EventDispatcher $eventDispatcher)
    {
    $this->eventDispatcher = $eventDispatcher
    }

    View Slide

  21. FROM THE PERSPECTIVE OF THE CONSUMER
    THE INTERFACE IS THE REAL THING

    View Slide

  22. “MATHEMATICS ABSTRACTION IS THE ART
    OF GIVING THE SAME NAME TO DIFFERENT
    THINGS.”
    ~
    HENRI POINCARÉ’S PROGRAMMER COUSIN

    View Slide

  23. /**
    * before:
    */
    public function search($searchTerm, $productCategory, $make, $color)
    {
    switch ($productType) {
    case ‘car’:
    // search cars
    case ‘boat’:
    // search boat
    // etc.
    }
    }

    View Slide

  24. /**
    * after:
    */
    public function search(SearchQuery $query)
    {
    $worker = $this->getWorkerForQuery($query);
    /** @var SearchResults $results */
    $results = $worker->process($query);
    return $results;
    }

    View Slide

  25. ”BUT... YOU JUST INTRODUCED COUPLING!”

    View Slide

  26. “Figuring out if two people are married is easy. Figuring out if they
    should be is hard.”
    - Michael Feathers

    View Slide

  27. LEVELS OF ABSTRACTION

    View Slide

  28. LOW LEVEL OF ABSTRACTION
    $statement = $database->prepare(
    “INSERT INTO `fish`(‘name’, ‘species’, ‘gender’, ‘tankId’) ” .
    “VALUES(?, ?, ?, ?)”
    );
    $statement->execute(array(‘Nemo’, $speciesId, ‘M’, $tankId));

    View Slide

  29. HIGH LEVEL OF ABSTRACTION
    $command = new IntroduceFishCommand($fish, $tank);
    $this->commandBus->execute($command);

    View Slide

  30. LAYERED ARCHITECTURE

    View Slide

  31. DATABASE QUERIES IN CONTROLLER CODE
    BUSINESS LOGIC IN VIEWS
    VIEW LOGIC IN DOMAIN OBJECTS

    View Slide

  32. MIXING LEVELS OF ABSTRACTION MAKES
    CODE HARDER TO UNDERSTAND

    View Slide

  33. “THE RATIO OF TIME SPENT READING CODE
    VERSUS WRITING IS WELL OVER 10 TO 1”
    ~
    UNCLE BOB

    View Slide

  34. “THERE ARE ONLY TWO HARD THINGS IN
    COMPUTER SCIENCE: CACHE INVALIDATION
    AND NAMING THINGS”
    ~
    PHIL KARLTON

    View Slide

  35. // not:
    $light->setStatus(true);
    // but:
    $light->switchOn();

    View Slide

  36. NAMES THAT LIE
    // neither of these is actually a locale
    $this->locale = $locale->locale;
    // does more than it says
    public function getItem() {
    // write to disk
    }

    View Slide

  37. EXTRACT METHOD
    // before:
    if (is_numeric($amount) && $amount > 0)
    // after:
    if ($this->isValidAmount($amount))

    View Slide

  38. VALUE OBJECTS
    $amount = new Amount($amount);
    // throws exception if amount is invalid

    View Slide

  39. CODE SAYS WHAT
    COMMENTS SAY WHY

    View Slide

  40. // set the patient’s clinic
    $patient->setClinic($clinic);
    // to register a patient, set the patient’s clinic
    $patient->setClinic($clinic);

    View Slide

  41. GOOD NAMING AND GOOD ABSTRACTIONS
    BEAT GOOD COMMENTS

    View Slide

  42. $clinic->registerPatient($patient);

    View Slide

  43. PRINCIPLE OF LEAST ASTONISHMENT
    (MINIMIZE THE NUMBER OF WTFS PER MINUTE)

    View Slide

  44. “I REUSE CODE IF, AND ONLY IF, I NEVER
    NEED TO LOOK AT THE SOURCE CODE”
    ~
    UNCLE BOB

    View Slide

  45. WELL-ABSTRACTED
    GOOD OUTWARD-FACING API
    DECOUPLED

    View Slide

  46. NAMESPACES
    PREVENTING NAMING COLLISIONS
    SINCE PHP 5.3

    View Slide

  47. COMPOSER

    View Slide

  48. OPEN SOURCE VIA GITHUB/PACKAGIST
    PRIVATE REPOSITORIES IN COMPOSER.JSON
    TORAN PROXY

    View Slide

  49. ADDED BONUS
    AUTOLOADING FOR INTERNAL CLASSES
    (THIS ALONE MAKES COMPOSER WORTH USING)

    View Slide

  50. PHPDOC DOCBLOCKS
    IDE USERS LOVE THIS

    View Slide

  51. ”SIMPLICITY IS PREREQUISITE FOR
    RELIABILITY.”
    ~
    EDSGER DIJKSTRA

    View Slide

  52. ”Rely only on reliable things”
    - The Pragmatic Programmer

    View Slide

  53. NOT A RELIABLE THING:
    THE PHP TYPE SYSTEM

    View Slide

  54. if (! $amount) {
    // do something
    }
    // $amount can actually be 0, “0”, “”, null or false for this to be true

    View Slide

  55. if ($amount == 0) {
    // do something
    }
    // $amount can now still be 0, “0” or false for this to be true

    View Slide

  56. if ($amount === 0) {
    // do something
    }
    // this will only evaluate to true when $amount is actually the number 0

    View Slide

  57. “CRASH, DON’T TRASH”
    ~
    THE PRAGMATIC PROGRAMMER

    View Slide

  58. DO NOT PROGRAM BY COINCIDENCE

    View Slide

  59. ”TEST YOUR SOFTWARE, OR YOUR USERS
    WILL”
    ~
    THE PRAGMATIC PROGRAMMER

    View Slide

  60. PHPUNIT
    PHPSPEC
    CODECEPTION
    BEHAT

    View Slide

  61. “WHEN YOU AREN’T AFRAID TO CHANGE
    YOUR CODE, YOU WILL CLEAN IT”
    ~
    UNCLE BOB

    View Slide

  62. LANGUAGE FEATURES
    TYPEHINTING
    VISIBILITY (PRIVATE BY DEFAULT)
    EXCEPTIONS

    View Slide

  63. CLOSING NOTES

    View Slide

  64. LEARNING ABOUT THIS STUFF IS EASY
    DOING IT RIGHT IS HARD

    View Slide

  65. “TO A MAN WITH A HAMMER, EVERYTHING
    LOOKS LIKE A NAIL.”
    ~
    ABRAHAM MASLOW

    View Slide

  66. NONE OF THESE IDEAS ARE NEW
    (IN FACT, MOST ARE PRETTY OLD)

    View Slide

  67. “THE MORE I LEARN, THE MORE I REALIZE
    HOW MUCH I DON’T KNOW”
    ~
    ALBERT EINSTEIN

    View Slide

  68. BOOKS
    Growing Object-Oriented Software, Guided By Tests
    The Pragmatic Programmer
    Domain-Driven Design
    Patterns of Enterprise Application Architecture
    Clean Code

    View Slide

  69. VIDEOS
    Models and Service Layers; Hemoglobin and Hobgoblins
    (https://www.youtube.com/watch?v=3uV3ngl1Z8g)
    Unbreakable Domain Models
    (https://www.youtube.com/watch?v=ZJ63ltuwMaE)
    The Framework As An Implementation Detail
    (https://www.youtube.com/watch?v=0L_9NutiJlc)

    View Slide

  70. PODCASTS
    Elephant in the Room (http://elephantintheroom.io)

    View Slide

  71. QUESTIONS?

    View Slide

  72. PLUG TIME
    WERKENBIJMIJNDOMEIN.NL

    View Slide

  73. BONUS STAGE
    SOLID PRINCIPLES

    View Slide

  74. “A CLASS SHOULD HAVE ONE, AND ONLY ONE,
    REASON TO CHANGE.”
    ~
    SOLID PRINCIPLE #1
    (SINGLE RESPONSIBILITY PRINCIPLE)

    View Slide

  75. “A CLASS SHOULD BE OPEN FOR EXTENSION,
    BUT CLOSED FOR MODIFICATION”
    ~
    SOLID PRINCIPLE #2
    (OPEN-CLOSED PRINCIPLE)

    View Slide

  76. ”CHANGE WHAT A CLASS DOES, BUT NOT
    WHAT IT IS”
    ~
    KONSTANTIN KUDRYASHOV

    View Slide

  77. “SUBCLASSES MUST BE SUBSTITUTABLE FOR
    THEIR BASE CLASSES”
    ~
    SOLID PRINCIPLE #3
    (LISKOV SUBSTITUTION PRINCIPLE)

    View Slide

  78. ”NEVER FORCE CLASSES TO IMPLEMENT
    METHODS THAT THEY DO NOT USE”
    ~
    SOLID PRINCIPLE #4
    (INTERFACE SEGREGATION PRINCIPLE)

    View Slide

  79. interface DoesAllTheThings {
    public function save(Soul $soul);
    public function addOneAndOne(One $one, One $one);
    public function shave(Yak $yak);
    }

    View Slide

  80. class DefaultCalculator implements Calculator {
    public function addOneAndOne(One $one, One $one)
    {
    return new Two;
    }
    }

    View Slide

  81. class DoesAllTheThings implements SoulSaver, Calculator, YakShaver {
    // can still do all the things
    }

    View Slide

  82. “DEPEND ON ABSTRACTIONS, NOT ON
    CONCRETIONS”
    ~
    SOLID PRINCIPLE #5
    (DEPENDENCY INVERSION PRINCIPLE)

    View Slide