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 Slide

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

    View Slide

  3. View Slide

  4. View Slide

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

    View Slide

  6. Paradigm

    View Slide

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

    View Slide

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

    View Slide

  9. DCI

    View Slide

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

    View Slide

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

    View Slide

  12. “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 Slide

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

    View Slide

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

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

    View Slide

  16. Problem

    View Slide

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

    View Slide

  18. We can’t avoid commonalizing
    even with DCI

    View Slide

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

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

    View Slide

  21. • 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 Slide

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

    View Slide

  23. Solution
    ( I hope it can be)

    View Slide

  24. View Slide

  25. Method-based
    Limitation

    View Slide

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

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

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

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

  30. Extension/Inclusion-based
    Limitation

    View Slide

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

    View Slide

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

    View Slide

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

  34. • 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 Slide

  35. Recap

    View Slide

  36. • 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 Slide