SOLID: What is it?

SOLID: What is it?

A quick explanation of what the SOLID principles are and how you can fix your code to meet these requirements of these principles.



July 16, 2014


  1. SOLID

  2. WHAT IS SOLID? A set of principles specifically designed by

    the great uncle Bob to ensure that an application is maintainable, extensible, and easy to understand.
  3. THE PRINCIPLES ▸ Single Responsibility ▸ Open Closed ▸ Liskov

    Substitution ▸ Interface Segregation ▸ Dependency Inversion
  4. THE SINGLE RESPONSIBILITY PRINCIPLE All classes should have only 1

    responsibility. No need to go hardcore purist with this though. An example of a class that still follows the single responsibility principle is an Auth class that handles things such as user login and registration.
  5. THE OPEN CLOSED PRINCIPLE Your code should be open to

    extension, but closed to modification.
  6. EXAMPLE OF VIOLATION function subtractDiscount($price, $months) { if ($months ==

    1) { $discount = 0; } else if ($months == 6) { $discount = $price * 0.15; } else if ($months == 12) { $discount = $price * 0.25; } return $price - $discount; }
  7. HOW TO FIX? Separate the extensible behaviour behind an interface

    and flip the dependencies.
  8. THE INTERFACE interface DiscountInterface { public function getDiscountedAmount($amount); }

  9. THE CLASS class AnnualDiscount implements DiscountInterface { const DISCOUNT_PERCENTAGE =

    0.25; public function getDiscountedAmount($amount) { return $amount - ($amount * self::DISCOUNT_PERCENTAGE); } }
  10. USING IT function subtractDiscount($price, DiscountInterface $discount) { return $discount->getDiscountedAmount($price); }

  11. THE LISKOV SUBSTITUTION PRINCIPLE If a module is using a

    base class then that reference to the base class should be able to be replaced by a derived class without affecting any of the existing functionality.
  12. EXAMPLE OF VIOLATION: PART 1 class Rectangle { protected $width;

    protected $height; public function setWidth($width) { $this->width = $width; } ... }
  13. EXAMPLE OF VIOLATION: PART 2 class Square extends Rectangle {

    public function setWidth($width) { $this->width = $width; $this->height = $width; } }
  14. HOW TO FIX? To fix any classes that violate this

    principle find the base functionality present in all the classes, separate this in a new base class and use that instead.
  15. THE INTERFACE SEGREGATION PRINCIPLE A class should not be forced

    to implement methods that it does not use. Basically, your interfaces should not force additional and unnecessary methods on classes.
  16. HOW TO FIX This does take some planning and additional

    thought. You will have to separate your interfaces so that only the required methods are present. A class CAN implement multiple interfaces.
  17. THE DEPENDENCY INVERSION PRINCIPLE A. High-level modules should not depend

    on low-level modules. Both should depend on abstractions. B. Abstractions should not depend upon details. Details should depend upon abstractions.
  18. WHY? Changes are risky. Depending on a concept is a

    lot safer than depending on an implementation.
  19. SCENARIO Logger class responsible of logging various bits of data.

    The original implementation was written in such a way that the logs are written to file. All of a sudden you change your mind and you want to log to a DB instead.
  20. HOW TO FIX? Ye olde Gateway Pattern to the rescue!!!

  21. CODE EXAMPLE: THE INTERFACE interface DataStoreInterface { public function log($data);

  22. CODE EXAMPLE: THE CLASS class FileStore implements DataStoreInterface { public

    function log($data) { return $this->write($data); } private function write($data) { try { return file_put_contents('log.txt', $data, FILE_APPEND); } catch (Exception $e) { return false; } } }
  23. CODE EXAMPLE: THE GATEWAY class Logger { private $store; public

    function __construct(DateStoreInterface $store) { $this->store = $store; } public function log($data) { return $this->store->log($data); } }
  24. CODE EXAMPLE: USAGE $logger = new Logger(new FileStore()); $logger->log('Hello'); If

    we eventually implement a DB storage class: $logger = new Logger(new DBStore()); $logger->log('Hello DB');