🐩

DDDを意識したNext.jsのディレクトリ戦略

2024/03/17に公開

WEBアプリ開発においてNext.jsを採用するシーンというのはかなり多くなってきた印象があります。

そういった中で設計思想や開発方針、メンバーの構成、スキルセットによってどのようなディレクトリの構成にするか、というところが現れるところだと思います。

今回、私が担当した案件ではディレクトリ戦略としてDDDの文脈を表現できるような形にしたいと思いトライしてみました。

前提

説明するにあたって前提をいくつか揃えておきます。

設計思想

DDDを採用し、参考としてこの本を読みながら実践したつもりです。

ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本/成瀬 允宣

https://www.amazon.co.jp/dp/B082WXZVPC

ライブラリ

ライブラリなどのバージョンはこちらです。

ライブラリ バージョン
Next.js 13.2.4
node 16.10.0

バックエンドのshopifyのgraphql、microCMSのrest APIからデータを取得するシステム構成です。デプロイ先はAWSのAmplifyを使いました。

スキルセット、メンバー

私は普段はバックエンドのコードを書くことが多く、Next.jsは個人的に少し触ったことがある程度でした。

今回の開発ではNext.jsを使ったほうが工数をかけずにリリースできると判断し、Next.jsを採用するに至りました。

開発メンバーはエンジニアの私一人とデザイナー2人、QAが2人、ビジネスサイドのメンバーは2人という全員で7人での開発になりました。

ディレクトリ戦略については、もう少しきれいに整理することができたのかもしれないと思っているところはあります。同じ轍を踏まないでいいようにここに書きます。俺の屍を超えていけ。

ビジネスに柔軟に簡単に対応するために

開発していくコードでは次の3つを重要視しました。

  • バックエンド/フロントエンドのコードを分ける
  • コードを読めば何をしているかわかる
  • ビジネス要件に柔軟に対応できる(DDDを取り入れる)

バックエンドとフロントエンド的な処理をできるだけコードを分けておくことで、これからシステムが大きくなっていくときにメリットがあると考えています。

また、できるだけ紳士協定的ではなく、コードで制約できるようにすることを意識し、ビジネス要件に柔軟に対応できるように、かつ、開発ができるだけわかりやすく簡単にできることを意識しました。

ディレクトリ構成全体像

結果を先に示すと、ディレクトリの構成の全体は以下のようにしました。

|- docker
|- src
    |- layouts
    |- models
    |- pages
        |- api
        |- index(ページ)
    |- reducers
    |- repositories
        |- interfaces
        |- (repository)
    |- services
    |- states
    |- stories
    |- tests
        |- repositories
        |- services
    |- types
    |- utils
    |- validators

以下、それぞれのディレクトリの説明をします。

docker

開発ではdockerを使っていました。src以下のディレクトリをdockerコンテナのボリュームとしてマウントします。

デプロイはAWSのAmplifyを使っていますが、この構成だと自動でコードを判別してNext.jsのアプリとしてデプロイが走るようになっています。

https://aws.amazon.com/jp/amplify/

src/layouts

pageに読み込むlaytoutを定義しています。案件の都合として複数のlayoutを使うことがあったので、layoutsのディレクトリを作成しました。

src/models

DDDにおけるモデルを定義したクラス群を格納しています。
DDDの思想に沿って、repositoryクラスの中で利用されることを想定しています。

src/pages

src/pages/apiにはNext.jsのapi routesのディレクトリを作成しています。
https://nextjs.org/docs/pages/building-your-application/routing/api-routes

そのほかは各ページのためのファイルが格納されます。

src/reducers

Reactのreducerを格納しています。DDDの文脈ではなくを横において、Reactの機能のディレクトリになっています。

src/repositories

src/repositories/interfaces というディレクトリには、リポジトリのインターフェースを格納しています。

というのも、バックエンドのシステムとしてshopifyとgraphqlと、microCMSの REST APIを使っています。
この取得処理の違うことはバックエンドの関心事であり、フロントエンドの関心事ではないはずです。

取得するデータのバリエーションをフロントエンドが取得処理の書き方が違いを意識しないでいいように、複数のバックエンドシステムでもinterfaceを揃えておくことがベターと思います。

src/services

DDDにおけるapplication serviceを定義しています。基本的にはrepositoryをラップしたり、ビジネスロジックが書かれることを想定しています。

DDDの文脈でのDomain service は極力、定義しないように心がけています。

src/states

Recoilを使っておりそれのディレクトリになります。ただRecoilを多用せず本当に必要な箇所、例えばページとページでstateを共有する必要がある場合にのみRecoilを使うようにしています。

src/stories

アトミックデザインを意識しており、この中にさらにatoms, molecules, organismas, templates のディレクトリを作成しています。

src/tests

src/repositorysrc/serviceのクラスのテストを定義します。それぞれsrc/tests/repositories, src/tests/servicesというディレクトリを作り、repository, serviceクラスをテストファイルを格納しています。

テストはjestを採用しています。

src/types

基本的にはmodelクラスをはじめ、そのクラスを定義したファイル内でで全てを記述するようにしています。
しかし、型が複雑になっていたりするものをそのファイルで書いてしまうことで可読性を下げると考え、
このsrc/typesディレクトリで別途、型定義するようにしています。

src/utils

このディレクトリではReactにおけるHookmicroCMSshopifyで使うユーティリティなコードをここに格納しています。

「util = なんでもあり」という感じがあるのであまり使いたくありませんでしたが、この名前がしっくりきているというのも事実です。

ReactのHookはHooksというディレクトリに切り出してもいいと思っています。

src/validators

Reactで作ったフォームのバリデータを格納しています。バリデーションのライブラリはシンプルに書けるreact-hook-formを使っています。

https://react-hook-form.com

感想、余談

DDDという思想が流行り廃りの早い技術の波の中で、まだ生きているのかわかりません。
とはいえ、開発時点ではDDDの文脈に重きを置きたい、プログラミング言語の仕様に引っ張られるようなディレクトリは作りたくない、と考えていました。
しかし、Reactの機能のディレクトリをいくつか作ることになってしまったのは悔しさがあります。

zod, yayを使うと良いよ、という周りからの声もありましたが、あまり恩恵を感じれそうになかったのでつ使っていません。typescriptの型定義で十分という思っているのが個人的な感想です。

また最近のフロントエンドでは、プレゼンテーション/コンテナパターンというディレクトリ戦略が最近あることを知りました。
フロントエンド的にはこういうほうが開発がしやすかったりするのか?と思ってたりもします。

https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0

カラビナテクノロジー デベロッパーブログ

Discussion