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

Go Northwest 2018: A Rubyist's (Poignant) Guide to Go

Go Northwest 2018: A Rubyist's (Poignant) Guide to Go

Hsing-Hui Hsu

July 30, 2018
Tweet

More Decks by Hsing-Hui Hsu

Other Decks in Programming

Transcript

  1. "

  2. GO NORTHWEST 2018 THINGS I LEARNED FROM RUBY ▸Objects are

    your friend ▸Duck typing ▸Test-Driven Development ✅ ▸Developer happiness
  3. ‣ Conceptual level: 
 A set of responsibilities ‣ Specification

    level: 
 A set of methods or behaviors that can be invoked by other objects or by itself ‣ Implementation level: 
 A set of code and data and computation interactions between them
  4. GO NORTHWEST 2018 GILDED ROSE REFACTORING KATA: THE REQUIREMENTS ▸

    All items have a Sell-In value which denotes the number of days in which the item must be sold ▸ All Items have a Quality value which denotes how valuable the item is ▸ At the end of each day our system lowers both values for every item
  5. GO NORTHWEST 2018 GILDED ROSE REFACTORING KATA: THE REQUIREMENTS ▸

    Once the sell-in date has passed, Quality degrades twice as fast ▸ The Quality of an item is never negative ▸ Some items actually increase in Quality the older it gets, e.g. “Aged Brie” ▸ The Quality of an item is never more than 50 ▸ "Sulfuras", being a legendary item, never has to be sold or decreases in Quality ▸ “Backstage passes", like Aged Brie, increases in Quality as it's SellIn value approaches; Quality increases by 2 when there are 10 days or less and by 3 when there are 5 days or less but Quality drops to 0 after the concerts have a Quality value which denotes how valuable the item is
  6. GO NORTHWEST 2018 ▸ We have recently signed a supplier

    of conjured items. This requires an update to our system: ▸ “Conjured” items degrade in Quality twice as fast as normal items GILDED ROSE REFACTORING KATA: THE REQUIREMENTS
  7. GO NORTHWEST 2018 package main type Item struct { name

    string sellIn, quality int } var items = []Item{ Item{"+5 Dexterity Vest", 10, 20}, Item{"Aged Brie", 2, 0}, Item{“Chunky Bacon", 5, 7}, Item{"Sulfuras, Hand of Ragnaros", 0, 80}, Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Conjured Mana Cake", 3, 6}, } func main() { GildedRose() } ...
  8. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { if items[i].name != "Aged Brie" && items[i].name != "Backstage passes to a TAFKAL80ETC concert" { if items[i].quality > 0 { if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].quality = items[i].quality - 1 } } } else { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 if items[i].name == "Backstage passes to a TAFKAL80ETC concert" { if items[i].sellIn < 11 { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 } } if items[i].sellIn < 6 { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 } } } } } // ...
  9. GO NORTHWEST 2018 // ...continued if items[i].name != "Sulfuras, Hand

    of Ragnaros" { items[i].sellIn = items[i].sellIn - 1 } if items[i].sellIn < 0 { if items[i].name != "Aged Brie" { if items[i].name != "Backstage passes to a TAFKAL80ETC concert" { if items[i].quality > 0 { if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].quality = items[i].quality - 1 } } } else { items[i].quality = items[i].quality - items[i].quality } } else { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 } } } } }
  10. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { if items[i].name != "Aged Brie" && items[i].name != "Backstage passes to a TAFKAL80ETC concert" { if items[i].quality > 0 { if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].quality = items[i].quality - 1 } } } else { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 if items[i].name == "Backstage passes to a TAFKAL80ETC concert" { if items[i].sellIn < 11 { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 } } if items[i].sellIn < 6 { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 } } } } } if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].sellIn = items[i].sellIn - 1 } if items[i].sellIn < 0 { if items[i].name != "Aged Brie" { if items[i].name != "Backstage passes to a TAFKAL80ETC concert" { if items[i].quality > 0 { if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].quality = items[i].quality - 1 } } } else { items[i].quality = items[i].quality - items[i].quality } } else { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 } } } } }
  11. “IF YOU KNOW THE ENEMY AND KNOW YOURSELF, YOU NEED

    NOT FEAR THE RESULT OF A HUNDRED BATTLES.” -Sun Tzu, The Art of War
  12. GO NORTHWEST 2018 ▸ All items have a SellIn value

    which denotes the number of days in which the item must be sold ▸ All Items have a Quality value which denotes how valuable the item is ▸ At the end of each day our system lowers both values for every item GILDED ROSE REFACTORING KATA: THE REQUIREMENTS
  13. GO NORTHWEST 2018 func TestNormal_BeforeSellDate(t *testing.T) { normal := Item{"Normal",

    2, 10} items = []Item{normal} GildedRose() got := items[0] expectedSellIn := normal.sellIn - 1 if got.sellIn != expectedSellIn { t.Fatalf("Sell In = %d, want %d", got.sellIn, expectedSellIn) }
 expectedQuality := normal.quality - 1 if got.quality != expectedQuality { t.Fatalf("Quality = %d, want %d", got.quality, expectedQuality) } } TDD! "
  14. GO NORTHWEST 2018 === RUN TestNormal_BeforeSellDate --- PASS: TestNormal_BeforeSellDate (0.00s)

    === RUN TestNormal_BeforeSellDate_WithMinQuality --- PASS: TestNormal_BeforeSellDate_WithMinQuality (0.00s) === RUN TestNormal_OnSellDate --- PASS: TestNormal_OnSellDate (0.00s) === RUN TestNormal_OnSellDate_WithMinQuality --- PASS: TestNormal_OnSellDate_WithMinQuality (0.00s) === RUN TestNormal_AfterSellDate --- PASS: TestNormal_AfterSellDate (0.00s) === RUN TestNormal_AfterSellDate_WithMinQuality --- PASS: TestNormal_AfterSellDate_WithMinQuality (0.00s) === RUN TestBrie_BeforeSellDate --- PASS: TestBrie_BeforeSellDate (0.00s) === RUN TestBrie_BeforeSellDate_WithMaxQuality --- PASS: TestBrie_BeforeSellDate_WithMaxQuality (0.00s) === RUN TestBrieOnSellDate --- PASS: TestBrieOnSellDate (0.00s) === RUN TestBrieOnSellDateWithMaxQuality --- PASS: TestBrieOnSellDateWithMaxQuality (0.00s) === RUN TestBrie_AfterSellDate --- PASS: TestBrie_AfterSellDate (0.00s) === RUN TestBrieAfterSellDate_WithMaxQuality --- PASS: TestBrieAfterSellDate_WithMaxQuality (0.00s) === RUN TestSulfuras_BeforeSellDate --- PASS: TestSulfuras_BeforeSellDate (0.00s) === RUN TestSulfuras_OnSellDate --- PASS: TestSulfuras_OnSellDate (0.00s) === RUN TestSulfuras_AfterSellDate --- PASS: TestSulfuras_AfterSellDate (0.00s) === RUN TestBackstagePass_LongBeforeSellDate --- PASS: TestBackstagePass_LongBeforeSellDate (0.00s) === RUN TestBackstagePass_LongBeforeSellDate_WithMaxQuality --- PASS: TestBackstagePass_LongBeforeSellDate_WithMaxQuality (0.00s) === RUN TestBackstagePass_MediumBeforeSellDate --- PASS: TestBackstagePass_MediumBeforeSellDate (0.00s) === RUN TestBackstagePass_MediumBeforeSellDate_WithMaxQuality --- PASS: TestBackstagePass_MediumBeforeSellDate_WithMaxQuality (0.00s) === RUN TestBackstagePass_JustBeforeSellDate --- PASS: TestBackstagePass_JustBeforeSellDate (0.00s) === RUN TestBackstagePass_JustBeforeSellDate_WithMaxQuality --- PASS: TestBackstagePass_JustBeforeSellDate_WithMaxQuality (0.00s) === RUN TestBackstagePassOnSellDate --- PASS: TestBackstagePassOnSellDate (0.00s) === RUN TestBackstagePass_AfterSellDate --- PASS: TestBackstagePass_AfterSellDate (0.00s) === RUN TestConjuredMana_BeforeSellDate --- PASS: TestConjuredMana_BeforeSellDate (0.00s) === RUN TestConjuredMana_BeforeSellDate_WithMinQuality --- PASS: TestConjuredMana_BeforeSellDate_WithMinQuality (0.00s) === RUN TestConjuredMana_OnSellDate --- PASS: TestConjuredMana_OnSellDate (0.00s) === RUN TestConjuredMana_OnSellDate_WithMinQuality --- PASS: TestConjuredMana_OnSellDate_WithMinQuality (0.00s) === RUN TestConjuredMana_AfterSellDate --- PASS: TestConjuredMana_AfterSellDate (0.00s) === RUN TestConjuredMana_AfterSellDate_WithMinQuality --- PASS: TestConjuredMana_AfterSellDate_WithMinQuality (0.00s) PASS ok gilded_rose 0.006s
  15. GO NORTHWEST 2018 // At the end of each day

    our system lowers both values for every item func GildedRose() { for i := 0; i < len(items); i++ { } items[i].SellIn -= 1 items[i].Quality -= 1
  16. GO NORTHWEST 2018 GILDED ROSE REFACTORING KATA: THE REQUIREMENTS ▸

    Once the sell by date has passed, Quality degrades twice as fast ▸ The Quality of an item is never negative ▸ Some items actually increase in Quality the older it gets, e.g. “Aged Brie” ▸ The Quality of an item is never more than 50 ▸ "Sulfuras", being a legendary item, never has to be sold or decreases in Quality ▸ “Backstage passes", like Aged Brie, increases in Quality as it's SellIn value approaches; Quality increases by 2 when there are 10 days or less and by 3 when there are 5 days or less but Quality drops to 0 after the concerts have a Quality value which denotes how valuable the item is
  17. GO NORTHWEST 2018 // Once the sell by date has

    passed, Quality degrades twice as fast func GildedRose() { for i := 0; i < len(items); i++ { items[i].sellIn -= 1 items[i].quality -= 1 } }
  18. GO NORTHWEST 2018 // Once the sell by date has

    passed, Quality degrades // twice as fast func GildedRose() { for i := 0; i < len(items); i++ { items[i].sellIn -= 1 if items[i].sellIn > 0 { items[i].quality -= 1 } if items[i].sellIn <= 0 { items[i].quality -= 2 } } }
  19. GO NORTHWEST 2018 GILDED ROSE REFACTORING KATA: THE REQUIREMENTS ▸

    Once the sell by date has passed, Quality degrades twice as fast ▸ The Quality of an item is never negative ▸ Some items actually increase in Quality the older it gets, e.g. “Aged Brie” ▸ The Quality of an item is never more than 50 ▸ "Sulfuras", being a legendary item, never has to be sold or decreases in Quality ▸ “Backstage passes", like Aged Brie, increases in Quality as it's SellIn value approaches; Quality increases by 2 when there are 10 days or less and by 3 when there are 5 days or less but Quality drops to 0 after the concerts have a Quality value which denotes how valuable the item is
  20. GO NORTHWEST 2018 // The Quality of an item is

    never negative func GildedRose() { for i := 0; i < len(items); i++ { items[i].sellIn -= 1 if items[i].sellIn > 0 { items[i].quality -= 1 } if items[i].sellIn <= 0 { items[i].quality -= 2 } } }
  21. GO NORTHWEST 2018 // The Quality of an item is

    never negative func GildedRose() { for i := 0; i < len(items); i++ { items[i].sellIn -= 1 
 if items[i].sellIn > 0 { items[i].quality -= 1 } if items[i].sellIn <= 0 { items[i].quality -= 2 } } }
  22. GO NORTHWEST 2018 // The Quality of an item is

    never negative func GildedRose() { for i := 0; i < len(items); i++ { items[i].sellIn -= 1 if items[i].quality > 0 {
 if items[i].sellIn > 0 { items[i].quality -= 1 } if items[i].sellIn <= 0 { items[i].quality -= 2 } } } }
  23. GO NORTHWEST 2018 ~/go/src/gilded_rose$ go test -v === RUN TestNormal_BeforeSellDate

    --- PASS: TestNormal_BeforeSellDate (0.00s) === RUN TestNormal_BeforeSellDate_WithMinQuality --- PASS: TestNormal_BeforeSellDate_WithMinQuality (0.00s) === RUN TestNormal_OnSellDate --- PASS: TestNormal_OnSellDate (0.00s) === RUN TestNormal_OnSellDate_WithMinQuality --- PASS: TestNormal_OnSellDate_WithMinQuality (0.00s) === RUN TestNormal_AfterSellDate --- PASS: TestNormal_AfterSellDate (0.00s) === RUN TestNormal_AfterSellDate_WithMinQuality --- PASS: TestNormal_AfterSellDate_WithMinQuality (0.00s) PASS ok gilded_rose 0.005s "
  24. GO NORTHWEST 2018 GILDED ROSE REFACTORING KATA: THE REQUIREMENTS ▸

    Once the sell by date has passed, Quality degrades twice as fast ▸ The Quality of an item is never negative ▸ Some items actually increase in Quality the older it gets, e.g. “Aged Brie” ▸ The Quality of an item is never more than 50 ▸ "Sulfuras", being a legendary item, never has to be sold or decreases in Quality ▸ “Backstage passes", like Aged Brie, increases in Quality as it's SellIn value approaches; Quality increases by 2 when there are 10 days or less and by 3 when there are 5 days or less but Quality drops to 0 after the concerts have a Quality value which denotes how valuable the item is
  25. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { items[i].sellIn -= 1 if items[i].quality > 0 {
 if items[i].sellIn > 0 { items[i].quality -= 1 } if items[i].sellIn <= 0 { items[i].quality -= 2 } } } }
  26. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { items[i].sellIn -= 1 if items[i].quality > 0 {
 if items[i].sellIn > 0 { items[i].quality -= 1 } if items[i].sellIn <= 0 { items[i].quality -= 2 } } } }
  27. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { items[i].sellIn -= 1 if items[i].name != "Aged Brie" { if items[i].quality > 0 {
 if items[i].sellIn > 0 { items[i].quality -= 1 } if items[i].sellIn <= 0 { items[i].quality -= 2 } } } } }
  28. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { items[i].sellIn -= 1 if items[i].name != "Aged Brie" { // stuff that’s not about Aged Brie } else { if items[i].quality < 50 {
 if items[i].sellIn > 0 { items[i].quality += 1 } if items[i].sellIn <= 0 { items[i].quality += 2 } } } } }
  29. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { items[i].sellIn -= 1 if items[i].name != "Aged Brie" { // stuff that’s not about Aged Brie } else { // Aged Brie if items[i].quality < 50 {
 if items[i].sellIn > 0 { items[i].quality += 1 } if items[i].sellIn <= 0 { items[i].quality += 2 } } } } }
  30. GO NORTHWEST 2018 ~/go/src/gilded_rose$ go test -v --- PASS: TestBrie_BeforeSellDate

    (0.00s) === RUN TestBrie_BeforeSellDate_WithMaxQuality --- PASS: TestBrie_BeforeSellDate_WithMaxQuality (0.00s) === RUN TestBrieOnSellDate --- PASS: TestBrieOnSellDate (0.00s) === RUN TestBrieOnSellDateWithMaxQuality --- PASS: TestBrieOnSellDateWithMaxQuality (0.00s) === RUN TestBrie_AfterSellDate --- PASS: TestBrie_AfterSellDate (0.00s) === RUN TestBrieAfterSellDate_WithMaxQuality --- PASS: TestBrieAfterSellDate_WithMaxQuality (0.00s) PASS ok gilded_rose 0.005s "
  31. GO NORTHWEST 2018 // "Sulfuras", being a legendary item, never

    has to be sold or decreases in Quality func GildedRose() { for i := 0; i < len(items); i++ { items[i].sellIn = items[i].sellIn - 1 if items[i].name != "Aged Brie" { if items[i].quality > 0 {
 if items[i].sellIn > 0 { items[i].quality -= 1 } if items[i].sellIn <= 0 { items[i].quality -= 2 } } } else { // Aged Brie if items[i].quality < 50 {
 if items[i].sellIn > 0 { items[i].quality += 1 } if items[i].sellIn <= 0 { items[i].quality += 2 } } } }
  32. GO NORTHWEST 2018 // "Sulfuras", being a legendary item, never

    has to be sold or decreases in Quality func GildedRose() { for i := 0; i < len(items); i++ { if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].sellIn = items[i].sellIn - 1 if items[i].name != "Aged Brie" { if items[i].quality > 0 {
 if items[i].sellIn > 0 { items[i].quality -= 1 } if items[i].sellIn <= 0 { items[i].quality -= 2 } } } else { // Aged Brie if items[i].quality < 50 {
 if items[i].sellIn > 0 { items[i].quality += 1 } if items[i].sellIn <= 0 { items[i].quality += 2 } } } } }
  33. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].sellIn = items[i].sellIn - 1 // Things whose quality decreases over time if items[i].name != "Aged Brie" && items[i].name != "Backstage passes to a TAFKAL80ETC concert" { if items[i].quality > 0 { if items[i].sellIn > 0 { items[i].quality -= 1 } if items[i].sellIn <= 0 { items[i].quality -= 2 } } // Things whose quality increases over time } else { // Aged Brie and Backstage passes // Quality can never exceed 50 if items[i].quality >= 50 { return } if items[i].name == "Aged Brie" { if items[i].sellIn > 0 { items[i].quality += 1 } if items[i].sellIn <= 0 { items[i].quality += 2 } } else if items[i].name == "Backstage passes to a TAFKAL80ETC concert" { if items[i].sellIn >= 10 { items[i].quality += 1 } if items[i].sellIn < 10 && items[i].sellIn > 5 { items[i].quality += 2 } if items[i].sellIn <= 5 && items[i].sellIn >= 0 { items[i].quality += 3 } if items[i].sellIn < 0 { items[i].quality = 0 } } } } } }
  34. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].sellIn = items[i].sellIn - 1 // Things whose quality decreases over time if items[i].name != "Aged Brie" && items[i].name != "Backstage passes to a TAFKAL80ETC concert" { if items[i].quality > 0 { if items[i].sellIn > 0 { items[i].quality -= 1 } if items[i].sellIn <= 0 { items[i].quality -= 2 } } // Things whose quality increases over time } else { // Aged Brie and Backstage passes // Quality can never exceed 50 if items[i].quality >= 50 { return } if items[i].name == "Aged Brie" { if items[i].sellIn > 0 { items[i].quality += 1 } if items[i].sellIn <= 0 { items[i].quality += 2 } } else if items[i].name == "Backstage passes to a TAFKAL80ETC concert" { if items[i].sellIn >= 10 { items[i].quality += 1 } if items[i].sellIn < 10 && items[i].sellIn > 5 { items[i].quality += 2 } if items[i].sellIn <= 5 && items[i].sellIn >= 0 { items[i].quality += 3 } if items[i].sellIn < 0 { items[i].quality = 0 }
  35. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].sellIn = items[i].sellIn - 1 // Things whose quality decreases over time if items[i].name != "Aged Brie" && items[i].name != "Backstage passes to a TAFKAL80ETC concert" { if items[i].quality == 0 { return } items[i].quality -= 1 if items[i].sellIn <= 0 { items[i].quality -= 1 } // Things whose quality increases over time } else { // Aged Brie and Backstage passes // Quality can never exceed 50 if items[i].quality >= 50 { return } items[i].quality += 1 if items[i].name == "Aged Brie" { if items[i].sellIn <= 0 { items[i].quality += 1 } } else if items[i].name == "Backstage passes to a TAFKAL80ETC concert" { if items[i].sellIn < 10 { items[i].quality += 1 } if items[i].sellIn < 5 { items[i].quality += 1 } if items[i].sellIn < 0 { items[i].quality = 0 } }
  36. GO NORTHWEST 2018 HOW DID WE MAKE SUCH A MESS?

    ▸Relatively Easy ▸Cheap ▸Abstraction was not yet clear
  37. HAVE EMPATHY FOR THE PROCESS AND THE DEVELOPERS WHO CAME

    BEFORE YOU (BECAUSE SOMETIMES THAT DEVELOPER WAS YOU)
  38. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { if items[i].name != "Aged Brie" && items[i].name != "Backstage passes to a TAFKAL80ETC concert" { if items[i].quality > 0 { if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].quality = items[i].quality - 1 } } } else { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 if items[i].name == "Backstage passes to a TAFKAL80ETC concert" { if items[i].sellIn < 11 { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 } } if items[i].sellIn < 6 { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 } } } } } if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].sellIn = items[i].sellIn - 1 } if items[i].sellIn < 0 { if items[i].name != "Aged Brie" { if items[i].name != "Backstage passes to a TAFKAL80ETC concert" { if items[i].quality > 0 { if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].quality = items[i].quality - 1 } } } else { items[i].quality = items[i].quality - items[i].quality } } else { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 } } } } }
  39. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { if items[i].name == "Normal" { update_normal(&items[i]) return } // Deal with quality // Things whose quality decreases over time if items[i].name != "Aged Brie" && items[i].name != "Backstage passes to a TAFKAL80ETC concert" { // Catch lower limit if items[i].quality > 0 { if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].quality = items[i].quality - 1 } }
  40. GO NORTHWEST 2018 --- FAIL: TestNormal_BeforeSellDate (0.00s) gilded_rose_test.go:19: Sell In

    = 2, want 1 --- FAIL: TestNormal_BeforeSellDate_WithMinQuality (0.00s) gilded_rose_test.go:36: Sell In = 2, want 1 --- FAIL: TestNormal_OnSellDate (0.00s) gilded_rose_test.go:53: Sell In = 0, want -1 --- FAIL: TestNormal_OnSellDate_WithMinQuality (0.00s) gilded_rose_test.go:71: Sell In = 0, want -1 --- FAIL: TestNormal_AfterSellDate (0.00s) gilded_rose_test.go:89: Sell In = -2, want -3 --- FAIL: TestNormal_AfterSellDate_WithMinQuality (0.00s) gilded_rose_test.go:106: Sell In = -2, want -3 FAIL exit status 1 FAIL gilded_rose 0.005s
  41. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].sellIn = items[i].sellIn - 1 if items[i].name != "Aged Brie" && items[i].name != "Backstage passes to a TAFKAL80ETC concert" { if items[i].quality == 0 { return } items[i].quality -= 1 if items[i].sellIn <= 0 { items[i].quality -= 1 } } else { if items[i].quality >= 50 { return } items[i].quality += 1 if items[i].name == "Aged Brie" { if items[i].sellIn <= 0 { items[i].quality += 1 } } else if items[i].name == "Backstage passes to a TAFKAL80ETC concert" { if items[i].sellIn < 10 { items[i].quality += 1 } if items[i].sellIn < 5 { items[i].quality += 1 } if items[i].sellIn < 0 { items[i].quality = 0 } } } } } }
  42. GO NORTHWEST 2018 func update_normal(item *Item) { item.sellIn -= 1

    if item.quality <= 0 { return } item.quality -= 1 if item.sellIn <= 0 { item.quality -= 1 } return }
  43. GO NORTHWEST 2018 --- PASS: TestNormal_BeforeSellDate (0.00s) === RUN TestNormal_BeforeSellDate_WithMinQuality

    --- PASS: TestNormal_BeforeSellDate_WithMinQuality (0.00s) === RUN TestNormal_OnSellDate --- PASS: TestNormal_OnSellDate (0.00s) === RUN TestNormal_OnSellDate_WithMinQuality --- PASS: TestNormal_OnSellDate_WithMinQuality (0.00s) === RUN TestNormal_AfterSellDate --- PASS: TestNormal_AfterSellDate (0.00s) === RUN TestNormal_AfterSellDate_WithMinQuality --- PASS: TestNormal_AfterSellDate_WithMinQuality (0.00s) PASS ok gilded_rose 0.006s "
  44. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { if items[i].name == "Normal" { update_normal(&items[i]) return } else if items[i].name == “Aged Brie" { update_brie(&items[i]) return } // ... existing mess
  45. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) return case "Aged Brie": update_brie(&items[i]) return } // ... existing mess
  46. GO NORTHWEST 2018 func update_brie(item *Item) { item.sellIn -= 1

    if item.quality >= 50 { return } item.quality += 1 if item.sellIn <= 0 { item.quality += 1 } return }
  47. GO NORTHWEST 2018 --- PASS: TestBrie_BeforeSellDate (0.00s) === RUN TestBrie_BeforeSellDate_WithMaxQuality

    --- PASS: TestBrie_BeforeSellDate_WithMaxQuality (0.00s) === RUN TestBrieOnSellDate --- PASS: TestBrieOnSellDate (0.00s) === RUN TestBrieOnSellDateWithMaxQuality --- PASS: TestBrieOnSellDateWithMaxQuality (0.00s) === RUN TestBrie_AfterSellDate --- PASS: TestBrie_AfterSellDate (0.00s) === RUN TestBrieAfterSellDate_WithMaxQuality --- PASS: TestBrieAfterSellDate_WithMaxQuality (0.00s) PASS ok gilded_rose 0.006s "
  48. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) return case "Aged Brie": update_brie(&items[i]) return } // ... existing mess
  49. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) return case "Aged Brie": update_brie(&items[i]) return case "Sulfuras, Hand of Ragnaros": update_sulfuras(&items[i]) return } // ... existing mess
  50. GO NORTHWEST 2018 GILDED ROSE REFACTORING KATA: THE REQUIREMENTS ▸

    Once the sell by date has passed, Quality degrades twice as fast ▸ The Quality of an item is never negative ▸ Some items actually increase in Quality the older it gets, e.g. “Aged Brie” ▸ The Quality of an item is never more than 50 ▸ "Sulfuras", being a legendary item, never has to be sold or decreases in Quality ▸ “Backstage passes", like Aged Brie, increases in Quality as it's SellIn value approaches; Quality increases by 2 when there are 10 days or less and by 3 when there are 5 days or less but Quality drops to 0 after the concerts have a Quality value which denotes how valuable the item is
  51. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) return case "Aged Brie": update_brie(&items[i]) return case "Sulfuras, Hand of Ragnaros": update_sulfuras(&items[i]) return case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) return } // ... existing mess
  52. GO NORTHWEST 2018 func update_backstage(item *Item) { item.sellIn -= 1

    if item.quality >= 50 { return } item.quality += 1 if item.sellIn < 10 { item.quality += 1 } if item.sellIn < 5 { item.quality += 1 } if item.sellIn < 0 { item.quality = 0 } return }
  53. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) return case "Aged Brie": update_brie(&items[i]) return case "Sulfuras, Hand of Ragnaros": update_sulfuras(&items[i]) return case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) return } // ... existing mess Default?
  54. GO NORTHWEST 2018 package main type Item struct { name

    string sellIn, quality int } var items = []Item{ Item{"+5 Dexterity Vest", 10, 20}, Item{"Aged Brie", 2, 0}, Item{“Chunky Bacon", 5, 7}, Item{"Sulfuras, Hand of Ragnaros", 0, 80}, Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Conjured Mana Cake", 3, 6}, } func main() { GildedRose() } ...
  55. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) return case "Aged Brie": update_brie(&items[i]) return case "Sulfuras, Hand of Ragnaros": update_sulfuras(&items[i]) return case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) return default: update_default(&items[i]) return } // ... existing mess
  56. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) return case "Aged Brie": update_brie(&items[i]) return case "Sulfuras, Hand of Ragnaros": update_sulfuras(&items[i]) return case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) return default: update_default(&items[i]) return } // ... existing mess
  57. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) return case "Aged Brie": update_brie(&items[i]) return case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) return default: update_default(&items[i]) return } // ... existing mess
  58. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) return case "Aged Brie": update_brie(&items[i]) return case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) return default: update_default(&items[i]) } // ... existing mess
  59. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) return case "Aged Brie": update_brie(&items[i]) return case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) return default: update_default(&items[i]) } } }
  60. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) case "Aged Brie": update_brie(&items[i]) case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) default: update_default(&items[i]) } return } }
  61. GO NORTHWEST 2018 ▸ We have recently signed a supplier

    of conjured items. This requires an update to our system: ▸ “Conjured” items degrade in Quality twice as fast as normal items GILDED ROSE REFACTORING KATA: THE NEW FEATURE
  62. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) case "Aged Brie": update_brie(&items[i]) case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) default: update_default(&items[i]) } return } }
  63. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) case "Aged Brie": update_brie(&items[i]) case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) case “Conjured Mana Cake": update_conjured(&items[i]) default: update_default(&items[i]) } return } }
  64. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) case "Aged Brie": update_brie(&items[i]) case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) case “Conjured Mana Cake": update_conjured(&items[i]) default: update_default(&items[i]) } return } }
  65. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) case "Aged Brie": update_brie(&items[i]) case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) case “Conjured Mana Cake": update_conjured(&items[i]) case “Chunky Bacon": update_bacon(&items[i]) default: update_default(&items[i]) } return } }
  66. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) case "Aged Brie": update_brie(&items[i]) case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) case “Conjured Mana Cake": update_conjured(&items[i]) case “Chunky Bacon": update_bacon(&items[i]) 
 case “+5 Dexterity Vest": update_vest(&items[i]) default: update_default(&items[i]) } return } }
  67. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) case "Aged Brie": update_brie(&items[i]) case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) case “Conjured Mana Cake": update_conjured(&items[i]) case “Chunky Bacon": update_bacon(&items[i]) case “+5 Dexterity Vest": update_vest(&items[i]) case “Gorbypuff Thunderhorse": update_cat(&items[i]) 
 default: update_default(&items[i]) } return } } ❌
  68. GO NORTHWEST 2018 #! /usr/local/bin/ruby class Default < Item class

    Normal < Item class Brie < Item class BackstagePass < Item
  69. GO NORTHWEST 2018 #! /usr/local/bin/ruby class Default < Item class

    Normal < Item class Brie < Item class BackstagePass < Item class ConjuredMana < Item
  70. "

  71. GO NORTHWEST 2018 type Normal struct { Item } type

    Brie struct { Item } type Sulfuras struct { Item } type BackstagePass struct { Item }
  72. GO NORTHWEST 2018 type Normal struct { Item } type

    Brie struct { Item } type Sulfuras struct { Item } type BackstagePass struct { Item } ❌
  73. ‣ Conceptual level: 
 A set of responsibilities ‣ Specification

    level: 
 A set of methods or behaviors that can be invoked by other objects or by itself ‣ Implementation level: 
 A set of code and data and computation interactions between them
  74. GO NORTHWEST 2018 type Normal struct { name string sellIn,

    quality int } type Item interface { Name() string SellIn() int Quality() int Update() }
  75. GO NORTHWEST 2018 type Normal struct { name string sellIn,

    quality int } func (item *Normal) Name() string { return item.name } func (item *Normal) SellIn() int { return item.sellIn } func (item *Normal) Quality() int { return item.quality }
  76. GO NORTHWEST 2018 func (item *Normal) Update() { item.sellIn -=

    1 if item.quality <= 0 { return } item.quality -= 1 if item.sellIn <= 0 { item.quality -= 1 } return }
  77. GO NORTHWEST 2018 type Normal struct { name string sellIn,

    quality int } func (item *Normal) Name() string { return item.name } func (item *Normal) SellIn() int { return item.sellIn } func (item *Normal) Quality() int { return item.quality } func (item *Normal) Update() { item.sellIn -= 1 if item.quality <= 0 { return } item.quality -= 1 if item.sellIn <= 0 { item.quality -= 1 } return }
  78. GO NORTHWEST 2018 var items = []Item{ Item{"+5 Dexterity Vest",

    10, 20}, Item{"Aged Brie", 2, 0}, Item{“Chunky Bacon”, 5, 7}, Item{"Sulfuras, Hand of Ragnaros", 0, 80}, Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Conjured Mana Cake", 3, 6}, }
  79. GO NORTHWEST 2018 type Item struct { name string sellIn,

    quality int } type Item interface { Name() string SellIn() int Quality() int Update() }
  80. GO NORTHWEST 2018 type Params struct { name string sellIn,

    quality int } type Item interface { Name() string SellIn() int Quality() int Update() } -
  81. GO NORTHWEST 2018 var items = []Item{ Item{"+5 Dexterity Vest",

    10, 20}, Item{"Aged Brie", 2, 0}, Item{“Chunky Bacon”, 5, 7}, Item{"Sulfuras, Hand of Ragnaros", 0, 80}, Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Conjured Mana Cake", 3, 6}, }
  82. GO NORTHWEST 2018 var items = []Params{ Params{"+5 Dexterity Vest",

    10, 20}, Params{"Aged Brie", 2, 0}, Params{“Chunky Bacon”, 5, 7}, Params{"Sulfuras, Hand of Ragnaros", 0, 80}, Params{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Params{"Conjured Mana Cake", 3, 6}, }
  83. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) case "Aged Brie": update_brie(&items[i]) case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) default: update_default(&items[i]) } return } }
  84. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { case "Normal": update_normal(&items[i]) case "Aged Brie": update_brie(&items[i]) case "Backstage passes to a TAFKAL80ETC concert": update_backstage(&items[i]) default: update_default(&items[i]) } return } }
  85. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { p := &items[i] case "Normal": update_normal(p) case "Aged Brie": update_brie(p) case "Backstage passes to a TAFKAL80ETC concert": update_backstage(p) default: update_default(p) } return } } Objects are created here
  86. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { p := &items[i] case "Normal": update_normal(p) case "Aged Brie": update_brie(p) case "Backstage passes to a TAFKAL80ETC concert": update_backstage(p) default: update_default(p) } return } }
  87. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { p := &items[i] case "Normal": item := Normal{p.name, p.sellIn, p.quality} item.Update() case "Aged Brie": item := Brie{p.name, p.sellIn, p.quality} item.Update() case "Backstage passes to a TAFKAL80ETC concert": item := BackstagePass{p.name, p.sellIn, p.quality} item.Update() default: item := Default{p.name, p.sellIn, p.quality} item.Update() } return } }
  88. GO NORTHWEST 2018 var items = []Params{ Params{"+5 Dexterity Vest",

    10, 20}, Params{"Aged Brie", 2, 0}, Params{"Chunky Bacon", 5, 7}, Params{"Sulfuras, Hand of Ragnaros", 0, 80}, Params{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Params{"Conjured Mana Cake", 3, 6}, }
  89. GO NORTHWEST 2018 var items = []Item{ Params{"+5 Dexterity Vest",

    10, 20}, Params{"Aged Brie", 2, 0}, Params{“Chunky Bacon”, 5, 7}, Params{"Sulfuras, Hand of Ragnaros", 0, 80}, Params{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Params{"Conjured Mana Cake", 3, 6}, }
  90. GO NORTHWEST 2018 var items = []Params{ Params{"+5 Dexterity Vest",

    10, 20}, Params{"Aged Brie", 2, 0}, Params{"Chunky Bacon", 5, 7}, Params{"Sulfuras, Hand of Ragnaros", 0, 80}, Params{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Params{"Conjured Mana Cake", 3, 6}, }
  91. GO NORTHWEST 2018 var items = []Item{ ItemFactory("+5 Dexterity Vest",

    10, 20), ItemFactory("Aged Brie", 2, 0), ItemFactory("Chunky Bacon", 5, 7), ItemFactory("Sulfuras, Hand of Ragnaros", 0, 80), ItemFactory("Backstage passes to a TAFKAL80ETC concert", 15, 20), ItemFactory("Conjured Mana Cake", 3, 6), }
  92. “Define an interface for creating an object, but let subclasses

    decide which class to instantiate. The Factory Method lets a class defer instantiation to subclasses.” — .. ..
  93. GO NORTHWEST 2018 type Factory func(string, int, int) Item func

    NewNormal(name string, sellIn, quality int) Item { return &Normal{name, sellIn, quality} }
  94. GO NORTHWEST 2018 type Normal struct { name string sellIn,

    quality int } type Params struct { name string sellIn, quality int }
  95. GO NORTHWEST 2018 type Normal struct { Params } type

    Params struct { name string sellIn, quality int } -
  96. GO NORTHWEST 2018 type Factory func(Params) Item func NewNormal(params Params)

    Item { return &Normal{params} } func NewBrie(params Params) Item { return &Brie{params} } func NewBackstagePass(params Params) Item { return &BackstagePass{params} } func NewDefault(params Params) Item { return &Default{params} }
  97. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { p := &items[i] case "Normal": item := Normal{p.name, p.sellIn, p.quality} item.Update() case "Aged Brie": item := Brie{p.name, p.sellIn, p.quality} item.Update() case "Backstage passes to a TAFKAL80ETC concert": item := BackstagePass{p.name, p.sellIn, p.quality} item.Update() default: item := Default{p.name, p.sellIn, p.quality} item.Update() } return } }
  98. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { p := &items[i] case "Normal": item := NewNormal(p) item.Update() case "Aged Brie": item := NewBrie(p) item.Update() case "Backstage passes to a TAFKAL80ETC concert": item := NewBackstagePass(p) item.Update() default: item := NewDefault(p) item.Update() } return } }
  99. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { switch items[i].name { p := &items[i] case "Normal": item := NewNormal(p) item.Update() case "Aged Brie": item := NewBrie(p) item.Update() case "Backstage passes to a TAFKAL80ETC concert": item := NewBackstagePass(p) item.Update() default: item := NewDefault(p) item.Update() } return } }
  100. GO NORTHWEST 2018 func ItemFactory(name string, sellIn, quality int) Item

    { params := Params{name, sellIn, quality} var item Item switch name { case "Normal": item = NewNormal(params) case "Aged Brie": item = NewBrie(params) case "Backstage passes to a TAFKAL80ETC concert": item = NewBackstagePass(params) default: item = NewDefault(params) } return item }
  101. GO NORTHWEST 2018 func ItemFactory(name string, sellIn, quality int) Item

    { params := Params{name, sellIn, quality} var item Item switch name { case "Normal": item = NewNormal(params) case "Aged Brie": item = NewBrie(params) case "Backstage passes to a TAFKAL80ETC concert": item = NewBackstagePass(params) default: item = NewDefault(params) } return item }
  102. GO NORTHWEST 2018 type Factory func(Params) Item var Factories =

    map[string]Factory{ "Normal": NewNormal, "Aged Brie": NewBrie, "Backstage passes to a TAFKAL80ETC concert": NewBackstagePass, } func ItemFactory(name string, sellIn, quality int) Item { params := Params{name, sellIn, quality} var item Item switch name { case "Normal": item = NewNormal(params) case "Aged Brie": item = NewBrie(params) case "Backstage passes to a TAFKAL80ETC concert": item = NewBackstagePass(params) default: item = NewDefault(params) } return item }
  103. GO NORTHWEST 2018 type Factory func(Params) Item var Factories =

    map[string]Factory{ "Normal": NewNormal, "Aged Brie": NewBrie, "Backstage passes to a TAFKAL80ETC concert": NewBackstagePass, } func ItemFactory(name string, sellIn, quality int) Item { params := Params{name, sellIn, quality} var item Item switch name { case "Normal": item = NewNormal(params) case "Aged Brie": item = NewBrie(params) case "Backstage passes to a TAFKAL80ETC concert": item = NewBackstagePass(params) default: item = NewDefault(params) } return item }
  104. GO NORTHWEST 2018 type Factory func(Params) Item var Factories =

    map[string]Factory{ "Normal": NewNormal, "Aged Brie": NewBrie, "Backstage passes to a TAFKAL80ETC concert": NewBackstagePass, } func ItemFactory(name string, sellIn, quality int) Item { params := Params{name, sellIn, quality} itemFactory, ok := Factories[name] if !ok { itemFactory = NewDefault } item := itemFactory(params) return item }
  105. GO NORTHWEST 2018 var items = []Item{ ItemFactory("+5 Dexterity Vest",

    10, 20), ItemFactory("Aged Brie", 2, 0), ItemFactory(“Chunky Bacon”, 5, 7), ItemFactory("Sulfuras, Hand of Ragnaros", 0, 80), ItemFactory("Backstage passes to a TAFKAL80ETC concert", 15, 20), ItemFactory("Conjured Mana Cake", 3, 6), } func GildedRose() { for i := 0; i < len(items); i++ { //... } } ACTUAL COLLECTION OF ITEMS
  106. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { item := items[i] item.Update() } }
  107. GO NORTHWEST 2018 type Item struct { name string sellIn,

    quality int } var items = []Item{ Item{"+5 Dexterity Vest", 10, 20}, Item{"Aged Brie", 2, 0}, Item{“Chunky Bacon”, 5, 7}, Item{"Sulfuras, Hand of Ragnaros", 0, 80}, Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Conjured Mana Cake", 3, 6}, }
  108. GO NORTHWEST 2018 type Item interface { Name() string SellIn()

    int Quality() int Update() } type Params struct { name string sellIn, quality int } var items = []Item{ ItemFactory("+5 Dexterity Vest", 10, 20), ItemFactory("Aged Brie", 2, 0), ItemFactory(“Chunky Bacon”, 5, 7), ItemFactory("Sulfuras, Hand of Ragnaros", 0, 80), ItemFactory("Backstage passes to a TAFKAL80ETC concert", 15, 20), ItemFactory("Conjured Mana Cake", 3, 6), }
  109. GO NORTHWEST 2018 type Factory func(Params) Item var Factories =

    map[string]Factory{ "Normal": NewNormal, "Aged Brie": NewBrie, "Backstage passes to a TAFKAL80ETC concert": NewBackstagePass, } func ItemFactory(name string, sellIn, quality int) Item { params := Params{name, sellIn, quality} itemFactory, ok := Factories[name] if !ok { itemFactory = NewDefault } item := itemFactory(params) return item }
  110. GO NORTHWEST 2018 type Default struct { Params } func

    NewDefault(params Params) Item { return &Default{params} } func (item *Default) Name() string { return item.name } func (item *Default) SellIn() int { return item.sellIn } func (item *Default) Quality() int { return item.quality } func (item *Default) Update() { return }
  111. GO NORTHWEST 2018 type Normal struct { Params } func

    NewNormal(params Params) Item { return &Normal{params} } func (item *Normal) Name() string { return item.name } func (item *Normal) SellIn() int { return item.sellIn } func (item *Normal) Quality() int { return item.quality } func (item *Normal) Update() { item.sellIn -= 1 if item.quality <= 0 { return } item.quality -= 1 if item.sellIn <= 0 { item.quality -= 1 } return } type BackstagePass struct { Params } func NewBackstagePass(params Params) Item { return &BackstagePass{params} } func (item *BackstagePass) Name() string { return item.name } func (item *BackstagePass) SellIn() int { return item.sellIn } func (item *BackstagePass) Quality() int { return item.quality } func (item *BackstagePass) Update() { item.sellIn -= 1 if item.quality >= 50 { return } item.quality += 1 if item.sellIn < 10 { item.quality += 1 } if item.sellIn < 5 { item.quality += 1 } if item.sellIn < 0 { item.quality = 0 } return } type Brie struct { Params } func NewBrie(params Params) Item { return &Brie{params} } func (item *Brie) Name() string { return item.name } func (item *Brie) SellIn() int { return item.sellIn } func (item *Brie) Quality() int { return item.quality } func (item *Brie) Update() { item.sellIn -= 1 if item.quality >= 50 { return } item.quality += 1 if item.sellIn <= 0 { item.quality += 1 } return }
  112. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { if items[i].name != "Aged Brie" && items[i].name != "Backstage passes to a TAFKAL80ETC concert" { if items[i].quality > 0 { if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].quality = items[i].quality - 1 } } } else { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 if items[i].name == "Backstage passes to a TAFKAL80ETC concert" { if items[i].sellIn < 11 { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 } } if items[i].sellIn < 6 { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 } } } } } if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].sellIn = items[i].sellIn - 1 } if items[i].sellIn < 0 { if items[i].name != "Aged Brie" { if items[i].name != "Backstage passes to a TAFKAL80ETC concert" { if items[i].quality > 0 { if items[i].name != "Sulfuras, Hand of Ragnaros" { items[i].quality = items[i].quality - 1 } } } else { items[i].quality = items[i].quality - items[i].quality } } else { if items[i].quality < 50 { items[i].quality = items[i].quality + 1 } // …
  113. GO NORTHWEST 2018 func GildedRose() { for i := 0;

    i < len(items); i++ { item := items[i] item.Update() } }
  114. GO NORTHWEST 2018 package main var inventory = []items.Item{ ItemFactory("+5

    Dexterity Vest", 10, 20), ItemFactory("Aged Brie", 2, 0), ItemFactory("Chunky Bacon", 5, 7), ItemFactory("Sulfuras, Hand of Ragnaros", 0, 80), ItemFactory("Backstage passes to a TAFKAL80ETC concert", 15, 20), ItemFactory("Conjured Mana Cake", 3, 6), } func main() { GildedRose() } func GildedRose() { for i := 0; i < len(inventory); i++ { item := inventory[i] item.Update() } }
  115. GO NORTHWEST 2018 package main type Item interface { Name()

    string SellIn() int Quality() int Update() } type Params struct { name string sellIn, quality int } type Factory func(Params) Item var Factories = map[string]Factory{ "Normal": NewNormal, "Aged Brie": NewBrie, "Backstage passes to a TAFKAL80ETC concert": NewBackstagePass, } func ItemFactory(name string, sellIn, quality int) Item { params := Params{name, sellIn, quality} itemFactory, ok := Factories[name] if !ok { itemFactory = NewDefault } item := itemFactory(params) return item }
  116. GO NORTHWEST 2018 module Item class ItemFactory ... def create

    ... end end class Default ...
 end def update ...
 end end item = Item::ItemFactory.create(name, sellIn, quality)
  117. GO NORTHWEST 2018 package main type Item interface { Name()

    string SellIn() int Quality() int Update() } type Params struct { name string sellIn, quality int } type Factory func(Params) Item var Factories = map[string]Factory{ "Normal": NewNormal, "Aged Brie": NewBrie, "Backstage passes to a TAFKAL80ETC concert": NewBackstagePass, } func ItemFactory(name string, sellIn, quality int) Item { params := Params{name, sellIn, quality} itemFactory, ok := Factories[name] if !ok { itemFactory = NewDefault } item := itemFactory(params) return item }
  118. GO NORTHWEST 2018 package items type Item interface { Name()

    string SellIn() int Quality() int Update() } type Params struct { name string sellIn, quality int } type Factory func(Params) Item var Factories = map[string]Factory{ "Normal": NewNormal, "Aged Brie": NewBrie, "Backstage passes to a TAFKAL80ETC concert": NewBackstagePass, } func ItemFactory(name string, sellIn, quality int) Item { params := Params{name, sellIn, quality} itemFactory, ok := Factories[name] if !ok { itemFactory = NewDefault } item := itemFactory(params) return item }
  119. GO NORTHWEST 2018 package main type Normal struct { Params

    } func NewNormal(params Params) Item { return &Normal{params} } func (item *Normal) Name() string { return "Normal" } func (item *Normal) SellIn() int { return item.sellIn } func (item *Normal) Quality() int { return item.quality } func (item *Normal) Update() { item.sellIn -= 1 if item.quality <= 0 { return } item.quality -= 1 if item.sellIn <= 0 { item.quality -= 1 } return }
  120. GO NORTHWEST 2018 package items type Normal struct { Params

    } func NewNormal(params Params) Item { return &Normal{params} } func (item *Normal) Name() string { return "Normal" } func (item *Normal) SellIn() int { return item.sellIn } func (item *Normal) Quality() int { return item.quality } func (item *Normal) Update() { item.sellIn -= 1 if item.quality <= 0 { return } item.quality -= 1 if item.sellIn <= 0 { item.quality -= 1 } return }
  121. GO NORTHWEST 2018 package main import ( "gilded_rose/items" ) var

    inventory = []items.Item{ items.ItemFactory("+5 Dexterity Vest", 10, 20), items.ItemFactory("Aged Brie", 2, 0), items.ItemFactory("Chunky Bacon", 5, 7), items.ItemFactory("Sulfuras, Hand of Ragnaros", 0, 80), items.ItemFactory("Backstage passes to a TAFKAL80ETC concert", 15, 20), items.ItemFactory("Conjured Mana Cake", 3, 6), } func main() { GildedRose() } func GildedRose() { for i := 0; i < len(inventory); i++ { item := inventory[i] item.Update() } }
  122. Gilded Rose Item Default Normal Brie Backstage Pass main.go items/item.go

    ItemFactory items/default.go items/normal.go items/brie.go items/backstage.go
  123. GO NORTHWEST 2018 package items type Default struct { name

    string sellIn, quality int } func NewDefault(name string, sellIn, quality int) Item { return &Default{name, sellIn, quality} } func (item *Default) Name() string { return item.name } func (item *Default) SellIn() int { return item.sellIn } func (item *Default) Quality() int { return item.quality } func (item *Default) Update() { return }
  124. GO NORTHWEST 2018 package items type Default struct { name

    string sellIn, quality int } func NewDefault(name string, sellIn, quality int) Item { return &Default{name, sellIn, quality} } func (item *Default) Name() string { return item.name } func (item *Default) SellIn() int { return item.sellIn } func (item *Default) Quality() int { return item.quality } func (item *Default) Update() { return }
  125. GO NORTHWEST 2018 package items type Normal struct { Params

    } func NewNormal(params Params) Item { return &Normal{params} } func (item *Normal) Name() string { return "Normal" } func (item *Normal) SellIn() int { return item.sellIn } func (item *Normal) Quality() int { return item.quality } func (item *Normal) Update() { item.sellIn -= 1 if item.quality <= 0 { return } item.quality -= 1 if item.sellIn <= 0 { item.quality -= 1 } return } package items type Brie struct { Params } func NewBrie(params Params) Item { return &Brie{params} } func (item *Brie) Name() string { return item.name } func (item *Brie) SellIn() int { return item.sellIn } func (item *Brie) Quality() int { return item.quality } func (item *Brie) Update() { item.sellIn -= 1 if item.quality >= 50 { return } item.quality += 1 if item.sellIn <= 0 { item.quality += 1 } return package items type BackstagePass struct { Params } func NewBackstagePass(params Params) Item { return &BackstagePass{params} } func (item *BackstagePass) Name() string { return item.name } func (item *BackstagePass) SellIn() int { return item.sellIn } func (item *BackstagePass) Quality() int { return item.quality } func (item *BackstagePass) Update() { item.sellIn -= 1 if item.quality >= 50 { return } item.quality += 1 if item.sellIn < 10 { item.quality += 1 } if item.sellIn < 5 { item.quality += 1 } if item.sellIn < 0 {
  126. GO NORTHWEST 2018 #! /usr/local/bin/ruby class Default attr_reader :name, sellIn,

    :quality def initialize name, sellIn, quality @name, @sellIn, @quality = name, sellIn, quality end def update end end class Brie < Default def update ... end end class Normal < Default def update ... end end class BackstagePass < Default def update ... end end
  127. GO NORTHWEST 2018 package items type Item interface { Name()

    string SellIn() int Quality() int Update() } type Params struct { name string sellIn, quality int } ...
  128. GO NORTHWEST 2018 package items type Default struct { name

    string sellIn, quality int } func NewDefault(name string, sellIn, quality int) Item { return &Default{name, sellIn, quality} } ...
  129. GO NORTHWEST 2018 package items type Normal struct { Params

    } func NewNormal(params Params) Item { return &Normal{params} } func (item *Normal) Name() string { return "Normal" } func (item *Normal) SellIn() int { return item.sellIn } func (item *Normal) Quality() int { return item.quality } func (item *Normal) Update() { item.sellIn -= 1 if item.quality <= 0 { return } item.quality -= 1 if item.sellIn <= 0 { item.quality -= 1 } return }
  130. GO NORTHWEST 2018 package items type Normal struct { Default

    } func NewNormal(params Params) Item { return &Normal{params} } func (item *Normal) Name() string { return "Normal" } func (item *Normal) SellIn() int { return item.sellIn } func (item *Normal) Quality() int { return item.quality } func (item *Normal) Update() { item.sellIn -= 1 if item.quality <= 0 { return } item.quality -= 1 if item.sellIn <= 0 { item.quality -= 1 } return }
  131. GO NORTHWEST 2018 package items type Normal struct { Default

    } func NewNormal(params Params) Item { return &Normal{params} } func (item *Normal) Name() string { return "Normal" } func (item *Normal) SellIn() int { return item.sellIn } func (item *Normal) Quality() int { return item.quality } func (item *Normal) Update() { item.sellIn -= 1 if item.quality <= 0 { return } item.quality -= 1 if item.sellIn <= 0 { item.quality -= 1 } return }
  132. GO NORTHWEST 2018 package items type Normal struct { Default

    } func NewNormal(params Params) Item { return &Normal{params} } func (item *Normal) Update() { item.sellIn -= 1 if item.quality <= 0 { return } item.quality -= 1 if item.sellIn <= 0 { item.quality -= 1 } return }
  133. GO NORTHWEST 2018 package items type Normal struct { Default

    } func NewNormal(params Params) Item { return &Normal{params} } func (item *Normal) Update() { item.sellIn -= 1 if item.quality <= 0 { return } item.quality -= 1 if item.sellIn <= 0 { item.quality -= 1 } return }
  134. GO NORTHWEST 2018 package items type Normal struct { Default

    } func NewNormal(params Params) Item { return &Normal{params} } func (item *Normal) Update() { item.sellIn -= 1 if item.quality <= 0 { return } item.quality -= 1 if item.sellIn <= 0 { item.quality -= 1 } return }
  135. GO NORTHWEST 2018 package items type Normal struct { Default

    } func NewNormal(name string, sellIn, quality int) Item { return &Normal{Default{name, sellIn, quality}} } func (item *Normal) Update() { item.sellIn -= 1 if item.quality <= 0 { return } item.quality -= 1 if item.sellIn <= 0 { item.quality -= 1 } return }
  136. GO NORTHWEST 2018 package items type Item interface { Name()

    string SellIn() int Quality() int Update() } type Params struct { name string sellIn, quality int } type Factory func(Params) Item var Factories = map[string]Factory{ "Normal": NewNormal, "Aged Brie": NewBrie, "Backstage passes to a TAFKAL80ETC concert": NewBackstagePass, } ...
  137. GO NORTHWEST 2018 package items type Item interface { Name()

    string SellIn() int Quality() int Update() } type Factory func(Params) Item var Factories = map[string]Factory{ "Normal": NewNormal, "Aged Brie": NewBrie, "Backstage passes to a TAFKAL80ETC concert": NewBackstagePass, } ...
  138. GO NORTHWEST 2018 package items type Item interface { Name()

    string SellIn() int Quality() int Update() } type Factory func(Params) Item var Factories = map[string]Factory{ "Normal": NewNormal, "Aged Brie": NewBrie, "Backstage passes to a TAFKAL80ETC concert": NewBackstagePass, } func ItemFactory(name string, sellIn, quality int) Item { params := Params{name, sellIn, quality} itemFactory, ok := Factories[name] if !ok { itemFactory = NewDefault } item := itemFactory(params) return item }
  139. GO NORTHWEST 2018 package items type Item interface { Name()

    string SellIn() int Quality() int Update() } type Factory func(Params) Item var Factories = map[string]Factory{ "Normal": NewNormal, "Aged Brie": NewBrie, "Backstage passes to a TAFKAL80ETC concert": NewBackstagePass, } func ItemFactory(name string, sellIn, quality int) Item { params := Params{name, sellIn, quality} itemFactory, ok := Factories[name] if !ok { itemFactory = NewDefault } item := itemFactory(params) return item }
  140. GO NORTHWEST 2018 package items type Item interface { Name()

    string SellIn() int Quality() int Update() } type Factory func(Params) Item var Factories = map[string]Factory{ "Normal": NewNormal, "Aged Brie": NewBrie, "Backstage passes to a TAFKAL80ETC concert": NewBackstagePass, } func ItemFactory(name string, sellIn, quality int) Item { itemFactory, ok := Factories[name] if !ok { itemFactory = NewDefault } item := itemFactory(name, sellIn, quality) return item }
  141. GO NORTHWEST 2018 package main var inventory = []items.Item{ ItemFactory("+5

    Dexterity Vest", 10, 20), ItemFactory("Aged Brie", 2, 0), ItemFactory("Chunky Bacon", 5, 7), ItemFactory("Sulfuras, Hand of Ragnaros", 0, 80), ItemFactory("Backstage passes to a TAFKAL80ETC concert", 15, 20), ItemFactory("Conjured Mana Cake", 3, 6), } func main() { GildedRose() } func GildedRose() { for i := 0; i < len(inventory); i++ { item := inventory[i] item.Update() } } DON’T HAVE TO CHANGE ANYTHING!
  142. GO NORTHWEST 2018 package items type ConjuredMana struct { Default

    } // Add factory func NewConjuredMana(name string, sellIn, quality int) Item { return &ConjuredMana{Default{name, sellIn, quality}} }
  143. GO NORTHWEST 2018 package items type ConjuredMana struct { Default

    } func NewConjuredMana(name string, sellIn, quality int) Item { return &ConjuredMana{Default{name, sellIn, quality}} } func (item *ConjuredMana) Update() { item.sellIn -= 1 if item.quality <= 0 { return } item.quality -= 2 if item.sellIn <= 0 { item.quality -= 2 } return }
  144. GO NORTHWEST 2018 package items type Item interface { Name()

    string SellIn() int Quality() int Update() } type Factory func(Params) Item var Factories = map[string]Factory{ "Normal": NewNormal, "Aged Brie": NewBrie, "Backstage passes to a TAFKAL80ETC concert": NewBackstagePass, } func ItemFactory(name string, sellIn, quality int) Item { itemFactory, ok := Factories[name] if !ok { itemFactory = NewDefault } item := itemFactory(name, sellIn, quality) return item }
  145. GO NORTHWEST 2018 package items type Item interface { Name()

    string SellIn() int Quality() int Update() } type Factory func(Params) Item var Factories = map[string]Factory{ "Normal": NewNormal, "Aged Brie": NewBrie, "Backstage passes to a TAFKAL80ETC concert": NewBackstagePass, "Conjured Mana Cake": NewConjuredMana, } func ItemFactory(name string, sellIn, quality int) Item { itemFactory, ok := Factories[name] if !ok { itemFactory = NewDefault } item := itemFactory(name, sellIn, quality) return item }
  146. GO NORTHWEST 2018 === RUN TestConjuredMana_BeforeSellDate --- PASS: TestConjuredMana_BeforeSellDate (0.00s)

    === RUN TestConjuredMana_BeforeSellDate_WithMinQuality --- PASS: TestConjuredMana_BeforeSellDate_WithMinQuality (0.00s) === RUN TestConjuredMana_OnSellDate --- PASS: TestConjuredMana_OnSellDate (0.00s) === RUN TestConjuredMana_OnSellDate_WithMinQuality --- PASS: TestConjuredMana_OnSellDate_WithMinQuality (0.00s) === RUN TestConjuredMana_AfterSellDate --- PASS: TestConjuredMana_AfterSellDate (0.00s) === RUN TestConjuredMana_AfterSellDate_WithMinQuality --- PASS: TestConjuredMana_AfterSellDate_WithMinQuality (0.00s) PASS ok gilded_rose 0.006s "
  147. GO NORTHWEST 2018 OBJECT-ORIENTATION IN GO ▸ Go structs can

    be conceptualized as a set of responsibilities ▸ Inheritance is possible through the use of interfaces and embedding ▸ Interfaces represent the specification of the object ▸ Embedding represents a portable encapsulation of a set of data/ behavior ▸ Namespacing can be achieved via packages
  148. " "

  149. “GIVE ME SIX HOURS TO CHOP DOWN A TREE, AND

    I WILL SPEND THE FIRST FOUR SHARPENING THE AXE.” — Abraham Lincoln
  150. “GIVE A DEVELOPER SIX HOURS TO CHOP DOWN A TREE,

    AND THEY WILL SPEND THE FIRST TWELVE SHARPENING THE AXE.” — also Abraham Lincoln
  151. GO NORTHWEST 2018 THANK YOU! Eric Hodel (@drbrain) Sam Karp

    (@samuelkarp) Allison Stanko (@allisaurus) Wesley Pettit (@pettitwesley) Elliot Isaacson Kate Fulton Lito Nicolai
  152. GO NORTHWEST 2018 RESOURCES ▸ Design Patterns: Elements of Object-Oriented

    Software, by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. ▸ Design Patterns Explained: A New Perspective on Object-Oriented Design, by Alan Shalloway and James R. Trott ▸ All the Little Things, Sandi Metz: https://confreaks.tv/videos/ railsconf2014-all-the-little-things ▸ https://xkcd.com/1428/