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

Evitando o Jenga® Driven Development @ RubyConf...

João Britto
November 17, 2017

Evitando o Jenga® Driven Development @ RubyConf BR 2017

Mover e remover código. Algo que fazemos praticamente todos os dias da nossa vida como programadores. O que podemos aprender a respeito de algo aparentemente tão mundano? Quais detalhes são frequentemente negligenciados e nos causam, silenciosamente, uma diversidade de problemas?

João Britto

November 17, 2017
Tweet

More Decks by João Britto

Other Decks in Programming

Transcript

  1. –Grant Ammons “A product with lots of features does not

    make a great product. A great product is one that solves the customer’s problem in the simplest way possible. Great products deliver value, not features.”
  2. –Sandi MacPherson “Whenever you build a new feature, you’re entering

    into a contract to keep that code up-to-date and compatible with all other features you’ll choose to add in the future.”
  3. –Jeff Atwood “Every new line of code you willingly bring

    into the world is code that has to be debugged, code that has to be read and understood, code that has to be supported. Every time you write new code, you should do so reluctantly, under duress, because you completely exhausted all your other options.”
  4. –Edsger W. Dijkstra “…if we wish to count lines of

    code, we should not regard them as ‘lines produced’ but as ‘lines spent’.”
  5. –Mike Perham “No code runs faster than no code. No

    code has fewer bugs than no code. No code uses less memory than no code. No code is easier to understand than no code.”
  6. –Thomas Figg “The easiest code to delete is the code

    you avoided writing in the first place.”
  7. Coisas mudam • Features nascem, crescem e eventualmente morrem. •

    Ainda faz sentido no contexto atual do meu produto? • Tem usuários suficientes para justificar sua existência? • Representa uma vulnerabilidade na stack? ou seja… • Está mais atrapalhando do que ajudando?
  8. –Sandi Metz “The problem with poorly designed small applications is

    that if they are successful they grow up to be poorly designed big applications.”
  9. Código pouco “removível” module Animals ANIMALS = %i(cat dog fox)

    def self.say(animal) if ANIMALS.include?(animal) send(animal) else raise "What does the #{animal} say?" end end def self.cat; "MEOW!"; end def self.dog; "WOOF!"; end def self.fox; "WHAT!"; end end Animals.say(:dog) # => "WOOF!"
  10. Código pouco “removível” module Animals ANIMALS = %i(cat dog fox)

    def self.say(animal) if ANIMALS.include?(animal) send(animal) else raise "What does the #{animal} say?" end end def self.cat; "MEOW!"; end def self.dog; "WOOF!"; end def self.fox; "WHAT!"; end end Animals.say(:dog) # => "WOOF!"
  11. Código pouco “removível” module Animals ANIMALS = %i(cat dog fox)

    def self.say(animal) if ANIMALS.include?(animal) send(animal) else raise "What does the #{animal} say?" end end def self.cat; "MEOW!"; end def self.fox; "WHAT!"; end end Animals.say(:dog) # => NoMethodError: undefined method `dog' for Animals:Module
  12. Código pouco “removível” module Animals ANIMALS = %i(cat dog fox)

    def self.say(animal) if ANIMALS.include?(animal) send(animal) else raise "What does the #{animal} say?" end end def self.cat; "MEOW!"; end def self.fox; "WHAT!"; end end Animals.say(:dog) # => NoMethodError: undefined method `dog' for Animals:Module
  13. Código pouco “removível” module Animals ANIMALS = %i(cat fox) def

    self.say(animal) if ANIMALS.include?(animal) send(animal) else raise "What does the #{animal} say?" end end def self.cat; "MEOW!"; end def self.fox; "WHAT!"; end end Animals.say(:dog) # => "What does the dog say?"
  14. Código mais “removível” module Animals ANIMALS = { cat: "MEOW!",

    dog: "WOOF!", fox: "WHAT!" } def self.say(animal) ANIMALS[animal] || "What does the #{animal} say?" end end Animals.say(:dog) # => "WOOF!" Animals.say(:cow) # => "What does the cow say?"
  15. Código mais “removível” module Animals ANIMALS = { cat: "MEOW!",

    dog: "WOOF!", fox: "WHAT!" } def self.say(animal) ANIMALS[animal] || "What does the #{animal} say?" end end Animals.say(:dog) # => "WOOF!" Animals.say(:cow) # => "What does the cow say?"
  16. Código mais “removível” module Animals ANIMALS = { cat: "MEOW!",

    dog: "WOOF!", fox: "WHAT!" } def self.say(animal) ANIMALS[animal] || "What does the #{animal} say?" end end Animals.say(:dog) # => "WOOF!" Animals.say(:cow) # => "What does the cow say?"
  17. –Thomas Figg “Good code isn’t about getting it right the

    first time. Good code is just legacy code that doesn’t get in the way.”
  18. Deveria ser tão simples quanto 1. Apagar o código 2.

    Apagar os testes 3. Partir pro abraço #
  19. –Ned Batchelder “Most developers don't like getting rid of stuff.

    They want to keep chunks of code around in case they need them again. They worked hard to write that chunk of code. They debugged it, it works. They don't want to just throw it away.”
  20. –Ned Batchelder “If you have a chunk of code you

    don't need any more, there's one big reason to delete it for real rather than leaving it in a disabled state: to reduce noise and uncertainty.”
  21. Remoção Incorreta module Animals ANIMALS = %i(cat dog fox) def

    self.say(animal) if ANIMALS.include?(animal) send(animal) else raise "What does the #{animal} say?" end end def self.cat; "MEOW!"; end def self.fox; "WHAT!"; end end Animals.say(:dog) # => NoMethodError: undefined method `dog' for Animals:Module
  22. Sacolejo Automático • Reduzir código entregue às máquinas • Passo

    de compilação/empacotamento • Código morto permanece no repositório
  23. Sacolejo Manual • Reduzir código entregue às pessoas • Parte

    do fluxo de desenvolvimento • Código removido em definitivo
  24. Removendo dependências <div class="actions"> <span class="parting-message"> <%= goodbye_to(@creature) %> </span>

    <%= button_to t('.sacrifice'), @creature, method: :delete, class: 'btn-delete-creature' %> </div>
  25. Removendo dependências <div class="actions"> <span class="parting-message"> <%= goodbye_to(@creature) %> </span>

    <%= button_to t('.sacrifice'), @creature, method: :delete, class: 'btn-delete-creature' %> </div>
  26. Removendo dependências <div class="actions"> <span class="parting-message"> <%= goodbye_to(@creature) %> </span>

    <%= button_to t('.sacrifice'), @creature, method: :delete, class: 'btn-delete-creature' %> </div>
  27. Removendo dependências <div class="actions"> <span class="parting-message"> <%= goodbye_to(@creature) %> </span>

    <%= button_to t('.sacrifice'), @creature, method: :delete, class: 'btn-delete-creature' %> </div>
  28. Removendo dependências class Player < ApplicationRecord has_many :creatures, after_remove: :notify_parents

    def notify_parents(creature) NotifyParentsJob.perform_later(creature) end end
  29. Removendo dependências class Player < ApplicationRecord has_many :creatures, after_remove: :notify_parents

    def notify_parents(creature) NotifyParentsJob.perform_later(creature) end end
  30. Removendo dependências class Player < ApplicationRecord has_many :creatures, after_remove: :notify_parents

    def notify_parents(creature) NotifyParentsJob.perform_later(creature) end end
  31. Removendo dependências <div class="actions"> <span class="parting-message"> <%= goodbye_to(@creature) %> </span>

    <%= button_to t('.sacrifice'), @creature, method: :delete, class: 'btn-delete-creature' %> </div>
  32. Removendo dependências <div class="actions"> <span class="parting-message"> <%= goodbye_to(@creature) %> </span>

    <%= button_to t('.sacrifice'), @creature, method: :delete, class: 'btn-delete-creature' %> </div>
  33. Removendo dependências <div class="actions"> <span class="parting-message"> <%= goodbye_to(@creature) %> </span>

    <%= button_to t('.sacrifice'), @creature, method: :delete, class: 'btn-delete-creature' %> </div>
  34. Removendo dependências <div class="actions"> <span class="parting-message"> <%= goodbye_to(@creature) %> </span>

    <%= button_to t('.sacrifice'), @creature, method: :delete, class: 'btn-delete-creature' %> </div>
  35. Removendo dependências <div class="actions"> <span class="parting-message"> <%= goodbye_to(@creature) %> </span>

    <%= button_to t('.sacrifice'), @creature, method: :delete, class: 'btn-delete-creature' %> </div>
  36. Removendo dependências <div class="actions"> <span class="parting-message"> <%= goodbye_to(@creature) %> </span>

    <%= button_to t('.sacrifice'), @creature, method: :delete, class: 'btn-delete-creature' %> </div>
  37. Removendo dependências <div class="actions"> <span class="parting-message"> <%= goodbye_to(@creature) %> </span>

    <%= button_to t('.sacrifice'), @creature, method: :delete, class: 'btn-delete-creature' %> </div>
  38. Removendo dependências <div class="actions"> <span class="parting-message"> <%= goodbye_to(@creature) %> </span>

    <%= button_to t('.sacrifice'), @creature, method: :delete, class: 'btn-delete-creature' %> </div>
  39. Removendo dependências <div class="actions"> <span class="parting-message"> <%= goodbye_to(@creature) %> </span>

    <%= button_to t('.sacrifice'), @creature, method: :delete, class: 'btn-delete-creature' %> </div>
  40. Removendo dependências <div class="actions"> <span class="parting-message"> <%= goodbye_to(@creature) %> </span>

    <%= button_to t('.sacrifice'), @creature, method: :delete, class: 'btn-delete-creature' %> </div>
  41. Checklist das dependências • CSS, JavaScript, Imagens, assets em geral

    • Chaves de cache de longa expiração • Tarefas assíncronas • Gemfile • Arquivos de configuração, I18n • Documentação, README, etc. • Receitas de provisionamento • Banco de dados: migrações, tabelas, colunas, views, triggers, etc. • Testes: shared examples, helpers, etc.
  42. Fontes e referências • The Pink Panther in “Pink Outs”

    • https:/ /youtu.be/1q2hu-mDtKs • Jenga® • https:/ /en.wikipedia.org/wiki/Jenga • Information is beautiful - Codebases • http:/ /www.informationisbeautiful.net/visualizations/million-lines-of-code/ • Feature Creep • https:/ /twitter.com/wakeupmrkim/status/925427903352922114 • Grant Ammons - Killing features — just as important as building them • https:/ /medium.com/@gammons/killing-features-just-as-important-as-building- them-7f4d64223585
  43. Fontes e referências • Sandi MacPherson - Tough tradeoffs: Removing

    product features is hard, but often necessary • https:/ /thenextweb.com/dd/2015/01/18/tough-tradeoffs-removing-product-features- hard-often-necessary/ • Jeff Atwood - The Best Code is No Code At All • https:/ /blog.codinghorror.com/the-best-code-is-no-code-at-all/ • Edsger W. Dijkstra - EWD 1036 • https:/ /www.cs.utexas.edu/~EWD/transcriptions/EWD10xx/EWD1036.html • Mike Perham - Kill Your Dependencies • http:/ /www.mikeperham.com/2016/02/09/kill-your-dependencies/ • Thomas Figg - Write code that is easy to delete, not easy to extend. • https:/ /programmingisterrible.com/post/139222674273/write-code-that-is-easy-to- delete-not-easy-to
  44. Fontes e referências • Sandi Metz - Practical Object-Oriented Design

    in Ruby • http:/ /www.poodr.com/ • Maslow’s Trapezoid of Code Cleaniness • https:/ /twitter.com/KellySutton/status/847875703383117824 • https:/ /twitter.com/compooter/status/847881828224684032 • Refactoring code • https:/ /twitter.com/olarclara/status/928802983130927104 • Ned Batchelder - Deleting code • https:/ /nedbatchelder.com/text/deleting-code.html • Tree Shaking • http:/ /gph.is/2pPEHXx
  45. Fontes e referências • Rollup.js • https:/ /rollupjs.org/ • Unused

    • https:/ /unused.codes/ • Google Chrome Dev Tools Code Coverage Tab • https:/ /developers.google.com/web/updates/2017/04/devtools-release- notes#coverage • Programming skills • https:/ /twitter.com/stephentyrone/status/930825774818455553 • Imagens de arquivo pessoal