Refactor like a boss with Sandi Metz
This post is inspired by:
RailsConf 2014 - All the Little Things by Sandi Metz
The code is on my GitHub: GildedRose Kata
in essence, here is how the code transforms:
from this infinite if clause inferno:
class GildedRose
# ...
def tick
# 16 if statements
# 7 !=
# 2 != with &&
# 3 magic strings
# ? magic numbers
if @name != 'Aged Brie' && @name != 'Backstage passes to a TAKFAL80ETC concert'
if @quality > 0
if @name != 'Sulfuras, Hand of Ragnaros'
@quality -= 1
end
end
else
if @quality < 50
@quality += 1
if @name == 'Backstage passes to a TAKFAL80ETC concert'
if @days_remaining < 11
if @quality < 50
@quality += 1
end
end
end
end
end
if @name != 'Sulfuras, Hand of Ragnaros'
@days_remaining -= 1
end
if @days_remaining < 0
if @name != 'Aged Brie'
if @name != 'Backstage passes to a TAKFAL80ETC concert'
if @quality > 0
if @name != 'Sulfuras, Hand of Ragnaros'
@quality -= 1
end
end
else
@quality = @quality - @quality
end
else
if @quality < 50
@quality += 1
end
end
end
end
end
to:
class GildedRose
# ...
def tick
# pass Item's Subclass name as String to factory
case @name
when 'normal'
item_factory "Normal"
when 'Aged Brie'
item_factory "Brie"
when 'Sulfuras, Hand of Ragnaros'
item_factory "Sulfuras"
when 'Backstage passes to a TAKFAL80ETC concert'
item_factory "Backstage"
end
end
private
def item_factory(name)
@item = Object.const_get(name).new(self)
@item.tick
end
end
class Item
attr_accessor :parent
def initialize(parent)
@parent = parent
end
def tick
end
private
def limit_quality_at(limit)
@parent.quality = limit if @parent.quality >= limit
end
def lower_quality_by(amount)
@parent.quality -= amount
end
def raise_quality_by(amount)
@parent.quality += amount
end
end
# Classes of Brie, Sulfuras and Backstage are skipped for brevity
class Normal < Item
def tick
@parent.days_remaining -= 1
return if @parent.quality == 0
lower_quality_by 1
lower_quality_by 1 if @parent.days_remaining <= 0
end
end
The total lines of code may grow, but the units and inner logic is much easier to reason about. The former in If-clauses encapsulated logic bred interdependencies. By implementing roles and classes, the code is logically grouped.
⬅️ Read previous Read next ➡️