$30 off During Our Annual Pro Sale. View Details »

Design Principles - A SOLID Introduction

Design Principles - A SOLID Introduction

This presentation gives an overview of the SOLID principles. What they are and what they mean. With examples in PHP.

Tom Van Herreweghe

September 04, 2018
Tweet

More Decks by Tom Van Herreweghe

Other Decks in Programming

Transcript

  1. DESIGN PRINCIPLES
    DESIGN PRINCIPLES
    A SOLID INTRODUCTION
    A SOLID INTRODUCTION

    View Slide

  2. WHAT ARE THE SOLID
    WHAT ARE THE SOLID
    PRINCIPLES?
    PRINCIPLES?

    View Slide

  3. Set of 5 Design Principles
    Robert C. Martin - "Uncle Bob"
    Agile methodology
    Design Principles and Design Patterns (2000)

    View Slide

  4. CODE BECOMES
    CODE BECOMES
    more understandable
    more flexible & decoupled
    easier to adapt & maintain

    View Slide

  5. QUIZ TIME!
    QUIZ TIME!
    Single Responsibility Principle
    Open/Closed Principle
    Liskov Substitution Principle
    Interface Segregation Principle
    Dependency Inversion Principle

    View Slide

  6. WHAT DO THEY MEAN?
    WHAT DO THEY MEAN?
    Let's find out together!
    ¯\_(
    ツ)_/¯

    View Slide

  7. SINGLE RESPONSIBILITY
    SINGLE RESPONSIBILITY
    PRINCIPLE
    PRINCIPLE

    View Slide

  8. A class should have
    only 1 responsibility

    View Slide

  9. View Slide

  10. A class should have
    only 1 responsibility reason to change

    View Slide

  11. View Slide

  12. class PostalCodeHelper
    {
    /* ... */
    public function getCity(string $zip) : string {
    return $this->map[$zip] ?? 'Black Hole';
    }
    public function format(string $zip) : string {
    $city = $this->mapCodeToCity($zip);
    return sprintf(
    '%1$s %2$s',
    $zip,
    $city

    View Slide

  13. REASONS FOR CHANGING:
    REASONS FOR CHANGING:
    Mapping changes
    Formatting changes
    Importing changes
    ...

    View Slide

  14. WHO WANTS TO MAINTAIN THIS?
    WHO WANTS TO MAINTAIN THIS?

    View Slide

  15. HOW TO FIX?
    HOW TO FIX?
    Extract Postal Code Mapper
    Extract Postal Code Repository
    Extract Postal Code Formatter
    Extract Postal Code Importer
    ...

    View Slide

  16. BUT ISN'T THIS MORE WORK?
    BUT ISN'T THIS MORE WORK?
    absolutely!

    View Slide

  17. SO WHAT IS THE BENEFIT?
    SO WHAT IS THE BENEFIT?
    Clear & concise classes,
    which are easier to grasp and therefore
    easier to maintain.

    View Slide

  18. HEURISTICS & CONVENTIONS
    HEURISTICS & CONVENTIONS
    Think before coding
    Keep classes small
    Extract whenever you detect a new responsibility
    Don't be lazy

    View Slide

  19. ANY QUESTIONS?
    ANY QUESTIONS?

    View Slide

  20. OPEN/CLOSED PRINCIPLE
    OPEN/CLOSED PRINCIPLE

    View Slide

  21. A CLASS/MODULE/PACKAGE SHOULD BE
    A CLASS/MODULE/PACKAGE SHOULD BE
    Open for extension
    Closed for modification

    View Slide

  22. 2 INTERPRETATIONS
    2 INTERPRETATIONS
    Meyer's Open/Closed Principle
    Polymorphic Open/Closed Principle

    View Slide

  23. MEYER'S OPEN/CLOSED PRINCIPLE
    MEYER'S OPEN/CLOSED PRINCIPLE
    Implementation Inheritance
    Introduces tight coupling

    View Slide

  24. POLYMORPHIC OPEN/CLOSED PRINCIPLE
    POLYMORPHIC OPEN/CLOSED PRINCIPLE
    Relies on abstractions
    Abstracts are closed for modification
    Implementation can change

    View Slide

  25. class Circle
    {
    /* ... */
    }
    class Rectangle
    {
    /* ... */
    }

    View Slide

  26. $shapes = [
    new Circle,
    new Circle,
    new Rectangle,
    new Circle,
    ];

    View Slide

  27. class ShapeDrawer
    {
    public function draw(array $shapes) : void
    {
    foreach ($shapes as $shape) {
    if ($shape instanceof Circle) {
    // ...
    }
    if ($shape instanceof Rectangle) {
    // ...
    }
    }
    }
    }

    View Slide

  28. VIOLATES OPEN/CLOSED PRINCIPLE
    VIOLATES OPEN/CLOSED PRINCIPLE
    New shape? => Modify ShapeDrawer
    => ShapeDrawer is not closed

    View Slide

  29. HOW TO FIX?
    HOW TO FIX?
    Define an abstraction
    Depend on abstraction (see later on)
    Implement different behaviors (polymorphism)

    View Slide

  30. interface Shape {
    public function draw(): void;
    }
    class Circle implements Shape
    {
    /* ... */
    }
    class Rectangle implements Shape
    {
    /* ... */
    }

    View Slide

  31. class ShapeDrawer
    {
    public function draw(array $shapes) : void
    {
    foreach ($shapes as $shape) {
    if (! $shape instanceof Shape) {
    continue;
    }
    $shape->draw();
    }
    }
    }

    View Slide

  32. HEURISTICS & CONVENTIONS
    HEURISTICS & CONVENTIONS
    Work towards closed classes
    Make functionality private
    Mark classes & methods as final
    No RTTI
    Specify abstractions

    View Slide

  33. ANY QUESTIONS?
    ANY QUESTIONS?

    View Slide

  34. LISKOV SUBSTITUTION
    LISKOV SUBSTITUTION
    PRINCIPLE
    PRINCIPLE

    View Slide

  35. LISKOV WHO?
    LISKOV WHO?

    View Slide

  36. BARBARA LISKOV
    BARBARA LISKOV

    View Slide

  37. BARBARA LISKOV
    BARBARA LISKOV
    American Computer Scientist
    MIT
    Turing Award winner
    Fields:
    Operating systems
    Programming languages
    Distributed systems
    Abstractions & modularity

    View Slide

  38. LSP
    LSP
    When B is a subtype of A,
    Then objects of type A may be replaced
    By objects of type B,
    Without altering the desirable properties
    Of the program

    View Slide

  39. LSP
    LSP
    When B is a child of parent A,
    Then objects of parent A may be replaced
    By objects of child B,
    Without altering the desirable properties
    Of the program

    View Slide

  40. CLASSIC
    CLASSIC WRONG
    WRONG EXAMPLE
    EXAMPLE

    View Slide

  41. class Rectangle {
    // ...
    public function setWidth(int $width) : void {
    $this->width = $width;
    }
    // ...
    }

    View Slide

  42. View Slide

  43. class Square extends Rectangle {
    // ...
    public function setWidth(int $width) : void {
    $this->width = $width;
    $this->height = $height;
    }
    // ...
    }

    View Slide

  44. WHO CAN EXPLAIN THE
    WHO CAN EXPLAIN THE UNDESIRABLE
    UNDESIRABLE
    CHANGE?
    CHANGE?

    View Slide

  45. function specifyDimensions(Rectangle $rectangle) {
    $rectangle->setWidth(100);
    $rectangle->setHeight(200);
    }
    $square = new Square;
    specifyDimensions($square);
    assert($square->getWidth() === 100); // fail?
    assert($square->getHeight() === 200); // fail?

    View Slide

  46. UNSURE ABOUT THE CORRECTNESS
    UNSURE ABOUT THE CORRECTNESS

    View Slide

  47. INFLUENCE OF LSP
    INFLUENCE OF LSP
    Standard requirements on method signature in OOP
    languages

    View Slide

  48. INFLUENCE OF LSP
    INFLUENCE OF LSP
    Contravariance of method arguments in subtype
    Covariance of return types in subtype

    View Slide

  49. View Slide

  50. CAN ANYONE EXPLAIN VARIANCE?
    CAN ANYONE EXPLAIN VARIANCE?

    View Slide

  51. View Slide

  52. Contravariance = Parameter type widening (less
    specific)
    Covariance = Return type narrowing (more specific)

    View Slide

  53. SOME EXAMPLES IN PHP
    SOME EXAMPLES IN PHP

    View Slide

  54. QUIZ! - WILL THIS WORK? (1/4)
    QUIZ! - WILL THIS WORK? (1/4)
    class Foo
    {
    public function bar() {}
    }
    class Woo extends Foo
    {
    public function bar() : int {}
    }

    View Slide

  55. QUIZ! - WILL THIS WORK? (2/4)
    QUIZ! - WILL THIS WORK? (2/4)
    class Foo
    {
    public function bar() : Rectangle {}
    }
    class Woo extends Foo
    {
    public function bar() : Square {}
    }

    View Slide

  56. PHP IS "1-LEVEL" COVARIANT
    PHP IS "1-LEVEL" COVARIANT
    Only works from "mixed" to "something else"
    Not from Supertype to Subtype

    View Slide

  57. QUIZ! - WILL THIS WORK? (3/4)
    QUIZ! - WILL THIS WORK? (3/4)
    class Foo
    {
    public function bar(string $baz) : int {}
    }
    class Woo extends Foo
    {
    public function bar($baz) : int {}
    }

    View Slide

  58. QUIZ! - WILL THIS WORK? (4/4)
    QUIZ! - WILL THIS WORK? (4/4)
    class Foo
    {
    public function bar(Square $baz) : int {}
    }
    class Woo extends Foo
    {
    public function bar(Rectangle $baz) : int {}
    }

    View Slide

  59. PHP IS "1-LEVEL" CONTRAVARIANT
    PHP IS "1-LEVEL" CONTRAVARIANT
    Only works from "something" to "mixed" (omitting)
    Not from Subtype to Supertype (scope widening)
    (only in PHP >= 7.2)

    View Slide

  60. CONCLUSION: PHP IS INVARIANT
    CONCLUSION: PHP IS INVARIANT

    View Slide

  61. HEURISTICS & CONVENTIONS
    HEURISTICS & CONVENTIONS
    LSP is about behavior. Think carefully when
    replaceing with a subtype
    PHP is Invariant
    Typehints can be omitted in subtypes
    Mixed return types can be specified in subtypes

    View Slide

  62. ANY QUESTIONS?
    ANY QUESTIONS?

    View Slide

  63. TIME FOR A

    TIME FOR A

    View Slide

  64. INTERFACE SEGREGATION
    INTERFACE SEGREGATION
    PRINCIPLE
    PRINCIPLE

    View Slide

  65. https://speakerdeck.com/miljar/there-is-an-i-in-solid

    View Slide

  66. No object should be forced to depend
    on methods it doesn't use

    View Slide

  67. Split large interfaces
    into smaller, more specific role interfaces

    View Slide

  68. Voorbeeldje

    View Slide

  69. HEURISTICS & CONVENTIONS
    HEURISTICS & CONVENTIONS
    When you need to implement more than you'd like,
    split the interface
    Implementation
    class Foo implements A, B, C
    interface Bar extends A, C

    View Slide

  70. INTERESTING READ
    INTERESTING READ
    Matthias Noback: When to add an interface to a class

    View Slide

  71. ANY QUESTIONS?
    ANY QUESTIONS?

    View Slide

  72. DEPENDENCY INVERSION
    DEPENDENCY INVERSION
    PRINCIPLE
    PRINCIPLE

    View Slide

  73. Abstractions should not depend on details. Details
    should depend on abstractions.
    High-level modules should not depend on low-level
    modules. Both should depend on abstractions.

    View Slide

  74. final class InMemoryRegistry
    {
    }

    View Slide

  75. interface ContextBuilder
    {
    public function setLocator(InMemoryRegistry $locator) : vo
    }

    View Slide

  76. ABSTRACTIONS SHOULD NOT DEPEND
    ABSTRACTIONS SHOULD NOT DEPEND
    ON DETAILS
    ON DETAILS

    View Slide

  77. interface ContextBuilderLocator
    {
    public function retrieve(string $key) : ContextBuilder;
    }
    final class InMemoryRegistry implements ContextBuilderLocator
    {
    }

    View Slide

  78. interface ContextBuilder
    {
    public function setLocator(ContextBuilderLocator $locator)
    }

    View Slide

  79. HIGH-LEVEL MODULES SHOULD NOT
    HIGH-LEVEL MODULES SHOULD NOT
    DEPEND ON LOW-LEVEL MODULES
    DEPEND ON LOW-LEVEL MODULES

    View Slide

  80. High Level: domain logic; further away from
    infrastructure
    Low Level: framework logic; closer to infrastructure

    View Slide

  81. https://speakerdeck.com/miljar/hexagonal-
    architecture-or-how-to-completely-overengineer-your-
    application

    View Slide

  82. HEURISTICS & CONVENTIONS
    HEURISTICS & CONVENTIONS

    View Slide

  83. CREATE ABSTRACTIONS ACCORDING THE
    CREATE ABSTRACTIONS ACCORDING THE
    OPEN/CLOSED PRINCIPLE
    OPEN/CLOSED PRINCIPLE
    interface ContactRepository

    View Slide

  84. DEPEND ON THESE ABSTRACTIONS
    DEPEND ON THESE ABSTRACTIONS
    public function
    __construct(ContactRepository $repo)

    View Slide

  85. MAKE LOW LEVEL SPECIFIC IMPLEMENTATIONS &
    MAKE LOW LEVEL SPECIFIC IMPLEMENTATIONS &
    NAME ACCORDINGLY
    NAME ACCORDINGLY
    DbalContactRepository or
    InMemoryContactRepository

    View Slide

  86. IT CAN HELP TO "PHYSICALLY" SPLIT FILES BETWEEN
    IT CAN HELP TO "PHYSICALLY" SPLIT FILES BETWEEN
    HIGH & LOW LEVEL
    HIGH & LOW LEVEL

    View Slide

  87. ANY QUESTIONS?
    ANY QUESTIONS?

    View Slide

  88. WRAPPIN' IT UP
    WRAPPIN' IT UP
    Single Responsibility Principle
    Open/Closed Principle
    Liskov Substitution Principle
    Interface Segregation Principle
    Dependency Inversion Principle

    View Slide

  89. HTTPS://JOIND.IN/TALK/B543A
    HTTPS://JOIND.IN/TALK/B543A

    View Slide

  90. THANKS!
    THANKS!

    View Slide