513 Views
June 18, 25
スライド概要
2025/6/8にVRChatにて開催されたweb技術集会にて使用した発表資料です
Webバックエンドのディレクトリ構造を考える 〜Golang編〜 Web技術集会 2025/06/18
自己紹介 kairox (回路) ● サーバーサイドエンジニア ○ あるメタバース(とされる)アプリのバックエンドを担当 ○ Unity以外何でも係 ■ クラウドインフラや⼀部Corp ITも業務範囲 ● SNS ○ X: qazx7412 ○ GitHub: limit7412 ○ VRChat: kairox(回路)
予防線 ● 今回はあくまで軽いノリでサクッとやる話 ● あくまで発表者はこういう感じでやってるんだなくらいで受け⽌めてほ しい
まず最初 ● とりあえずまっさらなプロジェクト ○ main.go: エントリーポイント ■ ⼀応命名がmainである必要は無い ○ go.mod: モジュール依存関係 ○ go.sum: 不正改竄チェック⽤
とりあえず本丸のアプリケーションとそれ以外は分けたい ● Goではディレクトリがpackage(=⼤体モ ジュール)として扱われる ● それぞれが単⼀のgo.modに依存してしまう ● 注意: ここではIaCの⾔語をGo前提で書いて いるがこの発表がGoにフォーカスしている から
モジュラーモノリスっぽく ● Goではgo.workを使うとモ ジュラーモノリス的に分ける ことができる
複数のエントリーポイント ● 通常のwebバックエンドの開発で(アプリケーション の)エントリーポイントが1つというのはあまり考えに くい ● 素直にエントリーポイントだけ分けるならこう ● 注意: ここでは名前をfaasとしているがあくま で話を⼀般論に寄せるためのもの ○ ex. lambda, uploder(機能)
複数のエントリーポイント ● こちらもモジュラーモノリスへ ● あえてここまでしないのも手かも ○ 本スライドでは以降この方針で
実はここまではディレクトリの話といいつつ… ● ここまではアプリケーション以前の(実質的に)各プロジェクトの分け ⽅とそれに対応するディレクトリの切り⽅の話だった ● ここからはプロジェクト内でのアプリケーションのモジュールの切り⽅ の話
予備知識: GoのWebフレームワーク事情 ● 現状のGoの主流なWebフレームワーク ○ Gin ○ Echo ● どちらも「いわゆる」マイクロフレームワーク的なもの ○ 定義に⾃信ニキでは無いので明⾔は避けておきます ● Railsのように「アーキテクチャ」を提供してくれない
予備知識: GoのWebフレームワーク事情 ● 現状のGoの主流なWebフレームワーク ○ Gin ○ Echo ● どちらも「いわゆる」マイクロフレームワーク的なもの ○ 定義に⾃信ニキでは無いので明⾔は避けておきます ● Railsのように「アーキテクチャ」を提供してくれない ● ⾃分達でディレクトリ構造を決める必要がある!!
アーキテクチャのセオリー? ● ⼀般的には(軽量)DDDやクリーンアーキテクチャが採⽤されがち? ○ 少なくとも過去⾃分が⾒たGoのプロダクトは2/3そうだった ● 今回は⼀旦DDDやクリーンアーキテクチャから⼀定の概念を拝借する形 を取ってみる ● 発表者は原書を読んだことが無いので細かい相違点などがあるかも…
ざっくりDDD(Go)における登場人物? ● 例の同⼼円や依存⽅向の話に関しては深く考えず⼀旦良く⾒るやつら ○ Handler ○ Usecase ○ Entity ○ Repository ■ QueryService ○ Infra ■ Adapter
ざっくりDDD(Go)における登場人物? ● 例の同⼼円や依存⽅向の話に関しては深く考えず⼀旦良く⾒るやつら ○ Handler: これは名前のまま ○ Usecase: ミドルウェアに依存にしないビジネスロジック層 ○ Entity: ドメインモデル置き場、Goだとstruct ○ Repository: ドメインモデルの永続化のためのやつ ■ QueryService: 複雑な参照系クエリを分ける⽤パターン(CQRS) ○ Infra: これも名前まま ■ Adapter: 外部接続だけこういう切り⽅をされることもある感
とりあえず素直にDDDしてみる ● (再)依存⽅向の話はここではしない!
EntityやRepositoryは共有物? ● EntityやRepositoryなどはプロジェクト共 通の概念なので(素直に作れば)各モ ジュール共⽤の領域を作りたくなる ● Entityの適切な場所って? ○ モジュール内で完結しうるEntityを考 えるべきか
更にモジュール化! ● 先ほどの構成だと各層が肥⼤化したとき⾟ いので何かしらの単位でもう⼀弾分ける ● Handlerだけ命名規則が違うのはGoの import仕様の都合 ○ Goのモジュールは外部からはディレ クトリ名で参照 ● 流⽯に階層深すぎか? ● 適切なモジュールの単位とは?
モジュールの単位の悩ましさ ● モジュールの単位、ドメインで切るか?機能で切るか? ○ 発表者は原書を読んだことが(ry ● ドメインで切ると同じ単位に違う機能が混じったりドメイン感で複雑に 参照しあってしまう ● 機能別で切るとディレクトリが乱⽴する ○ そもそもバックエンドで機能別に綺麗に切れるものですかね? ○ 機能を跨ぐ概念の管理をどうするのか
モジュールの単位の悩ましさ ● VRChatの機能で例えるなら ○ フレンド周りを考える ■ ドメイン別 ● Friends ○ List ○ FriendRequest ○ BlockRequest ● Favorite ○ Friends ● Social ■ 機能、画⾯別 ● FriendsList ● FriendRequest ● BlockRequest ● FavoriteFriends ● FriendsLocation
ドメイン単位で切る例 ● ここではドメイン単位で例を 作ってみる ● すべてRDBでやっている感じに なってしまっているのはあくま で例だから ● ワールドやインスタンスの概念 はあえて無視してる
まとめ ● モノレポ、モジュラーモノリス想定で作成したので仕⽅がないがなんか ディレクトリ階層深い感じになっちゃってたかも ● 今回はDDDを下敷きにしたがそうじゃない構成でもいいとは思った ○ ただその代わりになるものって? ● 正解は無い話なのでプロダクトやチームの状況で柔軟にやれば良いと思 いました(強引なまとめ)
付録 ● ドメインか機能、画⾯かの例を検討するときにGeminiに調査させたら結 構なものが出てきたのでおまけでリンクをのせる ○ https://docs.google.com/document/d/1BthEfOQllGD45eTft7Xtgic mHeHoYwtS92ceUI7n8UY/edit?usp=sharing