The DRY Principle has had a dramatic impact on the software development industry, however most software developers associate the DRY Principle with code duplication rather than duplicate knowledge.
In this talk we explore why the DRY Principle is related to domain driven design and how you can identify premature abstractions in your codebase.
9. # produce.rb
class Produce
def initialize(cost)
@cost = cost
end
def price
psychological_price(@cost * BigDecimal('100'))
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
PRODUCE
10. # dry_good.rb
class DryGood
def initialize(cost)
@cost = cost
end
def price
psychological_price(@cost * BigDecimal(‘200'))
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
DRY GOOD
11. # meat.rb
class Meat
def initialize(cost)
@cost = cost
end
def price
psychological_price(@cost * BigDecimal(‘300'))
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
MEAT
12. “DRY Principle is about removing
duplicate code
-Grocery App Developers
14. class Meat
def initialize(cost)
@cost = cost
end
def price
psychological_price(@cost * BigDecimal('300'))
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
class Produce
def initialize(cost)
@cost = cost
end
def price
psychological_price(@cost * BigDecimal('100'))
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
class DryGood
def initialize(cost)
@cost = cost
end
def price
psychological_price(@cost * BigDecimal('200'))
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
REMOVING CODE DUPLICATION
15. class Meat
def initialize(cost)
@cost = cost
end
def price
psychological_price(@cost * BigDecimal('300'))
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
class Produce
def initialize(cost)
@cost = cost
end
def price
psychological_price(@cost * BigDecimal('100'))
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
class DryGood
def initialize(cost)
@cost = cost
end
def price
psychological_price(@cost * BigDecimal('200'))
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
REMOVING CODE DUPLICATION
16. # priceable.rb
module Priceable
def price
psychological_price(@cost * @margin)
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
17. # priceable.rb
module Priceable
def price
psychological_price(@cost * @margin)
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
18. # produce.rb
class Produce
include Priceable
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
end
# meat.rb
class Meat
include Priceable
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
end
# dry_good.rb
class DryGood
include Priceable
def initialize(cost)
@cost = cost
@margin = BigDecimal('200')
end
end
19. # produce.rb
class Produce
include Priceable
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
end
# meat.rb
class Meat
include Priceable
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
end
# dry_good.rb
class DryGood
include Priceable
def initialize(cost)
@cost = cost
@margin = BigDecimal('200')
end
end
23. # priceable.rb
module Priceable
def price(season = nil)
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
46. BACKLOG
➤ Produce prices are based on season
➤ Meat prices are based on cut
➤ Produce prices are based on region
➤ Fish prices are based on rarity
➤ Produce prices end in “34”
47. BACKLOG
➤ Produce prices are based on season
➤ Meat prices are based on cut
➤ Produce prices are based on region
➤ Fish prices are based on rarity
➤ Produce prices end in “34”
57. # produce.rb
class Produce
include Priceable
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = 100.0
end
end
# meat.rb
class Meat
include Priceable
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = 300.0
end
end
# dry_good.rb
class DryGood
include Priceable
def initialize(cost)
@cost = cost
@margin = 200.0
end
end
SHOTGUN SURGERY
58. # produce.rb
class Produce
include Priceable
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = 100.0
end
end
# meat.rb
class Meat
include Priceable
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = 300.0
end
end
# dry_good.rb
class DryGood
include Priceable
def initialize(cost)
@cost = cost
@margin = 200.0
end
end
SHOTGUN SURGERY
59. # produce.rb
class Produce
include Priceable
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
end
# meat.rb
class Meat
include Priceable
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
end
# dry_good.rb
class DryGood
include Priceable
def initialize(cost)
@cost = cost
@margin = BigDecimal('200')
end
end
SHOTGUN SURGERY
60. # produce.rb
class Produce
include Priceable
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
end
# meat.rb
class Meat
include Priceable
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
end
# dry_good.rb
class DryGood
include Priceable
def initialize(cost)
@cost = cost
@margin = BigDecimal('200')
end
end
SHOTGUN SURGERY
62. # priceable.rb
module Priceable
def price
psychological_price(@cost * @margin)
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
DIVERGENT CHANGE
63. # priceable.rb
module Priceable
def price
psychological_price(@cost * @margin)
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
DIVERGENT CHANGE
Steak prices are based on cut
64. # priceable.rb
module Priceable
def price
total += psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
DIVERGENT CHANGE
Steak prices are based on cut
65. # priceable.rb
module Priceable
def price
total += psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
DIVERGENT CHANGE
66. # priceable.rb
module Priceable
def price
total += psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
DIVERGENT CHANGE
Produce prices are based on season
67. # priceable.rb
module Priceable
def price(season = nil)
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
DIVERGENT CHANGE
Produce prices are based on season
68. # priceable.rb
module Priceable
def price(season = nil)
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
DIVERGENT CHANGE
74. class Produce
include Priceable
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
end
75. class Produce
include Priceable
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
end
76. class Produce
include Priceable
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
end
77. class Produce
include Priceable
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
end
78. class Produce
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
def price(season = nil)
total = psychological_price(@price * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
79. class Produce
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
def price(season = nil)
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
80. class Produce
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
def price(season = nil)
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
81. class Produce
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
def price(season = nil)
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
82. class Produce
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
def price(season = nil)
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
83. class Produce
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
def price(season = nil)
total = psychological_price(@cost * @margin)
season != @growing_season ? total + 1 : total
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
87. class DryGood
def initialize(cost)
@cost = cost
@margin = BigDecimal('200')
end
def price(season = nil)
total = psychological_price(@price * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
88. class DryGood
def initialize(cost)
@cost = cost
@margin = BigDecimal('200')
end
def price(season = nil)
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
89. class DryGood
def initialize(cost)
@cost = cost
@margin = BigDecimal('200')
end
def price(season = nil)
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
90. class DryGood
def initialize(cost)
@cost = cost
@margin = BigDecimal('200')
end
def price(season = nil)
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
91. class DryGood
def initialize(cost)
@cost = cost
@margin = BigDecimal('200')
end
def price()
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
92. class DryGood
def initialize(cost)
@cost = cost
@margin = BigDecimal('200')
end
def price()
psychological_price(@cost * @margin)
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
93. class Meat
include Priceable
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
end
94. class Meat
include Priceable
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
end
95. class Meat
include Priceable
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
end
96. class Meat
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
def price(season = nil)
total = psychological_price(@price * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
97. class Meat
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
def price(season = nil)
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
98. class Meat
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
def price(season = nil)
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
99. class Meat
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
def price(season = nil)
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
100. class Meat
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
def price()
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
101. class Meat
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
def price()
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
102. module Priceable
def price(season = nil)
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
103.
104. module Priceable
def price(season = nil)
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
season != @growing_season ? total + 1 : total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
105. class Meat
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
def price()
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
class Produce
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
def price(season = nil)
total = psychological_price(@cost * @margin)
if season != @growing_season
total + 1
else
total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
class DryGood
def initialize(cost)
@cost = cost
@margin = BigDecimal('200')
end
def price()
psychological_price(@cost * @margin)
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
106. “So what is the correct abstraction?
- You (Maybe)
107. class Meat
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
def price()
total = psychological_price(@cost * @margin)
if @type == :steak && @cut == :flatiron
total + BigDecimal('5')
else
total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
class Produce
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
def price(season = nil)
total = psychological_price(@cost * @margin)
if season != @growing_season
total + 1
else
total
end
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
class DryGood
def initialize(cost)
@cost = cost
@margin = BigDecimal('200')
end
def price()
psychological_price(@cost * @margin)
end
private
def psychological_price(amount)
if amount.ceil == amount
(amount + BigDecimal('0.50')).ceil - BigDecimal('0.01')
else
(amount).ceil - BigDecimal('0.01')
end
end
end
108. BACKLOG
➤ Produce prices are based on season
➤ Meat prices are based on cut
➤ Produce prices are based on region
➤ Fish prices are based on rarity
➤ Produce prices end in “34”
109. BACKLOG
➤ Produce prices are based on season
➤ Meat prices are based on cut
➤ Produce prices are based on region
➤ Fish prices are based on rarity
➤ Produce prices end in “34”
111. ➤ DRY Principle is about duplicate knowledge
➤ Techniques to identify pre-mature abstractions
➤ Talk to product team
➤ Bits vs clumps
➤ Noticing Divergent Change
➤ Remove pre-mature abstractions
WHAT WE TALKED ABOUT