SlideShare a Scribd company logo
1 of 104
Download to read offline
THE DRY PRINCIPLE
IS MISUNDERSTOOD
Steven Solomon
Senior Software Engineer
Twitter: @ssolo112
Medium: @ssolomon
DRY
PRINCIPLE
By Annie Spratt on Unsplash
GROCERY APPLICATION
Dry Goods
Produce Meats
WHAT IS IN THE APPLICATION?
Dry Goods
Produce Meats
Margin: 300%
Margin: 200%
Margin: 100%
PRICING GROCERIES
# 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
# 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
# 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
“DRY Principle is about removing
duplicate code
-Grocery App Developers
By Annie Spratt on Unsplash
GROCERY APPLICATION
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
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
# 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
# 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
# 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
# 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
Djim Loic on Unsplash
Ricardo Viana on Unsplash
# 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
WHY DID THIS HAPPEN?
THE DRY PRINCIPLE
IS NOT ABOUT
DUPLICATE CODE
WHAT IS THE
DRY PRINCIPLE
REALLY ABOUT?
“Every piece of knowledge must have a
single, unambiguous, authoritative
representation within a system
-Dave Thomas & Andy Hunt
TECHNIQUES
TALKING TO
THE
PRODUCT
TEAM
BALANCED TEAM
Product Design
Software
BALANCED TEAM LANGUAGE
Business User
Technical
Balanced Language
BALANCED TEAM LANGUAGE
Business User
Technical
Balanced Language
Mark Rabe - Unsplash
Meat
Produce
Priceable
:price
DryGood
Meat
Produce
Priceable
:price
DryGood
???
Meat
Produce
Priceable
:price
DryGood
Meat
Produce
Priceable
:price
DryGood
Meat
Produce
:price DryGood
:price
:price
Business
User
Technical
BALANCED TEAM LANGUAGE
Business
User
Technical
DryGood
Produce
Meat
BALANCED TEAM LANGUAGE
Priceable
Business
User
Technical
DryGood
Produce
Meat
Priceable
BALANCED TEAM LANGUAGE
Business
User
Technical
DryGood
Produce
Meat
BALANCED TEAM LANGUAGE
Business
User
Technical
DryGood
Produce
Meat
BALANCED TEAM LANGUAGE
TALKING TO
THE
PRODUCT
TEAM
BITS
VS
CLUMPS
https://www.facebook.com/notes/kent-
beck/bits-clumps-and-just-right/
792597974106402
DryGood Produce
CAN I REASON ABOUT THESE SEPARATELY?
:price:price
DryGood Produce
CAN I REASON ABOUT THESE SEPARATELY?
:price:price
Yes
ARE THEY SEPARATE?
Produce
Priceable
:price
DryGood
ARE THEY SEPARATE?
Produce
Priceable
:price
DryGood
No
ARE THEY SEPARATE?
Produce
Priceable
:price
DryGood
ARE THEY SEPARATE?
Produce
Priceable
:price
DryGood
Priceable
:price
ARE THEY SEPARATE?
Produce
:price
DryGood
:price
BITS
VS
CLUMPS
NOTICING
DIVERGENT
CHANGE
SHOTGUN SURGERY
# 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
# 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
# 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
# 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
DIVERGENT CHANGE
# 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
# 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
# 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
# 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
# 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
# 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
# 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
Too
m
uch
duplication
N
ot
enough
separation
Too
m
uch
duplication
N
ot
enough
separation
Shotgun
Surgery
Divergent
Change
NOTICING
DIVERGENT
CHANGE
GETTING
BACK TO
SAFETY
class Produce
include Priceable
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
end
class Produce
include Priceable
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
end
class Produce
include Priceable
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
end
end
class Produce
include Priceable
def initialize(cost, growing_season)
@cost = cost
@growing_season = growing_season
@margin = BigDecimal('100')
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(@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
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
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
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
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
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
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 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
include Priceable
def initialize(cost)
@cost = cost
@margin = BigDecimal('200')
end
end
class DryGood
include Priceable
def initialize(cost)
@cost = cost
@margin = BigDecimal('200')
end
end
class DryGood
include Priceable
def initialize(cost)
@cost = cost
@margin = BigDecimal('200')
end
end
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
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
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
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
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
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
class Meat
include Priceable
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
end
class Meat
include Priceable
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
end
class Meat
include Priceable
def initialize(cost, type, cut)
@cost = cost
@type = type
@cut = cut
@margin = BigDecimal('300')
end
end
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
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
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
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
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
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 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
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(season = nil)
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
“So what is the correct abstraction?
- You (Maybe)
➤ 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
THANKS
I’m writing a book.
It is a software
book with a story
leanpub.com/agilesoftware
QUESTIONS
Steven Solomon
Senior Software Engineer
Twitter: @ssolo112
Medium: @ssolomon
leanpub.com/agilesoftware

More Related Content

Recently uploaded

SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 

Recently uploaded (20)

SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Exploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the ProcessExploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the Process
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 

Featured

PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Applitools
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at WorkGetSmarter
 
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...DevGAMM Conference
 
Barbie - Brand Strategy Presentation
Barbie - Brand Strategy PresentationBarbie - Brand Strategy Presentation
Barbie - Brand Strategy PresentationErica Santiago
 

Featured (20)

PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work
 
ChatGPT webinar slides
ChatGPT webinar slidesChatGPT webinar slides
ChatGPT webinar slides
 
More than Just Lines on a Map: Best Practices for U.S Bike Routes
More than Just Lines on a Map: Best Practices for U.S Bike RoutesMore than Just Lines on a Map: Best Practices for U.S Bike Routes
More than Just Lines on a Map: Best Practices for U.S Bike Routes
 
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
 
Barbie - Brand Strategy Presentation
Barbie - Brand Strategy PresentationBarbie - Brand Strategy Presentation
Barbie - Brand Strategy Presentation
 

Dry Principle Is Misunderstood

  • 1. THE DRY PRINCIPLE IS MISUNDERSTOOD
  • 2. Steven Solomon Senior Software Engineer Twitter: @ssolo112 Medium: @ssolomon
  • 4. By Annie Spratt on Unsplash GROCERY APPLICATION
  • 5. Dry Goods Produce Meats WHAT IS IN THE APPLICATION?
  • 6. Dry Goods Produce Meats Margin: 300% Margin: 200% Margin: 100% PRICING GROCERIES
  • 7. # 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
  • 8. # 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
  • 9. # 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
  • 10. “DRY Principle is about removing duplicate code -Grocery App Developers
  • 11. By Annie Spratt on Unsplash GROCERY APPLICATION
  • 12. 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
  • 13. 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
  • 14. # 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
  • 15. # 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
  • 16. # 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
  • 17. # 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
  • 18. Djim Loic on Unsplash
  • 19. Ricardo Viana on Unsplash
  • 20. # 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
  • 21. WHY DID THIS HAPPEN?
  • 22. THE DRY PRINCIPLE IS NOT ABOUT DUPLICATE CODE
  • 23. WHAT IS THE DRY PRINCIPLE REALLY ABOUT?
  • 24. “Every piece of knowledge must have a single, unambiguous, authoritative representation within a system -Dave Thomas & Andy Hunt
  • 28. BALANCED TEAM LANGUAGE Business User Technical Balanced Language
  • 29. BALANCED TEAM LANGUAGE Business User Technical Balanced Language
  • 30. Mark Rabe - Unsplash
  • 43. DryGood Produce CAN I REASON ABOUT THESE SEPARATELY? :price:price
  • 44. DryGood Produce CAN I REASON ABOUT THESE SEPARATELY? :price:price Yes
  • 53. # 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
  • 54. # 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
  • 55. # 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
  • 56. # 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
  • 58. # 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
  • 59. # 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
  • 60. # 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
  • 61. # 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
  • 62. # 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
  • 63. # 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
  • 64. # 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
  • 69. class Produce include Priceable def initialize(cost, growing_season) @cost = cost @growing_season = growing_season @margin = BigDecimal('100') end end
  • 70. class Produce include Priceable def initialize(cost, growing_season) @cost = cost @growing_season = growing_season @margin = BigDecimal('100') end end
  • 71. class Produce include Priceable def initialize(cost, growing_season) @cost = cost @growing_season = growing_season @margin = BigDecimal('100') end end
  • 72. class Produce include Priceable def initialize(cost, growing_season) @cost = cost @growing_season = growing_season @margin = BigDecimal('100') end end
  • 73. 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
  • 74. 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
  • 75. 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
  • 76. 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
  • 77. 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
  • 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(@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
  • 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 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
  • 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 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
  • 81. class DryGood include Priceable def initialize(cost) @cost = cost @margin = BigDecimal('200') end end
  • 82. class DryGood include Priceable def initialize(cost) @cost = cost @margin = BigDecimal('200') end end
  • 83. class DryGood include Priceable def initialize(cost) @cost = cost @margin = BigDecimal('200') end end
  • 84. 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
  • 85. 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
  • 86. 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
  • 87. 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
  • 88. 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
  • 89. 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
  • 90. class Meat include Priceable def initialize(cost, type, cut) @cost = cost @type = type @cut = cut @margin = BigDecimal('300') end end
  • 91. class Meat include Priceable def initialize(cost, type, cut) @cost = cost @type = type @cut = cut @margin = BigDecimal('300') end end
  • 92. class Meat include Priceable def initialize(cost, type, cut) @cost = cost @type = type @cut = cut @margin = BigDecimal('300') end end
  • 93. 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
  • 94. 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
  • 95. 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
  • 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(@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
  • 97. 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
  • 98. 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
  • 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 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(season = nil) 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
  • 100. “So what is the correct abstraction? - You (Maybe)
  • 101. ➤ 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
  • 102. THANKS
  • 103. I’m writing a book. It is a software book with a story leanpub.com/agilesoftware
  • 104. QUESTIONS Steven Solomon Senior Software Engineer Twitter: @ssolo112 Medium: @ssolomon leanpub.com/agilesoftware