Upgrade to Pro — share decks privately, control downloads, hide ads and more …

A Missing Part of OOP

A Missing Part of OOP

#dcimeetup

Kentaro Kuribayashi

March 08, 2013
Tweet

More Decks by Kentaro Kuribayashi

Other Decks in Technology

Transcript

  1. A Missing Part of OOP
    @kentaro

    View full-size slide

  2. @kentaro
    Software engineer
    Rubyist / Perl Monger
    Kentaro Kuribayashi
    Spiritual Software
    http://spiritualsoftware.org/

    View full-size slide

  3. https://speakerdeck.com/kentaro/software-and-spiritual-ability

    View full-size slide

  4. • Goto + Condition
    • Structural Programming
    • Subroutines
    • Object-Oriented Programming

    View full-size slide

  5. http://www.software-architect.co.uk/slides/sa10-JimCoplien_Patterns.pdf

    View full-size slide

  6. http://qconlondon.com/dl/qcon-london-2010/slides/JimO.Coplien_TheDCIArchitectureLeanAndAgileAtTheCodeLevel.pdf
    “goto” Programming

    View full-size slide

  7. • Static Class-based OOP is
    like “goto” programming
    • It can’t describe use cases
    as code.

    View full-size slide

  8. “In the old days of FORTRAN and Pascal,
    I could convert a Use Case scenario into
    code, give it to my office mate with the
    scenario description, and ask him or her
    to desk check it. Today, after the
    polymorphism and object orientation of
    1967, I can't do that. Our ability to
    reason about systems has been lost.”
    http://qconlondon.com/dl/qcon-london-2010/slides/JimO.Coplien_TheDCIArchitectureLeanAndAgileAtTheCodeLevel.pdf

    View full-size slide

  9. http://qconlondon.com/dl/qcon-london-2010/slides/JimO.Coplien_TheDCIArchitectureLeanAndAgileAtTheCodeLevel.pdf

    View full-size slide

  10. class MoneyTransfer
    def initialize(source, destination)
    @source = source
    @source.extend(Transferrer)
    @destination = destination
    end
    def execute(amount)
    @source.transfer_to(@destination, amount)
    end
    module Transferrer
    def transfer_to(destination, amount)
    self.balance -= amount
    destination.balance += amount
    end
    end
    end
    Methodful
    Role

    View full-size slide

  11. • Interaction of objects
    happens in a certain context
    • Methodful role holds
    methods to be added
    • Role is combined to object
    dynamically at runtime

    View full-size slide

  12. http://qconlondon.com/dl/qcon-london-2010/slides/JimO.Coplien_TheDCIArchitectureLeanAndAgileAtTheCodeLevel.pdf

    View full-size slide

  13. We can’t avoid commonalizing
    even with DCI

    View full-size slide

  14. class FooTransfer
    def initialize(source, destination)
    @source = source.extend(Transferrer)
    @destination = destination
    end
    ...
    class BarTransfer
    def initialize(source, destination)
    @source = source.extend(Transferrer)
    @destination = destination
    end
    ...
    class BazTransfer
    def initialize(source, destination)
    @source = source.extend(Transferrer)
    @destination = destination
    end
    ...
    module Transferrer
    ...
    end

    View full-size slide

  15. That’s nothing but
    “goto”-like programming...

    View full-size slide

  16. • Methods in roles can be
    called from anywhere.
    • When we read the code, it’s
    such a bad dream of “goto”-
    like programming, isn’t it?

    View full-size slide

  17. What actually matters is
    commonalization
    (without any limitation)

    View full-size slide

  18. Solution
    ( I hope it can be)

    View full-size slide

  19. Method-based
    Limitation

    View full-size slide

  20. module Repository
    include MethodRepository
    insert :method1, in: %w[Foo Bar] do; end
    insert :method2, in: %w[Baz] do; end
    end
    class Foo; end
    class Bar; end
    class Baz; end
    class Qux; end

    View full-size slide

  21. Foo.extend(Repository)
    Bar.extend(Repository)
    Baz.extend(Repository)
    Qux.extend(Repository)
    Foo.respond_to?(:method1) #=> true
    Bar.respond_to?(:method1) #=> true
    Baz.respond_to?(:method1) #=> false
    Qux.respond_to?(:method1) #=> false
    Foo.respond_to?(:method2) #=> false
    Bar.respond_to?(:method2) #=> false
    Baz.respond_to?(:method2) #=> true
    Qux.respond_to?(:method2) #=> false

    View full-size slide

  22. foo = Foo.new; foo.extend(Repository)
    bar = Bar.new; bar.extend(Repository)
    baz = Baz.new; bar.extend(Repository)
    qux = Qux.new; qux.extend(Repository)
    foo.respond_to?(:method1) #=> true
    bar.respond_to?(:method1) #=> true
    baz.respond_to?(:method1) #=> false
    qux.respond_to?(:method1) #=> false
    foo.respond_to?(:method2) #=> false
    bar.respond_to?(:method2) #=> false
    baz.respond_to?(:method2) #=> true
    qux.respond_to?(:method2) #=> false

    View full-size slide

  23. Foo.send(:include, Repository)
    Bar.send(:include, Repository)
    Baz.send(:include, Repository)
    Qux.send(:include, Repository)
    Foo.new.respond_to?(:method1) #=> true
    Bar.new.respond_to?(:method1) #=> true
    Baz.new.respond_to?(:method1) #=> false
    Qux.new.respond_to?(:method1) #=> false
    Foo.new.respond_to?(:method2) #=> false
    Bar.new.respond_to?(:method2) #=> false
    Baz.new.respond_to?(:method2) #=> true
    Qux.new.respond_to?(:method2) #=> false

    View full-size slide

  24. Extension/Inclusion-based
    Limitation

    View full-size slide

  25. module Extendable
    include MethodRepository
    extendable_by 'Hoge'
    end
    module Includable
    include MethodRepository
    includable_by 'Hoge'
    end
    class Hoge; end
    class Fuga; end

    View full-size slide

  26. Hoge.extend(Extendable)
    Hoge.send(:include, Includable)
    Fuga.extend(Extendable)
    Fuga.send(:include, Includable)
    Extendable/Includable
    NotPermittedError Raised

    View full-size slide

  27. class FooTransfer
    def initialize(source, destination)
    @source = source.extend(Transferrer)
    @destination = destination
    end
    ...
    class BarTransfer
    def initialize(source, destination)
    @source = source.extend(Transferrer)
    @destination = destination
    end
    ...
    class BazTransfer
    def initialize(source, destination)
    @source = source.extend(Transferrer)
    @destination = destination
    end
    ...
    module Transferrer
    extendable_by
    ‘Account’
    ...
    end
    ×
    Limits extending when
    class doesn’t comply with
    definition of the module.

    View full-size slide

  28. • Commonalizes methods in
    a usual way
    • But limits them where to
    be inserted
    • Methods won’t be called
    from somewhere we don’t
    know. So, we won’t be
    burdened to dig around the
    code.

    View full-size slide

  29. • DCI is worth considering
    • We need commonalization
    even with DCI
    • Commonalization can cause
    “goto”-like programming
    without any limitation
    • method_repository can
    help you.

    View full-size slide