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

はじめての Go 言語のプロジェクトを AWS Lambda + API Gateway でやったのでパッケージ構成を晒すよ

はじめての Go 言語のプロジェクトを AWS Lambda + API Gateway でやったのでパッケージ構成を晒すよ

2019/01/31 開催のGo(Un)Confernce(Goあんこ)LT大会 5kg (https://gounconference.connpass.com/event/112942/) の発表資料です。

Shohei Okada

January 31, 2019
Tweet

More Decks by Shohei Okada

Other Decks in Programming

Transcript

  1. はじめての Go 言語 のプロジェクトを
    AWS Lambda + API Gateway
    でやったので パッケージ構成 を晒すよ
    Go(Un)Conference(Goあんこ)LT大会 5kg
    @okashoi

    View Slide

  2. 岡田 正平(おかだ しょうへい)@okashoi
    • 株式会社ウィルゲート
    • Gopher にもなりたい PHPer
    • 2019 年は技術書執筆にチャレンジ!
    2
    自己紹介

    View Slide

  3. • 構成: Go + AWS Lambda + Amazon API Gateway + DynamoDB
    • 一部に web クローリング処理を含む社内システム
    • 小規模(8 エンドポイント程度)
    • 社内初のフル Go 言語プロジェクト
    • Go 言語未経験者も多い
    3
    プロジェクト概要

    View Slide

  4. • 書籍『みんなのGo言語』の内容を倣った
    • レイヤードアーキテクチャを採用
    • Semantic Import Versioning
    4
    全体像

    View Slide

  5. • 書籍『みんなのGo言語』の内容を倣った
    • レイヤードアーキテクチャを採用
    • Semantic Import Versioning
    5
    全体像





    View Slide

  6. • 書籍『みんなのGo言語』の内容を倣った
    • レイヤードアーキテクチャを採用
    • Semantic Import Versioning
    6
    全体像
    • import path にメジャーバージョンを含める
    • ほぼ確実に v2 が作られることはないが
    メンバーに「推奨されているやりかた」
    を知ってもらう目的

    View Slide

  7. • controller, usecase, presenter
    • presenter は interface を定義して
    メディアタイプごとに実装 (json, xml, text)
    7
    application
    画像出典:Clean Coder Blog
    https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

    View Slide

  8. • 他のパッケージに依存しない
    • import するのは標準パッケージに限定
    • データ操作に関する interface を定義
    • クローリングのための HTTP リクエストを
    CQRS における Query とみなした
    • 今思えば ~Repository じゃなくて
    ~Command という方が分かりやすかった?
    8
    domain

    View Slide

  9. • domain で定義した interface を実装
    • DynamoDB への Read/Write
    • HTTP クライアント + HTML パーサ
    • 実際のクローリング対象ページの HTML を
    testdata 下に設置してパーサのテストを書いた
    9
    infrastructure

    View Slide

  10. • request/response を独自のものに変換してから
    application.controller に渡す
    • ルーティング
    • DI
    10
    main.go

    View Slide

  11. • request/response を独自のものに変換してから~
    • パッケージを AWS のものに依存させないため
    11
    main.go
    func newRequest(awsRequest events.APIGatewayProxyRequest) application.Request {
    return application.Request{
    Path: awsRequest.Path,
    HTTPMethod: awsRequest.HTTPMethod,
    Headers: awsRequest.Headers,
    QueryStringParameters: awsRequest.QueryStringParameters,
    PathParameters: awsRequest.PathParameters,
    }
    }
    func convertToAwsResponse(res application.Response) events.APIGatewayProxyResponse {
    return events.APIGatewayProxyResponse{
    StatusCode: res.StatusCode,
    Headers: res.Headers,
    Body: res.Body,
    }
    }

    View Slide

  12. • ルーティング
    • 愚直に文字列比較の switch case
    • これで充分な用途だったため
    12
    main.go
    switch {
    case req.HTTPMethod == "GET" && req.Path == "/v1/hoge":
    res = hogeController.Hoge(req)
    case req.HTTPMethod == "GET" && req.Path == "/v1/fuga":
    res = fugaController.Fuga(req)
    // ...(略)
    }

    View Slide

  13. • DI
    • 詳細→
    • シンプルで Go らしくて素敵だと思った
    (初心者並感)
    13
    main.go
    https://speakerdeck.com/morikuni/golang-dot-tokyo-number-11

    View Slide

  14. いまのところこんな感じで大きく破綻はしていない
    • これ以上大きくなるとやや自信ない(もうちょっと細分化したい)
    Go 未経験者がいるプロジェクトでもタスクが振りやすかった
    • まずは repository の 1 メソッドからやってもらう
    • 習熟してきたら usecase 以下をまるごと任せる
    • 型 + ビルドが通っている事実 + テストコード = レビューするのも楽
    14
    やってみて所感

    View Slide

  15. JSON(HTTP レスポンス)←→ DynamoDB のマッピング方法悩む
    • 構造体定義にタグをつければ変換できるのは便利
    • domain に定義したエンティティにタグをつけるとよさそうだが
    HTTP や DB に関する知識が domain に漏れ出すことになる
    • 最終的にはエンティティにつけることにしたが...
    • そういうことは考えずにシンプルにやろうというのが Go の思想っぽい?
    エラーハンドリングどうしようか悩む
    • 独自エラーを定義してログなどに欲しい情報を出力するなどした
    • 下位で生成したエラーを上位に渡していくのがやや煩雑
    15
    やってみて所感

    View Slide