![Page 1: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/1.jpg)
Enable Labs @mark_menard
Let’s Do Some Upfront Design
Mark Menard
Windy City Rails 2014
@mark_menard !Enable Labs
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 2: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/2.jpg)
Enable Labs @mark_menard
Who likes TDD?
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 3: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/3.jpg)
Enable Labs @mark_menard
Who likes refactoring?
Rename Method
Rename Class
Extract Method
Inline Method
Replace Temp with Query
Replace Method with Method Object
Move Method
Extract Class
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 4: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/4.jpg)
Enable Labs @mark_menard5
Extract Method
Replace Method with Method Object
Move Method
Extract Class
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 5: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/5.jpg)
Enable Labs @mark_menard
A Tale of a Refactoring
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 6: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/6.jpg)
Enable Labs @mark_menard
# some_ruby_program -v -efoo
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 7: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/7.jpg)
Enable Labs @mark_menard8
# some_ruby_program -v -efoo !options = CommandLineOptions.new(ARGV) do option :v option :e, :string end !if options.has(:v) # Do something end !if options.has(:e) some_value = options.value(:e) # Do something with the expression end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 8: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/8.jpg)
Enable Labs @mark_menard
describe CommandLineOptions do ! describe "boolean options" do let(:options) { CommandLineOptions.new { option :c } } it "are true if present" do … it "are false if absent" do … end ! describe "string options" do let(:options) { CommandLineOptions.new { option :e, :string } } it "must have content" do … it "can return the value" do … it "return nil if not in argv" do … end end
9
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 9: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/9.jpg)
Enable Labs @mark_menard10
CommandLineOptions boolean options are true if present are false if absent string options must have content can return the value return nil if not in argv!
Finished in 0.00236 seconds5 examples, 0 failures
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 10: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/10.jpg)
Enable Labs @mark_menard11
class CommandLineOptions ! attr_accessor :argv attr_reader :options ! def initialize (argv = [], &block) @options = {} @argv = argv instance_eval &block end ! def has (option_flag) options.include?(option_flag) && argv.include?("-#{option_flag}") end ! def option (option_flag, option_type = :boolean) options[option_flag] = option_type end ! def valid? options.each do |option_flag, option_type| return false if option_type == :string && raw_value_for_option(option_flag).length < 3 end end ! def value (option_flag) raw_option_value = raw_value_for_option(option_flag) return nil unless raw_option_value option_type = options[option_flag] return raw_option_value[2..-1] if option_type == :string end ! private def raw_value_for_option (option_flag) argv.find { |arg| arg =~ /-#{option_flag}/ } end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 11: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/11.jpg)
Enable Labs @mark_menard12
# some_ruby_program -v -efoo -i100 !
options = CommandLineOptions.new(ARGV) do option :v option :e, :string option :i, :integer end !
verbose = options.value(:v) expression = options.value(:e) iteration_count = options.value(:i) || 1
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 12: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/12.jpg)
Enable Labs @mark_menard13
describe "integer options" do it "must have content" it "must be an integer" it "can return the value as an integer" it "returns nil if not in argv" end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 13: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/13.jpg)
Enable Labs @mark_menard14
CommandLineOptions boolean options are true if present are false if absent string options must have content can return the value return nil if not in argv integer options must have content (PENDING: No reason given) must be an integer (PENDING: Not yet implemented) can return the value as an integer (PENDING: Not yet implemented) returns nil if not in argv (PENDING: Not yet implemented)
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 14: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/14.jpg)
Enable Labs @mark_menard15
CommandLineOptions boolean options are true if present are false if absent string options must have content is valid when there is content can return the value return nil if not in argv integer options must have content must be an integer can return the value as an integer returns nil if not in argv (PENDING: Not yet implemented)!Pending: CommandLineOptions integer options returns nil if not in argv # Not yet implemented # ./spec/command_line_options_spec.rb:61!Finished in 0.00291 seconds10 examples, 0 failures, 1 pending
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 15: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/15.jpg)
Enable Labs @mark_menard16
class CommandLineOptions ! attr_accessor :argv attr_reader :options ! def initialize (argv = [], &block) @options = {} @argv = argv instance_eval &block end ! def has (option_flag) options.include?(option_flag) && argv.include?("-#{option_flag}") end ! def valid? options.each do |option_flag, option_type| return false unless option_valid?(option_type, raw_value_for_option(option_flag)) end end ! def value (option_flag) raw_option_value = raw_value_for_option(option_flag) return nil unless raw_option_value option_type = options[option_flag] return extract_value_from_raw_value(raw_option_value) if option_type == :string end ! private def option (option_flag, option_type = :boolean) options[option_flag] = option_type end ! private def option_valid? (option_type, raw_value) send("#{option_type}_option_valid?", raw_value) end ! private def string_option_valid? (raw_value) extract_value_from_raw_value(raw_value).length > 0 end ! private def integer_option_valid? (raw_value) extract_value_from_raw_value(raw_value).length > 0 && (Integer(extract_value_from_raw_value(raw_value)) rescue false) end ! private def boolean_option_valid? (raw_value) true end ! private def extract_value_from_raw_value (raw_value) raw_value[2..-1] end ! private def raw_value_for_option (option_flag) argv.find { |arg| arg =~ /-#{option_flag}/ } end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 16: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/16.jpg)
Enable Labs @mark_menard
Oooooof! !!
This class is getting big…
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 17: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/17.jpg)
Enable Labs @mark_menard
So… let’s extract a class and move some methods.
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 18: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/18.jpg)
Enable Labs @mark_menard19
describe StringOption do let(:string_option) { StringOption.new('s', '-sfoo') } ! it "has a flag" it "is valid when it has a value" it "can return it's value when present" it "returns nil if the flag has no raw value" end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 19: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/19.jpg)
Enable Labs @mark_menard20
CommandLineOptions boolean options are true if present are false if absent string options must have content is valid when there is content can return the value return nil if not in argv integer options must have content must be an integer can return the value as an integer returns nil if not in argv (PENDING: Not yet implemented)!StringOption has a flag (PENDING: No reason given) is valid when it has a value (PENDING: Not yet implemented) can return it's value when present (PENDING: Not yet implemented) returns nil if the flag has no raw value (PENDING: Not yet implemented)
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 20: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/20.jpg)
Enable Labs @mark_menard21
class StringOption !
attr_reader :flag !
def initialize (flag, raw_value) @flag = flag @raw_value = raw_value end !
end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 21: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/21.jpg)
Enable Labs @mark_menard22
class CommandLineOptions ! private def string_option_valid? (raw_value) extract_value_from_raw_value(raw_value).length > 0 end !end
class StringOption ! attr_reader :flag, :raw_value ! def initialize (flag, raw_value) @flag = flag @raw_value = raw_value end ! def valid? extract_value_from_raw_value.length > 0 end ! private def extract_value_from_raw_value raw_value[2..-1] end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 22: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/22.jpg)
Enable Labs @mark_menard
Ow, ow, ow, ow… ow!
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 23: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/23.jpg)
Enable Labs @mark_menard
The Extract Class and Move Method refactorings are VERY expensive.
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 24: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/24.jpg)
Enable Labs @mark_menard28
class StringOption ! attr_reader :flag, :raw_value ! def initialize (flag, raw_value) @flag = flag @raw_value = raw_value end ! def valid? extract_value_from_raw_value.length > 0 end ! private def extract_value_from_raw_value raw_value[2..-1] end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 25: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/25.jpg)
Enable Labs @mark_menard29
class IntegerOption ! attr_reader :flag, :raw_value ! def initialize (flag, raw_value) @flag = flag @raw_value = raw_value end ! def valid? extract_value_from_raw_value.length > 0 && real_value_is_integer? end ! private def extract_value_from_raw_value raw_value[2..-1] end ! private def real_value_is_integer? (Integer(extract_value_from_raw_value) rescue false) end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 26: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/26.jpg)
Enable Labs @mark_menard30
class BooleanOption ! attr_reader :flag, :raw_value ! def initialize (flag, raw_value) @flag = flag @raw_value = raw_value end ! def valid? true end ! def value !!raw_value end end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 27: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/27.jpg)
Enable Labs @mark_menard31
class Option ! attr_reader :flag, :raw_value ! def initialize (flag, raw_value) @flag = flag @raw_value = raw_value end !end !
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 28: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/28.jpg)
Enable Labs @mark_menard32
class StringOption < Option ! def valid? extract_value_from_raw_value.length > 0 end ! private def extract_value_from_raw_value raw_value[2..-1] end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 29: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/29.jpg)
Enable Labs @mark_menard33
class IntegerOption < Option ! def valid? extract_value_from_raw_value.length > 0 && real_value_is_integer? end ! private def extract_value_from_raw_value raw_value[2..-1] end ! private def real_value_is_integer? (Integer(extract_value_from_raw_value) rescue false) end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 30: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/30.jpg)
Enable Labs @mark_menard34
class BooleanOption < Option ! def valid? true end ! def value !!raw_value end end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 31: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/31.jpg)
Enable Labs @mark_menard35
CommandLineOptions boolean options are true if present are false if absent string options must have content is valid when there is content can return the value return nil if not in argv integer options must have content must be an integer can return the value as an integer returns nil if not in argv!StringOption has a flag is valid when it has a value can return it's value when present returns nil if the flag has no raw value
Duplication!
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 32: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/32.jpg)
Enable Labs @mark_menard
All code is an impediment to change.
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 33: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/33.jpg)
Enable Labs @mark_menard
Including your tests!
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 34: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/34.jpg)
Enable Labs @mark_menard
Can we avoid this churn?
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 35: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/35.jpg)
Enable Labs @mark_menard
Do some upfront design!
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 36: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/36.jpg)
Enable Labs @mark_menard
But that’s not agile… right?
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 37: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/37.jpg)
Enable Labs @mark_menard
Sequence Diagrams!
Collaboration Diagrams!
Mental Experiments!
Playing with Code / Exploratory Tests
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 38: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/38.jpg)
Enable Labs @mark_menard
Container Cost Calculations
• Bunker Charge (fuel charge)!
• Taxes!
• Carrier Surcharges
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 39: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/39.jpg)
Enable Labs @mark_menard43
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 40: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/40.jpg)
Enable Labs @mark_menard44
class ShipmentCostCalculator def initialize (type: type, shipment: shipment) @type = type @shipment = shipment end ! def calculate cost = 0 itinerary = shipment.itinerary carrier = shipment.carrier ! # Calculate bunker charge ! distance = itinerary.segments.sum(&:distance_in_km) cost += carrier.bunker_charge_per_km * distance ! # Calculate taxes ! cost += itinerary.segments.select { |s| s.taxable? }.sum(&:tax_fee) ! # Calculate surcharges ! cost += carrier.surcharges.sum(&:charge) cost end end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 41: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/41.jpg)
Enable Labs @mark_menard44
class ShipmentCostCalculator def initialize (type: type, shipment: shipment) @type = type @shipment = shipment end ! def calculate cost = 0 itinerary = shipment.itinerary carrier = shipment.carrier ! # Calculate bunker charge ! distance = itinerary.segments.sum(&:distance_in_km) cost += carrier.bunker_charge_per_km * distance ! # Calculate taxes ! cost += itinerary.segments.select { |s| s.taxable? }.sum(&:tax_fee) ! # Calculate surcharges ! cost += carrier.surcharges.sum(&:charge) cost end end
What
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 42: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/42.jpg)
Enable Labs @mark_menard44
class ShipmentCostCalculator def initialize (type: type, shipment: shipment) @type = type @shipment = shipment end ! def calculate cost = 0 itinerary = shipment.itinerary carrier = shipment.carrier ! # Calculate bunker charge ! distance = itinerary.segments.sum(&:distance_in_km) cost += carrier.bunker_charge_per_km * distance ! # Calculate taxes ! cost += itinerary.segments.select { |s| s.taxable? }.sum(&:tax_fee) ! # Calculate surcharges ! cost += carrier.surcharges.sum(&:charge) cost end end
How
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 43: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/43.jpg)
Enable Labs @mark_menard45
class ShipmentCostCalculator def initialize (type: type, shipment: shipment) @type = type @shipment = shipment end ! def calculate cost = 0 itinerary = shipment.itinerary carrier = shipment.carrier ! # Calculate bunker charge ! distance = itinerary.segments.sum(&:distance_in_km) cost += carrier.bunker_charge_per_km * distance ! # Calculate taxes ! cost += itinerary.segments.select { |s| s.taxable? }.sum(&:tax_fee) ! # Calculate surcharges ! cost += carrier.surcharges.sum(&:charge) cost end end
What
How
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 44: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/44.jpg)
Enable Labs @mark_menard46
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 45: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/45.jpg)
Enable Labs @mark_menard47
class ShipmentCostCalculator attr_reader :shipment, :itinerary, :carrier ! def initialize (shipment: shipment) @shipment = shipment @itinerary = shipment.itinerary @carrier = shipment.carrier end ! def calculate calculate_bunker_charge + calculate_tax_charge + calculate_surcharge end ! def calculate_bunker_charge distance = itinerary.segments.sum(&:distance_in_km) carrier.bunker_charge_per_km * distance end ! def calculate_tax_charge itinerary.segments.select { |s| s.taxable? }.sum(&:tax_fee) end ! def calculate_surcharge carrier.surcharges.sum(&:charge) end !end
What
How
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 46: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/46.jpg)
Enable Labs @mark_menard
CoordinatorProcessor
Processor
Processor
Coordinator
Processor
Coordinator Coordinator
Processor
Processor
ProcessorProcessor
Processor
ProcessorCoordinators vs Processors
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 47: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/47.jpg)
Enable Labs @mark_menard
WhatHow
How
How
What
How
What What
How
How
HowHow
How
HowCoordinators vs Processors
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 48: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/48.jpg)
Enable Labs @mark_menard
Container Cost Calculations
• Bunker Charge (fuel charge)!
• Taxes!
• Carrier Surcharges
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 49: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/49.jpg)
Enable Labs @mark_menard50
What How
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 50: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/50.jpg)
Enable Labs @mark_menard51
Coordinator Processor
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 51: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/51.jpg)
Enable Labs @mark_menard
So, how do I build that without the churn?
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 52: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/52.jpg)
Enable Labs @mark_menard
So, how do I build that without the churn?
1. Identify a top level Coordinator and give it a descriptive name based on the use case.
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 53: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/53.jpg)
Enable Labs @mark_menard54
class ShipmentCostCalculator end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 54: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/54.jpg)
Enable Labs @mark_menard
So, how do I build that without the churn?
1. Identify a top level Coordinator and give it a descriptive name based on the use case.!
2. Write a failing top level feature spec that runs everything without test doubles using real data.
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 55: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/55.jpg)
Enable Labs @mark_menard56
require 'spec_helper' !describe "shipment cost calculation feature" do before(:each) do setup_itineraries setup_carrier_charges end ! describe "basic shipment" do let(:shipment) { build(:basic_shipment) } ! it "should correctly calculate shipment charge" do calculator = ShipmentCostCalculator.new(shipment: shipment) expect(calculator.calculate).to eq(1200) end end ! # more scenarios... !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 56: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/56.jpg)
Enable Labs @mark_menard56
require 'spec_helper' !describe "shipment cost calculation feature" do before(:each) do setup_itineraries setup_carrier_charges end ! describe "basic shipment" do let(:shipment) { build(:basic_shipment) } ! it "should correctly calculate shipment charge" do calculator = ShipmentCostCalculator.new(shipment: shipment) expect(calculator.calculate).to eq(1200) end end ! # more scenarios... !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 57: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/57.jpg)
Enable Labs @mark_menard56
require 'spec_helper' !describe "shipment cost calculation feature" do before(:each) do setup_itineraries setup_carrier_charges end ! describe "basic shipment" do let(:shipment) { build(:basic_shipment) } ! it "should correctly calculate shipment charge" do calculator = ShipmentCostCalculator.new(shipment: shipment) expect(calculator.calculate).to eq(1200) end end ! # more scenarios... !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 58: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/58.jpg)
Enable Labs @mark_menard56
require 'spec_helper' !describe "shipment cost calculation feature" do before(:each) do setup_itineraries setup_carrier_charges end ! describe "basic shipment" do let(:shipment) { build(:basic_shipment) } ! it "should correctly calculate shipment charge" do calculator = ShipmentCostCalculator.new(shipment: shipment) expect(calculator.calculate).to eq(1200) end end ! # more scenarios... !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 59: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/59.jpg)
Enable Labs @mark_menard57
class ShipmentCostCalculator attr_reader :shipment !
def initialize (shipment:) @shipment = shipment end !
def calculate end end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 60: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/60.jpg)
Enable Labs @mark_menard
So, how do I build that without the churn?
1. Identify a top level Coordinator and give it a descriptive name based on the use case.!
2. Write a failing top level feature spec that runs everything without test doubles using real data.!
3. Write a failing coordinator spec using test doubles for the top level coordinator.!
1. Identify other collaborators and inject them using test doubles.
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 61: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/61.jpg)
Enable Labs @mark_menard59
require 'spec_helper' !describe "shipment cost calculation" do ! let(:shipment) { double } let(:bunker_charge_calculator) { double("bunker_charge_calculator", :calculate => 1) } ! let(:shipment_cost_calculator) { ShipmentCostCalculator.new(shipment: shipment) } ! before(:each) do expect(BunkerChargeCalculator).to receive(:new).and_return(bunker_charge_calculator) end ! it "uses a bunker charge calculator" do expect(bunker_charge_calculator).to receive(:calculate).once.with(shipment) shipment_cost_calculator.calculate end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 62: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/62.jpg)
Enable Labs @mark_menard59
require 'spec_helper' !describe "shipment cost calculation" do ! let(:shipment) { double } let(:bunker_charge_calculator) { double("bunker_charge_calculator", :calculate => 1) } ! let(:shipment_cost_calculator) { ShipmentCostCalculator.new(shipment: shipment) } ! before(:each) do expect(BunkerChargeCalculator).to receive(:new).and_return(bunker_charge_calculator) end ! it "uses a bunker charge calculator" do expect(bunker_charge_calculator).to receive(:calculate).once.with(shipment) shipment_cost_calculator.calculate end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 63: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/63.jpg)
Enable Labs @mark_menard59
require 'spec_helper' !describe "shipment cost calculation" do ! let(:shipment) { double } let(:bunker_charge_calculator) { double("bunker_charge_calculator", :calculate => 1) } ! let(:shipment_cost_calculator) { ShipmentCostCalculator.new(shipment: shipment) } ! before(:each) do expect(BunkerChargeCalculator).to receive(:new).and_return(bunker_charge_calculator) end ! it "uses a bunker charge calculator" do expect(bunker_charge_calculator).to receive(:calculate).once.with(shipment) shipment_cost_calculator.calculate end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 64: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/64.jpg)
Enable Labs @mark_menard59
require 'spec_helper' !describe "shipment cost calculation" do ! let(:shipment) { double } let(:bunker_charge_calculator) { double("bunker_charge_calculator", :calculate => 1) } ! let(:shipment_cost_calculator) { ShipmentCostCalculator.new(shipment: shipment) } ! before(:each) do expect(BunkerChargeCalculator).to receive(:new).and_return(bunker_charge_calculator) end ! it "uses a bunker charge calculator" do expect(bunker_charge_calculator).to receive(:calculate).once.with(shipment) shipment_cost_calculator.calculate end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 65: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/65.jpg)
Enable Labs @mark_menard59
require 'spec_helper' !describe "shipment cost calculation" do ! let(:shipment) { double } let(:bunker_charge_calculator) { double("bunker_charge_calculator", :calculate => 1) } ! let(:shipment_cost_calculator) { ShipmentCostCalculator.new(shipment: shipment) } ! before(:each) do expect(BunkerChargeCalculator).to receive(:new).and_return(bunker_charge_calculator) end ! it "uses a bunker charge calculator" do expect(bunker_charge_calculator).to receive(:calculate).once.with(shipment) shipment_cost_calculator.calculate end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 66: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/66.jpg)
Enable Labs @mark_menard59
require 'spec_helper' !describe "shipment cost calculation" do ! let(:shipment) { double } let(:bunker_charge_calculator) { double("bunker_charge_calculator", :calculate => 1) } ! let(:shipment_cost_calculator) { ShipmentCostCalculator.new(shipment: shipment) } ! before(:each) do expect(BunkerChargeCalculator).to receive(:new).and_return(bunker_charge_calculator) end ! it "uses a bunker charge calculator" do expect(bunker_charge_calculator).to receive(:calculate).once.with(shipment) shipment_cost_calculator.calculate end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 67: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/67.jpg)
Enable Labs @mark_menard59
require 'spec_helper' !describe "shipment cost calculation" do ! let(:shipment) { double } let(:bunker_charge_calculator) { double("bunker_charge_calculator", :calculate => 1) } ! let(:shipment_cost_calculator) { ShipmentCostCalculator.new(shipment: shipment) } ! before(:each) do expect(BunkerChargeCalculator).to receive(:new).and_return(bunker_charge_calculator) end ! it "uses a bunker charge calculator" do expect(bunker_charge_calculator).to receive(:calculate).once.with(shipment) shipment_cost_calculator.calculate end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 68: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/68.jpg)
Enable Labs @mark_menard
So, how do I build that without the churn?
1. Identify a top level Coordinator and give it a descriptive name based on the use case.!
2. Write a failing top level feature spec that runs everything without test doubles using real data.!
3. Write a failing coordinator spec using test doubles for the top level coordinator.!
1. Identify other collaborators and inject them using test doubles.!
4. Make the top level Coordinator pass the spec.
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 69: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/69.jpg)
Enable Labs @mark_menard61
class ShipmentCostCalculator attr_reader :shipment, :bunker_charge_calculator ! def initialize (shipment:, bunker_charge_calculator: BunkerChargeCalculator.new) ! @shipment = shipment @bunker_charge_calculator = bunker_charge_calculator end ! def calculate bunker_charge_calculator.calculate(shipment) end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 70: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/70.jpg)
Enable Labs @mark_menard61
class ShipmentCostCalculator attr_reader :shipment, :bunker_charge_calculator ! def initialize (shipment:, bunker_charge_calculator: BunkerChargeCalculator.new) ! @shipment = shipment @bunker_charge_calculator = bunker_charge_calculator end ! def calculate bunker_charge_calculator.calculate(shipment) end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 71: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/71.jpg)
Enable Labs @mark_menard61
class ShipmentCostCalculator attr_reader :shipment, :bunker_charge_calculator ! def initialize (shipment:, bunker_charge_calculator: BunkerChargeCalculator.new) ! @shipment = shipment @bunker_charge_calculator = bunker_charge_calculator end ! def calculate bunker_charge_calculator.calculate(shipment) end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 72: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/72.jpg)
Enable Labs @mark_menard62
require 'spec_helper' !describe "shipment cost calculation" do ! let(:shipment) { double } let(:bunker_charge_calculator) { double("bunker_charge_calculator", :calculate => 1) } ! let(:shipment_cost_calculator) { ShipmentCostCalculator.new(shipment: shipment) } ! before(:each) do expect(BunkerChargeCalculator).to receive(:new).and_return(bunker_charge_calculator) expect(TaxChargeCalculator).to receive(:new).and_return(tax_charge_calculator) expect(SurchargeCalculator).to receive(:new).and_return(surcharge_calculator) end ! it "uses a bunker charge calculator" do expect(bunker_charge_calculator).to receive(:calculate).once.with(shipment) shipment_cost_calculator.calculate end ! it "uses a tax charge calculator" do expect(tax_charge_calculator).to receive(:calculate).once.with(shipment) shipment_cost_calculator.calculate end ! it "uses a surcharge calculator" do expect(surcharge_calculator).to receive(:calculate).once.with(shipment) shipment_cost_calculator.calculate end ! it "returns the sum of bunker charge, tax charge, and shurcharges" do expect(shipment_cost_calculator.calculate).to eq(6) end end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 73: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/73.jpg)
Enable Labs @mark_menard63
class ShipmentCostCalculator attr_reader :shipment, :bunker_charge_calculator attr_reader :tax_charge_calculator, :surcharge_calculator ! def initialize (shipment:, bunker_charge_calculator: BunkerChargeCalculator.new, tax_charge_calculator: TaxChargeCalculator.new, surcharge_calculator: SurchargeCalculator.new) ! @shipment = shipment @bunker_charge_calculator = bunker_charge_calculator @tax_charge_calculator = tax_charge_calculator @surcharge_calculator = surcharge_calculator end ! def calculate bunker_charge_calculator.calculate(shipment) + tax_charge_calculator.calculate(shipment) + surcharge_calculator.calculate(shipment) end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 74: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/74.jpg)
Enable Labs @mark_menard63
class ShipmentCostCalculator attr_reader :shipment, :bunker_charge_calculator attr_reader :tax_charge_calculator, :surcharge_calculator ! def initialize (shipment:, bunker_charge_calculator: BunkerChargeCalculator.new, tax_charge_calculator: TaxChargeCalculator.new, surcharge_calculator: SurchargeCalculator.new) ! @shipment = shipment @bunker_charge_calculator = bunker_charge_calculator @tax_charge_calculator = tax_charge_calculator @surcharge_calculator = surcharge_calculator end ! def calculate bunker_charge_calculator.calculate(shipment) + tax_charge_calculator.calculate(shipment) + surcharge_calculator.calculate(shipment) end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 75: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/75.jpg)
Enable Labs @mark_menard63
class ShipmentCostCalculator attr_reader :shipment, :bunker_charge_calculator attr_reader :tax_charge_calculator, :surcharge_calculator ! def initialize (shipment:, bunker_charge_calculator: BunkerChargeCalculator.new, tax_charge_calculator: TaxChargeCalculator.new, surcharge_calculator: SurchargeCalculator.new) ! @shipment = shipment @bunker_charge_calculator = bunker_charge_calculator @tax_charge_calculator = tax_charge_calculator @surcharge_calculator = surcharge_calculator end ! def calculate bunker_charge_calculator.calculate(shipment) + tax_charge_calculator.calculate(shipment) + surcharge_calculator.calculate(shipment) end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 76: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/76.jpg)
Enable Labs @mark_menard63
class ShipmentCostCalculator attr_reader :shipment, :bunker_charge_calculator attr_reader :tax_charge_calculator, :surcharge_calculator ! def initialize (shipment:, bunker_charge_calculator: BunkerChargeCalculator.new, tax_charge_calculator: TaxChargeCalculator.new, surcharge_calculator: SurchargeCalculator.new) ! @shipment = shipment @bunker_charge_calculator = bunker_charge_calculator @tax_charge_calculator = tax_charge_calculator @surcharge_calculator = surcharge_calculator end ! def calculate bunker_charge_calculator.calculate(shipment) + tax_charge_calculator.calculate(shipment) + surcharge_calculator.calculate(shipment) end !end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 77: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/77.jpg)
Enable Labs @mark_menard64
require 'spec_helper' !describe "shipment cost calculation" do ! # . . . it "returns the sum of bunker charge, tax charge, and shurcharges" do expect(shipment_cost_calculator.calculate).to eq(6) end end
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 78: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/78.jpg)
Enable Labs @mark_menard
So, how do I build that without the churn?
1. Identify a top level Coordinator and give it a descriptive name based on the use case.!
2. Write a top level feature spec that runs everything without test doubles using real data.!
3. Write a coordinator spec using test doubles for the top level coordinator.!
1. Identify other collaborators and inject them using test doubles.!
4. Make the top level Coordinator pass the spec.!
5. Repeat 2-3 for the identified collaborators until you can’t delegate anymore.
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 79: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/79.jpg)
Enable Labs @mark_menard66
Coordinator ?
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 80: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/80.jpg)
Enable Labs @mark_menard67
Shipment Cost
Calculator Surcharge Calculator
Tax Charge Calculator
Bunker Charge
Calculator
Bunker Rate Repository
Container Weight
Calculator
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 81: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/81.jpg)
Enable Labs @mark_menard
I can’t delegate anymore!!!
Now what do I do?
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 82: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/82.jpg)
Enable Labs @mark_menard69
Enable LabsTriage and !Training
Two days on-site at your place of business.!! !First Day: Code Deep Dive!!• Code Review!• OO Design Review!• Testing Strategy Review!• Hands-on Pairing!
!Second Day: Training!!• Directly address issues identified on day one.
Get hands-on mentoring and help with your project.
Two days on-site hands-on.
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 83: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/83.jpg)
Enable Labs @mark_menard70
Enable LabsSmall Code!WorkshopLearn how to write small beautiful code.
Smaller classes and systems are easier to build and maintain. From fundamentals through system design the Small Code Workshop teaches:!!• Method Design!• Naming Strategies!• Class Design!• Inheritance vs Composition!• Exploratory Testing!• Dependency Management!• Directed Refactorings!• … and more
Two to four days on-site hands-on.
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 84: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/84.jpg)
Enable Labs @mark_menard71
Enable LabsOn the Project !TrainingWork hand in hand!with Enable Labs!staff on your projects.
You’ll work hands on with Enable Labs developers and trainers on your project using your code. Our developers will focus on teaching the fundamental principles of Small Code and good object oriented design while moving your project forward.!!You get to define your objectives for the two weeks and our team will focus on getting you and your team to a better place.!!We will focus on:!!• Immediate improvements to the design of your most difficult
components.!• Improving your test suite design to assure it’s delivering maximum
value.!• Teaching fundamentals of class naming, class design, separation
of concerns and more.
Level up in two weeks while working in your code base.
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 85: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/85.jpg)
Enable Labs @mark_menard72
Enable LabsCustom App!DevelopmentFull life-cycle project development
From idea to deployment our team can bring your vision to life. Using a highly interactive process our team will work directly with your stake holders to create your applications.
Fully co-located cross functional team
We use:!!• Test Driven Development!• Client on-site!• Pair Programming
We work with:!!• Ruby!• Rails!• AngularJS!• iOS!• Android!• … and much more
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014
![Page 86: Let's Do Some Upfront Design - WindyCityRails 2014](https://reader034.vdocuments.site/reader034/viewer/2022051818/54bc891c4a7959163e8b4596/html5/thumbnails/86.jpg)
Enable Labs @mark_menard73
http://www.enablelabs.com/
866-895-8189
Enable Labs@mark_menard
LetsDoSomeUpfrontDesign-WindyCityRails2014 - September 4, 2014