hey Product Blog

こだわりを持ったお商売を支えるプラットフォーム「STORES」の開発チームによる技術ブログです。

Go で実装した ID 基盤のアプリケーションアーキテクチャ

こんにちは。hey 株式会社 プラットフォーム本部 基盤グループの inari111 です。
私の部署は STORES 各プロダクトへ導入する共通基盤を開発しており、1つ目のプロダクトとして ID 基盤を Go で実装しました。
この記事では、その Go アプリケーションのアーキテクチャについて紹介したいと思います。

アーキテクチャ

開発するメンバーは MVC + Service の構成で Go を書いた経験がありました。
まず、以前と同じような MVC + Service にするか、フラット(レイヤーを作らない)にするか、レイヤーを分けるかを検討しました。
MVC + Service の構成で開発していたときは、ファットモデル、ファットコントローラーになってしまい、アーキテクチャを変更したいと考えるタイミングがありました。詳しくはこちらの登壇資料を御覧ください。

speakerdeck.com

また、フラットのようなシンプルな構成は、辛くなってきてレイヤー化していく際に、レビューコストが高くリファクタする時間がかかることを経験したことがあり、小さいアプリケーションを作る場合を除き、避けたいと考えていました。

今回は各プロダクトに導入する共通基盤ということで、長い間メンテナンスされること、 Phase1 のリリース後も機能追加が続きコード量が多くなることが考えられたため、今回はレイヤーを分けることによって関心事の分離を行うことにしました。

ID 基盤のアーキテクチャはこのようになっています。
本などでよく見る図だと思います。

f:id:inari111:20211101165528p:plain

各レイヤーについて説明します。

DI

google/wire を使って DI を行っています。

Handler

Handler 層ではルーティング、リクエスト値のバリデーションを行い、 Application の呼び出しを行います。
Application 層から返ってきたエラーを元に、適切な HTTP status code と JSON を返します。
context 周りの処理など、ミドルウェアの実装もこのレイヤーに置いています。
ルーターには go-chi/chi を使っています。

Application

ユースケースと言われるような、アプリケーションのビジネスルールを表現するレイヤーです。
具体的には、Domain 層の呼び出し、 Repository を使ったデータの永続化や取得、外部 API の呼び出しなどを行います。
また、DB のトランザクション処理はここで行っています。

Domain

ドメインモデル、ドメインロジック、Repository 等の interface を置いています。
他のレイヤーが実装の詳細を知らなくていいようにするため、モックを差し込めるようにするためにも interface はあったほうがいいと思っています。

Infra

Infra 層では DB モデル、ドメイン層で定義した Repository の実装、その他 interface の実装を置いています。
ちなみに ORM は使っていません。

レイヤードアーキテクチャのよかった点・悪かった点

よかった点は

  • 関心事の分離ができた
  • 単純な API を作るのであれば既存の実装を参考に作っていける
  • 仕様を確認する際に、コード全体を見る必要がなくなった
  • モック化しやすくなった

悪かった点は

  • 各レイヤーに値を渡すときに詰め替えが発生するためコードが増えた
  • フレームワークへの依存が少なくなった分、今までフレームワークで提供していた機能を満たすライブラリを探す必要があった
    • logger, validation, config など
  • 何をどこに書くか判断をするのが最初は難しい
    • 学習コストがあり、慣れるまで少し迷う

よかった点、悪かった点それぞれありますが、レイヤードアーキテクチャを採用してよかったと思っています。
関心事の分離を行うことで各レイヤーの責務を細かく分けることができたので、得られるメリットは大きかったです。

各レイヤーになにを書くべきか

GitHub の README に各レイヤーの説明を書いておき、あとは既存の実装を見ながら実装という感じになっています。
細かいところは言語化できておらず、気になった箇所はコードレビュー時に議論することが多かったです。
各レイヤーの依存関係は静的解析でチェックしています。例えば、 Handler 層から Infra 層を import していると検出され、 CI が落ちるようになっています。

おわりに

ID 基盤のアプリケーションアーキテクチャについて紹介しました。
アーキテクチャには正解はなく、作るものやリリースまでの期間、メンバーによって変わると思いますが、チームで納得感のある意思決定をすることが大切です。
また機会があれば Go 関連の記事を書けたらと思います。

この度、hey は Go Conference 2021 Autumn をシルバースポンサーさせていただきます。オフィスアワーブースがあるので、興味がある方はご参加ください。

Go エンジニア以外も募集しています。こちらからどうぞ。 hey.jp

hello.hey.jp