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

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.

Giuseppe Mazzapica

November 18, 2017
Tweet

More Decks by Giuseppe Mazzapica

Other Decks in Programming

Transcript

  1. Rock-SOLID code
    Giuseppe Mazzapica

    View Slide

  2. S O L I D
    . . . . .
    5 design principles intended
    to make software designs more
    understandable
    flexible
    maintainable
    Robert Cecil Martin (Uncle Bob)

    View Slide

  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

    View Slide

  4. S
    O
    L
    I
    D
    ingle Responsibility Principle
    pen/Closed Principle
    iskov Substitution Principle
    nterface Segregation Principle
    ependency Inversion Principle

    View Slide

  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

    View Slide

  6. SRP
    High Cohesion
    Low Coupling
    Keep togheter things that
    really belong togheter.
    Don’t relate unrelated things.
    ü
    ü
    enables:

    View Slide

  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
    û

    View Slide

  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
    ü

    View Slide

  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
    û

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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
    ...
    û

    View Slide

  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
    }
    ü

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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
    û

    View Slide

  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
    ü

    View Slide

  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

    View Slide

  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

    View Slide

  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
    û

    View Slide

  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
    ...

    View Slide

  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

    View Slide

  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
    û
    û
    û

    View Slide

  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
    û

    View Slide

  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
    û

    View Slide

  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
    ü

    View Slide

  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
    ...
    }
    }
    ü

    View Slide

  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
    ü

    View Slide

  31. RECAP
    Keep things focused
    Keep things clear
    Keep things distinct
    Keep things extensible
    Keep things simple
    Keep things SOLID

    View Slide

  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 ?

    View Slide