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

Implementing Go Go Go

azihsoyn
October 02, 2016

Implementing Go Go Go

Implementing Domain-Driven Design in golang

https://github.com/azihsoyn/IDDD_go_sample

azihsoyn

October 02, 2016
Tweet

More Decks by azihsoyn

Other Decks in Technology

Transcript

  1. ࣮ફGoGoGo
    Gunosy Inc.
    2016.10

    View full-size slide

  2. ©Gunosy Inc. 2
    ࣗݾ঺հ
    ■ azihsoyn (͋͡;ͦ΍Μ)
    – Twitter
    – Github
    – …etc
    ■ ۀ຿
    – GoͰAPIαʔόͷ։ൃɾӡ༻
    ■ झຯ
    – ௼Γ(6ׂ)
    ● ઒΍ւͰϧΞʔ௼Γ
    – Ξχϝ(4ׂ)
    ● μΠϠ༷ʙ
    ■ ۙگ
    – isucon6ຊઓग़·͢ʂ

    (νʔϜ: ͝஫จ͸poyoͰ͔͢ʁ)
    ٢ᖒ ௚࠸

    View full-size slide

  3. ©Gunosy Inc. 3
    Gunosy͸ ৘ใΩϡϨʔγϣϯαʔϏεʮά
    ϊγʔʯͱ
    2016೥6݄1೔ʹKDDIגࣜձࣾͱڞಉͰϦϦʔεͨ͠

    ແྉχϡʔε഑৴ΞϓϦʮχϡʔεύεʯΛఏڙ͢Δ
    ձࣾͰ͢ɻʮ৘ใΛੈքதͷਓʹ࠷దʹಧ͚ΔʯΛ

    Ϗδϣϯʹ׆ಈ͍ͯ͠·͢ɻ
    ωοτ্ʹଘࡏ͢Δ͞·͟·ͳ৘ใΛɺ

    ಠࣗͷΞϧΰϦζϜͰऩूɺධՁ෇͚Λߦ͍

    Ϣʔβʔʹಧ͚·͢ɻ
    ৘ใΩϡϨʔγϣϯαʔϏε

    ʮά
    ϊγʔʯ
    200ഔମҎ্ͷχϡʔειʔεΛϕʔεʹɺ

    ৽ͨʹ։ൃͨ͠৘ใղੳɾ഑৴ٕज़Λ༻͍ͯࣗಈతʹ

    બఆͨ͠χϡʔε΍৘ใΛϢʔβʔʹಧ͚·͢ɻ
    ແྉχϡʔε഑৴ΞϓϦ

    ʮχϡʔεύεʯ
    גࣜձࣾGunosy – ʮ৘ใΛੈքதͷਓʹ࠷దʹಧ͚Δʯ

    View full-size slide

  4. ©Gunosy Inc. 4
    GoͰDDD΍ͬͯΔ࿩
    ࠓ೔ͷ࿩

    View full-size slide

  5. ©Gunosy Inc. 5
    ࣮ફDDDಡΈऴΘͬͯͳ͍Ͱ͢
    DDDͷํ͸ಡΜͩΜͰ͕͢…
    લఏ

    View full-size slide

  6. ©Gunosy Inc. 6
    ■ https://github.com/citerus/dddsample-core
    – DDDͷαϯϓϧ࣮૷(Java)
    ■ https://github.com/VaughnVernon/IDDD_Samples
    – ࣮ફDDDͷαϯϓϧ࣮૷(Java)
    ■ https://github.com/marcusolsson/goddd
    – DDDͷαϯϓϧ࣮૷(golang)
    ͜ͷ͋ͨΓͷίʔυಡΈͳ͕ΒϓϩμΫτʹམͱ͜͠Μͩײ͡Ͱ͢

    View full-size slide

  7. ©Gunosy Inc. 7
    ࣝऀͷํʑ͔ΒͷಥͬࠐΈେ׻ܴͰ͢

    View full-size slide

  8. ©Gunosy Inc. 8
    վΊͯࠓ೔ͷ࿩
    ࿩͢͜ͱ ࿩͞ͳ͍͜ͱ
    ■ GoͰAPIॻ͘ͱ͖ʹؾΛ͚ͭͯΔ͜ͱ
    ■ ύοέʔδߏ੒
    ■ ϋϚͬͨ͜ͱ
    ■ DDDͷ༻ޠͷઆ໌ͱ͔
    ■ ϥΠϒϥϦͷ࢖͍ํͱ͔
    GoͰDDDΛ΍ͬͯࢼߦࡨޡͨ͠࿩Λ͍ͨ͠ͱࢥ͍·͢

    View full-size slide

  9. ©Gunosy Inc. 9
    هࣄΛฦ͢APIΛ࡞Δ৔߹Λ૝ఆͯ͠ΈΔ

    View full-size slide

  10. ©Gunosy Inc. 10
    ■ main.goΛॻ͘
    ■ handlerΛॻ͘
    ■ هࣄͷmodelΛॻ͘
    ■ هࣄͷmodelΛσʔλετΞ͔Βऔಘ͢ΔॲཧΛ࣮૷
    ■ jsonͱ͔ʹม׵ͯ͠ฦ͢
    େମ͜ΜͳྲྀΕʹͳΔͱࢥ͍·͢

    View full-size slide

  11. ©Gunosy Inc. 11
    ·ͣ͸main.go

    View full-size slide

  12. ©Gunosy Inc. 12
    // main.go
    package main
    import (
    "context"
    "github.com/azihsoyn/IDDD_go_sample/article"
    "github.com/azihsoyn/IDDD_go_sample/internal/repository"
    "github.com/guregu/kami"
    )
    func main() {
    ctx := context.Background()
    ctx = repository.NewContext(ctx)
    kami.Context = ctx
    kami.Get("/articles", article.ArticleListHandler)
    kami.Get("/article/:article_id", article.ArticleHandler)
    kami.Serve()
    }
    repositoryͱ͍͏ͷΛNewͯ͠ΔҎ֎ಛʹมΘͬͨ͜ͱ͸ͯ͠ͳ͍

    View full-size slide

  13. ©Gunosy Inc. 13
    ࣍ʹhandler

    View full-size slide

  14. ©Gunosy Inc. 14
    handler (1)
    // article/api_article.go
    package article
    import (
    "context"
    "net/http"
    "github.com/azihsoyn/IDDD_go_sample/internal/repository"
    )
    func ArticleHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
    req := articleRequest{}
    if err := req.Parse(ctx); err != nil {
    renderer.JSON(w, http.StatusBadRequest, err.Error())
    }
    a, err := repository.FromContext(ctx).ArticleRepository.ResolveByID(req.ArticleID)
    if err != nil {
    renderer.JSON(w, http.StatusBadRequest, err.Error())
    }
    renderArticleView(w, a)
    }

    View full-size slide

  15. ©Gunosy Inc. 15
    handler (2) - request
    // article/request_article.go
    package article
    import (
    "context"
    "strconv"
    "github.com/azihsoyn/IDDD_go_sample/internal/domain/article"
    "github.com/guregu/kami"
    )
    type articleRequest struct {
    ArticleID article.Identifier
    }
    func (req *articleRequest) Parse(ctx context.Context) error {
    articleID, err := strconv.ParseInt(kami.Param(ctx, "article_id"), 10, 64)
    if err != nil {
    return err
    }
    req.ArticleID = article.Identifier(articleID)
    return nil
    }

    View full-size slide

  16. ©Gunosy Inc. 16
    handler (3) - view
    // article/view_article.go
    package article
    import (
    "net/http"
    "github.com/azihsoyn/IDDD_go_sample/internal/domain/article"
    )
    type articleView struct {
    ID int64 `json:"id"`
    Title string `json:"title"`
    Content string `json:"content"`
    }
    func renderArticleView(w http.ResponseWriter, a article.Article) {
    view := articleView{
    ID: int64(a.ID),
    Title: a.Title,
    Content: a.Content,
    }
    renderer.JSON(w, http.StatusOK, view)
    }

    View full-size slide

  17. ©Gunosy Inc. 17
    ■ handlerͰ΍Δ͜ͱΛγϯϓϧʹ͢Δ
    – ϦΫΤετͷύʔε&όϦσʔγϣϯ
    – modelΛऔಘ
    – Ϩεϙϯε༻ʹviewΛੜ੒
    ΤϥʔϋϯυϦϯά͕ଟ͘ͳΒͳ͍Α͏ʹͯ͠Δ
    ■ ϑΝΠϧΛׂΓͱ෼ׂ͢Δ
    – ϦΫΤετ༻ͷϑΝΠϧ
    – Ϩεϙϯε༻ͷϑΝΠϧ
    – handler༻ͷϑΝΠϧ
    ϑΝΠϧ໊ͰԿͯ͠Δ͔෼͔ΔΑ͏ʹ
    handlerͰҙ͍ࣝͯ͠Δ͜ͱ
    ͱʹ͔͘ݟ΍͘͢γϯϓϧʹʂ

    View full-size slide

  18. ©Gunosy Inc. 18
    ଓ͍ͯmodelͷఆٛ

    View full-size slide

  19. ©Gunosy Inc. 19
    modelͷఆٛ
    // internal/domain/article/article.go
    package article
    type Identifier int64
    type Article struct {
    ID Identifier
    Title string
    Content string
    }

    View full-size slide

  20. ©Gunosy Inc. 20
    modelͷऔಘ(repository)
    // internal/domain/article/repository.go
    package article
    //go:generate mockgen -package article -source repository.go -destination mock/
    repository_mock.go -imports .=github.com/azihsoyn/IDDD_go_sample/internal/domain/article
    type Repository interface {
    ResolveByID(articleID Identifier) (Article, error)
    ResolveAll() ([]Article, error)
    }

    View full-size slide

  21. ©Gunosy Inc. 21
    ■ modelΛhandlerͷviewͱڞ༻ʹ͠ͳ͍
    – modelʹ͸jsonͷstruct tag͸͚ͭͳ͍
    ■ model͸DBͷςʔϒϧߏ଄ͱҰக͢Δͱ͸ݶΒͳ͍
    – joinͨ݁͠Ռͷ৔߹΋͋Δ
    – ෆཁͳΧϥϜΛmodelʹ࣋ͭඞཁ͸ͳ͍
    ■ ϑΝΠϧΛׂΓͱ෼ׂ͢Δ
    – model༻ͷϑΝΠϧ
    – interface༻ͷϑΝΠϧ
    ϑΝΠϧ໊ͰԿͯ͠Δ͔෼͔ΔΑ͏ʹ
    modelͰҙ͍ࣝͯ͠Δ͜ͱ1

    View full-size slide

  22. ©Gunosy Inc. 22
    ■ repositoryΛinterfaceʹ࣮ͯ͠૷ͱ෼཭͢Δ
    – articleͱ͍͏modelΛͲ͔͜Βऔಘ͢Δ͔Λҙࣝ͠ͳ͍
    – interfaceʹ͓ͯ͘͜͠ͱͰmockͷੜ੒͕؆୯
    ■ gomockΛ࢖ͬͯinterface͔ΒmockΛੜ੒
    – https://github.com/golang/mock
    – mock͸mock༻ͷσΟϨΫτϦʹ

    articleσΟϨΫτϦͷΧόϨοδΛԼ͛ͳ͍ͨΊ

    (CI࣌ʹmockΛੜ੒ͯ͠ίϛοτ͠ͳ͍ํ๏΋͋Δͱ͔)
    ■ ࢀরܥ͸ResolveXXXɺߋ৽ܥ͸StoreXXX
    – ໋໊Ͱ೰·ͳ͍Α͏ʹ
    – ྫ֎΋͋Δ
    modelͰҙ͍ࣝͯ͠Δ͜ͱ2
    ͱʹ͔͘ݟ΍͘͢γϯϓϧʹʂ

    View full-size slide

  23. ©Gunosy Inc. 23
    repositoryͷ࣮૷(mock൛)

    View full-size slide

  24. ©Gunosy Inc. 24
    // main.go
    package main
    import (
    "context"
    "github.com/azihsoyn/IDDD_go_sample/article"
    "github.com/azihsoyn/IDDD_go_sample/internal/repository"
    "github.com/guregu/kami"
    )
    func main() {
    ctx := context.Background()
    ctx = repository.NewContext(ctx)
    kami.Context = ctx
    kami.Get("/articles", article.ArticleListHandler)
    kami.Get("/article/:article_id", article.ArticleHandler)
    kami.Serve()
    }

    View full-size slide

  25. ©Gunosy Inc. 25
    ·ͣ͸context͔ΒrepositoryΛऔΕΔΑ͏ʹ
    // internal/repository/context.go
    package repository
    import (…)
    type Repository struct {
    ArticleRepository article.Repository
    // ଞͷmodelͷrepository͕Ͱ͖ͨΒ௥Ճ͍ͯ͘͠
    }
    func NewContext(ctx context.Context) context.Context {
    return context.WithValue(ctx, contextKey, newRepository(ctx))
    }

    View full-size slide

  26. ©Gunosy Inc. 26
    mockΛੜ੒
    $ mkdir ./internal/domain/article/mock
    $ go generate ./...

    View full-size slide

  27. ©Gunosy Inc. 27
    mockΛ࢖ͬͯrepositoryΛ࣮૷
    // internal/repository/context.go
    func newRepository(ctx context.Context) *Repository {
    t := new(testing.T)
    ctrl := gomock.NewController(t)
    repo := articlemock.NewMockRepository(ctrl)
    repo.EXPECT().ResolveByID(article.Identifier(1)).Return(article.Article{
    ID: 1,
    Title: "hello",
    Content: "world",
    }, nil).Times(100)
    return &Repository{
    ArticleRepository: repo,
    }
    }
    ͜͜·ͰͰAPIαʔόͱͯ͠ಈ͘Α͏ʹͳΔ

    View full-size slide

  28. ©Gunosy Inc. 28
    repositoryͷ࣮૷(ͪΌΜͱͨ͠൛)

    View full-size slide

  29. ©Gunosy Inc. 29
    // internal/repository/article/repository.go
    package articlerepo
    import (…)
    type articleRepository struct{}
    var _ article.Repository = (*articleRepository)(nil)
    func New() article.Repository {
    return &articleRepository{}
    }
    func (repo *articleRepository) ResolveByID(articleID article.Identifier) (article.Article
    error) {
    // DB΍Ωϟογϡ͔ΒarticleΛऔಘ͢Δॲཧ
    return article.Article{}, errors.New("not implemented")
    }
    func (repo *articleRepository) ResolveAll() ([]article.Article, error) {
    // DB΍Ωϟογϡ͔ΒarticleΛऔಘ͢Δॲཧ
    return nil, errors.New("not implemented")
    }

    View full-size slide

  30. ©Gunosy Inc. 30
    // internal/repository/context.go
    package repository
    func newRepository(ctx context.Context) *Repository {
    /*
    t := new(testing.T)
    ctrl := gomock.NewController(t)
    repo := articlemock.NewMockRepository(ctrl)
    repo.EXPECT().ResolveByID(article.Identifier(1)).Return(article.Article{
    ID: 1,
    Title: "hello",
    Content: "world",
    }, nil).Times(100)
    */
    repo := articlerepo.New()
    return &Repository{
    ArticleRepository: repo,
    }
    }
    context.goΛ௚͚ͩ͢Ͱmockͱ࣮૷͕੾ΓସΘΔ

    View full-size slide

  31. ©Gunosy Inc. 31
    ͜͜·Ͱ͸γϯϓϧͳ࣮૷ͩͬͨͷͰ
    ΋͏গ͠ෳࡶͳ࣮૷Λߟ͑ͯΈΔ

    View full-size slide

  32. ©Gunosy Inc. 32
    ϢʔβʔʹΑͬͯهࣄΛग़͠෼͚͍ͨ
    ͱ͍͏ཁ๬͕͋ͬͨͱ͖

    View full-size slide

  33. ©Gunosy Inc. 33
    ͜Μͳॲཧ
    func UserSpecificArticles(as []Article, userID int64) []Article {
    ret := make([]Article, 0, len(as))
    // userID͕ಛఆͷ஋(= 1)ͩͬͨΒهࣄID͕100ͷهࣄΛઌ಄ʹग़͢
    if userID == 1 {
    ret = append(ret, Article{
    ID: 100,
    Title: "for user 1",
    Content: "this is recommended by your activity",
    })
    }
    ret = append(ret, as...)
    return ret
    }
    Ͳ͜ʹ࣮૷͢Δ͔ʁ

    View full-size slide

  34. ©Gunosy Inc. 34
    Ҋ1) articleͷrepositoryʹ࣮૷
    repository͸͋͘·ͰσʔλετΞͱͷ΍ΓͱΓʹཹΊΔ΂͖
    // internal/repository/article/repository.go
    package articlerepo
    func (repo *articleRepository) ResolveAll() ([]article.Article, error) {
    as, err := repo.resolveAllFromMySQL()
    if err != nil {
    return nil, err
    }
    as = userSpecificArticles(as, req.UserID)
    return ret
    }

    View full-size slide

  35. ©Gunosy Inc. 35
    Ҋ2) handlerʹ࣮૷
    handler͕articleΛՃ޻ͯ͠͠·͍੹຿͕෼ࢄͯ͠Δ
    // article/api_article_list.go
    package article
    import (…)
    func ArticleListHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
    req := articleListRequest{}
    if err := req.Parse(ctx, r); err != nil {
    renderer.JSON(w, http.StatusBadRequest, err.Error())
    }
    as, err := repository.FromContext(ctx).ArticleRepository.ResolveAll(req.UserID)
    if err != nil {
    renderer.JSON(w, http.StatusBadRequest, err.Error())
    }
    as = userSpecificArticles(as, req.UserID)
    renderArticleListView(w, as)
    }
    ˚

    View full-size slide

  36. ©Gunosy Inc. 36
    Ҋ3) domain modelʹ࣮૷͢Δ
    هࣄͷϩδοΫͳͷͰ੹຿͸Αͦ͞͏ɻ
    ͨͩhandlerͰݺͼग़͢ͷ͸มΘΒͳ͍
    ̋
    // article/api_article_list.go
    package article
    import (…)
    func ArticleListHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
    req := articleListRequest{}
    if err := req.Parse(ctx, r); err != nil {
    renderer.JSON(w, http.StatusBadRequest, err.Error())
    }
    as, err := repository.FromContext(ctx).ArticleRepository.ResolveAll(req.UserID)
    if err != nil {
    renderer.JSON(w, http.StatusBadRequest, err.Error())
    }
    as = article.UserSpecificArticles(as, req.UserID)
    renderArticleListView(w, as)
    }

    View full-size slide

  37. ©Gunosy Inc. 37
    ■ handlerͰ΍Δ͜ͱΛγϯϓϧʹ͢Δ
    – ϦΫΤετͷύʔε&όϦσʔγϣϯ
    – modelΛऔಘ
    – Ϩεϙϯε༻ʹviewΛੜ੒
    ΤϥʔϋϯυϦϯά͕ଟ͘ͳΒͳ͍Α͏ʹͯ͠Δ
    ■ ϑΝΠϧΛׂΓͱ෼ׂ͢Δ
    – ϦΫΤετ༻ͷϑΝΠϧ
    – Ϩεϙϯε༻ͷϑΝΠϧ
    – handler༻ͷϑΝΠϧ
    ϑΝΠϧ໊ͰԿͯ͠Δ͔෼͔ΔΑ͏ʹ
    handlerͰҙ͍ࣝͯ͠Δ͜ͱ(࠶ܝ)
    ͱʹ͔͘ݟ΍͘͢γϯϓϧʹʂ

    View full-size slide

  38. ©Gunosy Inc. 38
    handlerͰϏδωεϩδοΫΛ࢖͏͜ͱʹͳΔͷͰ
    ॲཧ͕ෳࡶʹͳ͍ͬͯ͘ͱhandler͕ͲΜͲΜංେԽ͍ͯ͘͠

    View full-size slide

  39. ©Gunosy Inc. 39
    Ͳ͏͢Δ͔

    View full-size slide

  40. ©Gunosy Inc. 40
    αʔϏεͱ͍͏΋ͷΛ༻ҙ͢Δ

    View full-size slide

  41. ©Gunosy Inc. 41
    “ ཁٻʹԠͯ͡ΫϥΠΞϯτͷͨΊʹߦΘΕΔԿ͔Ͱ͋Δɻ”
    “ Ϟσϧʹ͓͍ͯಠཱͨ͠ΠϯλϑΣʔεͱͯ͠ఏڙ͞ΕΔૢ࡞”
    ΤϦοΫɾΤϰΝϯεͷυϝΠϯۦಈઃܭ ୈ2෦ ୈ5ষ ΑΓ

    αʔϏεͱ͸

    View full-size slide

  42. ©Gunosy Inc. 42
    ???

    View full-size slide

  43. ©Gunosy Inc. 43
    - ෳ਺ͷϞσϧΛѻͬͯෳࡶͳ͜ͱΛͯ͘͠ΕΔ΍ͭ
    - repository͔Βऔಘͨ͠objectΛ͞ΒʹՃ޻͢Δ΍ͭ
    ͜Μͳೝࣝ

    View full-size slide

  44. ©Gunosy Inc. 44
    αʔϏεͰ࣮૷ (1)
    // internal/domain/article/user_specific_article_service.go
    package article
    type UserSpecificArticleService interface {
    Get(userID int64) ([]Article, error)
    }
    // internal/service/article/user_specific_article_service.go
    type userSpecificArticleService struct {
    repo Repository
    }
    func NewUserSpecificArticleService(articleRepo Repository) UserSpecificArticleService {
    return &userSpecificArticleService{
    repo: articleRepo,
    }
    }

    View full-size slide

  45. ©Gunosy Inc. 45
    αʔϏεͰ࣮૷ (2)
    func (s *userSpecificArticleService) Get(userID int64) ([]Article, error) {
    as, err := s.repo.ResolveAll()
    if err != nil {
    return nil, err
    }
    as = article.UserSpecificArticles(as, userID)
    return as, nil
    }
    service͕repository΍ϏδωεϩδοΫΛ࢖͏

    View full-size slide

  46. ©Gunosy Inc.
    // article/api_article_list.go
    package article
    import (…)
    func ArticleListHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
    req := articleRequest{}
    if err := req.Parse(ctx); err != nil {
    renderer.JSON(w, http.StatusBadRequest, err.Error())
    }
    as, err := service.FromContext(ctx).UserSpecificArticleService.Get(req.UserID)
    if err != nil {
    renderer.JSON(w, http.StatusBadRequest, err.Error())
    }
    renderArticleListView(w, as)
    }
    46
    αʔϏεͰ࣮૷ (3)
    handlerͷγϯϓϧ͕͞อͨΕͨ
    ˕

    View full-size slide

  47. ©Gunosy Inc. 47
    ಛఆͷϢʔβʔʹରͯ͠ಛఆͷهࣄΛ௥Ճͨ͠Γ͠ͳ͔ͬͨΓ͢Δ
    ̍
    ಛఆͷϢʔβʔʹରͯ͠ಛఆͷλϒΛ௥Ճͨ͠Γฒͼସ͑ͨΓ͢Δ
    ̎
    GunosyͰαʔϏεʹͯ͠Δॲཧྫ
    ■ A/Bςετͱ͔
    ■ ߟ͑ΒΕΔύϥϝʔλ
    – ϢʔβʔID OS ΞϓϦέʔγϣϯͷόʔδϣϯ...etc
    ■ A/Bςετͱ͔
    ■ ߟ͑ΒΕΔύϥϝʔλ
    – ϢʔβʔID OS ΞϓϦέʔγϣϯͷόʔδϣϯ...etc
    xxx_serviceͬͯͷ͕͋ͬͨΒԿ͔ෳࡶͳ͜ͱΛ΍ͬͯΔͳͬͯΠϝʔδ

    View full-size slide

  48. ©Gunosy Inc. 48
    ϋϚͬͨͱ͜Ζ

    View full-size slide

  49. ©Gunosy Inc. 49
    ϋϚͬͨͱ͜Ζ
    ■ package໊ͷॏෳ
    – domainͱrepository͕େମಉ͡ߏ੒ʹͳΔͨΊ
    – ࢓ํ͕ͳ͍ͷͰrepositoryͷํʹsuffixΛ͚͍ͭͯΔ
    – ྫ) repository/article → package artilcerepo
    – ߋʹimport͢Δͱ͖͸໊લ෇͖ʹ͠ͳ͍ͱ͏·͘ิ׬͕ޮ͔ͳ͍
    ■ cyclic import
    – σΟϨΫτϦΛ෼ׂ͢Δฐ֐
    – ਂ͍֊૚ʹ͍ΔϑΝΠϧͷςετͰϓϩδΣΫτશମͰ࢖͑ΔΑ͏
    ͳศརhelperΛݺͼग़ͦ͏ͱͯ͠Τϥʔ͍ͬͯ͏ͷ͕Α͋ͬͨ͘
    – σΟϨΫτϦ΍ϑΝΠϧΛখ͍ͯ͘͞͠ΔͷͰศརhelperʹཔΒͣʹ
    ςετΛॻ͘Α͏ʹͨ͠

    View full-size slide

  50. ©Gunosy Inc. 50
    ·ͱΊ
    ■ DDD͸ҰਓͰ΍ͬͯ΋ҙຯ͕͋Δʂ(ͱࢥ͏)
    – Ͳ͜ΛͲ͏௚ͤ͹͍͍͔͙͢ΠϝʔδͰ͖Δ
    – मਖ਼ൣғΛখ͘͞Ͱ͖Δ
    – ϨϏϡʔ͠΍͘͢Ͱ͖Δ(ࠓޙਓ͕૿͑ͨͱ͖)
    ■ ϑΝΠϧ͸ҙຯͷ͋Δ୯Ґʹ෼ׂ͢Δ
    ■ ύοέʔδ΋ҙຯͷ͋Δ୯Ґʹ෼ׂ͢Δ
    ■ ؾ͍ͮͨΒϦϑΝΫλϦϯά͢Δ
    – ύοέʔδʹҧ࿨ײ͕Ͱ͖ͯͨΒ
    – ϦϑΝΫλ͠΍͍͢Α͏ʹϦϑΝΫλ͍ͯ͘͠

    View full-size slide

  51. ©Gunosy Inc. 51
    Gunosy͸Ұॹʹ՝୊Λղܾ͢Δ
    Go / Python ΤϯδχΞΛืू͍ͯ͠·͢ʂ
    https://js01.jposting.net/gunosy/u/job.phtml?job_code=6

    View full-size slide

  52. ©Gunosy Inc. 52
    ͦͷଞࢿྉ
    ■ https://github.com/azihsoyn/IDDD_go_sample
    – ࠓճͷαϯϓϧϓϩδΣΫτ
    ■ https://github.com/guregu/kami
    – contextରԠͷWAF
    ■ https://github.com/azihsoyn/lwcache
    – [એ఻] ϓϩηεΩϟογϡϥΠϒϥϦ
    ■ https://github.com/golang/mock
    – interface͔Βmockੜ੒ͯ͘͠ΕΔπʔϧ

    View full-size slide