Pro Yearly is on sale from $80 to $50! »

Rock-SOLID code

Rock-SOLID code

The SOLID acronym is often used as synonymous of quality OOP code.
Following the SOLID principles developers can create and maintain code that is strong but flexible to grow and change with minimal difficulty.
In this talk the SOLID principles will be explained with the help of basic code samples in the context of WordPress.

Fac44f6299128cc787cfaa20941f2233?s=128

Giuseppe Mazzapica

November 18, 2017
Tweet

Transcript

  1. Rock-SOLID code Giuseppe Mazzapica

  2. S O L I D . . . . .

    5 design principles intended to make software designs more understandable flexible maintainable Robert Cecil Martin (Uncle Bob)
  3. Maintainability is obtained: when things are easily understood code must

    be readable code must be explicit when large, complex problems are split in small problems objects must be small objects bust be focused when things are easily changed objects must be decoupled object relation must be supple
  4. S O L I D ingle Responsibility Principle pen/Closed Principle

    iskov Substitution Principle nterface Segregation Principle ependency Inversion Principle
  5. Single Responsibility Principle SRP a class should have only a

    single responsibility “ a class should do only a single “thing” there should be only a single reason to change a class ü û SOLID
  6. SRP High Cohesion Low Coupling Keep togheter things that really

    belong togheter. Don’t relate unrelated things. ü ü enables:
  7. class _Singleton { Poor_Men_Namespace_Plugin feed_the_dog() { public function ... }

    save_the_world() { public function ... } make_money_in_meantime() { public function ... } 42 43 44 ... 260 261 262 ... 512 513 514 ... 2514 û
  8. namespace MyCompany\MyPlugin; class implements { DogSitter DogFeeder ; private $food_provider

    ( ) { public $food_provider function __construct FoodProvider -> ; $this food_provider = $food_provider } ( ... ) { public $dogs function feedDogs Dog ( , [ , ] ); array_walk $dogs $this ‘feed_dog’ } private $dog ( ) { function feedDog Dog -> ( -> -> ( ) ); $dog $dog eat provideTo $this food_provider 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ü
  9. final class { My_Company_My_Plugin () { private function __construct (

    , ( , ) ); add_action array ‘init’ ‘init’ $this ( , ( , ) ); add_action array ‘admin_init’ ‘admin_init’ $this ( , ( , ) ); add_filter array ‘the_title’ ‘the_title’ $this ... ( , ( , ) ); add_filter array ‘signup_user_meta’ ‘signup_user_meta’ $this } instance() { public static function ( == :: ) :: = (); if $instance $instance new null self self self :: ; return self $instance } public init() { } function ... ... } My_Company_My_Plugin:: (); instance 13 15 16 17 18 19 ... 99 100 101 102 103 104 105 106 107 ... 2025 2026 2027 û
  10. ü MyCompany\MyPlugin; namespace main() { function Autoloader:: ()-> ( ,

    . ); create register __NAMESPACE__ __DIR__ ‘/src’ ( , () { add_action ‘init’ function = Entity\Product(); $cpt new -> (); $cpt register } ); ( , function() { add_action ‘admin_init’ = Admin\PagesRegistar(); $admin_pages_registar new -> ( Admin\Page\OptionsPage() ); $admin_pages_registar new register } ); } ( , . , ); add_action __NAMESPACE__ ‘plugins_loaded’ ‘\\main’ 100 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
  11. software entities should be open for extension, but closed for

    modification. “ implementation inheritance abstraction inheritance ü ûgetters and setters û polymorphism and encapsulation ü S LID O Open/Closed Principle OCP
  12. OCP Extending behavior of existing entities without editing their code.

    Polimorphism ü Composition ü is about Supple behavior obtained via collaboration of specialized objects Abstraction is concretized in many shapes via replaceable concrete implementations
  13. class { Dog_Caretaker Chihuahua( ) { public $chihuahua function feed

    ... } public $great_dane feedGreatDane( ) { function ... } public $german_shepherd feedGermanShepherd( ) { function ... } public $mongrel feedMongrel( ) { function ... 2 3 4 ... 30 31 32 ... 58 59 60 ... 86 87 88 ... û
  14. interface { DogFoodProvider provideFood( Dog ); public $dog function }

    2 3 4 2 3 4 5 2 3 4 interface Dog { size() : DogSize; public function public $food eat( Food ) : Hunger; function } interface extends PureBreedDog Dog { breed() : DogBreed; public function } ü
  15. ü 4 ... 10 11 12 13 14 15 16

    17 18 19 20 21 class implements DogCaretaker DogFoodProvider { ... public __construct( function Pantry $pantry, \ArrayAccess $config ) { -> = ; $this pantry $pantry $this config -> = ; $config } public $dog provideFood( Dog ) { function = -> [ :: ]; $type $this config self DOG_FOOD = -> ( ); $amount $this calcFoodAmount size $dog-> () -> -> ( , ) $dog-> ( ); eat pop $this pantry $type $amount
  16. objects should be replaceable with instances of their subtypes without

    altering the correctness of the program “ design by contract ü design via inheritance û SO ID L Liskow Substitution Principle LSP
  17. LSP Shifting the design of subtypes from “is-a” to “is-replacable-with”

    relationship. “Dog” is an “Animal”, but not all references to “Animal” can be replaced with “Dog”. Design to Interface ü Tell, don’t ask! ü is about
  18. class { WP_Model_Saver save_object( WP_Model ) { public $obj function

    ( ( , ) ) { if is_a $obj ‘My_Post_Model’ ( -> () ); wp_update_post to_array $obj } ( ( , ) ) { elseif is_a $obj ‘My_Term_Model’ ( -> (), -> (), -> () ); wp_update_term id type to_array $obj $obj $obj } ( ( , ) ) { elseif is_a $obj ‘My_User_Model’ ( -> () ); wp_update_user to_array $obj } abstract class My_WP_Model { (); abstract public function to_array (); abstract public function id } 7 8 9 10 11 7 8 9 10 11 12 13 14 15 16 û
  19. class implements { Post Model persist() : { public function

    bool ( -> ); return ( ) bool wp_update_post $this data } } class { ModelSaver persistModel( Model ) : { public function $model bool -> (); return $model persist } interface Model { () : ; public function persist bool } 7 8 9 7 8 9 10 11 12 7 8 9 10 11 ü
  20. many client-specific interfaces are better than one general purpose interface

    “ many small, cohesive interfaces ü interfaces “as generic as possible” û SOL D I Interface Segregation Principle ISP
  21. ISP Reducing system coupling thanks to small, cohesive contracts: clients

    should not be forced to depends on things they don’t use. In other words: describe behavior in many small chunks, then make each client depend on the specific chunk it really needs. is about
  22. class { Attachment_Model Post_Model implements ... featured_image_id() : { public

    function int ( , ); _doing_it_wrong __FUNCTION__ ‘...’, ‘1.0’ return 0; } interface Post_Model { id() : ; public function int type() : Post_Type_Object; public function permalink() : ; public function string featured_image_id() : ; public function int ... } 7 8 9 10 11 ... 75 7 ... 42 43 44 45 û
  23. ü interface Entity { id() : ; public function int

    persist() : ; public function bool } 7 8 9 10 7 8 9 10 7 8 9 7 8 ... interface extends Post Entity { status() : PostStatus; public function type() : PostType; public function } interface extends ThumbLiablePost Post { thumbnail() : Attachment; public function } interface extends Attachment Entity { media_url() : ; public function string ...
  24. High-level modules should not depend on low-level modules. Both should

    depend on abstractions. “ Abstractions should not depend on details. Details should depend on abstractions. “ SOLID Dependency Inversion Principle DIP
  25. Dependency Inversion Principle DIP it’s about object relations, not objects

    ü obtained only via auto-wiring DIC is the same of “Dependency Injection” all objects should have an interface û û û
  26. class My_Metabox { print_metabox( ) { public $post function =

    My_Metabox_Fields( ); $fields new $post = My_Template_Engine(); $engine new -> ( , ); $engine $fields render ‘my_metabox’ } } 7 8 9 10 11 12 13 14 15 16 17 18 19 û
  27. class My_Metabox { __construct( public function My_Template_Engine , $engine $fields

    My_Metabox_Fields ) { -> = ; $this engine $engine -> = ; $this fields $fields } print_metabox( ) { public function $post = -> -> ( ); $fields $this fields set_post $post -> -> ( , ); $this engine render ‘my_metabox’ $fields } } 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 û
  28. interface MetaboxDataBuilder { buildFor( \WP_Post ) : ; public $post

    function array } interface TemplateEngine { ( , ) : ; public $template $data function render string array string } interface Metabox { renderBoxFor( \WP_Post ); public $post function } 7 8 9 10 7 8 9 10 7 8 9 10 ü
  29. class implements MyMetaboxDataBuilder MetaboxDataBuilder { ... public $post function buildFor(

    \WP_Post ) : { array return [ => ( , ), ‘title’ ‘My Metabox’ ‘my-txt-domain’ __ => -> ( ) ‘fields’ $this fieldsData $post ]; } ... } 7 8 9 10 11 12 13 14 ... 33 7 8 9 ... 23 24 class implements MustacheEngine TemplateEngine { render( , ) : { public $template $data function string array string ... } } ü
  30. class implements TemplateEngineMetabox Metabox { ... __construct( public function TemplateEngine

    , $engine MetaboxDataBuilder $data_builder, $template string ) { -> = ; $this engine $engine -> = ; $this builder $data_builder -> = ; $this template $template } renderBoxFor( \WP_Post ) { public $post function = -> -> ( ); $data $this builder buildFor $post -> -> ( -> , ); print $data $this engine $this template render } 7 ... 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ü
  31. RECAP Keep things focused Keep things clear Keep things distinct

    Keep things extensible Keep things simple Keep things SOLID
  32. PHP developer since 2005, first met WordPress in 2006. Moderator

    at wordpress.stackexchange.com Giuseppe Mazzapica Biggest German WordPress Agency WordPress.com Featured Service Partner Gold Certified WooCommerce Expert https://gmazzap.me @gmazzap github.com/gmazzap UESTIONS Q ?