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

Object Reorientation

Object Reorientation

http://verraes.net/2014/11/object-reorientation/

Talk for DrupalCamp Ghent, November 2014

Mathias Verraes

November 07, 2014
Tweet

More Decks by Mathias Verraes

Other Decks in Programming

Transcript

  1. Object
    Reorientation
    @mathiasverraes

    View Slide

  2. Mathias
    Verraes
    Independent Consultant
    @mathiasverraes
    verraes.net

    View Slide

  3. Systems are all about
    behaviour

    View Slide

  4. State as a side effect

    View Slide

  5. Functions
    f(x, y) -> z

    View Slide

  6. What does
    it do?
    f(x, y) -> z

    View Slide

  7. Types
    f(x, y) -> z
    where
    x : "A dog named Charles"
    y : [[1, 4], [76, "D5004375571"]]
    z : WAT?!

    View Slide

  8. Types
    f(x, y) -> z
    where
    x : int
    y : int
    z : 1 | 0 | -1

    View Slide

  9. Types
    function compare($left, $right)
    {
    if($left > $right) return 1;
    elseif($left == $right) return 0;
    else return -1;
    }

    View Slide

  10. Hacklang
    function compare(int $left, int $right) : int
    {
    if($left > $right) return 1;
    elseif($left == $right) return 0;
    else return -1;
    }

    View Slide

  11. Types are
    logical
    propositions
    about your code

    View Slide

  12. Types make it
    easier for programs to
    reason
    about programs

    View Slide

  13. Tools for typing in PHP:
    Classes
    interfaces
    type hints

    View Slide

  14. Types prevent type bugs
    function send(
    $articleId, $subscriberId
    )
    send($subscriberId, $articleId) // bug
    function send(
    ArticleId $articleId, SubscriberId $subscriberId
    )

    View Slide

  15. Recurring
    pattern
    f(d : T, a, b) -> d' : T

    View Slide

  16. Recurring pattern
    function doOperation($onData, $withArg, $andArg)
    {
    // ...
    return $newData;
    }
    function otherOp($onData, $withArg)
    {
    // ...
    return $newData;
    }

    View Slide

  17. Encapsulation

    View Slide

  18. $article = [
    'title' => "Object Reorientation",
    'body' => "Encapsulate all the things",
    'author' => "@mathiasverraes",
    'published' => "no",
    ];
    $article['published'] = "yes";

    View Slide

  19. without encapsulation,
    changes propagate
    $article = [
    'title' => "Object Reorientation",
    'body' => "Encapsulate all the things",
    'author' => "@mathiasverraes",
    'published' => false,
    ];
    $publishedArticle = publish($article, 10);
    $publishedArticle = [
    'title' => "Object Reorientation",
    'body' => "Encapsulate all the things",
    'author' => "@mathiasverraes",
    'published' => false,
    ];

    View Slide

  20. That's not what arrays are for

    View Slide

  21. Arrays are
    collections
    of values of the
    same type

    View Slide

  22. NOT OK
    $article = [
    'title' => "Object Reorientation",
    'body' => "Encapsulate all the things",
    'author' => "@mathiasverraes",
    'published' => false,
    ];

    View Slide

  23. OK
    $fib = [1, 1, 2, 3, 5, 8, 13];
    $articles = [
    $objectReorientation,
    $understandingFibonacci,
    ];
    $indexedArticles = [
    34 => $objectReorientation,
    951 => $understandingFibonacci,
    ];

    View Slide

  24. Encapsulation
    doOperation($onData, $withArg, $andArg)
    ->
    $object->doOperation($withArg, $andArg)
    $article->publish()

    View Slide

  25. Design objects from the
    outside
    $article = new Article($title, $body, $author);
    $article->publish();
    $this->setExpectedException(
    CantChangePublishedArticle::class
    );
    $this->rename($newTitle); // throws!

    View Slide

  26. Objects guard their own
    consistency
    $article = new Article(); // <-inconsistent
    $article->setTitle($title); // <-inconsistent
    $article->setBody($body); // <-inconsistent
    $article->setAuthor($author); // <-consistent

    View Slide

  27. Objects guard their own
    consistency
    final class Article
    {
    private $title, $body, $author;
    public function __construct($title, $body, $author)
    {
    if(empty($title) || !is_string($title)) {
    throw new InvalidArgumentException;
    }
    // etc...
    $this->body = $body;
    $this->author = $author;
    $this->title = $title;
    }
    }

    View Slide

  28. Objects are contracts
    final class StoryUpdates
    {
    public function notify(Article $source, Subscriber $subscriber)
    {
    // ...
    }
    }

    View Slide

  29. Objects compose
    final class Article
    {
    private $title;
    private $body;
    private $author;
    public function __construct(
    Title $title, Body $body, Author $author
    ) {
    $this->body = $body;
    $this->author = $author;
    $this->title = $title;
    }
    }

    View Slide

  30. Objects decompose
    final class TimeSlot
    {
    public function __construct(
    Time $startTime, Time $endTime
    )
    { // ... }
    }

    View Slide

  31. Object patterns

    View Slide

  32. Value Object
    final class TwitterHandle
    {
    private $name;
    public function __construct($name)
    {
    if (!preg_match('/^[A-Za-z0-9_]{1,15}$/', $name)) {
    throw new InvalidArgumentException;
    }
    $this->name = $name;
    }
    public function __toString()
    {
    return $this->name;
    }
    }

    View Slide

  33. No, you will not have too many objects.

    View Slide

  34. Trust me on that.

    View Slide

  35. Value Object
    final class Money
    {
    private $amount;
    private $currency;
    public function __construct($amount, Currency $currency)
    {
    // guards ...
    $this->amount = $amount;
    $this->currency = $currency;
    }
    }

    View Slide

  36. attracts behaviour
    final class Money
    {
    /** @return Money **/
    public function add(Money $other)
    /** @return Money[] **/
    public function allocate([6, 3, 1])
    }

    View Slide

  37. values are immutable
    $jim_price = new Money(2500, new Currency('EUR'));
    $hannah_price = $jim_price;
    $coupon = new Money(500, new Currency('EUR'));
    $jim_price->subtract($coupon);
    $jim_price->equals($hannah_price); // true!

    View Slide

  38. values objects are
    immutable
    $new_price = $jim_price->subtract($coupon);

    View Slide

  39. values objects are
    immutable
    /** @return Money **/
    public function add(Money $other)
    {
    if(!$this->hasSameCurrencyAs($other)){
    throw new CantAddDifferentCurrencies;
    }
    return new Money(
    $this->amount + $other->amount,
    $this->currency
    );
    }

    View Slide

  40. Entity
    final class Article
    {
    private $id;
    private $title;
    private $published = false;
    public function __construct(ArticleId $id, Title $title)
    {
    $this->id = $id;
    $this->title = $title;
    }
    public function publish()
    {
    $this->published = true;
    }
    }

    View Slide

  41. lifecycle
    changes over
    time
    stable identity

    View Slide

  42. Repositories collect
    entities
    final class ArticleRepository
    {
    private $db;
    public function __construct(Database $db)
    /** @return Article */
    public function find(ArticleId $articleId)
    /** @return Article[] */
    public function findAll()
    /** @return Article[] */
    public function findByAuthor(Author $author)
    }

    View Slide

  43. Procedural
    ->
    abstractions
    into objects

    View Slide

  44. $countOrders = DB::query(
    'SELECT COUNT(*) FROM orders WHERE customerId = :customerId',
    [ 'customerId' => $customer['id']]
    );
    if($countOrders > 5) {
    $template = 'gold.html';
    sendMail($template, ...);
    } else {
    $totalAmountSpent = DB::query(
    'SELECT ...', [ 'customerId' => $customer['id']]
    );
    if($totalAmountSpent > 5000) {
    $template = 'silver.html';
    sendMail($template, ...);
    } else {
    $template = 'bronze.html';
    sendMail($template, ...);
    }
    }

    View Slide

  45. $customer['id']
    vs
    $customer->getId();

    View Slide

  46. Specification
    final class CustomerHas5Orders
    {
    private $db;
    public function __construct(DB $db)
    {
    $this->db = $db;
    }
    /** @return bool */
    public function isSatisfiedBy(Customer $customer)
    {
    // ...
    }
    }

    View Slide

  47. Strategy
    final class MailingTemplateStrategy
    {
    //...
    private $strategy;
    public function __construct(Db $db, Mailer $mailer)
    {
    //...
    $this->strategy = [
    'gold.html' => new CustomerHas5Orders($db),
    'silver.html' => new CustomerSpent5000EUR($db),
    'bronze.html' => new CustomerBought1Product($db),
    ];
    }
    public function getTemplateFor(Customer $customer)
    {
    // ...
    return $template;
    }
    }

    View Slide

  48. Polymorphism
    final class TenantAStrategy implements MailingTemplateStrategy
    { /* ... */}
    final class TenantBStrategy implements MailingTemplateStrategy
    { /* ... */}

    View Slide

  49. Give up control
    $campaign = new PromotionCampagin(
    new TenantAStrategy()
    );
    tell a story
    $campaign->sendNewsletterTo(
    $customers->registeredBefore($date)
    );

    View Slide

  50. looks like code
    $countOrders = DB::query(
    'SELECT COUNT(*) FROM orders WHERE customerId = :customerId',
    [ 'customerId' => $customer['id']]
    );
    if($countOrders > 5) {
    $template = 'gold.html';
    sendMail($template, ...);
    } else {
    $totalAmountSpent = DB::query(
    'SELECT ...', [ 'customerId' => $customer['id']]
    );
    if($totalAmountSpent > 5000) {
    $template = 'silver.html';
    sendMail($template, ...);
    } else {
    $template = 'bronze.html';
    sendMail($template, ...);
    }
    }

    View Slide

  51. looks like business
    $campaign->sendNewsletterTo(
    $customers->registeredBefore($date)
    );

    View Slide

  52. great programming is great
    Storytelling

    View Slide

  53. verraes.net
    @mathiasverraes

    View Slide

  54. Links
    » Final Classes, Mathias Verraes
    » DRY is about Knowledge, Mathias Verraes
    » Value Objects, Tony Piper
    » Object Thinking, David West
    » Patterns of Enterprise Application
    Architecture, Martin Fowler
    » Domain-Driven Design, Eric Evans

    View Slide

  55. inheritance is (mostly) evil

    View Slide