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

Eastward HO!

Jim Gay
November 19, 2014

Eastward HO!

Jim Gay

November 19, 2014
Tweet

More Decks by Jim Gay

Other Decks in Technology

Transcript

  1. IF

  2. IF

  3. class Person! attr_reader :address! ! def display_address! ! end! end!

    "123 Main St. Arlington" ! "123 Main St. VA 22222" "123 Main St. Arlington, VA 22222” ! "Arlington, VA"
  4. class Person! attr_reader :address! ! def display_address! ! end! end!

    "123 Main St. Arlington" ! "123 Main St. VA 22222" "123 Main St. Arlington, VA 22222” ! "Arlington, VA"
  5. class Person! def display_address! "".tap do |string|! if !address.street.nil? ||

    !address.street.empty?! string << address.street! end! ! string << "\n" unless string.empty?! ! if !address.city.nil? address.city.empty? || address.city.nil?! string << address.city! end! ! if address.province || address.postal_code! string << ", "! end! ! if address.province || address.postal_code! if address.province! string << address.province! end! ! string << " "! ! "123 Main St. Arlington" ! "123 Main St. VA 22222" "123 Main St. Arlington, VA 22222” ! "Arlington, VA"
  6. class Person! def display_address! ! ! ! ! ! !

    ! # … all the code …! ! ! ! ! ! ! ! ! ! ! self! end! end! "123 Main St. Arlington" ! "123 Main St. VA 22222" "123 Main St. Arlington, VA 22222” ! "Arlington, VA" RULE 1
  7. class Person! def display_address! ! ! ! ! ! !

    ! # … all the code …! ! ! ! ! ! ! ! ! ! ! self! end! end! "123 Main St. Arlington" ! "123 Main St. VA 22222" "123 Main St. Arlington, VA 22222” ! "Arlington, VA"
  8. Tell,  Don’t Ask ensure a correct 
 division of

    responsibility that places the right functionality in the 
 right class 
 without causing 
 excess coupling 
 to other classes. Andy Hunt and 
 Dave Thomas
  9. Tell,  Don’t Ask ensure a correct 
 division of

    responsibility that places the right functionality in the 
 right class 
 without causing 
 excess coupling 
 to other classes. Andy Hunt and 
 Dave Thomas
  10. Command,  Don’t Query ! ! ! if !address.street.nil? ||

    !address.street.empty?! string << address.street! end
  11. Command,  Don’t Query ! ! ! if !address.street.nil? ||

    !address.street.empty?! string << address.street! end
  12. Command,  Don’t Query ! ! ! if !address.street.nil? ||

    !address.street.empty?! string << address.street! end
  13. Command,  Don’t Query ! ! ! if !address.street.nil? ||

    !address.street.empty?! string << address.street! end
  14. class Person! def display_address! "".tap do |string|! if !address.street.nil? ||

    !address.street.empty?! string << address.street! end! ! string << "\n" unless string.empty?! ! if !address.city.nil? address.city.empty? || address.city.nil?! string << address.city! end! ! if address.province || address.postal_code! string << ", "! end! ! if address.province || address.postal_code! if address.province! string << address.province! end! ! string << " "! !
  15. The Pretty Good Idea of Demeter ! ! ! if

    !address.street.nil? || !address.street.empty?! string << address.street! end
  16. The Pretty Good Idea of Demeter ! ! ! if

    !address.street.nil? || !address.street.empty?! string << address.street! end
  17. The Pretty Good Idea of Demeter ! ! ! if

    !address.street.nil? || !address.street.empty?! string << address.street! end
  18. The Pretty Good Idea of Demeter ! ! ! if

    !address.street.nil? || !address.street.empty?! string << address.street! end
  19. The Pretty Good Idea of Demeter ! ! ! if

    !address.street.nil? || !address.street.empty?! string << address.street! end
  20. class Person! def display_address! "".tap do |string|! if !address.street.nil? ||

    !address.street.empty?! string << address.street! end! ! string << "\n" unless string.empty?! ! if !address.city.nil? address.city.empty? || address.city.nil?! string << address.city! end! ! if address.province || address.postal_code! string << ", "! end! ! if address.province || address.postal_code! if address.province! string << address.province! end! ! string << " "! !
  21. class Person! def display_address! address.display! ! ! self! end! end!

    ! class Address! def display! "".tap do |string|! if !street.nil? || !street.empty?! string << street! end! ! string << "\n" unless string.empty?! ! if !city.nil? city.empty? || city.nil?! string << city! end! ! if province || postal_code! string << ", "! end!
  22. class Person! def display_address! address.display! ! ! self! end! end!

    ! class Address! def display! "".tap do |string|! if !street.nil? || !street.empty?! string << street! end! ! string << "\n" unless string.empty?! ! if !city.nil? city.empty? || city.nil?! string << city! end! ! if province || postal_code! string << ", "! end! RULE 2
  23. class Address! def display! province_and_postal_code = [province, postal_code].compact.join(' ')! province_and_postal_code

    = nil if province_and_postal_code.empty?! ! ! ! ! ! end! end "" "VA 22222" "VA 22222” "VA"
  24. class Address! def display! province_and_postal_code = [province, postal_code].compact.join(' ')! province_and_postal_code

    = nil if province_and_postal_code.empty?! ! city_province_postal_code = [city, province_and_postal_code].compact.join(', ')! city_province_postal_code = nil if city_province_postal_code.empty?! ! ! end! end "Arlington" "VA 22222" “Arlington, VA 22222” “Arlington, VA"
  25. class Address! def display! province_and_postal_code = [province, postal_code].compact.join(' ')! province_and_postal_code

    = nil if province_and_postal_code.empty?! ! city_province_postal_code = [city, province_and_postal_code].compact.join(', ')! city_province_postal_code = nil if city_province_postal_code.empty?! ! [street, city_province_postal_code].compact.join("\n")! end! end “123 Main St. Arlington” “123 Main St. VA 22222" “123 Main St. Arlington, VA 22222” “Arlington, VA"
  26. class Address! def display! province_and_postal_code = [province, postal_code].compact.join(' ')! province_and_postal_code

    = nil if province_and_postal_code.empty?! ! city_province_postal_code = [city, province_and_postal_code].compact.join(', ')! city_province_postal_code = nil if city_province_postal_code.empty?! ! [street, city_province_postal_code].compact.join("\n")! end! end
  27. class Address! def display(line_break="\n")! province_and_postal_code = [province, postal_code].compact.join(' ')! province_and_postal_code

    = nil if province_and_postal_code.empty?! ! city_province_postal_code = [city, province_and_postal_code].compact.join(', ')! city_province_postal_code = nil if city_province_postal_code.empty?! ! [street, city_province_postal_code].compact.join(line_break)! end! end
  28. class Address! def display(line_break="\n")! province_and_postal_code = [province, postal_code].compact.join(' ')! province_and_postal_code

    = nil if province_and_postal_code.empty?! ! city_province_postal_code = [city, province_and_postal_code].compact.join(', ')! city_province_postal_code = nil if city_province_postal_code.empty?! ! [street, city_province_postal_code].compact.join(line_break)! end! end! ! class Person! def display_address(line_break)! address.display(line_break)! self! end! end
  29. class Address! def display(line_break="\n")! province_and_postal_code = [province, postal_code].compact.join(' ')! province_and_postal_code

    = nil if province_and_postal_code.empty?! ! city_province_postal_code = [city, province_and_postal_code].compact.join(', ')! city_province_postal_code = nil if city_province_postal_code.empty?! ! [street, city_province_postal_code].compact.join(line_break)! end! end! ! class Person! def display_address(line_break)! address.display(line_break)! self! end! end
  30. class Template! def display_address(address)! province_and_postal_code = [address.province, address.postal_code].compact.join(' ' province_and_postal_code

    = nil if province_and_postal_code.empty?! ! city_province_postal_code = [address.city, province_and_postal_code].compact.join(' city_province_postal_code = nil if city_province_postal_code.empty?! ! STDOUT.puts [address.street, city_province_postal_code].compact.join(“\n")! ! self! end! end
  31. class Template! def display_address(address)! province_and_postal_code = [address.province, address.postal_code].compact.join(' ' province_and_postal_code

    = nil if province_and_postal_code.empty?! ! city_province_postal_code = [address.city, province_and_postal_code].compact.join(' city_province_postal_code = nil if city_province_postal_code.empty?! ! STDOUT.puts [address.street, city_province_postal_code].compact.join(“\n")! ! self! end! end! ! class HtmlTemplate! def display_address(address)! ! ! # data processing… ! ! File.open ‘address.html’ do |file|! file.write [address.street, city_province_postal_code].compact.join("<br />”)! end! ! self! end!
  32. class Person! def display_address(template=Template.new)! address.display(template)! self! end! end! ! class

    Address! def display(template)! template.display_address(self)! self! end! end!
  33. class Person! def display_address(template=Template.new)! address.display(template)! self! end! end! ! class

    Address! def display(template)! template.display_address(self)! self! end! end! ! class Template! def display_address(address)! # data processing…! ! ! STDOUT.puts [address.street, city_province_postal_code].compact.join(“\n")! ! self! end! end
  34. class Person! def display_address(template=Template.new)! address.display(template)! self! end! end! ! class

    Address! def display(template)! template.display_address(self)! self! end! end
  35. class Person! def display_address(template=Template.new)! address.display(template)! self! end! end! ! !

    ! ! class Address! def display(template)! template.display_address(self)! self! end! end
  36. class Person! def display_address(template=Template.new)! address.display(template)! self! end! ! private! attr_reader

    :address! end! ! class Address! def display(template)! template.display_address(self)! self! end! ! private! attr_reader :street, :city, :province, :postal_code! end
  37. class Address! def display(template)! template.display_address(self)! self! end! ! private! attr_reader

    :street, :city, :province, :postal_code! end! ! class Template! def display_address(address)! province_and_postal_code = [address.province, address.postal_code].compact.join(' ' province_and_postal_code = nil if province_and_postal_code.empty?! ! city_province_postal_code = [address.city, province_and_postal_code].compact.join(' city_province_postal_code = nil if city_province_postal_code.empty?! ! STDOUT.puts [address.street, city_province_postal_code].compact.join(“\n")! ! self! end! end
  38. class Address! def display(template)! template.display_address(self)! self! end! ! private! attr_reader

    :street, :city, :province, :postal_code! end! ! ! ! ! ! ! class Template! def display_address(address)! # …code…! end! end
  39. class Address! def display(template)! template.display_address(to_value)! self! end! ! private! attr_reader

    :street, :city, :province, :postal_code! ! require ‘ostruct’! def to_value! OpenStruct.new(street: street, city: city, province: province, postal_code: postal_ end! end! ! class Template! def display_address(address)! # …code…! end! end
  40. class Address! def display(template)! template.display_address(to_value)! self! end! ! private! attr_reader

    :street, :city, :province, :postal_code! ! require ‘ostruct’! def to_value! OpenStruct.new(street: street, city: city, province: province, postal_code: postal_ end! end! ! class Template! def display_address(address)! # …code…! end! end
  41. “123 Main St. Arlington” “123 Main St. VA 22222" “123

    Main St. Arlington, VA 22222” “Arlington, VA"
  42. class Address! def display(template)! template.display_address(to_value)! self! end! ! private! attr_reader

    :street, :city, :province, :postal_code! ! require ‘ostruct’! def to_value! OpenStruct.new(street: street, city: city, province: province, postal_code: postal_ end! end
  43. class Address! def display(template)! template.display_address(to_value)! self! end! ! private! attr_reader

    :street, :city, :province, :postal_code! ! require ‘ostruct’! def to_value! if protect_privacy?! OpenStruct.new(street: nil, city: city, province: province, postal_code: nil)! else! OpenStruct.new(street: street, city: city, province: province, postal_code: posta end! end! end
  44. class Template! def display_address(address)! province_and_postal_code = [address.province, address.postal_code].compact.join(' ' province_and_postal_code

    = nil if province_and_postal_code.empty?! ! city_province_postal_code = [address.city, province_and_postal_code].compact.join(' city_province_postal_code = nil if city_province_postal_code.empty?! ! STDOUT.puts [address.street, city_province_postal_code].compact.join(“\n")! ! self! end! end
  45. class Template! def display_address(address)! province_and_postal_code = [address.province, address.postal_code].compact.join(' ' province_and_postal_code

    = nil if province_and_postal_code.empty?! ! city_province_postal_code = [address.city, province_and_postal_code].compact.join(' city_province_postal_code = nil if city_province_postal_code.empty?! ! STDOUT.puts [address.street, city_province_postal_code].compact.join(“\n")! ! self! end! end QUERIES EVERYWHERE
  46. class Person! def display_address(template=Template.new)! address.display(template)! self! end! end! ! class

    Address! def display(template)! template.display_address(self)! self! end! end! ! class Template! def display_address(address)! # data processing…! ! ! STDOUT.puts […].compact.join(“\n”)! ! self! end! end
  47. EAST ORIENTED James Ladd The structuring of code to an

    
 East orientation decreases coupling and the amount of code needed to be written, whilst increasing code clarity, cohesion and flexibility.
  48. EAST ORIENTED James Ladd The structuring of code to an

    
 East orientation decreases coupling and the amount of code needed to be written, whilst increasing code clarity, cohesion and flexibility.
  49. TELL JAMES THANKS @jamesladd The East principle 
 is not

    like the 
 “Tell, Don’t Ask” principle because there is no ambiguity, you simply cannot ask, you can only tell.
  50. TELL JAMES THANKS @jamesladd The East principle 
 is not

    like the 
 “Tell, Don’t Ask” principle because there is no ambiguity, you simply cannot ask, you can only tell.
  51. class Person! ! ! attr_reader :friend! end! ! class Friend!

    def make_me_a_sandwich! Table.place "a sandwich!"! end! end!
  52. class Person! ! ! attr_reader :friend! ! def make_me_a_sandwich! friend.make_me_a_sandwich!

    end! end! ! class Friend! def make_me_a_sandwich! Table.place "a sandwich!"! end! end
  53. class Person! extend Forwardable! delegate :make_me_a_sandwich => :friend! attr_reader :friend!

    end! ! class Friend! def make_me_a_sandwich! Table.place "a sandwich!"! end! end!
  54. describe Direction do! let(:friend){ Friend.new }! let(:person){ person = Person.new!

    person.friend = friend! person! }! before do! Table.clear! end! it 'forwards a message to another object' do! assert_equal [], Table.contents! person.make_me_a_sandwich! assert_includes Table.contents, "a sandwich!"! end! end
  55. describe Direction do! let(:friend){ Friend.new }! let(:person){ person = Person.new!

    person.friend = friend! person! }! before do! Table.clear! end! it 'forwards a message to another object' do! assert_equal [], Table.contents! person.friend.make_me_a_sandwich! assert_includes Table.contents, "a sandwich!"! end! ! ! !
  56. class Person! extend Forwardable! delegate :make_me_a_sandwich => :friend! attr_reader :friend!

    end! ! class Friend! def make_me_a_sandwich! Table.place "a sandwich!"! end! end!
  57. class Person! extend Forwardable! delegate :make_me_a_sandwich => :friend! ! private!

    attr_reader :friend! end! ! class Friend! def make_me_a_sandwich! Table.place "a sandwich!"! end! end!
  58. class Person! extend Direction! command :make_me_a_sandwich => :friend! ! private!

    attr_accessor :friend! end! ! class Friend! def make_me_a_sandwich! Table.place "a sandwich!"! end! end!
  59. describe Direction do! let(:friend){ Friend.new }! let(:person){ person = Person.new!

    person.friend = friend! person! }! before do! Table.clear! end! it 'forwards a message to another object' do! assert_equal [], Table.contents! person.make_me_a_sandwich! assert_includes Table.contents, "a sandwich!"! end! ! it 'returns the original receiver' do! assert_equal person, person.make_me_a_sandwich! end!
  60. describe Direction do! ! it 'returns the original receiver' do!

    assert_equal person, person.make_me_a_sandwich! end! end
  61. describe Direction do! ! it 'returns the original receiver' do!

    assert_equal person, person.make_me_a_sandwich. ! ! get_me_a_drink! end! end
  62. describe Direction do ! it 'returns the original receiver' do!

    assert_equal person, person.make_me_a_sandwich. ! ! get_me_a_drink. ! ! wash_the_car! end! end
  63. describe Direction do! ! it 'returns the original receiver' do!

    assert_equal person, person.make_me_a_sandwich. ! ! get_me_a_drink. ! ! wash_the_car. ! ! jump! end! end
  64. describe Direction do! ! it 'returns the original receiver' do!

    assert_equal person, person.make_me_a_sandwich. ! ! get_me_a_drink. ! ! wash_the_car. ! ! jump. ! ! gimme_five! end! end
  65. describe Direction do! ! it 'returns the original receiver' do!

    assert_equal person, person.make_me_a_sandwich. ! ! get_me_a_drink. ! ! wash_the_car. ! ! jump. ! ! gimme_five. ! ! up_high! end! end
  66. describe Direction do! ! it 'returns the original receiver' do!

    assert_equal person, person.make_me_a_sandwich. ! ! get_me_a_drink. ! ! wash_the_car. ! ! jump. ! ! gimme_five. ! ! up_high. ! ! down_low! end! end
  67. describe Direction do! ! it 'returns the original receiver' do!

    assert_equal person, person.make_me_a_sandwich. ! ! get_me_a_drink. ! ! wash_the_car. ! ! jump. ! ! gimme_five. ! ! up_high. ! ! down_low. ! ! too_slow! end! end
  68. module Direction! def command(options)! method_defs = []! options.each_pair do |key,

    value|! Array(key).map do |command_name|! method_defs.unshift %{! def #{command_name}(*args, &block)! #{value}.__send__(:#{command_name}, *args, &block)! self! end! }! end! end! self.class_eval method_defs.join(' ')! end! end
  69. module Direction! def command(options)! method_defs = []! options.each_pair do |key,

    value|! Array(key).map do |command_name|! method_defs.unshift %{! def #{command_name}(*args, &block)! #{value}.__send__(:#{command_name}, *args, &block)! self! end! }! end! end! self.class_eval method_defs.join(' ')! end! end
  70. class Person! extend Direction! command [:make_me_a_sandwich, :other] => :friend! !

    private! attr_accessor :friend! end! ! class Friend! def make_me_a_sandwich! Table.place "a sandwich!"! end! end!