Slide 1

Slide 1 text

A RUBYIST’S (POIGNANT) GUIDE TO GO HSING-HUI HSU @SOMANYHS

Slide 2

Slide 2 text

GO NORTHWEST 2018

Slide 3

Slide 3 text

GO NORTHWEST 2018 RUBY! GO NORTHWEST 2018

Slide 4

Slide 4 text

GO NORTHWEST 2018 RUBY!

Slide 5

Slide 5 text

GO NORTHWEST 2018 GO!

Slide 6

Slide 6 text

"

Slide 7

Slide 7 text

GO NORTHWEST 2018 THINGS I LEARNED FROM RUBY ▸Objects are your friend ▸Duck typing ▸Test-Driven Development ✅ ▸Developer happiness

Slide 8

Slide 8 text

GO NORTHWEST 2018 ▸Static types?! ▸No objects?! ▸No meta programming?! ▸…No developer happiness?? FROM RUBY TO GO

Slide 9

Slide 9 text

OBJECT-ORIENTED DESIGN

Slide 10

Slide 10 text

WHAT ARE OBJECTS?

Slide 11

Slide 11 text

OBJECTS 
 ENCAPSULATION OF DATA + BEHAVIOR USED TO INTERACT WITH THAT DATA BUT THAT’S NOT ALL!

Slide 12

Slide 12 text

‣ 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

Slide 13

Slide 13 text

HOW TO THINK ABOUT OBJECTS IN GO?

Slide 14

Slide 14 text

GILDED ROSE KATA

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

THE LEGACY CODE

Slide 19

Slide 19 text

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() } ...

Slide 20

Slide 20 text

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 } } } } } // ...

Slide 21

Slide 21 text

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 } } } } }

Slide 22

Slide 22 text

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 } } } } }

Slide 23

Slide 23 text

HOW DID WE GET IN THIS MESS?

Slide 24

Slide 24 text

“IF YOU KNOW THE ENEMY AND KNOW YOURSELF, YOU NEED NOT FEAR THE RESULT OF A HUNDRED BATTLES.” -Sun Tzu, The Art of War

Slide 25

Slide 25 text

I WANTED TO MAKE MY OWN MESS

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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! "

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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 } }

Slide 32

Slide 32 text

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 } } }

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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 } } }

Slide 35

Slide 35 text

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 } } }

Slide 36

Slide 36 text

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 } } } }

Slide 37

Slide 37 text

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 "

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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 } } } }

Slide 40

Slide 40 text

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 } } } }

Slide 41

Slide 41 text

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 } } } } }

Slide 42

Slide 42 text

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 } } } } }

Slide 43

Slide 43 text

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 } } } } }

Slide 44

Slide 44 text

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 "

Slide 45

Slide 45 text

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 } } } }

Slide 46

Slide 46 text

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 } } } } }

Slide 47

Slide 47 text

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 } } } } } }

Slide 48

Slide 48 text

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 }

Slide 49

Slide 49 text

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 } }

Slide 50

Slide 50 text

GO NORTHWEST 2018 HOW DID WE MAKE SUCH A MESS? ▸Relatively Easy ▸Cheap ▸Abstraction was not yet clear

Slide 51

Slide 51 text

BUT AT SOME POINT WE HAVE TO BALANCE DELIVERY WITH MAINTAINABILITY

Slide 52

Slide 52 text

HAVE EMPATHY FOR THE PROCESS AND THE DEVELOPERS WHO CAME BEFORE YOU (BECAUSE SOMETIMES THAT DEVELOPER WAS YOU)

Slide 53

Slide 53 text

HOW DO WE FIX IT?

Slide 54

Slide 54 text

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 } } } } }

Slide 55

Slide 55 text

OBJECTS 
 ENCAPSULATION OF DATA + BEHAVIOR USED TO INTERACT WITH THAT DATA

Slide 56

Slide 56 text

OBJECTS 
 ENCAPSULATION OF DATA + BEHAVIOR USED TO INTERACT WITH THAT DATA

Slide 57

Slide 57 text

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 } }

Slide 58

Slide 58 text

GO NORTHWEST 2018 func update_normal(item *Item) { return }

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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 } } } } } }

Slide 61

Slide 61 text

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 }

Slide 62

Slide 62 text

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 "

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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 }

Slide 66

Slide 66 text

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 "

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

GO NORTHWEST 2018 func update_sulfuras(item *Item) { return }

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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 }

Slide 73

Slide 73 text

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?

Slide 74

Slide 74 text

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() } ...

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

GO NORTHWEST 2018 func update_default(item *Item) { return }

Slide 77

Slide 77 text

GO NORTHWEST 2018 func update_sulfuras(item *Item) { return }

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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]) } } }

Slide 82

Slide 82 text

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 } }

Slide 83

Slide 83 text

GO NORTHWEST 2018 $ go test PASS ok gilded_rose 0.006s "

Slide 84

Slide 84 text

ADDING THE NEW FEATURE…

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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 } }

Slide 87

Slide 87 text

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 } }

Slide 88

Slide 88 text

SOMETHING FEELS WRONG

Slide 89

Slide 89 text

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 } }

Slide 90

Slide 90 text

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 } }

Slide 91

Slide 91 text

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 } }

Slide 92

Slide 92 text

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 } } ❌

Slide 93

Slide 93 text

ENCAPSULATION WITHOUT OBJECT-ORIENTATION

Slide 94

Slide 94 text

SOLID DESIGN

Slide 95

Slide 95 text

SOLID DESIGN

Slide 96

Slide 96 text

OPEN/CLOSED: OPEN FOR EXTENSION CLOSED FOR MODIFICATION

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

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

Slide 99

Slide 99 text

INHERITANCE (…IN GO?!)

Slide 100

Slide 100 text

"

Slide 101

Slide 101 text

GO NORTHWEST 2018 type Item struct { name string sellIn, quality int }

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

EMBEDDING

Slide 104

Slide 104 text

COMPOSITION -

Slide 105

Slide 105 text

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

Slide 106

Slide 106 text

‣ 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

Slide 107

Slide 107 text

USING INTERFACES AS SPECIFICATION FOR OBJECTS

Slide 108

Slide 108 text

GO NORTHWEST 2018 type Item struct { name string sellIn int quality int }

Slide 109

Slide 109 text

GO NORTHWEST 2018 type Item interface { name string sellIn int quality int }

Slide 110

Slide 110 text

GO NORTHWEST 2018 type Item interface { Name() string SellIn() int Quality() int }

Slide 111

Slide 111 text

GO NORTHWEST 2018 type Item interface { Name() string SellIn() int Quality() int Update() }

Slide 112

Slide 112 text

CONCRETE IMPLEMENTATION OF OBJECT INTERFACE

Slide 113

Slide 113 text

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

Slide 114

Slide 114 text

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 }

Slide 115

Slide 115 text

GO NORTHWEST 2018 func (item *Normal) Update() { }

Slide 116

Slide 116 text

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 }

Slide 117

Slide 117 text

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 }

Slide 118

Slide 118 text

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}, }

Slide 119

Slide 119 text

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

Slide 120

Slide 120 text

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

Slide 121

Slide 121 text

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}, }

Slide 122

Slide 122 text

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}, }

Slide 123

Slide 123 text

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 } }

Slide 124

Slide 124 text

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 } }

Slide 125

Slide 125 text

GO NORTHWEST 2018 func update_normal(p *Params) { item := Normal{p.name, p.sellIn, p.quality} item.Update() }

Slide 126

Slide 126 text

SOMETHING FEELS WRONG

Slide 127

Slide 127 text

GO NORTHWEST 2018 func update_normal(p *Params) { item := Normal{p.name, p.sellIn, p.quality} item.Update() }

Slide 128

Slide 128 text

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

Slide 129

Slide 129 text

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 } }

Slide 130

Slide 130 text

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 } }

Slide 131

Slide 131 text

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}, }

Slide 132

Slide 132 text

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}, }

Slide 133

Slide 133 text

FACTORY PATTERN

Slide 134

Slide 134 text

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}, }

Slide 135

Slide 135 text

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), }

Slide 136

Slide 136 text

“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.” — .. ..

Slide 137

Slide 137 text

GO NORTHWEST 2018 type Factory func(string, int, int) Item

Slide 138

Slide 138 text

GO NORTHWEST 2018 type Factory func(string, int, int) Item // Normal{p.name, p.sellIn, p.quality}

Slide 139

Slide 139 text

GO NORTHWEST 2018 type Factory func(string, int, int) Item func NewNormal(name string, sellIn, quality int) Item { return &Normal{name, sellIn, quality} }

Slide 140

Slide 140 text

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

Slide 141

Slide 141 text

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

Slide 142

Slide 142 text

GO NORTHWEST 2018 type Factory func(Params) Item func NewNormal(params Params) Item { return &Normal{params} }

Slide 143

Slide 143 text

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} }

Slide 144

Slide 144 text

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 } }

Slide 145

Slide 145 text

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 } }

Slide 146

Slide 146 text

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 } }

Slide 147

Slide 147 text

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 }

Slide 148

Slide 148 text

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 }

Slide 149

Slide 149 text

REGISTER FACTORIES

Slide 150

Slide 150 text

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 }

Slide 151

Slide 151 text

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 }

Slide 152

Slide 152 text

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 }

Slide 153

Slide 153 text

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

Slide 154

Slide 154 text

GO NORTHWEST 2018 func GildedRose() { for i := 0; i < len(items); i++ { item := items[i] item.Update() } }

Slide 155

Slide 155 text

WHERE WE ARE SO FAR

Slide 156

Slide 156 text

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}, }

Slide 157

Slide 157 text

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), }

Slide 158

Slide 158 text

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 }

Slide 159

Slide 159 text

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 }

Slide 160

Slide 160 text

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 }

Slide 161

Slide 161 text

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 } // …

Slide 162

Slide 162 text

GO NORTHWEST 2018 func GildedRose() { for i := 0; i < len(items); i++ { item := items[i] item.Update() } }

Slide 163

Slide 163 text

A NOTE ON CODE ORGANIZATION

Slide 164

Slide 164 text

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() } }

Slide 165

Slide 165 text

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 }

Slide 166

Slide 166 text

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)

Slide 167

Slide 167 text

PACKAGES AS OBJECT NAMESPACES

Slide 168

Slide 168 text

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 }

Slide 169

Slide 169 text

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 }

Slide 170

Slide 170 text

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 }

Slide 171

Slide 171 text

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 }

Slide 172

Slide 172 text

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() } }

Slide 173

Slide 173 text

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

Slide 174

Slide 174 text

BUT WAIT, THERE’S MORE!

Slide 175

Slide 175 text

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 }

Slide 176

Slide 176 text

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 }

Slide 177

Slide 177 text

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 {

Slide 178

Slide 178 text

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

Slide 179

Slide 179 text

INHERITANCE USING EMBEDDING

Slide 180

Slide 180 text

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

Slide 181

Slide 181 text

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} } ...

Slide 182

Slide 182 text

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 }

Slide 183

Slide 183 text

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 }

Slide 184

Slide 184 text

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 }

Slide 185

Slide 185 text

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 }

Slide 186

Slide 186 text

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 }

Slide 187

Slide 187 text

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 }

Slide 188

Slide 188 text

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 }

Slide 189

Slide 189 text

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, } ...

Slide 190

Slide 190 text

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, } ...

Slide 191

Slide 191 text

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 }

Slide 192

Slide 192 text

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 }

Slide 193

Slide 193 text

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 }

Slide 194

Slide 194 text

FINALLY…

Slide 195

Slide 195 text

…ADDING THE NEW FEATURE…

Slide 196

Slide 196 text

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!

Slide 197

Slide 197 text

GO NORTHWEST 2018 package items type ConjuredMana struct { }

Slide 198

Slide 198 text

GO NORTHWEST 2018 package items type ConjuredMana struct { Default }

Slide 199

Slide 199 text

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}} }

Slide 200

Slide 200 text

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 }

Slide 201

Slide 201 text

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 }

Slide 202

Slide 202 text

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 }

Slide 203

Slide 203 text

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 "

Slide 204

Slide 204 text

WHAT HAVE WE LEARNED?

Slide 205

Slide 205 text

OBJECT-ORIENTATION IS POSSIBLE IN GO

Slide 206

Slide 206 text

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

Slide 207

Slide 207 text

" "

Slide 208

Slide 208 text

OBJECT ORIENTATION IS ONE TOOL THAT CAN BE USED TO MAKE CODE MORE MAINTAINABLE

Slide 209

Slide 209 text

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

Slide 210

Slide 210 text

“GIVE A DEVELOPER SIX HOURS TO CHOP DOWN A TREE, AND THEY WILL SPEND THE FIRST TWELVE SHARPENING THE AXE.” — also Abraham Lincoln

Slide 211

Slide 211 text

“MOVE FAST AND BREAK THINGS” — Capitalism

Slide 212

Slide 212 text

DEVELOPERS WANT TO MOVE FAST

Slide 213

Slide 213 text

BUT WE DON’T WANT TO BREAK THINGS

Slide 214

Slide 214 text

FALLACY: PAYING DOWN TECH DEBT IS THE OPPOSITE OF MOVING FAST

Slide 215

Slide 215 text

GOOD ENGINEERS INVEST IN MAINTAINABLE CODE IN ORDER TO MOVE FAST

Slide 216

Slide 216 text

DEVELOPER HAPPINESS "

Slide 217

Slide 217 text

GO NORTHWEST 2018 THANK YOU! Eric Hodel (@drbrain) Sam Karp (@samuelkarp) Allison Stanko (@allisaurus) Wesley Pettit (@pettitwesley) Elliot Isaacson Kate Fulton Lito Nicolai

Slide 218

Slide 218 text

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/

Slide 219

Slide 219 text

HSING-HUI HSU @SOMANYHS