A Missing Part of OOP

A Missing Part of OOP

#dcimeetup

23f4d5d797a91b6d17d627b90b5a42d9?s=128

Kentaro Kuribayashi

March 08, 2013
Tweet

Transcript

  1. A Missing Part of OOP @kentaro

  2. @kentaro Software engineer Rubyist / Perl Monger Kentaro Kuribayashi Spiritual

    Software http://spiritualsoftware.org/
  3. None
  4. None
  5. https://speakerdeck.com/kentaro/software-and-spiritual-ability

  6. Paradigm

  7. • Goto + Condition • Structural Programming • Subroutines •

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

  9. DCI

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

  11. • Static Class-based OOP is like “goto” programming • It

    can’t describe use cases as code.
  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
  13. http://qconlondon.com/dl/qcon-london-2010/slides/JimO.Coplien_TheDCIArchitectureLeanAndAgileAtTheCodeLevel.pdf

  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
  15. • Interaction of objects happens in a certain context •

    Methodful role holds methods to be added • Role is combined to object dynamically at runtime
  16. Problem

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

  18. We can’t avoid commonalizing even with DCI

  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
  20. That’s nothing but “goto”-like programming...

  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?
  22. What actually matters is commonalization (without any limitation)

  23. Solution ( I hope it can be)

  24. None
  25. Method-based Limitation

  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
  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
  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
  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
  30. Extension/Inclusion-based Limitation

  31. module Extendable include MethodRepository extendable_by 'Hoge' end module Includable include

    MethodRepository includable_by 'Hoge' end class Hoge; end class Fuga; end
  32. Hoge.extend(Extendable) Hoge.send(:include, Includable) Fuga.extend(Extendable) Fuga.send(:include, Includable) Extendable/Includable NotPermittedError Raised

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

  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.