$30 off During Our Annual Pro Sale. View Details »

やはり俺の Go アプリケーション設計はまちがっている。 / My Go Application Design Is Wrong, As I Expected

ktr
September 23, 2018

やはり俺の Go アプリケーション設計はまちがっている。 / My Go Application Design Is Wrong, As I Expected

Student Go #1

ktr

September 23, 2018
Tweet

More Decks by ktr

Other Decks in Technology

Transcript

  1. at Student Go #1
    ΍͸ΓԶͷ Go ΞϓϦέʔγϣϯઃܭ͸

    ·͕͍ͪͬͯΔɻ

    View Slide

  2. LUS !LUS@!LUS

    6OJWFSTJUZPG"J[V
    XIPBNJ

    View Slide

  3. w (Pͷࢥ૝ͱඪ४ύοέʔδͷಛ௃
    w (PΞϓϦέʔγϣϯͷઃܭ
    ࠓ೔͓࿩͢Δ͜ͱ

    View Slide

  4. w Զͷߟ͑ͨ࠷ڧͷΞʔΩςΫνϟ
    w ΞϓϦέʔγϣϯ֎෦ͷ͜ͱ %#ɺ8FCαʔόɺ
    FUD

    ࠓ೔͓࿩͠ͳ͍͜ͱ

    View Slide

  5. w ͳͥઃܭΛ͢Δͷ͔ʁ
    w ΦϒδΣΫτࢦ޲ͱϞδϡʔϧ
    w (Pͷࢥ૝ͱύοέʔδઃܭ
    w (PΞϓϦέʔγϣϯઃܭ
    ΞδΣϯμ

    View Slide

  6. w ͳͥઃܭΛ͢Δͷ͔ʁ
    w ΦϒδΣΫτࢦ޲ͱϞδϡʔϧ
    w (Pͷࢥ૝ͱύοέʔδઃܭ
    w (PΞϓϦέʔγϣϯઃܭ
    ΞδΣϯμ

    View Slide

  7. ͳͥઃܭΛ͢Δͷ͔ʁ

    View Slide

  8. w ਓؒ͸ඞͣؒҧ͑Δ
    w Ϧιʔε͸ৗʹ༗ݶ
    ιϑτ΢ΣΞ͸ਓ͕͍ؒͭͬͯ͘Δ

    View Slide

  9. w ૝ఆ֎ͷৼΔ෣͍ όά
    ΁ͷίετΛ࠷খݶʹ
    w मਖ਼΁ͷίετΛ࠷খݶʹ
    ݶΒΕͨϦιʔεͰιϑτ΢ΣΞΛ

    ͭ͘ΔͨΊʹ

    View Slide

  10. w Ϗδωεʹجͮ͘࡞ۀɾۀ຿ɾ࢓ࣄ υϝΠϯ

    ΛࣗಈԽ͢Δͷ͕ΞϓϦέʔγϣϯ։ൃ
    w ͜ΕΒ͸ৗʹมԽ͠ଓ͚Δ
    ΞϓϦέʔγϣϯ։ൃͷδϨϯϚ

    View Slide

  11. w Ϗδωεʹجͮ͘࡞ۀɾۀ຿ɾ࢓ࣄ υϝΠϯ

    ΛࣗಈԽ͢Δͷ͕ΞϓϦέʔγϣϯ։ൃ
    w ͜ΕΒ͸ৗʹมԽ͠ଓ͚Δ
    ΞϓϦέʔγϣϯ։ൃͷδϨϯϚ
    ΞϓϦέʔγϣϯΤϯδχΞ͸

    ৗʹมԽ͠ଓ͚Δ΋ͷΛ

    ௥͍ଓ͚ͳ͚Ε͹ͳΒͳ͍

    View Slide

  12. ଎͘ਐΉ།Ұͷํ๏͸ɺ͏·͘ਐΉ͜ͱͰ͋Δɻ
    — Clean Architecture ୡਓʹֶͿιϑτ΢ΣΞͷߏ଄ͱઃܭ

    View Slide

  13. w ࢓༷௨Γʹಈ࡞͢Δ͔
    w ࢓༷มߋʹదԠͰ͖Δ͔
    w ιϑτ΢ΣΞͷ࠶ར༻ੑ
    w FUD
    ιϑτ΢ΣΞʹٻΊΔ͜ͱ

    View Slide

  14. w ίʔυͷมߋ͠΍͢͞
    w ίʔυͷཧղ͠΍͢͞ɺՄಡੑ
    w FUD
    ͦͷͨΊʹඞཁͳ΋ͷ

    View Slide

  15. w ։ൃऀ͕υϝΠϯϩδοΫʹूதͰ͖Δ
    w ਖ਼ղͰ͸ͳ͘ͱ΋ܾΊΔ͜ͱࣗମʹՁ஋͕͋Δ
    ઃܭɾΞʔΩςΫνϟͷՁ஋
    *1: https://speakerdeck.com/sonatard/next-currency-gaego

    View Slide

  16. w ͳͥઃܭΛ͢Δͷ͔ʁ
    w ΦϒδΣΫτࢦ޲ͱϞδϡʔϧ
    w (Pͷࢥ૝ͱύοέʔδઃܭ
    w (PΞϓϦέʔγϣϯઃܭ
    ΞδΣϯμ

    View Slide

  17. ΦϒδΣΫτࢦ޲ͱϞδϡʔϧ

    View Slide

  18. ΦϒδΣΫτࢦ޲Ϋϥεࢦ޲

    View Slide

  19. w :FTBOEOP
    w $ݴޠΑΓΦϒδΣΫτࢦ޲ͳݴޠ
    w ΦϒδΣΫτࢦ޲͔Ͳ͏͔͸ਅِ஋Ͱ͸ͳ͍
    (P͸ΦϒδΣΫτࢦ޲ݴޠ͔ʁ
    *1: https://golang.org/doc/faq#Is_Go_an_object-oriented_language
    *2: ΦϒδΣΫτࢦ޲ೖ໳ ୈ 2 ൛ ݪଇɾίϯηϓτ

    View Slide

  20. w ιϑτ΢ΣΞͷ࣋ͭ΂͖ػೳͷ࢓༷͸ඇৗʹ੬͍
    w ৗʹιϑτ΢ΣΞશମ͕มߋ͞ΕΔՄೳੑ͕

    ෇͖·ͱ͏
    ػೳϕʔεͷϞσϦϯά

    View Slide


  21. ίϯύΠϥ
    w MFYFS
    w QBSTFS
    w "45
    ΦϒδΣΫτϕʔεͷϞσϦϯά

    View Slide

  22. ίϯύΠϥʹ৽͍͠ػೳ͕௥Ճ͞Εͨͱͯ͠΋

    ΦϒδΣΫτʹมߋ͸ੜ͡ʹ͍͘
    ΦϒδΣΫτϕʔεͷϞσϦϯά

    View Slide

  23. ιϑτ΢ΣΞͷ࣋ͭ΂͖ػೳͰ͸ͳ͘ɺ

    ૢ࡞͢ΔΦϒδΣΫτͷܕ͔Βಋ͔ΕΔϞδϡʔϧ
    ΛجຊʹΞʔΩςΫνϟΛߏங͢Δ։ൃख๏
    ΦϒδΣΫτࢦ޲ʹΑΔ։ൃ
    — ΦϒδΣΫτࢦ޲ೖ໳ ୈ 2 ൛ ݪଇɾίϯηϓτ (Ұ෦վม)

    View Slide

  24. ιϑτ΢ΣΞͷ࣋ͭ΂͖ػೳͰ͸ͳ͘ɺ

    ૢ࡞͢ΔΦϒδΣΫτͷܕ͔Βಋ͔ΕΔϞδϡʔϧ
    ΛجຊʹΞʔΩςΫνϟΛߏங͢Δ։ൃख๏
    ΦϒδΣΫτࢦ޲ʹΑΔ։ൃ
    — ΦϒδΣΫτࢦ޲ೖ໳ ୈ 2 ൛ ݪଇɾίϯηϓτ (Ұ෦վม)

    View Slide

  25. w /P
    w ػೳΛ஌Βͳ͚Ε͹ιϑτ΢ΣΞΛߏஙͰ͖ͳ͍
    w ػೳΑΓઌʹΦϒδΣΫτͷܕΛ෼ੳ͢Δ
    ػೳʹ͍ͭͯߟ͑Δ΂͖Ͱ͸ͳ͍ʁ

    View Slide

  26. w QBDLBHF࠷খͷϞδϡʔϧ୯Ґ
    w (PNPEVMFTQBDLBHFͷίϨΫγϣϯ୯Ґ
    (PͷϞδϡʔϧγεςϜ

    View Slide

  27. w มߋʹڧ͍ߏ଄Λͭ͘ΔͨΊ
    w ཧղ͠΍͍͢ߏ଄Λͭ͘ΔͨΊ
    w ૊Έ߹Θͤ΍͍͢ߏ଄Λͭ͘ΔͨΊ
    ͳͥϞδϡʔϧ͕ඞཁ͔ʁ

    View Slide

  28. w ͳͥઃܭΛ͢Δͷ͔ʁ
    w ΦϒδΣΫτࢦ޲ͱϞδϡʔϧ
    w (Pͷࢥ૝ͱύοέʔδઃܭ
    w (PΞϓϦέʔγϣϯઃܭ
    ΞδΣϯμ

    View Slide

  29. (Pͷࢥ૝ͱύοέʔδߏ੒

    View Slide

  30. w l1BDLBHFYYYQSPWJEFT PSJNQMFNFOUT
    z͔Β

    ࢝·ΔυΩϡϝϯτ
    ඞ໊ͣࢺ͕ύοέʔδ໊ʹͳΔ
    w 4IPSU DPODJTF FWPDBUJWF
    w "WPJETUVUUFS
    w 40-*%ݪଇʹجͮ͘
    (Pͷඪ४ύοέʔδͷಛ௃
    *1: https://golang.org/doc/effective_go.html?#package-names

    View Slide

  31. !IUUQ)5514FSWFS
    IUUQ4FSWFS
    "WPJETUVUUFS ٣Ի

    https://blog.golang.org/package-names

    View Slide

  32. w 4JOHMF3FTQPOTJCJMJUZ1SJODJQBM
    w Ϟδϡʔϧ͸ͨͬͨҰͭͷΞΫλʔʹରͯ͠

    ੹຿Λෛ͏΂͖Ͱ͋Δ
    4୯Ұ੹೚ݪଇ

    View Slide

  33. w ύοέʔδ໊͕ද͢υϝΠϯʹͷΈ੹຿Λ࣋ͭ
    w JPˠೖग़ྗΛந৅Խͨ͠ΠϯλʔϑΣʔεͷఏڙ
    w GNUˠೖग़ྗͷϑΥʔϚοτ
    4୯Ұ੹೚ݪଇ

    View Slide

  34. w 0QFO$MPTFE1SJODJQBM
    w Ϟδϡʔϧ͸֦ுʹରͯ͠։͍͍ͯͯɺ

    मਖ਼ʹରͯ͠ด͍ͯ͡ͳ͚Ε͹ͳΒͳ͍
    0։์ด࠯ݪଇ

    View Slide

  35. type nopCloser struct {
    io.Reader
    }
    func (nopCloser) Close() error { return nil }
    func NopCloser(r io.Reader) io.ReadCloser {
    return nopCloser{r}
    }

    View Slide

  36. package cli
    func Run(cmd string, args []string) {
    switch cmd {
    case "echo":
    fmt.Println(strings.Join(args, " "))
    case "reverse":
    reversed := reverse(args)
    fmt.Println(strings.Join(reversed, " "))
    default:
    fmt.Println("unknown command")
    }
    }
    $ ./app echo foo bar
    foo bar

    View Slide

  37. package cli
    type Command interface {
    Run(args []string)
    }
    func Run(cmd Command, args []string) {
    cmd.Run(args)
    }

    View Slide

  38. package main
    type echoCommand struct{}
    func (c *echoCommand) Run(args []string) {
    // logic
    }
    type reverseCommand struct{}
    func (c *reverseCommand) Run(args []string) {
    // logic
    }

    View Slide

  39. package main
    func main() {
    cmdName := os.Args[1]
    args := os.Args[2:]
    var cmd cli.Command
    switch cmdName {
    case "echo":
    cmd = &echoCommand{}
    case "reverse":
    cmd = &reverseCommand{}
    default:
    // unknown command
    }
    cli.Run(cmd, args)
    }

    View Slide

  40. w ιϑτ΢ΣΞ͕બ୒ࢶΛఏڙ͠ͳ͚Ε͹ͳΒͳ͍
    ࣌ɺͨͩҰͭͷϞδϡʔϧ͚͕ͩͦͷબ୒ࢶͷ͢
    ΂ͯΛ೺Ѳ͢΂͖Ͱ͋Δ
    ୯Ұબ୒੹೚

    View Slide

  41. package cli
    type CLI struct {
    Commands map[string]Command
    }
    func (c *CLI) Run(args []string) error {
    cmdName := args[0]
    cmd, ok := c.Commands[cmdName]
    if !ok {
    return errors.New("unknown command")
    }
    cmd.Run(args[1:])
    return nil
    }

    View Slide

  42. package main
    func main() {
    args := os.Args[1:]
    c := &cli.CLI{}
    c.Commands = map[string]cli.Command{
    “echo": &echoCommand{},
    "reverse": &reverseCommand{},
    }
    c.Run(args)
    }

    View Slide

  43. w 4ܕͷΦϒδΣΫτPͱ5ܕͷΦϒδΣΫτ
    P͕͋Γɺ5Λ࢖ͬͯఆٛ͞ΕͨϓϩάϥϜʹ
    ରͯ͠Pͷ୅ΘΓʹPΛ࢖ͬͯ΋ϓϩάϥϜ
    ͷৼΔ෣͍͕มΘΒͳ͍৔߹ɺ4͸5ͷ೿ੜܕ
    ͱݴ͑Δ
    -Ϧείϑͷஔ׵ݪଇ

    View Slide

  44. 3FDUBOHMF
    4RVBSF
    $MJFOU

    View Slide

  45. type Rectangle interface {
    SetX(x int)
    SetY(y int)
    }
    type Square struct {
    x, y int
    }
    func (s *Square) SetX(x int) {
    s.x, s.y = x, x
    }
    func (s *Square) SetY(y int) {
    s.x, s.y = y, y
    }

    View Slide

  46. func TestRectangle(t *testing.T) {
    var r Rectangle = &Square{}
    expectedX, expectedY := 100, 200
    r.SetX(100)
    r.SetY(200)
    if x := r.GetX(); x != expectedX {
    t.Errorf("x expected %d, but got %d", expectedX, x)
    }
    if y := r.GetY(); y != expectedY {
    t.Errorf("y expected %d, but got %d", expectedX, y)
    }
    }

    View Slide

  47. w ΠϯλʔϑΣʔεͷΫϥΠΞϯτʹΫϥΠΞϯτ
    ͕ར༻͠ͳ͍ϝιου΁ͷґଘΛڧ੍ͯ͠͸ͳΒ
    ͳ͍
    *ΠϯλʔϑΣʔε෼཭ͷݪଇ

    View Slide

  48. w 5IFCJHHFSUIFJOUFSGBDF UIFXFBLFSUIF
    BCTUSBDUJPO
    w ඪ४ύοέʔδͷΠϯλʔϑΣʔε͸ඇৗʹ

    খ͘͞ɺগͳ͘อͨΕ͍ͯΔ
    *ΠϯλʔϑΣʔε෼཭ͷݪଇ
    *1: Go Proverbs (https://go-proverbs.github.io/)
    *2: The Go Blog - Organizing Go code

    View Slide

  49. w JP3FBEFS JP8SJUFS
    w IUUQ)BOEMFS
    w FUD
    *ΠϯλʔϑΣʔε෼཭ͷݪଇ

    View Slide

  50. w ্ҐϨϕϧͷϞδϡʔϧ͸ԼҐϨϕϧͷϞδϡʔϧʹґ
    ଘͯ͠͸ͳΒͳ͍ɻ྆ํͱ΋ந৅ʹґଘ͢΂͖Ͱ͋Δɻ
    w ந৅͸ৄࡉʹґଘͯ͠͸ͳΒͳ͍ɻৄࡉ͕ந৅ʹґଘ͢
    ΂͖Ͱ͋Δɻ
    %ґଘؔ܎ٯసͷݪଇ

    View Slide

  51. w *NQPSUDZDMFOPUBMMPXFE
    w ҆ఆͨ͠ந৅͸ґଘάϥϑͷԼҐϨϕϧ΁ɺ

    ৄࡉ͸্ҐϨϕϧ΁
    %ґଘؔ܎ٯసͷݪଇ

    View Slide

  52. w ΞʔΩςΫνϟΛઃܭ͠ɺ
    w ద੾ͳ໊લΛϞδϡʔϧ΁͚ͭɺ
    w ͦΕҎ֎ͷৄࡉ͸υΩϡϝϯτʹ࢒͢
    w ݸਓతʹ
    ࠷΋कΒΕ͍ͯͳ͍ݪଇͩͱࢥ͏
    %FTJHOUIFBSDIJUFDUVSF 

    OBNFUIFDPNQPOFOUT EPDVNFOUUIFEFUBJMT

    View Slide

  53. (PΞϓϦέʔγϣϯͷઃܭ

    View Slide

  54. w ϥΠϒϥϦͱ͸ҧ͍ɺ࣮ߦՄೳϑΝΠϧ
    ֎෦ʹΫϥΠΞϯτ͕ଘࡏ͢Δ

    ϒϥ΢βɺϞόΠϧɺϚΠΫϩαʔϏεɺFUD

    w ΫϥΠΞϯτʹఏڙ͢ΔϢʔεέʔε͕ଘࡏ͢Δ
    ΞϓϦέʔγϣϯ

    View Slide

  55. w ϢʔεέʔεϩδοΫ

    ϢʔεέʔεΛ࣮ݱ͢ΔͨΊͷϩδοΫ
    w υϝΠϯϩδοΫ

    Ϣʔεέʔεʹґଘ͠ͳ͍ϩδοΫ
    ϢʔεέʔεϩδοΫɺυϝΠϯϩδοΫ

    View Slide

  56. w 6*΍"1*ΠϯλʔϑΣʔεʹґଘ͢Δ
    w ϖʔδϯά෇͖ͷҰཡը໘
    w ೖྗ஋Λݩʹͨ͠Ϣʔβొ࿥
    w FUD
    ۩ମతͳϢʔεέʔεϩδοΫ

    View Slide

  57. w Ϣʔεέʔεʹґଘ͠ͳ͍
    w υϝΠϯ஌ࣝΛϞσϦϯά͠ɺ֤ཁૉΛ

    Ϟδϡʔϧ΁෼཭͢Δ
    w ৄ͘͠͸%%%*%%%Λࢀর
    υϝΠϯϩδοΫ

    View Slide

  58. w (Pͷඪ४ύοέʔδͱಉ͡ํ਑Ͱ
    w 40-*%ݪଇΛकΔ
    w ໌֬ͳ໊ࢺΛύοέʔδ໊ʹ͢Δ
    w ύοέʔδ໊ͱΤϯςΟςΟ໊ΛৗʹηοτͰߟ͑Δ
    Ϟδϡʔϧ෼ׂͷ୯Ґ

    View Slide

  59. w ίʔυ͚ͩͰ͸Θ͔Βͳ͍ɺΘ͔ΓͮΒ͍ৄࡉ΍
    ࢓༷Λ࢒͢
    w ϞδϡʔϧͷΫϥΠΞϯτʹͰ͖ΔݶΓ

    ࣮૷Λಡ·ͤͳ͍Α͏ʹ͢Δ
    υΩϡϝϯτ

    View Slide

  60. type ResponseWriter interface {
    // WriteHeader sends an HTTP response header with the provided
    // status code.
    //
    // If WriteHeader is not called explicitly, the first call to Write
    // will trigger an implicit WriteHeader(http.StatusOK).
    // Thus explicit calls to WriteHeader are mainly used to
    // send error codes.
    //
    // The provided code must be a valid HTTP 1xx-5xx status code.
    // Only one header may be written. Go does not currently
    // support sending user-defined 1xx informational headers,
    // with the exception of 100-continue response header that the
    // Server sends automatically when the Request.Body is read.
    WriteHeader(statusCode int)
    }

    View Slide

  61. type ResponseWriter interface {
    // WriteHeader sends an HTTP response header with the provided
    // status code.
    //
    // If WriteHeader is not called explicitly, the first call to Write
    // will trigger an implicit WriteHeader(http.StatusOK).
    // Thus explicit calls to WriteHeader are mainly used to
    // send error codes.
    //
    // The provided code must be a valid HTTP 1xx-5xx status code.
    // Only one header may be written. Go does not currently
    // support sending user-defined 1xx informational headers,
    // with the exception of 100-continue response header that the
    // Server sends automatically when the Request.Body is read.
    WriteHeader(statusCode int)
    }

    View Slide

  62. ·ͱΊ

    View Slide

  63. υϝΠϯ஌ࣝΛे෼ʹಘΔ
    ҆ఆͨ͠ந৅Λݟ͚ͭͯɺܕͱ໊લΛ͚ͭΔ
    w ΞϓϦέʔγϣϯʹґଘ͠ͳ͍͜ͱ
    ಘΒΕͨܕΛ40-*%΍(Pͷࢥ૝ʹج͍ͮͯ

    ϞδϡʔϧԽ͢Δ
    Ϟδϡʔϧͷఆٛɾߏங

    View Slide

  64. ػೳ Ϣʔεέʔε
    Λ೺Ѳ͢Δ
    ϞδϡʔϧΛ૊Έ߹Θ࣮ͤͯݱ͢Δ
    w ఆٛͨ͠Ϟδϡʔϧ಺ʹ࣮૷͠ͳ͍͜ͱ
    ΞϓϦέʔγϣϯͷߏங

    View Slide

  65. w ͱ͸͍͑ɺઃܭ͸೉͍͠
    w ϕετͳઃܭ͸ଘࡏ͠ͳ͍
    w ঢ়گʹԠͯ͡ϕλʔͳઃܭΛݟ͚͍ͭͯ͜͏
    ·ͱΊ

    View Slide

  66. w ΞʔΩςΫνϟύλʔϯ΍ɺઃܭͷݪଇ
    w ͔ͳΓΘ͔Γ΍͍͕͢ɺ֤ݪଇͷৄࡉ͸

    ผͷຊͷ΄͏͕ৄ͍͠
    $MFBO"SDIJUFDUVSF
    ୡਓʹֶͿιϑτ΢ΣΞͷߏ଄ͱઃܭ

    View Slide

  67. w ΦϒδΣΫτࢦ޲ͷ໨తɺఆٛɺݪଇ
    w ϖʔδʂ
    w จষ͕೉ղ͕ͩɺΦϒδΣΫτࢦ޲ʹؔ͢Δ
    ͍͍ͩͨͷ͜ͱ͸ॻ͍ͯ͋Δ
    ΦϒδΣΫτࢦ޲ೖ໳ୈ൛
    ݪଇɾίϯηϓτ

    View Slide

  68. w %%%ຊ
    w υϝΠϯΛத৺ʹઃܭ͢Δ͜ͱͷॏཁੑ΍ཧ
    ࿦ɺͦͷख๏Λѻ͏
    w ந৅తͳදݱ͕ଟͯ͘೉͍͠
    ΤϦοΫɾΤϰΝϯεͷυϝΠϯ
    ۦಈઃܭ

    View Slide

  69. w *%%%ຊ
    w %%%Λ࣮ࡍͷઃܭʹԠ༻͢Δ
    w %%%ຊΛಡΜͰͳ͍ͱΘ͔Βͳ͍఺΋͋Δ
    ࣮ફυϝΠϯۦಈઃܭ

    View Slide

  70. w 5IF(P#MPHIUUQTCMPHHPMBOHPSH
    w 5IF(P1SPHSBNNJOH-BOHVBHF%PDVNFOUBUJPOIUUQTHPMBOHPSHEPD
    w 40-*%(P%FTJHOIUUQTEBWFDIFOFZOFUTPMJEHPEFTJHO
    w ʮ(PݴޠΒ͠͞ʯͱ͸Կ͔ʁ4JNQMJDJUZͷ఩ֶΛཧղ͠ɺ(P8BZʹԊͬͨ։ൃΛ
    ਐΊΔ͜ͱͷྑ͞

    IUUQTFNQMPZNFOUFOKBQBODPNFOHJOFFSIVCFOUSZ
    8FC

    View Slide