フルスクラッチでプロジェクトを始めるときにやっていること

この記事は、[Wano Group Advent Calendar 2024](https://qiita.com/advent-calendar/2024/wano-group)の3日目の記事です。
2日目は...自分の[GoでTSVからエラーレスポンス用のコードを自動生成する](https://qiita.com/ktat/items/1cb5e68585392f4145e2)でした。
グループ会社のEDOCODEも[Advent Calendar](https://adventar.org/calendars/10618)をやっていますので、そちらもどうぞ。

## フルスクラッチでプロジェクトを始める

そんな経験はありますか？
僕は、最近は一つのプロジェクトを長くやることが多いので、そんなに機会はないのですが、規模を問わなければ、1〜2年に1回くらいはある気がします。

そんなときに、最初に何をやっているかという話をしたいと思います。

## 一番大事なことは何か？

端的に言うと「関わる開発者が迷わないようにする」ということが大事なんじゃないかなと思っています。

最初にこのプロジェクトでは「こうやって作る」という筋道を立ててしまう(独断と偏見で(時間があれば、みんなの意見を聞きながらゆっくりやれればよいけど))。それにしたがって作ってもらえれば、開発の枝葉末節について迷わなくて済むんじゃないかなと思っています。
もちろん、開発する機能について頭を悩ますことは当然あるとしても、余計なところであまり頭を使わないほうが良いよね、というスタンスです。

そういうわけで、直近のプロジェクトで、どんなことを決めたのかを書いてみます。ちなみにこの開発ではAPIのみの開発でした。

## やったことリスト

最初にやったことをズラッと並べました。

1. 言語の選定
2. フレームワークの選定
3. ORM/migrationツールの選定
4. ディレクトリ構成の決定
5. エラーの取り扱い
6. ルーティングを決める
7. ミドルウェアを作る
8. リクエスト/レスポンスの取り扱い
9. テストの書き方
10. ドキュメントを書く

## 1. 言語の設定

今回はGoにしました。経験者がそれなりにいるのと、速度的に十分というところでの選定です。
個人的には、Pythonもありかなぁという気分を持ち続けているのですが、まぁ、Goのほうが速いしちおうことでGoにしました。
Rustという考えもなくはないのですが、Rustはみんなが書くにはハードルが高すぎると思ったので、Goにしました。

## 2. フレームワークの選定

最近速いと話に聞いたので、fiberを選びました。今まではecho、その前は、Beegoを使っていましたが、fiberを調べて、API書くのには何の問題もなさそうでしたので、選んでみました。
機能で気になるのは、ルーター、リクエスト、レスポンスの書き方、ミドルウェアを書けるか、あたりが気になるくらいです。既存のミドルウェアが多くあれば、それも良いですね(使うか、使わないかは別に参考にできる)。

大したこと書いてないですが、[記事にしてる](https://qiita.com/ktat/items/c5e22a7cc47e41fd4b95#fiber)ので、よかったらどうぞ。

## 3. ORM/migrationツールの選定

既に何回も書いたのですが、ORMは[sqlc](https://github.com/sqlc-dev/sqlc)です。毎回変えてたんですが、これで落ち着けそうな気がしています。
毎回変えてたら、知識がたまらんやんという向きもあるかもしれませんが、個人的には毎回忘れてるレベルなのでなんの問題もないです…というのは半分くらい本気ですが、ORMくらいなら見たら思い出すし、そんなややこしいことはないですね。

ただ、sqlcは今まで見た中でも、だいぶ単純明快です。複雑なことを簡単にできる(というか、複雑なことはSQLとして隠蔽できる。where句をコードで表現するなんてアホらしいし、insert selectも悩まずにかける。

[sqlc記事まとめ](https://qiita.com/ktat/items/89bd5dbfed238e761b44)を作っているので、よろしければどうぞ。

migrationツールは、sqlcのドキュメントで紹介されていた、[Dbmate](https://github.com/amacneil/dbmate)にしました。Dbmateを選んだ経緯については、[この辺](https://qiita.com/ktat/items/486c41fa43cebb0e07bc#dbmate%E3%81%AE%E5%88%A9%E7%94%A8)に書いてます。

## 4.ディレクトリ構成の決定

今回DDDでやることにしましたが、僕自身そんなに知見があるわけでもないです。
これに関しては、ChatGPTに相談して、複数案を出してもらって、いい感じにミックスして決めました。

DDDですが、プロジェクトを終わらせないとどうしようもないので、なんとなくそれっぽくくらいで、あまりこだわってはいません(つもりですが、割とレビューで直しは要求しているかも…)。

## 5. エラーの取り扱い

エラーレスポンスを、どう返すか、同じやり方で返すように決めています。増やしたい時の増やし方も決めておきます。[自動生成するようにしました](https://qiita.com/ktat/items/1cb5e68585392f4145e2)。

## 6. ルーティングを決める

グルーピングの仕方、ルーティングの書き方をサンプルとして書いておきます。

## 7. ミドルウェアを書く

APIだったので認証を取り扱うAPIを用意しておきました。ユーザー情報など、よく使う必要な情報は意識しなくてもカスタムコンテキストから取れるようにしておきます。

## 8. リクエスト/レスポンスの取り扱い

サンプルとして書いておいて、こうしてください、というのを指定しておきます。
以下のようなことをやりました。

[[Go]Genericsを使ってWebアプリの共通処理をまとめて行う](https://qiita.com/ktat/items/9a4c89a1cc859b74b30f)を参照。

## 9. テストの書き方

今回はなるべくテストを書くことにしたので、テストの書き方についても決めました。

- テストを、どう動かすのか
- DBを使ったテストはどう書くのか
- どこにテストデータを書くのか
- ルーティングのテストや、リポジトリのテストなどを、サンプルとして用意

一部は、[go-mysql-serverを使ってテンポラリなDBを立ち上げてテストを行う](https://qiita.com/ktat/items/486c41fa43cebb0e07bc)に書きました。

## 10. ドキュメント

READMEみたらセットアップできるようにしておきます。サーバーの動かし方についても書いておきます。

必要に応じて、他のドキュメントも書きます。今回は、以下のようなドキュメントを最初から用意しておきました。

- development.md ... 開発の方針
- sqlc_dbmate.md ... sqlc/dbmateの基本的な使い方
- test.md ... テストの書き方
- errors.md ... エラー処理の仕方
- how_to_write_api.md ... APIを新規に作る場合のやり方
- how_to_write_middleware.md ... ミドルウェアを作る方法

## 終わり

最初から完璧である必要はないですが、これくらいを早い段階で用意して、プロジェクトに入れば、開発者はロジック部分だけに集中してもらえるんではないかと思います。ちなみに別に順番通りにやっているわけでもないですし、毎回全部やっているわけでもないです。今回はこれくらいやりました、という感じです。

後は、方針と逸れているコードは、コードレビューで直してもらえば良いかと思います。

以上、参考になれば幸いです。

明日は、@_tachi_ の、「[フルスタックエンジニアの頭の中](https://qiita.com/_tachi_/items/1387cdfbc5878503a739)」になります。