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

Go言語で作られたAPIのレガシーコードと戦った話 / Go Conference 2015 winter

kyokomi
December 06, 2015

Go言語で作られたAPIのレガシーコードと戦った話 / Go Conference 2015 winter

Go言語で作られたAPIのレガシーコードと戦った話

kyokomi

December 06, 2015
Tweet

More Decks by kyokomi

Other Decks in Technology

Transcript

  1. աڈʹ࡞ͬͨ΋ͷ঺հ1 • github.com/kyokomi/slackbot • slackઐ༻ͷGo੡ͷhubot • ϓϥάΠϯ௥Ճ͠΍͍͢Α͏ʹͯ͠Δͭ΋Γ • github.com/kyokomi/emoji •

    λʔϛφϧֆจࣈϥΠϒϥϦ • ૣ͍ऀউͪͰ࡞ͬͨײ͡ɻελʔ70௒͑ͨ7⭐ @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 3
  2. աڈʹ࡞ͬͨ΋ͷ঺հ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
  3. ରॲޙʢίʔυྫʣ // ٖࣅίʔυͰ͢ʢ͜ΜͳΠϝʔδʣ 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
  4. errorΛѲΓͭͿͯ͠Δ data, _ := json.Marshal(resp.Body) if data == nil {

    // ... } !!!!!!! @kyokomi,(2015/12/06(ʮGo(Conference(2015(winterʯ 33
  5. ରॲޙ ී௨ʹΤϥʔϋϯυϦϯάɻ৔߹ʹΑͬͯ͸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
  6. 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
  7. ࣾ಺ڞ௨ϥΠϒϥϦతͳڞ௨ύοέʔδ ├── 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
  8. 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
  9. ιʔείʔυ 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
  10. 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
  11. ࢖͍ํৄࡉ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
  12. ࢖͍ํৄࡉ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