google/wireを使った Goらしいアーキテクチャへの取り組み / gocon-fukuoka-2019-summer

google/wireを使った Goらしいアーキテクチャへの取り組み / gocon-fukuoka-2019-summer

2019/07/13 に行われたGo Conference '19 Summer in Fukuoka で発表した資料です。

https://fukuoka.gocon.jp/ja/speakers/budougumi0617/

Eb6be531bcfaa99714d8d3b48665a5a9?s=128

Yoichiro Shimizu

July 13, 2019
Tweet

Transcript

  1. GoConference’19 google/wireを使った Goらしいアーキテクチャへの取り組み Go Conference ‘19 in Summer 2019/07/13 Yoichiro

    Shimizu @budougumi0617
  2. GoConference’19 2 Yoichiro Shimizu @freee K.K. https://budougumi0617.github.io/

  3. GoConference’19 3

  4. 4

  5. 今日のゴール • google/wireの概要・利用方法を紹介する • (私が考える)Goらしいパッケージ設計の共有する • 実際にgoogle/wireを使ったコードの紹介する • google/wireのCons/Prodを共有する 5

  6. google/wire 6 /

  7. Dependency Injection 7

  8. github.com/google/wire • DIを行うためのCLIツールと実装用APIライブラリ ◦ 2018年7月に公開されたgoogle/go-cloudに付属 ◦ 同年12月頃に独立したリポジトリに分離 ◦ 現在 v0.3.0(beta

    release) ◦ DIの定義をするライブラリ ◦ 定義からDIコードを自動生成するCLI 8
  9. wireがもつ2つの概念 • Provider ◦ どのような依存関係があるのか • Injector ◦ どうやって依存を解決するのか 9

  10. Provider wire.NewSetで定義 10

  11. wire show 11

  12. Inejctor wire.Buildで定義 12 この宣言はBuild Constraintsを使ってgo build時には使われない

  13. wire gen 依存性を解決したコードを自動生成 13 wire genで生成したこちらのコードが go build時に利用される

  14. Inejctor 先ほど程度ではあまりメリットを感じないが… 14

  15. wire gen 自動生成結果 クリーンアップ処理も よしなに書いてくれる 15

  16. wireを使った アーキテクチャ 16 /

  17. その前に 17 /

  18. Goらしい 設計とは? 18 /

  19. 良いアーキテクチャ設計をしたい • Goにおいて何をもって「よい」と言えるのか? ◦ フラットパッケージにすればよい? ◦ DDDのような本のレイヤー構成通りにすればよい? • 言語思想に沿った設計を心がける ◦

    Simplicity 19
  20. Simplicity - 徹底的な簡潔性 • GoのMission ◦ Creating software at scale

    ◦ Running software at scale • システムは成長する際に、デザインの簡潔性を通してのみ、 安定し、安全であり、首尾一貫したままでいられる 20 Go's New Brand の Mission, プログラミング言語 Go まえがき より
  21. • 小さなInterfaceで他pkgへの依存を絞る ◦ 高々1つしかメソッドを持たないXXXer • Interfaceとダックタイピング ◦ 利用package側でInterfaceを宣言 疎でひとつのことをうまくやるレイヤー構成 21

  22. コード 22 /

  23. 各レイヤーの実装イメージを簡単に紹介 • 題材: OAuth2.0トークンを生成するHTTPサーバ ◦ HTTPリクエストパラメータを使って認可サーバからトークンを 生成する ◦ 生成したアクセストークンをDBに永続化 23

  24. package構成 24 entity データの定義 domain ドメインロジックの実装 repository データの永続化 usecase ドメインモデルとリポジトリからシナリオを作る

    http HTTPとプリミティブなパラメータを仲介 app Injectorを配置し自動生成コードを置く
  25. entity 素朴なデータ構造 25

  26. domain ドメインロジックの実 装 ダミー認可サーバを 使ったテストなど結 構真面目に書いて いる 26

  27. repository RDBMSに対する CRUD UTではsqlmockな どを利用 27 モックで済ませているのは基盤ライブラリを使っているからという事情もある

  28. usecase 1 リポジトリ層に対す る抽象化 28

  29. usecase 2 ドメインモデルとリポ ジトリを組み合わせ る層 UTではgo-mockを 利用 wireでSetを定義 29 リポジトリは各ユースケース共通になることが多いのでドメインモデルのみ

    DIしている
  30. http HTTPリクエストをプ リミティブなパラメー タに分解 UTではgo-mockと httptestを利用 wireでSetを定義 30

  31. app 全ての依存関係の 解決方法を定義 wire genでコードを 自動生成する 31 HealthCheckやメトリクスチェックなどアプリとして必要な機能も全て DIしている

  32. 所感と利点 32 /

  33. • package間のインターフェイスにwire wayができる ◦ wireが使いやすい構造 == 疎な構造 • パッケージ間の依存関係を機械的に表現できる ◦

    wire show • あまり独自要素がない ◦ ロジック部分に癒着しないので最悪すぐ辞められる 使っていてよいところ 33
  34. • 単純にDIコードを書かなくて済んでいる ◦ 自動生成前 36行 / 自動生成後 91行 ▪ 4

    API, RDS, KMS, Redis etc... • wireコマンド自体も使いやすい ◦ エラーメッセージなどが親切 使っていてよいところ 34
  35. • 先月にbetaリリース ◦ まだ破壊的変更が入る可能性がある • 単純に依存するツールが増える ◦ wire”コマンド”もバージョン管理しないといけない • Interface増えがち

    ◦ wireのためのInterfaceになっている気もする 難しいところ 35
  36. まとめ 36 /

  37. 今日のゴール • google/wireの概要・利用方法を紹介する • (私が考える)Goらしいパッケージ設計の共有する • 実際にgoogle/wireを使ったコードの紹介する • google/wireのCons/Prodを共有する 37