開発プロジェクトのフォルダ構成って毎回悩みますよね。
プロジェクトやチーム、個人の設計思想によってかなり違ってきますし、プロジェクトのフェーズ(序盤・中盤・終盤)によっても「使いにくいフォルダ構成だな」「もっとこうしておけば良かった…」というように考え方が変わったりします。
考え始めると意外と難しいものではありますが、フォルダ構成について悩むのもソフトウェア開発の醍醐味で、プロジェクト立ち上げ時のワクワクを感じるひとつの楽しみでもあると思います。
そんなフォルダ構成について、今回はNext.jsプロジェクトにおけるフォルダ構成をアトミックデザインをベースとして考えてみました。
先に結論
調べたり考えたりした結果、個人的には以下の構成が良いなとなりました。
next/
|-- __tests__/
| |-- api/
| |-- components/
| | |-- atoms/
| | |-- molecules/
| | |-- organisms/
| | `-- templates/
| |-- hooks/
| |-- lib/
| `-- pages/
| `-- api/
|-- public/
`-- src/
|-- api/
|-- components/
| |-- atoms/
| |-- molecules/
| |-- organisms/
| `-- templates/
|-- hooks/
|-- lib/
|-- pages/
| `-- api/
|-- theme/
`-- types/
src
,__tests__
を一括で作るコマンドはこちら。
mkdir -p __tests__ __tests__/api __tests__/components __tests__/components/atoms __tests__/components/molecules __tests__/components/organisms __tests__/components/templates __tests__/hooks __tests__/lib __tests__/pages __tests__/pages/api src src/api src/components src/components/atoms src/components/molecules src/components/organisms src/components/templates src/hooks src/lib src/pages src/pages/api src/theme src/types
Next.jsなところ
まずNext.jsではpages
配下が自動的にルーティングされる部分。
基本的に変更しようがない部分ではありますし、変更する意味もなさそうです。create-next-app
するとpages
,pages/api
が作成されますが、これはそのままで良いと思います。
しかし、
- コードの肥大化を防ぐ
- 再利用しやすいコードにする
ということは意識していきたいです。
そのため、pages
はNext.jsアプリケーションのエントリポイントとしての役割のみを持たせ、詳細な実装は別フォルダへ委譲します。pages
配下のソースコードからは別フォルダのソースコードをimport
して呼び出すくらいになるのが理想です。
あとはどこで管理するかくらいですが、最終的に以下のようにすることにしました。
- APIの詳細部分は単純に
api
にまとめる - UIの詳細部分は
components
にまとめる(後述のアトミックデザインにならう)
UIコンポーネント
UIの詳細はアトミックデザインにならって以下のような構成にします。
components/
|-- atoms/
|-- molecules/
|-- organisms/
`-- templates/
アトミックデザインを採用する理由は、Reactのようなコンポーネント主体のライブラリとアトミックデザインの設計思想との親和性が高いと考えるからです。
UIパーツを細分化して、大きなものは小さなものの集合という構成はわかりやすくて良いです。
アトミックデザインの詳細については、さまざまなサイトで解説されていること、考案者のBrad Frost氏によってそのドキュメントがWeb上で公開されていることから省きます。
Reactなところ
UIコンポーネントについてはすでに書いた通り。
React関連で残すところは、フック(hook)とスタイル、状態管理くらいでしょうか?
hook
これは単純にhooks
で良さそう。
Reactを使っていることがパッとわかるのも良いです。
スタイル
ReactのコンポーネントライブラリとしてChakra UIを使うことが多いので、スタイル関連はtheme
へまとめています。
ただし、Chakra UIのようなコンポーネントライブラリを使わない場合はstyles
がわかりやすいかなと思います。
状態管理
フロントエンド側では状態管理する必要がないような設計が好みなのであまりきちんと調べず。
必要に応じて、使用する状態管理ライブラリに合わせたフォルダを作れば良いかなと思います。
フォルダ名はライブラリによって変わると思うので割愛。
共通処理・共通定義
言語やフレームワークにはあまり依存しないところとして、共通処理や型定義が考えられます。
共通処理
共通処理はどんなプロジェクトでも用意するかと思います。
いろいろ考えた結果、共通処理はlib
にまとめるのが良いかなと思います。
今まで携わったプロジェクトではutil
やcommon
が多かったのですが、
util/util.js
やcommon/common.js
のような同じ名前が2重に続くファイルが作られがち。util.js
やcommon.js
にとりあえずでなんでも書いてしまう人がいる。- 上記のファイルが編集しやすく、複数人で編集するため肥大化する・競合しやすい。
ということが多くて嫌でした。
なので誰でも使いやすい名前は避けるべきかなという思いがあります。
特に「とりあえず」で編集しやすいファイルはなくしたいです。
libという名前をベースとすると、lib.js
は意味がわからないので作られにくそうですし、lib/util.js
も変なので作られにくそう。
libという名前からイメージするのがライブラリやモジュールなので、lib
配下は意味のある単位でファイルを分割して作ってくれそうだなという独断と偏見からlib
を推したいと思います。
型定義
独自の型定義を別ファイルにするような言語の場合は、types
にまとめておきます。
TypeScript由来なところはありますが、わかりやすくて良いなと感じています。
ユニットテスト
__tests__
配下で行うテストはユニットテストです。
ソースコードごとにテストすることを想定しているため、基本的にはsrc
と同様の構成がわかりやすいかなと考えています。
機能ベースでテストするなど、テスト対象がある程度まとまりを持ったものとなる場合は、違うフォルダ構成にすべきかなというところです。
最後に
フォルダ構成と書くとなんか簡単そうな響きですが、考え出すとなかなか難しいところ。
「そんなの適当でいい」という人も多いかもしれませんが、チーム開発をする場合には管理しやすいフォルダ構成にするのは必須事項というのが筆者の意見です。(個人で開発する分には適当でよいかもしれませんが)
最終的にはチーム内ですり合わせをして、共通理解・共通認識を持つことができればどんなフォルダ構成でもOKだと思いますが、ベースとなる考え方がひとつあるだけでも検討しやすいかと思います。