0
Managing Complexity                                Sam Goldman                              @nontrivialzeros              ...
What is Complexity?                   • Lines of code?                   • Duplication?                   • Coupling?     ...
Noticing Complexity                   • Feature development costs increase                   • Bugs increase superlinearly...
Reasoning about                            Complexity                   • How can you compare two solutions?              ...
Factorization                   • Large numbers factorized by primes                    • 288 = 2 × 2 × 2 × 2 × 2 × 3 × 3 ...
Probabilistic Factors                   • Take binary random variables A, B, and C                   • P(A) has two possib...
Probabilistic Factors                   • Distributions factorized by independence                   • P(A, B) = P(A)P(B) ...
Probabilistic FactorsMonday, December 17, 12
OOP                   • Software is factorized by encapsulation                   • Controlling dependencies is key       ...
Tell, Don’t Ask                   • Depending on collaborators’ states breaks                          encapsulation      ...
Asking   Questionnaire = Struct.new(:questions) do     def render(html)       html.form         questions.each do |questio...
Telling                          Questionnaire = Struct.new(:questions) do                            def render(html)    ...
Telling                          ShortAnswerQuestion = Struct.new(:id, :prompt) do                            def render(h...
Mocks                   • How can we write assertions when objects                          hide their internal state?    ...
Mocks                          describe Questionnaire do                            it "renders every question" do        ...
Mocks Aren’t Stubs                          describe ArrearsReport do                            it "displays customers wh...
Mocks Aren’t Stubs                          describe ArrearsReport do                            it "displays customers wh...
Values                   • SmartLogic’s Nerdword project                   • Services: Player, Pouch, Board               ...
Values                          module Direction                            HORIZONTAL = "Horizontal".freeze              ...
Values                          Position = Struct.new(:col, :row) do                            def shift(offset, directio...
Values                          Move = Struct.new(:word, :position, :direction) do                            def each_pos...
Values                   • We happily depend on Array, Date, String...                   • Create values in your domain   ...
Abstractions                   • RemoteFile, not S3                   • PaymentProcessor, not Braintree                   ...
Acceptance Tests                   • “How does the client know it works?”                   • Write acceptance tests your ...
Integration Tests                   • “How do we know if it works?”                   • Ports and Adapters is a good facto...
Thank you                               @smartlogic                          facebook.com/smartlogic                      ...
Upcoming SlideShare
Loading in...5
×

Managing complexity

303

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
303
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
4
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Transcript of "Managing complexity"

  1. 1. Managing Complexity Sam Goldman @nontrivialzeros github.com/samwgoldmanMonday, December 17, 12
  2. 2. What is Complexity? • Lines of code? • Duplication? • Coupling? • LOC/Method? • # Methods/Class? • # Features?Monday, December 17, 12
  3. 3. Noticing Complexity • Feature development costs increase • Bugs increase superlinearly with code size • “Boring bugs” keep happening • New dev onboarding takes weeks • Local changes have unexpected, non-local effectsMonday, December 17, 12
  4. 4. Reasoning about Complexity • How can you compare two solutions? • Lots of guidelines, e.g., SOLID • Lots of cargo culting • We need to do better than a gut check • Patterns are still goodMonday, December 17, 12
  5. 5. Factorization • Large numbers factorized by primes • 288 = 2 × 2 × 2 × 2 × 2 × 3 × 3 • Some large numbers can’t be factorized • 195845982777569926302400511 • Fundamental theorem of arithmetic • No efficient algorithmMonday, December 17, 12
  6. 6. Probabilistic Factors • Take binary random variables A, B, and C • P(A) has two possible configurations • P(A, B) has 4 • P(A, B, C) has 8 • Joint configurations grow exponentiallyMonday, December 17, 12
  7. 7. Probabilistic Factors • Distributions factorized by independence • P(A, B) = P(A)P(B) if A, B are independent • Let A and B each have 100 discrete values • Not independent: 10000 configurations • Independent: 200 configurationsMonday, December 17, 12
  8. 8. Probabilistic FactorsMonday, December 17, 12
  9. 9. OOP • Software is factorized by encapsulation • Controlling dependencies is key • Conversely: Discover independenciesMonday, December 17, 12
  10. 10. Tell, Don’t Ask • Depending on collaborators’ states breaks encapsulation • Depend on behaviors, not state • Law of DemeterMonday, December 17, 12
  11. 11. Asking Questionnaire = Struct.new(:questions) do def render(html) html.form questions.each do |question| html.fieldset { case question when ShortAnswerQuestion html.label(:for => question.id) { html.text question.prompt } html.input(:type => "text", :id => question.id, :name => question.id) when MultipleChoiceQuestion html.label { html.text question.prompt } html.ul { question.choices.each do |choice| html.li { html.label(:for => choice.id) { html.text choice.title } html.input(:type => "radio", :id => choice.id, :name => choice.id) } end } end } end end end endMonday, December 17, 12
  12. 12. Telling Questionnaire = Struct.new(:questions) do def render(html) html.form do questions.each do |question| html.fieldset { question.render(html) } end end end endMonday, December 17, 12
  13. 13. Telling ShortAnswerQuestion = Struct.new(:id, :prompt) do def render(html) html.label(:for => id) { html.text prompt } html.input(:type => "text", :id => id, :name => id) end end MultipleChoiceQuestion = Struct.new(:id, :prompt, :choices) do def render(html) html.label { html.text prompt } html.ul { choices.each do |choice| html.li { choice.render(html) } end } end end Choice = Struct.new(:id, :title) do def render(html) html.label(:for => id) { html.text title } html.input(:type => "radio", :id => id, :name => id) end endMonday, December 17, 12
  14. 14. Mocks • How can we write assertions when objects hide their internal state? • We need to assert that objects are sending the right messages to one anotherMonday, December 17, 12
  15. 15. Mocks describe Questionnaire do it "renders every question" do question1 = mock question2 = mock questionnaire = Questionnaire.new([question1, question2]) builder = stub question1.should_receive(:render).with(builder).ordered question2.should_receive(:render).with(builder).ordered questionnaire.render(builder) end endMonday, December 17, 12
  16. 16. Mocks Aren’t Stubs describe ArrearsReport do it "displays customers who owe money" do report = ArrearsReport.new foo_customer = stub(:in_arrears? => true) bar_customer = stub(:in_arrears? => false) result = report.run([foo_customer, bar_customer]) result.should eq([foo_customer]) end end describe Questionnaire do it "renders every question" do question1 = mock question2 = mock questionnaire = Questionnaire.new([question1, question2]) builder = stub question1.should_receive(:render).with(builder).ordered question2.should_receive(:render).with(builder).ordered questionnaire.render(builder) end endMonday, December 17, 12
  17. 17. Mocks Aren’t Stubs describe ArrearsReport do it "displays customers who owe money" do report = ArrearsReport.new foo_customer = stub(:in_arrears? => true) Stub Queries bar_customer = stub(:in_arrears? => false) result = report.run([foo_customer, bar_customer]) result.should eq([foo_customer]) end end describe Questionnaire do it "renders every question" do question1 = mock question2 = mock questionnaire = Questionnaire.new([question1, question2]) builder = stub Mock Actions question1.should_receive(:render).with(builder).ordered question2.should_receive(:render).with(builder).ordered questionnaire.render(builder) end endMonday, December 17, 12
  18. 18. Values • SmartLogic’s Nerdword project • Services: Player, Pouch, Board • Values: Move, Direction, PositionMonday, December 17, 12
  19. 19. Values module Direction HORIZONTAL = "Horizontal".freeze VERTICAL = "Vertical".freeze def self.opposite(direction) if direction == HORIZONTAL VERTICAL else HORIZONTAL end end endMonday, December 17, 12
  20. 20. Values Position = Struct.new(:col, :row) do def shift(offset, direction) if direction == Direction::HORIZONTAL Position.new(col + offset, row) else Position.new(col, row + offset) end end def previous(direction) shift(-1, direction) end def next(direction) shift(1, direction) end endMonday, December 17, 12
  21. 21. Values Move = Struct.new(:word, :position, :direction) do def each_position word.length.times do |i| yield position.shift(i, direction) end end endMonday, December 17, 12
  22. 22. Values • We happily depend on Array, Date, String... • Create values in your domain • Separate services from values • Better messages, better factors • Don’t stub valuesMonday, December 17, 12
  23. 23. Abstractions • RemoteFile, not S3 • PaymentProcessor, not Braintree • Wrap services around 3rd party code • “Ports and Adapters” • Write integrated tests for wrapper services • “Test double” wrapper services elsewhere • ActiveRecord?Monday, December 17, 12
  24. 24. Acceptance Tests • “How does the client know it works?” • Write acceptance tests your client would understand • Write acceptance tests your client would want to read • Write as few acceptance tests as possibleMonday, December 17, 12
  25. 25. Integration Tests • “How do we know if it works?” • Ports and Adapters is a good factorization • Write as few integration tests as you need • You don’t need as many as you thinkMonday, December 17, 12
  26. 26. Thank you @smartlogic facebook.com/smartlogic github.com/smartlogicMonday, December 17, 12
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×