typescript × express × prisma × nuxt での ドメイン駆動設計開発

カラダノートでエンジニアをしている田中です。 弊社ではドメイン駆動設計を導入しており、実際に運用しているパッケージ構成についてまとめようと思います。

ちなみにですが、参考書籍の記述では、「ドメイン駆動設計にとってアーキテクチャは主役でない」とのことでした。ビジネスモデルに合わせたドメイン知識を主役に処理を作っていく中で、アーキテクチャはあくまでドメイン駆動設計の開発思想を実装に落とし込むための副産物なのだと解釈しています。

今回、説明する構成も弊社で扱う開発の中で模索した一例です。ドメイン駆動設計のパッケージ構成に無理やり合わせるばかりではなく、使っているフレームワークがあるならば、基本的にはフレームワークの構成、規則に従って開発をすることが個人的には安定した開発につながると思っています。

express × prisma × nuxt での開発構成

さっそくですが、パッケージ構成を下記に記載します。

├── app
│   ├── api (backend 構成)
│   │   ├── controller
│   │   ├── index.ts
│   │   └── router.ts
│   ├── client (frontend 構成 [nuxt])
│   │   ├── assets
│   │   ├── components
│   │   ├── layouts
│   │   ├── middleware
│   │   ├── pages
│   │   ├── plugins
│   │   ├── static
│   │   ├── stores
│   │   └── utils
│   ├── domain 
│   │   └── model
│   ├── infrastructure
│   │   └── prisma
│   ├── nuxt.config.js

nuxt init で作成されるフロントエンドのソースを client/ 、 バックエンドのソースを api/ 、 汎用的に使われるドメインモデルを domain/ 、 他の層を支える技術基盤との連携処理を infrastructure/ で扱っています。

ドメイン駆動設計の説明で扱われる一般的なアーキテクチャとして下記が挙げられますが、特にレイヤードアーキテクチャに沿った構成にしています。

レイヤードアーキテクチャとはドメイン駆動設計の文脈の中でも、よく出てくるアーキテクチャで下記 4 層のレイヤーに分け、役割を分割したものです。

  • ユーザインターフェース
  • アプリケーション
  • ドメイン
  • インフラストラクチャ

これに記載したディレクトリを当てはめていくと下記のようになります。

  • ユーザインターフェース: client/
  • アプリケーション: api/
  • ドメインdomain/
  • インフラストラクチャ: infrastructure/

それぞれの構成について説明していきます。

client/

├── client (frontend 構成 [nuxt])
│   ├── assets
│   ├── components
│   ├── layouts
│   ├── middleware
│   ├── pages
│   ├── plugins
│   ├── static
│   ├── stores
│   └── utils

client/ 配下は前述した通り、 nuxt の構成を基本としています。

基本的にはフレームワークの構成、規則に従って開発をすることが個人的には安定した開発につながると思っています。

アプリケーション層

├── api (backend 構成)
│   ├── controller
│    │   ├── [usecase].ts
│   ├── index.ts
│   └── router.ts

バックエンドのアプリケーションリソースを扱っています。 上記の構成で api/controller/ に持たせてアプリケーションのユースケース毎にファイルを作っておりその中で各処理を記述しています。

ドメイン

├── domain 
│   └── model

ここでは、ドメイン駆動設計の名の通りドメイン知識を扱っています。 弊社ではここに設計に沿った値オブジェクトや使い回しのできる軽量なドメインモデルを実装しています。

下記記事を参考にしてください。

tech-karadanote.hateblo.jp

tech-karadanote.hateblo.jp

インフラストラクチャ層

├── infrastructure
│   └── [module_name]

ここでは、他の層を支える技術基盤との連携処理を扱っています。 弊社で使っている例としては下記が挙げられます。

  • ORMツールを利用した、データベースからのデータの取得や更新処理
  • 外部ストレージへの画像保存処理
  • メール送信処理

ここで定義した処理を api/controller/ で呼び出すことでアプリケーションの構築をしています。

f:id:karadanote:20220117102717p:plain
インフラストラクチャ図

まとめ

ドメイン駆動設計を進めていくに当たり、アーキテクチャ、パッケージ構成についてまとめてみました。主に新規開発で取り入れているため、まだまだ軽量な設計で運用しています。 これからプロダクトが継続して進めばシステム規模も大きくなり、処理も増えていくので、現在の構成を改善していくことも検討していこうと思います。

参考