Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

729 views

Published on

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

Published in: Software
  • Be the first to comment

  • Be the first to like this

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

  1. 1. はじめての Go 言語 のプロジェクトを AWS Lambda + API Gateway でやったので パッケージ構成 を晒すよ Go(Un)Conference(Goあんこ)LT大会 5kg @okashoi
  2. 2. 岡田 正平(おかだ しょうへい)@okashoi • 株式会社ウィルゲート • Gopher にもなりたい PHPer • 2019 年は技術書執筆にチャレンジ! 2 自己紹介
  3. 3. • 構成: Go + AWS Lambda + Amazon API Gateway + DynamoDB • 一部に web クローリング処理を含む社内システム • 小規模(8 エンドポイント程度) • 社内初のフル Go 言語プロジェクト • Go 言語未経験者も多い 3 プロジェクト概要
  4. 4. • 書籍『みんなのGo言語』の内容を倣った • レイヤードアーキテクチャを採用 • Semantic Import Versioning 4 全体像
  5. 5. • 書籍『みんなのGo言語』の内容を倣った • レイヤードアーキテクチャを採用 • Semantic Import Versioning 5 全体像 依 存 の 方 向
  6. 6. • 書籍『みんなのGo言語』の内容を倣った • レイヤードアーキテクチャを採用 • Semantic Import Versioning 6 全体像 • import path にメジャーバージョンを含める • ほぼ確実に v2 が作られることはないが メンバーに「推奨されているやりかた」 を知ってもらう目的
  7. 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
  8. 8. • 他のパッケージに依存しない • import するのは標準パッケージに限定 • データ操作に関する interface を定義 • クローリングのための HTTP リクエストを CQRS における Query とみなした • 今思えば ~Repository じゃなくて ~Command という方が分かりやすかった? 8 domain
  9. 9. • domain で定義した interface を実装 • DynamoDB への Read/Write • HTTP クライアント + HTML パーサ • 実際のクローリング対象ページの HTML を testdata 下に設置してパーサのテストを書いた 9 infrastructure
  10. 10. • request/response を独自のものに変換してから application.controller に渡す • ルーティング • DI 10 main.go
  11. 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, } }
  12. 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) // ...(略) }
  13. 13. • DI • 詳細→ • シンプルで Go らしくて素敵だと思った (初心者並感) 13 main.go https://speakerdeck.com/morikuni/golang-dot-tokyo-number-11
  14. 14. いまのところこんな感じで大きく破綻はしていない • これ以上大きくなるとやや自信ない(もうちょっと細分化したい) Go 未経験者がいるプロジェクトでもタスクが振りやすかった • まずは repository の 1 メソッドからやってもらう • 習熟してきたら usecase 以下をまるごと任せる • 型 + ビルドが通っている事実 + テストコード = レビューするのも楽 14 やってみて所感
  15. 15. JSON(HTTP レスポンス)←→ DynamoDB のマッピング方法悩む • 構造体定義にタグをつければ変換できるのは便利 • domain に定義したエンティティにタグをつけるとよさそうだが HTTP や DB に関する知識が domain に漏れ出すことになる • 最終的にはエンティティにつけることにしたが... • そういうことは考えずにシンプルにやろうというのが Go の思想っぽい? エラーハンドリングどうしようか悩む • 独自エラーを定義してログなどに欲しい情報を出力するなどした • 下位で生成したエラーを上位に渡していくのがやや煩雑 15 やってみて所感

×