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

Down the Rabbit Hole: An Adventure in Legacy Code

Down the Rabbit Hole: An Adventure in Legacy Code

Legacy code is unpredictable & difficult to understand. Most of us will work with legacy code, so it’s important for us to understand its major pain points & their underlying causes. You’ ll come away from this talk with practical strategies to help you understand, improve, & even love legacy code.

Avatar for Loren Crawford

Loren Crawford

April 17, 2018
Tweet

Other Decks in Technology

Transcript

  1. Table of Contents 1. What’s up with legacy code? 2.

    Pain points a. Adding a Feature b. Fixing a Bug 3. Lessons Learned 4. Other recommendations
  2. Table of Contents 1. What’s up with legacy code? 2.

    Pain points a. Adding a Feature b. Fixing a Bug 3. Lessons Learned 4. Other recommendations
  3. Table of Contents 1. What’s up with legacy code? 2.

    Pain points a. Adding a Feature b. Fixing a Bug 3. Lessons Learned 4. Other recommendations
  4. Table of Contents 1. What’s up with legacy code? 2.

    Pain points a. Adding a Feature b. Fixing a Bug 3. Lessons Learned 4. Other recommendations
  5. Table of Contents 1. What’s up with legacy code? 2.

    Pain points a. Adding a Feature b. Fixing a Bug 3. Lessons Learned 4. Other recommendations
  6. Table of Contents 1. What’s up with legacy code? 2.

    Pain points a. Adding a Feature b. Fixing a Bug 3. Lessons Learned 4. Other recommendations
  7. Table of Contents 1. What’s up with legacy code? 2.

    Pain points a. Adding a Feature b. Fixing a Bug 3. Lessons Learned 4. Other recommendations
  8. “When someone makes fun of legacy code remember legacy is

    a funny way to spell successful. Your startup with perfect code with fail.” Dustin Shields-Cloues what’s up with legacy code?
  9. legacy code is a system of working software written by

    many developers over time that is often hard to change & contains business logic complexities that are not easily distilled from the code* * my working definition what’s up with legacy code?
  10. Users want to be able to search online sellers for

    Alpaca yarn. add a feature adding a feature
  11. where do I test the thing? - What class am

    I calling in the test? - What type of object am I using? - What is the expected behavior? adding a feature
  12. “it’s better to confront the beast than to hide from

    it.” Michael Feathers ⃟ Working Effectively with Legacy Code adding a feature
  13. Prove code works & your assumptions are correct. Uncover trivial

    bugs. Document how code actually works. adding a feature
  14. Prove code works & your assumptions are correct. Uncover trivial

    bugs. Document how code actually works. Help design better code. adding a feature
  15. Working Effectively with Legacy Code Michael Feathers Chapter 6 I

    Don’t Have Much Time and I Have to Change It adding a feature
  16. Users want to be able to search online sellers for

    Alpaca yarn. add a feature adding a feature Must also be fair trade & organic.
  17. class Yarn < ApplicationRecord ... def self.get_sellers(name, gauge=nil, color=nil, weight=nil)

    found_sellers = [] case name when "wool" if(gauge && !color && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "wool", gauge: gauge }) found_sellers << sellers elsif(color && !gauge && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "wool", color: color }) found_sellers << sellers elsif(weight && !gauge && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "wool", color: weight }) found_sellers << sellers elsif(gauge && color && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "wool", gauge: gauge, color:color }) found_sellers << sellers elsif(gauge && weight && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "wool", gauge: gauge, weight:weight }) found_sellers << sellers elsif (color && weight && !gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "wool", color: color, weight: weight }) found_sellers << sellers elsif (color && weight && gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "wool", gauge: gauge, color: color, weight: weight }) found_sellers << sellers else sellers = Seller.joins(:yarn).where(yarns: {name: "wool"}) found_sellers << sellers end found_sellers.flatten! preferred_sellers = [] mid_sellers = [] found_sellers.each do |seller| if(seller.is_in_good_standing?) if(seller.is_organic? && seller.is_fair_trade?) preferred_sellers << seller elsif (seller.is_organic? && !seller.is_fair_trade?) mid_sellers << seller end end end if preferred_sellers.count > mid_sellers.count return preferred_sellers + mid_sellers elsif return found_sellers end adding a feature Don’t try to read this
  18. when "cotton" ... when "silk" ... when "mohair" ... when

    "cashmere" ... when "synthetic" ... when "angora" ... else ... adding a feature
  19. class Yarn < ApplicationRecord ... def self.get_sellers(name, gauge=nil, color=nil, weight=nil)

    found_sellers = [] case name when "wool" ... found_sellers.each do |seller| if(seller.is_in_good_standing?) if(seller.is_organic? && seller.is_fair_trade?) preferred_sellers << seller elsif (seller.is_organic? && !seller.is_fair_trade?) mid_sellers << seller end end end if preferred_sellers.count > mid_sellers.count return preferred_sellers + mid_sellers else return found_sellers end adding a feature
  20. class Yarn < ApplicationRecord ... def self.get_sellers(name, gauge=nil, color=nil, weight=nil)

    found_sellers = [] case name when "wool" ... found_sellers.each do |seller| if(seller.is_in_good_standing?) if(seller.is_organic? && seller.is_fair_trade?) preferred_sellers << seller elsif (seller.is_organic? && !seller.is_fair_trade?) mid_sellers << seller end end end if preferred_sellers.count > mid_sellers.count return preferred_sellers + mid_sellers else return found_sellers end adding a feature
  21. class Yarn < ApplicationRecord ... def self.get_sellers(name, gauge=nil, color=nil, weight=nil)

    found_sellers = [] case name when "wool" ... found_sellers.each do |seller| if(seller.is_in_good_standing?) if(seller.is_organic? && seller.is_fair_trade?) preferred_sellers << seller elsif (seller.is_organic? && !seller.is_fair_trade?) mid_sellers << seller end end end if preferred_sellers.count > mid_sellers.count return preferred_sellers + mid_sellers else return found_sellers end adding a feature
  22. class Yarn < ApplicationRecord ... def self.get_sellers(name, gauge=nil, color=nil, weight=nil)

    found_sellers = [] case name when "wool" ... found_sellers.each do |seller| if(seller.is_in_good_standing?) if(seller.is_organic? && seller.is_fair_trade?) preferred_sellers << seller elsif (seller.is_organic? && !seller.is_fair_trade?) mid_sellers << seller end end end if preferred_sellers.count > mid_sellers.count return preferred_sellers + mid_sellers else return found_sellers end adding a feature
  23. class Yarn < ApplicationRecord ... def self.get_sellers(name, gauge=nil, color=nil, weight=nil)

    found_sellers = [] case name when "wool" ... found_sellers.each do |seller| if(seller.is_in_good_standing?) if(seller.is_organic? && seller.is_fair_trade?) preferred_sellers << seller elsif (seller.is_organic? && !seller.is_fair_trade?) mid_sellers << seller end end end if preferred_sellers.count > mid_sellers.count return preferred_sellers + mid_sellers else return found_sellers end adding a feature
  24. class Yarn < ApplicationRecord ... def self.get_sellers(name, gauge=nil, color=nil, weight=nil)

    found_sellers = [] case name when "wool" ... found_sellers.each do |seller| if(seller.is_in_good_standing?) if(seller.is_organic? && seller.is_fair_trade?) preferred_sellers << seller elsif (seller.is_organic? && !seller.is_fair_trade?) mid_sellers << seller end end end if preferred_sellers.count > mid_sellers.count return preferred_sellers + mid_sellers else return found_sellers end adding a feature
  25. class Yarn < ApplicationRecord ... def self.get_sellers(name, gauge=nil, color=nil, weight=nil)

    found_sellers = [] case name when "wool" ... found_sellers.each do |seller| if(seller.is_in_good_standing?) if(seller.is_organic? && seller.is_fair_trade?) preferred_sellers << seller elsif (seller.is_organic? && !seller.is_fair_trade?) mid_sellers << seller end end end if preferred_sellers.count > mid_sellers.count return preferred_sellers + mid_sellers else return found_sellers end adding a feature
  26. class Yarn < ApplicationRecord ... def self.get_sellers(name, gauge=nil, color=nil, weight=nil)

    found_sellers = [] case name when "wool" ... found_sellers.each do |seller| if(seller.is_in_good_standing?) if(seller.is_organic? && seller.is_fair_trade?) preferred_sellers << seller elsif (seller.is_organic? && !seller.is_fair_trade?) mid_sellers << seller end end end if preferred_sellers.count > mid_sellers.count return preferred_sellers + mid_sellers else return found_sellers end adding a feature
  27. RSpec.describe Yarn, "#get_seller" do context "when you pass in wool

    as yarn_name" do it "returns one found seller" do ... end end end adding a feature Test
  28. it "returns one found seller" do seller = Seller.create(name: "Get

    Stitching", is_organic: true) ... end adding a feature Test
  29. it "returns one found seller" do seller = Seller.create(name: "Get

    Stitching", is_organic: true, is_fair_trade: true) ... end adding a feature Test
  30. it "returns one found seller" do seller = Seller.create(name: "Get

    Stitching", is_organic: true, is_fair_trade: true, in_good_standing: true) ... end adding a feature Test
  31. it "returns one found seller" do seller = Seller.create(name: "Get

    Stitching", is_organic: true, is_fair_trade: true, in_good_standing: true) yarn = Yarn.create(name: "wool", seller: seller) ... end adding a feature Test
  32. it "returns one found seller" do seller = Seller.create(name: "Get

    Stitching", is_organic: true, is_fair_trade: true, in_good_standing: true) yarn = Yarn.create(name: "wool", seller: seller, is_organic:true) ... end adding a feature Test
  33. it "returns one found seller" do seller = Seller.create(name: "Get

    Stitching", is_organic: true, is_fair_trade: true, in_good_standing: true) yarn = Yarn.create(name: "wool", seller: seller, is_organic:true, is_fair_trade: true) ... end adding a feature Test
  34. it "returns two found sellers" do ... found_sellers = Yarn.get_sellers("wool")

    expect(found_sellers.count).to eq 1 expect(found_sellers.first).to eq(seller) end adding a feature Test
  35. class Yarn < ApplicationRecord ... def self.get_sellers(name, gauge=nil, color=nil, weight=nil)

    found_sellers = [] case name when "wool" ... found_sellers.each do |seller| if(seller.is_in_good_standing?) if(seller.is_organic? && seller.is_fair_trade?) preferred_sellers << seller elsif (seller.is_organic? && !seller.is_fair_trade?) mid_sellers << seller end end end if preferred_sellers.count > mid_sellers.count return preferred_sellers + mid_sellers else return found_sellers end adding a feature
  36. class Yarn < ApplicationRecord ... def self.get_sellers(name, gauge=nil, color=nil, weight=nil)

    found_sellers = [] case name when "wool" ... found_sellers.each do |seller| if(seller.is_in_good_standing?) if(seller.is_organic? && seller.is_fair_trade?) preferred_sellers << seller elsif (seller.is_organic? && !seller.is_fair_trade?) mid_sellers << seller end end end if preferred_sellers.count > mid_sellers.count return preferred_sellers + mid_sellers else return found_sellers end adding a feature
  37. class Yarn < ApplicationRecord ... def self.get_sellers(name, gauge=nil, color=nil, weight=nil)

    found_sellers = [] case name when "wool" ... found_sellers.each do |seller| if(seller.is_in_good_standing?) if(seller.is_organic? && seller.is_fair_trade?) preferred_sellers << seller elsif (seller.is_organic? && !seller.is_fair_trade?) mid_sellers << seller end end end if preferred_sellers.count > mid_sellers.count return preferred_sellers + mid_sellers else return found_sellers end adding a feature
  38. context "when you have more preferred sellers than mid_sellers" do

    it "returns an array with preferred sellers before mid_sellers" do ... end end adding a feature Test
  39. context "when you have more preferred sellers than mid_sellers" do

    it "returns an array with preferred sellers and mid_sellers" do preferred_seller_1 = Seller.create(name: "Preferred seller 1", is_organic: true, is_fair_trade: true) preferred_seller_2 = Seller.create(name: "Preferred seller 2", is_organic: true, is_fair_trade: true) mid_seller = Seller.create(name: "mid seller", is_organic: true, is_fair_trade: false) end end adding a feature Test
  40. context "when you have more preferred sellers than mid_sellers" do

    it "returns an array with preferred sellers and mid_sellers" do preferred_seller_1 = Seller.create(name: "Preferred seller 1", is_organic: true, is_fair_trade: true) preferred_seller_2 = Seller.create(name: "Preferred seller 2", is_organic: true, is_fair_trade: true) mid_seller = Seller.create(name: "mid seller", is_organic: true, is_fair_trade: false) end end adding a feature Test
  41. it "returns an array with preferred sellers and mid_sellers" do

    preferred_seller_1 = Seller.create(name: "Preferred seller 1", is_organic: true, is_fair_trade: true) preferred_seller_2 = Seller.create(name: "Preferred seller 2", is_organic: true, is_fair_trade: true) mid_seller = Seller.create(name: "mid seller", is_organic: true, is_fair_trade: false) end end adding a feature Test
  42. context "when you have more preferred sellers than mid_sellers" do

    it "returns an array with preferred sellers and mid_sellers" do preferred_seller_1 = ... preferred_seller_2 = ... mid_seller = ... Yarn.create(name: "wool", seller: preferred_seller_1, ...) Yarn.create(name: "wool", seller: preferred_seller_2, ...) Yarn.create(name: "wool", seller: mid_seller, ...) end end adding a feature Test
  43. context "when you have more preferred sellers than mid_sellers" do

    it "returns an array with preferred sellers and mid_sellers" do // setup found_sellers = Yarn.get_sellers("wool") end end adding a feature Test
  44. context "when you have more preferred sellers than mid_sellers" do

    it "returns an array with preferred sellers and mid_sellers" do // setup found_sellers = Yarn.get_sellers("wool") expect(found_sellers.count).to eq 3 expect(found_sellers.last).to eq(mid_seller) end end adding a feature Test
  45. “Whenever I do a refactoring, the first step is always

    the same. I need to build a solid set of tests for that section of code. The tests are essential because even though I following refactorings structured to avoid most of the opportunities for introducing bugs, I’m still human and still make mistakes.” Martin Fowler Refactoring: Improving the Design of Existing Code
  46. Users want to be able to search online sellers for

    Alpaca yarn. add a feature adding a feature
  47. context "when you pass in alpaca as yarn_name" do it

    "returns sellers with only yarn that is fair trade and organic" do end end add a feature adding a feature Test
  48. context "when you pass in alpaca as yarn_name" do it

    "returns sellers with only yarn that is fair trade and organic" do seller = Seller.create(name: "Alpaca good seller", is_organic: true, is_fair_trade: true) not_included_seller = Seller.create(name: "Alpaca bad seller", is_organic: false, is_fair_trade: false) end end add a feature adding a feature Test
  49. context "when you pass in alpaca as yarn_name" do it

    "returns sellers with only yarn that is fair trade and organic" do seller = Seller.create(name: "Alpaca good seller", is_organic: true, is_fair_trade: true) not_included_seller = Seller.create(name: "Alpaca bad seller", is_organic: false, is_fair_trade: false) end end adding a feature Test
  50. context "when you pass in alpaca as yarn_name" do it

    "returns sellers with only yarn that is fair trade and organic" do seller = Seller.create(...) not_included_seller = Seller.create(...) Yarn.create(name: "alpaca", seller: seller, ...) Yarn.create(name: "alpaca", seller: not_included_seller, ...) end end add a feature adding a feature Test
  51. context "when you pass in alpaca as yarn_name" do it

    "returns sellers with only yarn that is fair trade and organic" do // setup found_sellers = Yarn.get_sellers("alpaca") end end add a feature adding a feature Test
  52. context "when you pass in alpaca as yarn_name" do it

    "returns sellers with only yarn that is fair trade and organic" do // setup found_sellers = Yarn.get_sellers("alpaca") expect(found_sellers.count).to eq 1 expect(found_sellers.first).to eq(seller) end end add a feature adding a feature Test
  53. when "alpaca" sellers = Seller.joins(:yarn).where(yarns: {name: "alpaca"}) found_sellers = []

    sellers.each do |seller| ... end add a feature adding a feature
  54. when "alpaca" sellers = Seller.joins(:yarn).where(yarns: {name: "alpaca"}) found_sellers = []

    sellers.each do |seller| if(seller.is_organic? && seller.is_fair_trade?) ... end end add a feature adding a feature
  55. when "alpaca" sellers = Seller.joins(:yarn).where(yarns: {name: "alpaca"}) found_sellers = []

    sellers.each do |seller| if(seller.is_organic? && seller.is_fair_trade?) found_sellers << seller end end return found_sellers add a feature adding a feature
  56. when "alpaca" sellers = Seller.joins(:yarn).where(yarns: {name: "alpaca"}) found_sellers = []

    sellers.each do |seller| if(seller.is_organic? && seller.is_fair_trade?) found_sellers << seller end end return found_sellers add a feature adding a feature
  57. class Yarn < ApplicationRecord ... def self.get_sellers(name, gauge=nil, color=nil, weight=nil)

    found_sellers = [] case name when "wool" if(gauge && !color && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "wool", gauge: gauge }) found_sellers << sellers elsif(color && !gauge && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "wool", color: color }) found_sellers << sellers elsif(weight && !gauge && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "wool", color: weight }) found_sellers << sellers elsif(gauge && color && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "wool", gauge: gauge, color:color }) found_sellers << sellers elsif(gauge && weight && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "wool", gauge: gauge, weight:weight }) found_sellers << sellers elsif (color && weight && !gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "wool", color: color, weight: weight }) found_sellers << sellers elsif (color && weight && gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "wool", gauge: gauge, color: color, weight: weight }) found_sellers << sellers else sellers = Seller.joins(:yarn).where(yarns: {name: "wool"}) found_sellers << sellers end found_sellers.flatten! preferred_sellers = [] mid_sellers = [] found_sellers.each do |seller| if(seller.is_in_good_standing?) if(seller.is_organic? && seller.is_fair_trade?) preferred_sellers << seller elsif (seller.is_organic? && !seller.is_fair_trade?) mid_sellers << seller end end end if preferred_sellers.count > mid_sellers.count return preferred_sellers + mid_sellers elsif return found_sellers end adding a feature Don’t try to read this
  58. class Yarn def self.get_sellers(name, gauge=nil, color=nil, weight=nil) found_sellers = []

    case name when "wool" ... when "cashmere" ... when "cotton" ... when "alpaca" ... when "silk" ... when "synthetic" ... Good opportunity to replace conditional with polymorphism adding a feature
  59. class Yarn def self.get_sellers(name, gauge=nil, color=nil, weight=nil) found_sellers = []

    case name when "wool" ... when "cashmere" ... when "cotton" ... when "alpaca" ... when "silk" ... when "synthetic" ... Good opportunity to replace conditional with subclasses adding a feature
  60. Table of Contents 1. What’s up with legacy code? 2.

    Pain points a. Adding a Feature b. Fixing a Bug 3. Lessons Learned 4. Other recommendations
  61. Table of Contents 1. What’s up with legacy code? 2.

    Pain points a. Adding a Feature b. Fixing a Bug 3. Lessons Learned 4. Other recommendations
  62. Table of Contents 1. What’s up with legacy code? 2.

    Pain points a. Adding a Feature b. Fixing a Bug 3. Lessons Learned 4. Other recommendations
  63. context "when you pass in silk as yarn_name" do it

    "returns sellers with silk and silk blend yarns" do ... end end fixing a bug Test
  64. context "when you pass in silk as yarn_name" do it

    "returns sellers with silk and silk blend yarns" do seller = Seller.create(name: "Silk seller", is_organic: true) silk_blend_seller = Seller.create(name: "Silk blend seller", is_organic: true,) end end fixing a bug Test
  65. context "when you pass in silk as yarn_name" do it

    "returns sellers with silk and silk blend yarns" do seller = ... silk_blend_seller = ... Yarn.create(name: "silk", seller: seller, is_organic:true, ..) Yarn.create(name: "silk-blend", seller: silk_blend_seller, is_organic:true,...) end end fixing a bug Test
  66. context "when you pass in silk as yarn_name" do it

    "returns sellers with silk and silk blend yarns" do seller = ... silk_blend_seller = ... Yarn.create(name: "silk", seller: seller, is_organic:true, ..) Yarn.create(name: "silk-blend", seller: silk_blend_seller, is_organic:true,...) end end fixing a bug Test
  67. context "when you pass in silk as yarn_name" do it

    "returns sellers with silk and silk blend yarns" do //setup found_sellers = Yarn.get_sellers("silk") end end fixing a bug Test
  68. context "when you pass in silk as yarn_name" do it

    "returns sellers with silk and silk blend yarns" do //setup found_sellers = Yarn.get_sellers("silk") expect(found_sellers.count).to eq 2 expect(found_sellers).to include(silk_blend_seller) end end fixing a bug Test
  69. Yarn#get_seller when you pass in silk as yarn_name returns sellers

    with silk and silk blend yarns Failure/Error: expect(found_sellers.count).to eq 2 expected: 2 got: 1 (compared using ==) add a feature fixing a bug
  70. when "silk" if(gauge && !color && !weight) sellers = Seller.joins(:yarn).where(yarns:

    { name: "silk", gauge: gauge }) found_sellers << sellers elsif(color && !gauge && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color }) found_sellers << sellers elsif(weight && !gauge && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: weight }) found_sellers << sellers elsif(gauge && color && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color:color }) found_sellers << sellers elsif(gauge && weight && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, weight:weight }) found_sellers << sellers elsif (color && weight && !gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color, weight: weight }) found_sellers << sellers elsif (color && weight && gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color: color, weight: weight }) found_sellers << sellers else sellers = Seller.joins(:yarn).where(yarns: {name: ["silk", "silk-blend"]}) found_sellers << sellers end fixing a bug
  71. when "silk" if(gauge && !color && !weight) sellers = Seller.joins(:yarn).where(yarns:

    { name: "silk", gauge: gauge }) found_sellers << sellers elsif(color && !gauge && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color }) found_sellers << sellers elsif(weight && !gauge && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: weight }) found_sellers << sellers elsif(gauge && color && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color:color }) found_sellers << sellers elsif(gauge && weight && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, weight:weight }) found_sellers << sellers elsif (color && weight && !gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color, weight: weight }) found_sellers << sellers elsif (color && weight && gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color: color, weight: weight }) found_sellers << sellers else sellers = Seller.joins(:yarn).where(yarns: {name: ["silk", "silk-blend"]}) found_sellers << sellers end fixing a bug
  72. when "silk" if(gauge && !color && !weight) sellers = Seller.joins(:yarn).where(yarns:

    { name: "silk", gauge: gauge }) found_sellers << sellers elsif(color && !gauge && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color }) found_sellers << sellers elsif(weight && !gauge && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: weight }) found_sellers << sellers elsif(gauge && color && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color:color }) found_sellers << sellers elsif(gauge && weight && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, weight:weight }) found_sellers << sellers elsif (color && weight && !gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color, weight: weight }) found_sellers << sellers elsif (color && weight && gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color: color, weight: weight }) found_sellers << sellers else sellers = Seller.joins(:yarn).where(yarns: {name: ["silk", "silk-blend"]}) found_sellers << sellers end fixing a bug
  73. when "silk" if(gauge && !color && !weight) sellers = Seller.joins(:yarn).where(yarns:

    { name: "silk", gauge: gauge }) found_sellers << sellers elsif(color && !gauge && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color }) found_sellers << sellers elsif(weight && !gauge && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: weight }) found_sellers << sellers elsif(gauge && color && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color:color }) found_sellers << sellers elsif(gauge && weight && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, weight:weight }) found_sellers << sellers elsif (color && weight && !gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color, weight: weight }) found_sellers << sellers elsif (color && weight && gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color: color, weight: weight }) found_sellers << sellers else sellers = Seller.joins(:yarn).where(yarns: {name: ["silk", "silk-blend"]}) found_sellers << sellers end fixing a bug
  74. when "silk" if(gauge && !color && !weight) sellers = Seller.joins(:yarn).where(yarns:

    { name: "silk", gauge: gauge }) found_sellers << sellers elsif(color && !gauge && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color }) found_sellers << sellers elsif(weight && !gauge && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: weight }) found_sellers << sellers elsif(gauge && color && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color:color }) found_sellers << sellers elsif(gauge && weight && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, weight:weight }) found_sellers << sellers elsif (color && weight && !gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color, weight: weight }) found_sellers << sellers elsif (color && weight && gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color: color, weight: weight }) found_sellers << sellers else sellers = Seller.joins(:yarn).where(yarns: {name: ["silk", "silk-blend"]}) found_sellers << sellers end fixing a bug
  75. when "silk" if(gauge && !color && !weight) sellers = Seller.joins(:yarn).where(yarns:

    { name: "silk", gauge: gauge }) found_sellers << sellers elsif(color && !gauge && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color }) found_sellers << sellers elsif(weight && !gauge && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: weight }) found_sellers << sellers elsif(gauge && color && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color:color }) found_sellers << sellers elsif(gauge && weight && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, weight:weight }) found_sellers << sellers elsif (color && weight && !gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color, weight: weight }) found_sellers << sellers elsif (color && weight && gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color: color, weight: weight }) found_sellers << sellers else sellers = Seller.joins(:yarn).where(yarns: {name: ["silk", "silk-blend"]}) found_sellers << sellers end fixing a bug
  76. when "silk" if(gauge && !color && !weight) sellers = Seller.joins(:yarn).where(yarns:

    { name: "silk", gauge: gauge }) found_sellers << sellers elsif(color && !gauge && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color }) found_sellers << sellers elsif(weight && !gauge && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: weight }) found_sellers << sellers elsif(gauge && color && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color:color }) found_sellers << sellers elsif(gauge && weight && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, weight:weight }) found_sellers << sellers elsif (color && weight && !gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color, weight: weight }) found_sellers << sellers elsif (color && weight && gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color: color, weight: weight }) found_sellers << sellers else sellers = Seller.joins(:yarn).where(yarns: {name: ["silk", "silk-blend"]}) found_sellers << sellers end fixing a bug
  77. when "silk" if(gauge && !color && !weight) sellers = Seller.joins(:yarn).where(yarns:

    { name: "silk", gauge: gauge }) found_sellers << sellers elsif(color && !gauge && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color }) found_sellers << sellers elsif(weight && !gauge && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: weight }) found_sellers << sellers elsif(gauge && color && !weight) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color:color }) found_sellers << sellers elsif(gauge && weight && !color) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, weight:weight }) found_sellers << sellers elsif (color && weight && !gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", color: color, weight: weight }) found_sellers << sellers elsif (color && weight && gauge) sellers = Seller.joins(:yarn).where(yarns: { name: "silk", gauge: gauge, color: color, weight: weight }) found_sellers << sellers else sellers = Seller.joins(:yarn).where(yarns: {name: ["silk", "silk-blend"]}) found_sellers << sellers end fixing a bug
  78. when "silk" if(gauge && !color && !weight) sellers = Seller.joins(:yarn).where(yarns:

    { name: "silk", gauge: gauge }) found_sellers << sellers ... fixing a bug
  79. context "when you pass in silk as yarn_name" do it

    "returns sellers with silk and silk blend yarns" do seller = ... silk_blend_seller = ... Yarn.create(name: "silk", seller: seller, is_organic:true, gauge: 6, ...) Yarn.create(name: "silk-blend", seller: silk_blend_seller, is_organic:true, gauge: 6, ...) end end fixing a bug Test
  80. context "when you pass in silk as yarn_name" do it

    "returns sellers with silk and silk blend yarns" do //setup found_sellers = Yarn.get_sellers("silk", 6) expect(found_sellers.count).to eq 2 expect(found_sellers).to include(silk_blend_seller) end end fixing a bug Test
  81. Yarn#get_seller when you pass in silk as yarn_name returns sellers

    with silk and silk blend yarns Failure/Error: expect(found_sellers.count).to eq 2 expected: 2 got: 1 (compared using ==) add a feature fixing a bug
  82. when "silk" ... sellers = Seller.joins(:yarn).where(yarns: { name: ["silk", "silk-blend"],

    gauge: gauge }) found_sellers << sellers end fixing a bug
  83. Table of Contents 1. What’s up with legacy code? 2.

    Pain points a. Adding a Feature b. Fixing a Bug 3. Lessons Learned 4. Other recommendations
  84. lessons learned add tests when you touch code that is

    currently untested. BONUS: THIS WILL HELP YOU LEARN QUICKLY THINGS ABOUT HOW YOUR APP WORKS
  85. other recommendations Refactoring: Improving the Design of Existing Code Martin

    Fowler Working Effectively With Legacy Code Michael C. Feathers Object Oriented Design In Ruby Sandi Metz Apprenticeship Patterns Adewale Oshineye and Dave Hoover A Common Taxonomy of Bugs and How to Catch Them Kylie Stradley Get a Whiff of This Sandi Metz https://sourcemaking.com/refactoring/smells/