Slide 1

Slide 1 text

GoݴޠͰ࡞ΒΕͨ APIͷϨΨγʔίʔυͱઓͬͨ࿩ Go#Conference#2015#winter @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 1

Slide 2

Slide 2 text

ࣗݾ঺հ • Twi%er:)@k_yokomi)ʢ͖ΐ͜Έʣ※1 • ࢓ࣄ͸GoͰAPIॻ͍ͯ·͢(1೥͘Β͍) • ੲ͸Cocos2d

Slide 3

Slide 3 text

աڈʹ࡞ͬͨ΋ͷ঺հ1 • github.com/kyokomi/slackbot • slackઐ༻ͷGo੡ͷhubot • ϓϥάΠϯ௥Ճ͠΍͍͢Α͏ʹͯ͠Δͭ΋Γ • github.com/kyokomi/emoji • λʔϛφϧֆจࣈϥΠϒϥϦ • ૣ͍ऀউͪͰ࡞ͬͨײ͡ɻελʔ70௒͑ͨ7⭐ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 3

Slide 4

Slide 4 text

աڈʹ࡞ͬͨ΋ͷ঺հ2 • github.com/kyokomi/go/docomo/docomo • docomoͷAPIϥΠϒϥϦʢࡶஊɺ஌ࣝQ&Aͱ͔ରԠʣ • github.com/kyokomi/goma • DBΞΫηεϑϨʔϜϫʔΫతͳ෺(JavaͷdomaΠϯεύΠΞ) • ҰԠɺখن໛ͳϓϩμΫγϣϯͰ࢖ͬͯΔ • ՝୊͕ଟ͘ɻݱঢ়ͷར༻͸Φεεϝ͠ͳ͍...=! @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 4

Slide 5

Slide 5 text

໨࣍ • ϨΨγʔίʔυ͍ͭͯ • ࣮ࡍʹग़ձͬͨϨΨγʔίʔυͷ঺հ • ϨΨγʔίʔυվળͷͨΊʹ΍ͬͨ͜ͱΛ঺հ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 5

Slide 6

Slide 6 text

ϨΨγʔίʔυʹ͍ͭͯ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 6

Slide 7

Slide 7 text

ϨΨγʔίʔυʹ͍ͭͯ • ۀքͰҰൠతͳղऍ • ॻ੶:#ϨΨγʔίʔυվળΨΠυͷղऍ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 7

Slide 8

Slide 8 text

ۀքͰҰൠతͳղऍ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 8

Slide 9

Slide 9 text

!!ཧղͰ͖ͣ!! มߋͷ೉͍͠ίʔυΛࢦ͢ଏޠɻ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 9

Slide 10

Slide 10 text

ཧղͰ͖ͣɺมߋͷ೉͍͠ίʔυΛࢦ͢ଏޠ • ಺༰͕ෳࡶͰԿΛ͍ͯ͠Δͷ͔Α͘෼͔Βͣɺ·ͱ΋ͳ࢓༷ॻ ΋ͳ͍ • ౓ॏͳΔ࢓༷มߋͰख͕Ճ͑ΒΕͨίʔυ͸ࠞཚ͠ɺ؆୯ͳػ ೳ௥ՃͰ͋ͬͯ΋ଟ͘ͷ࿑ྗͱ࣌ؒΛඞཁͱ͢Δঢ়ଶͳͲ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 10

Slide 11

Slide 11 text

ॻ੶ ʮϨΨγʔίʔυվળ ΨΠυʯͷղऍ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 11

Slide 12

Slide 12 text

!!୯ʹςετ͕ͳ͍ίʔυ!! @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 12

Slide 13

Slide 13 text

୯ʹςετ͕ͳ͍ίʔυ ςετͷͳ͍ίʔυ͸ѱ͍ίʔυͰ͋ΔɻͲΕ͚ͩ͏·͘ॻ͔Ε ͍ͯΔ͔͸ؔ܎ͳ͍ɻͲΕ͚ͩඒ͍͔͠ɺΦϒδΣΫτࢦ޲͔ɺ ͖ͪΜͱΧϓηϧԽ͞Ε͍ͯΔ͔͸ؔ܎ͳ͍ɻςετ͕͋Ε͹ɺ ݕূ͠ͳ͕Βίʔυͷಈ͖Λૉૣ͘มߋ͢Δ͜ͱ͕Ͱ͖Δɻςε τ͕ͳ͚Ε͹ɺίʔυ͕ྑ͘ͳ͍ͬͯΔͷ͔ѱ͘ͳ͍ͬͯΔͷ͔ ͕ຊ౰ʹΘ͔Βͳ͍ɻ※2 ※2"ϨΨγʔίʔυվળΨΠυͷʮ͸͡ΊʹʯͷจষΑΓ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 13

Slide 14

Slide 14 text

ϨΨγʔίʔυͱରቂͨ࣌͠ͷ2୒ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 14

Slide 15

Slide 15 text

ฤूͯ͠فΔ!!!͔ อޢͯ͠มߋ͢Δ!!!͔ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 15

Slide 16

Slide 16 text

ฤूͯ͠فΔ!!!※3 ʮฤूͯ͠فΔʯ͸ɺطଘͷίʔυΛ஫ҙਂ͘ௐ΂ͳ͕Βमਖ਼͢Δํ๏Ͱ͢ɻ ͜ͷ৔߹ͷखॱΛ૝૾ͯ͠Έ·͠ΐ͏ɻ ·ͣ͸εςοϓ͝ͱʹԿ͕ى͜Δ͔Λ໌֬ʹཧղ͠ɺίʔυมߋͷӨڹൣғΛ೺Ѳ͠·͢ɻ ࣍ʹɺ࣌ؒΛ͔͚ͯ஫ҙਂ͘ίʔυΛॻ͖ɺίʔυมߋ͕͢΂ͯऴΘͬͨΒɺفΔؾ࣋ͪͰಈ͔ͯ͠Έ·͢ɻ ͦͷ݁Ռ͸ʮ͋Εʁ มߋՕॴ͸େৎ෉͚ͩͲ……ผͷػೳ͕ಈ͔ͳ͘ͳͬͯ͠·ͬͨ……ʯɻ ʮ஫ҙΛΑΓଟ͘෷͔ͬͨΒͱ͍ͬͯɺඞͣ͠΋ͦΕʹൺྫͯ҆͠શੑ͕޲্͢Δͱ͸ݶΒͳ͍ʯͱஶऀ͸ڧ͘ड़΂͍ͯ·͢ɻ طଘίʔυʹखΛೖΕΔࡍʹ͸ɺʮ࢒ΓͷৼΔ෣͍Λม͑ͣʹࡁ·ͤΔ͜ͱ͕Ͱ͖Δ͔͕ॏཁʯͰ͕͢ɺ஫ҙਂ͍͚ͩͰ͸ɺ ଞͷ෦෼ʹӨڹ͕ٴΜͰ͍Δ͔Ͳ͏͔·Ͱ͸࠷ޙʹಈ͔ͯ͠Έͳ͍ͱ෼͔Γ·ͤΜɻ ͲΜͳʹ஫ҙਂ͘ਐΊͯ΋ɺ݁ہ͸ʮฤूͯ͠فΔʯ͜ͱʹͳͬͯ͠·͍·͢ɻ ※3"CodeZineʮϨΨγʔίʔυվળΨΠυʯͷεεϝΑΓ"h+p:/ /codezine.jp/ar5cle/detail/4103 @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 16

Slide 17

Slide 17 text

อޢͯ͠ฤू͢Δ!!!※3 ΋͏1ͭͷʮอޢͯ͠มߋ͢Δʯ͸ɺςετΛ༻ҙͨ͠͏͑ͰطଘͷίʔυΛमਖ਼͢Δํ๏Ͱ͢ɻ ίʔυͷมߋ͕೉͍͠ཧ༝ΛΑ͘ߟ͑ͯΈΔͱɺςετ͕͋Ε͹ίʔυͷมߋ͕؆୯ʹͳΔͱ͍͏ɺ ҙ֎ͱ୯७ͳ͜ͱʹؾ͕͖ͭ·͢ɻ ΋͠ɺมߋ͍ͯ͠Δ࠷தʹ͏·͘มߋͰ͖͍ͯΔ͔Ͳ͏͔ɺ ଞͷ෦෼ʹӨڹ͕ٴΜͰ͍ͳ͍͔Ͳ͏͔Λ֬ೝ͢Δखஈ͕͋ͬͨͱͨ͠ΒͲ͏ͳΔͰ͠ΐ͏͔ɻ ͦͷ৔߹͸ɺগ͠มߋΛͯ͠ɺେৎ෉͔Ͳ͏͔Λ֬ೝͯ͠ɺ ·ͨগ͠มߋΛͯ͠ɺͱ͍͏࡞ۀΛ܁Γฦ͠ͳ͕ΒਐΊΔ͜ͱ͕ՄೳʹͳΓ·͢ɻ ※3"CodeZineʮϨΨγʔίʔυվળΨΠυʯͷεεϝΑΓ"h+p:/ /codezine.jp/ar5cle/detail/4103 @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 17

Slide 18

Slide 18 text

Ҏ্Λ౿·͑ͯ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 18

Slide 19

Slide 19 text

ࠓճࣗ෼͕࿩͢ ϨΨγʔίʔυ͸ɾɾɾ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 19

Slide 20

Slide 20 text

࢓༷͕ཧղͰ͖ͣɺมߋ͕೉͘͠ ςετίʔυ͕ͳ͍GoͰ͢#! @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 20

Slide 21

Slide 21 text

͜ͷ1೥ APIαʔόʔΛGoͰॻ͍͍ͯͯ ࣮ࡍʹ͋ͬͨϨΨγʔίʔυΛ঺հ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 21

Slide 22

Slide 22 text

※஫ҙࣄ߲ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 22

Slide 23

Slide 23 text

Goʹ͋·Γؔ܎ͳ͍಺༰΋͋Γ·͢ ͦΜͳ౰ͨΓલͷઃܭ΋ͯ͠ͳ͍ͷʁͱ͍͏ Α͏ͳ಺༰΋͋Γ·͢ ͝༰͍ࣻͩ͘͞!!!!!!!!!! @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 23

Slide 24

Slide 24 text

ʊਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓʊ ʼɹςετίʔυ͕΄ͱΜͲͳ͍ɹʻ ʉY^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Yʉ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 24

Slide 25

Slide 25 text

ग़Φνײ͋Γ·͕͢... • ͋Δʹ͸͋Δ͕ɺtestίʔυ͔Β࢓༷͕ಡΈऔΕͳ͍ • ϝιουΛݺͼͩͤΔͷΛ֬ೝ͢Δ͚͕ͩ໨తʹͳ͍ͬͯΔ • Test͕௨Βͳͯ͘ίϝϯτΞ΢τ͞Ε͍ͯͨΓ • ͦ΋ͦ΋ςετίʔυ͕ͳ͍ύοέʔδ΋ଟʑ͋Γ • globalม਺Λ͋ͪͪ͜Ͱ࢖͍ͬͯΔͨΊMock͕೉͍͠ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 25

Slide 26

Slide 26 text

ରॲޙ ͺͬͱݟͰෆཁʹͳΓͦ͏ͳίʔυ΍ϦϑΝΫλϦϯάޙεϚʔ τʹςετॻ͚ͦ͏ɾɾɾͱ͍͏ࢥ͍Λ͙ͬͱת͑Δɻ • ແବʹͳΔ͔΋͠Εͳ͍͕Ұ୴ςετίʔυΛॻ͘ • ॻ͍ͨςετίʔυͰ࢓༷Λຬ͍ͨͤͯΔ͔ෆ͕҆ͩفΔ • ϦϑΝΫλϦϯά͢Δ • ෆཁͳͬͨςετίʔυΛফ͢ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 26

Slide 27

Slide 27 text

ςετίʔυ͕΄ͱΜͲͳ͍ ࣮͸ɺ͠͹Β͘खΛग़͢ͷ͕ڪΖͯ͘͠ɺΘ͔ͬͯ͸͍Δ΋ͷͷ ϦϑΝΫλϦϯά͸͍ͯ͠·ͤΜͰͨ͠ɻ ͳͷͰςετίʔυ΋ಉ༷ʹखग़͠Ͱ͖ͣɺ೔ʑͷӡ༻Ͱػೳ௥ Ճ΍վमͰͻͨ͢Βݕূͯ͠فΔΑ͏ʹσϓϩΠͯ͠·ͨ͠ɻ ͜ͷঢ়گΛվળ͢ΔͨΊͷࢼΈ͸ɺޙ൒Ͱ΋͏Ұ౓঺հ͠·͢ɻ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 27

Slide 28

Slide 28 text

ʊਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓਓʊ ʼɹϩʔΧϧϑΝΠϧಡΈࠐΈ·͘Γɹʻ ʉY^Y^Y^Y^Y^Y^Y^YY^Y^Y^Y^Y^Y^Yʉ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 28

Slide 29

Slide 29 text

ϩʔΧϧϑΝΠϧಡΈࠐΈ·͘Γ RedisΛϚελʔσʔλతͳ࢖͍͔ͨ͢ΔΑΓ͸શવྑ͍ʂ ͕ɾɾɾ͔͠͠ɻɻɻ ͦͷϩʔΧϧϑΝΠϧมߋස౓ߴ͍ͷͰɺϑΝΠϧ͚͍ͩͬͯ͡ deploy͢Δ͜ͱ͕ଟʑ͋Γɻ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 29

Slide 30

Slide 30 text

ରॲޙ • ϩʔΧϧͱಉ͡ߏ੒ͷAmazon(S3͔ΒಡΈࠐΉΑ͏ʹमਖ਼ • ϑΥʔϧόοΫઌͱͯ͠ϩʔΧϧϑΝΠϧΛಡΈࠐΉʹमਖ਼ • ϑΥʔϧόοΫͯ͠Δ͜ͱΛairbrake౳ͷΤϥʔ௨஌αʔϏεʹ ௨஌ʢϥΠϒϥϦ͸(github.com/airbrake/gobrakeʣ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 30

Slide 31

Slide 31 text

ରॲޙʢίʔυྫʣ // ٖࣅίʔυͰ͢ʢ͜ΜͳΠϝʔδʣ data, err := AmazonS3.Get(bucketName, filePath) if err != nil { // airbrake͢Δ data, err = Local.Get("filePath") if err != nil { // ී௨ʹerror } } @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 31

Slide 32

Slide 32 text

ʊਓਓਓਓਓਓਓਓਓਓਓਓਓʊ ʼɹerrorΛѲΓͭͿͯ͠Δɹʻ ʉY^Y^Y^Y^Y^Y^Y^YY^Y^Y^ʉ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 32

Slide 33

Slide 33 text

errorΛѲΓͭͿͯ͠Δ data, _ := json.Marshal(resp.Body) if data == nil { // ... } !!!!!!! @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 33

Slide 34

Slide 34 text

ରॲޙ ී௨ʹΤϥʔϋϯυϦϯάɻ৔߹ʹΑͬͯ͸Airbrake౳Ͱ௨஌ɻ data, err := json.Marshal(resp.Body) if err != nil { return fmt.Errorf("XXXXͷjsonͷMarshalͰࣦഊͯ͠Δ %s", err) } if data == nil { // ... } @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 34

Slide 35

Slide 35 text

ʊਓਓਓਓਓਓਓਓਓʊ ʼɹgorou%neཚ༻ɹʻ ʉY^Y^Y^Y^Y^Y^Y^Yʉ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 35

Slide 36

Slide 36 text

gorou%neͷཚ༻ ฒߦॲཧͯ͠΋େৎ෉ͦ͏ͱ͍͏ཧ༝Ͱ ΊͪΌͪ͘Όgorou%neΛ࢖͍ͬͯΔɻ WaitGroupͱChannelΛ͋ͪͪ͜Ͱ౉ͯ͠ ࢖͍ͬͯͯɺͺͬͱݟԿ͍ͨ͠ͷ͔Θ͔ Β͵Ͱ͟͝ΔΑɾɾɾ ʢͦ΋ͦ΋ઃܭ͕͓͔͍͠ؾ͕͢Δʣ var wg sync.WaitGroup dataCh := make(chan string) for _, t := range hogeList { // ... লུ ... go hoge(dataCh, &wg) for _, c := range t.Contents { // ... লུ ... wg.Add(1) go func() { source(dataCh, c) wg.Done() }() } } wg.Wait() close(dataCh) @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 36

Slide 37

Slide 37 text

ରॲʁޙ ຊ౰ʹύϑΥʔϚϯε͕ཁٻ͞ΕΔ࢓༷͔֬ೝͯ͠ɺҰ୴͸ී௨ ʹ૊ΜͰΈΑ͏ɻ ΋͠Ծʹੑೳཁ͕݅ຬͨͤͳ͍ͱͨ͠Βɺ ϕϯνϚʔΫΛͱ͔ͬͯΒ͜͏͍͏վम·ͨ͸ઃܭΛมߋ͢Δํ ޲Ͱɾɾɾͱ་͢ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 37

Slide 38

Slide 38 text

ʊਓਓਓਓਓਓਓਓਓਓਓਓਓਓʊ ʼɹύοέʔδ෼͚೉͍͠໰୊ɹʻ ʉY^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Yʉ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 38

Slide 39

Slide 39 text

ࣾ಺ڞ௨ϥΠϒϥϦతͳڞ௨ύοέʔδ APIͷϦϙδτϦͱ͸ผͰɺ$go get͍ͯͨࣾ͠಺GoϓϩδΣΫ τڞ௨ϥΠϒϥϦతͳ΋ͷɻʢͩͬͨ΋ͷ...ʣ ݁ߏAPIʹґଘͨ͠ίʔυ͕ଟ͘ɻ͜ͷϥΠϒϥϦ͚ͩΛվमͯ͠ ϦϦʔε$͜ͱ΋ଟʑ͋ͬͨɻ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 39

Slide 40

Slide 40 text

ࣾ಺ڞ௨ϥΠϒϥϦతͳڞ௨ύοέʔδ ├── gocommon // ࣾ಺ڞ௨ϥΠϒϥϦͷϦϙδτϦ │ ├── airbrake // ࣾ಺GoϓϩδΣΫτͰڞ௨ͷϥΠϒϥϦ │ ├── aws │ ├── db │ ├── logger │ ├── xxxx // hoge-apiͰ͔͠࢖Θͳ͍Α͏ͳڞ௨ॲཧ܈ │ ├── yyyy │ └── zzzz └── hoge-api // apiͷϦϙδτϦʢgocommonόϦόϦ࢖͏ʣ ├── aaaa └── bbbb @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 40

Slide 41

Slide 41 text

APIґଘ͍ͯ͠Δ΋ͷΛinternalԼʹҠಈͨ͠ ├── gocommon // ࣾ಺ڞ௨ϥΠϒϥϦͷϦϙδτϦ │ ├── airbrake // ࣾ಺GoϓϩδΣΫτͰڞ௨ͷϥΠϒϥϦ │ ├── aws │ ├── db │ └── logger └── hoge-api // apiͷϦϙδτϦ ├── aaaa // TODO: ͪ͜Β΋internal΁Ҡಈ༧ఆ ├── bbbb // TODO: ͪ͜Β΋internal΁Ҡಈ༧ఆ └── internal // apiͷڞ௨ϥΠϒϥϦ ├── xxxx ├── yyyy └── zzzz @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 41

Slide 42

Slide 42 text

΋ͬͱͨ͘͞Μ͋Γ·͕͢ɺ ࣌ؒ΋ͳ͘ͳΔ͠ң΋௧͘ͳΔͷͰ Ұ୴͜͜·ͰͰɾɾɾ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 42

Slide 43

Slide 43 text

͔͜͜Β͸ վળͷͨΊʹ΍ͬͨ͜ͱΛ঺հ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 43

Slide 44

Slide 44 text

طଘϨΨγʔίʔυͷಈ࡞Λҡ࣋͢Δ WAFΛzenazn/goji*+>*guregu/kami$ʹ੾Γସ͑Δ࣌ʹ΍ͬͨ͜ͱ ʢϫʔΫΞϥ΢ϯυͰ͕͢ɾɾɾʣ • Өڹ͕େ͖ͦ͏/ṖͳAPI͸gojiͷHandler··ಈ͘Α͏ʹ͢Δ • x/net/contextͷத਎Λgojiͷweb.Cʹ͍ΕΔ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 44

Slide 45

Slide 45 text

ιʔείʔυ func goji2kami(gojiFn web.HandlerFunc) kami.HandlerFunc { return func(ctx context.Context, w http.ResponseWriter, r *http.Request) { env := make(map[interface{}]interface{}) if di, ok := device.FromContext(ctx); ok { env["device"] = di } if u, ok := user.FromContext(ctx); ok { env["user"] = &models.User{ID: int(u.ID)} } else { env["user"] = (*models.User)(nil) } gojiFn(web.C{Env: env}, w, r) } } @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 45

Slide 46

Slide 46 text

ϦϑΝΫλϦϯάDay ຖि༵ۚ೔ʹͻͨ͢ΒϦϑΝΫλϦϯά͢Δ೔ͱܾΊͨɻ աڈͷҨ࢈΍ྺ࢙తܦҢΛ౰࣌ͷϝϯόʔʹฉ͍ͨΓɺDBͷߏ଄ ΍࢑ఆાஔͷҋΛ෷ͬͨΓɻ • ෆཁͳίʔυΛ࡟আ • ςετ͕ແ͍Օॴͷςετ௥Ճ • ΉͪΌͪ͘ΌͳґଘΛ͍ͯ͠Δίʔυͷґଘؔ܎Λ੾Γ཭͢ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 46

Slide 47

Slide 47 text

testॻ͍ͯͳ͍໰୊ ͦ΋ͦ΋ϨΨγʔͳίʔυ͕ଟ͗ͯ͢ॻ͘ؾྗ͕ى͖ͳ͍ͱ͔ ʢΘ͔Βͳ͘΋ͳ͍͕ɺ͜ͷ··Ͱ͸·͍ͣɾɾɾʣ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 47

Slide 48

Slide 48 text

testॻ͍ͯͳ͍໰୊ͱ޲͖߹ͬͨ • CircleCIͰࣗಈςετ • CoverallsͰΧόϨοδΛՄࢹԽ-! • શͯͷΧόϨοδΛऔΔͷʹgithub.com/pierrre/gotestcoverΛ ར༻ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 48

Slide 49

Slide 49 text

ΧόϨοδͷվળ ΧόϨοδ20%$%>$50%෇ۙ΁ ͻͱ·ͣɺtestΛॻ͘จԽΛ࡞Δ͜ͱʹ੒ޭ!❗!❗!❗!❗!❗ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 49

Slide 50

Slide 50 text

gomockΛಋೖ ϦϑΝΫλϦϯάͷࡍʹɺґଘؔ܎Λഉআ͢ΔͨΊinterfaceԽ͠ ͯgomock͕࢖͑ΔΑ͏ʹͳͬͨͷͰಋೖɻ @tenntenn͞ΜͷQiitaهࣄ͕ͱͯ΋෼͔Γ΍͍͢Ͱ͢ɻ Go#MockͰΠϯλϑΣʔεͷϞοΫΛ࡞ͬͯςετ͢Δ h(p:/ /qiita.com/tenntenn/items/24fc34ec0c31f6474e6d @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 50

Slide 51

Slide 51 text

hhthͷಋೖ Go͸testॻ͘ͷָ͚ͩͲɺAPIͷςετΛॻ͘ͷ͕ͪΐͬͱΊΜͲ ͏ɻɻɻ h*ptest࢖ͬͯ݁ߏΰϦΰϦίʔυॻ͔ͳ͍ͱ͍͚ͳ͍ɻ github.com/kyokomi/hhth.Λ࡞ͬͨɻ ※·ͩҰ෦Ͱ͔͠࢖͍ͬͯͳ͍&·ͩ·ͩվળͷ༨஍͕͋Δ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 51

Slide 52

Slide 52 text

hhthಛ௃ h"ptestͷhelperΫϥεతͳҐஔ෇͚ɻ h"ptestͰAPIΛݺͼग़ͨ݁͠ՌͷνΣοΫॲཧΛ࢖͍·ΘͤΔɻ • StatusCode • ContentLength • jsonͷParse • Response @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 52

Slide 53

Slide 53 text

hhth#࢖͍ํྫ ʢ͕࣌ؒ͋Ε͹ɾɾɾʣ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 53

Slide 54

Slide 54 text

package example_test import ( "net/http" "testing" "github.com/kyokomi/hhth" ) func TestHogeHandler(t *testing.T) { hhtHelper := hhth.New(http.DefaultServeMux) hhtHelper.SetTestCase( hhth.TestCaseStatusCode(http.StatusOK), hhth.TestCaseContentType("text/plain; charset=utf-8"), ) resp := hhtHelper.Get("/hoge") if resp.Error() != nil { t.Errorf("error %s", resp.Error()) } if resp.String() != "hoge" { t.Errorf("error response body hoge != %s", resp.String()) } } @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 54

Slide 55

Slide 55 text

࢖͍ํৄࡉ1 // HanderΛηοτͯ͠એݴ hhtHelper := hhth.New(http.DefaultServeMux) // TestCaseΛઃఆʢStatusCodeͱContentTypeͷνΣοΫʣ hhtHelper.SetTestCase( hhth.TestCaseStatusCode(http.StatusOK), hhth.TestCaseContentType("text/plain; charset=utf-8"), ) @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 55

Slide 56

Slide 56 text

࢖͍ํৄࡉ2 // GET /hogeΛςετ͢Δ resp := hhtHelper.Get("/hoge") // ઌ΄Ͳઃఆͨ͠handlerΛݺͼग़ͨ݁͠Ռ or TestCaseͷΤϥʔ͕ฦͬͯ͘Δ if resp.Error() != nil { t.Errorf("error %s", resp.Error()) } @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 56

Slide 57

Slide 57 text

࢖͍ํৄࡉ3 // CustomTestCaseΛ௥ՃʢJSONΛύʔεͯ͠த਎ΛνΣοΫʣ hhtHelper.Get("/hoge", func(resp hhth.Response) error { var hoge Hoge if err := resp.JSON(&hoge); err != nil { return fmt.Errorf("hoge parse error %s", err.Error()) } if hoge.Num() != 100 { return fmt.Errorf("hoge num 100 != %d", hoge.Num()) } return nil }) @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 57

Slide 58

Slide 58 text

·ͱΊ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 58

Slide 59

Slide 59 text

·ͱΊ 1. GoݴޠͰ΋ϨΨγʔίʔυ͕؆୯ʹੜ·Ε·͢ %>'࢓༷΍ઃܭ͸ͪΌΜͱݕ౼ͯ͠·ͱΊΑ͏ 2. ςετίʔυ͕ແ͍ͱʮ͔ΘΓʹفΔ͕࣌ؒ૿͑ͨʯͱ͔ݴ͍ ͩ͠·͢ %>'·ͣ͸ςετίʔυΛͪΌΜͱॻ͜͏ %>'ͦͯ͠ܧଓతʹϦϑΝΫλϦϯά͍ͯ͘͠จԽʹ͠Α͏ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 59

Slide 60

Slide 60 text

͓ΘΓ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 60