自分でいつもコロケーションという単語を忘れてしまうので備忘録として残しておきます。
ここで言うコロケーション(Colocation)とは、プログラミングにおいてコードや関連リソースを意味的にまとまった単位(ドメインや機能単位)でディレクトリ構造に整理するアプローチです。
これにより、人間の可読性やトレーサビリティが向上し、開発者がコード全体の意図を素早く把握しやすくなります。
とりあえず最近触ってるNext.jsのPage Routerを用いたコロケーションの例について書きます。
Next.jsのPage Routerにおけるコロケーション
2.1 Next.jsのディレクトリ構造
Next.jsのPage Routerはpagesディレクトリを基点としてルーティングを行います。以下の例は画面定義を前提としたコロケーションです:
/pages
/about
index.tsx # Aboutページのエントリーポイント
about.module.css # Aboutページ専用のCSS
about.test.tsx # Aboutページのテストコード
/dashboard
index.tsx # ダッシュボードのエントリーポイント
components/
Widget.tsx # ダッシュボード内のウィジェットコンポーネント
Widget.module.css
utils/
dataFetcher.ts # ダッシュボード専用のユーティリティ
ドメインで分ける場合はもうUI層とドメイン層を分解するほうがいいかもしれません。私はこんな感じで使ってます。
/pages
/about
index.tsx # Aboutページのエントリーポイント
about.module.css # Aboutページ専用のCSS
about.test.tsx # Aboutページのテストコード
/dashboard
index.tsx # ダッシュボードのエントリーポイント
utils/
dataFetcher.ts # ダッシュボード専用のユーティリティ
/components
/OwnCompanyInfo # Aboutページに使うドメイン
/handlers # onSubmitやonClickを扱う
/hooks # Hooksを扱う(useXXX)
/services # APIやデータ変換
/ui # UIコンポーネント群
/view # 参照系のUIコンポーネント
/edit # 編集系のコンポーネント
/UserProfile # ダッシュボードに使うドメイン
このディレクトリ構成でPage Routerを使っていると、実はApp Routerに移行するときもすんなりできてしまうメリットもあります。
ui
と hooks
ディレクトリはClient Component、 hndlers
はServer Component、 services
は Server Action という感じです。
循環参照をなくす
コロケーションを使う場合はあまり気にしなくても良いですが、ドメインを分割する場合は各コンポーネント定義がバラバラになるので循環参照が発生する index.ts
によるエクスポートを使わないようにすると良いかもしれません。Barrel Filesと言われているようです。
export { CompanyInfo, CompanyDetail } from './OwnCompanyInfo';
export { UserProfile, UserPhoto } from './UserProfile';
これを import { xxx } from '@components'
のように使ってしまうと、例えばAbutページでは不要な CompanyInfo
のコンポーネントも事前ロードされてしまいます。何かしらの共通処理やグローバルな状態管理を使ってると意図しないデータ参照・取得が行われてしまうので注意が必要です。
私は知らなかったので目からウロコでした。
まとめ
- コロケーションはファイルをたくさん開くと混乱する人には親切設計
- 人間がわかりやすい実装は結果的に保守性やメンテナンス性の向上になる
- どこまでやるかはメンバーと相談して決めましょう
- ベストプラクティスはないので、都度システムやチームに応じてアーキテクチャもディレクトリごと変える覚悟は必要