DDDで変化をしていくサービスを開発できるようにする

私が開発に参加しているラストワンマイル配送支援システムのCREW ExpressではRailsでDDDをしながら開発しています。

私達のプロジェクトではDDDを取り入れたRailsでシステム開発をしていますが、DDDを導入したことによる開発効率があがった面が多くありそのことについて解説をしたいと思います。・

DDDを導入したことのメリット

- ドメインモデルを活用することでサービスの規模が大きくなってもActiveRecordの肥大化を防ぎつつ凝集度を高く保つ開発ができる
- 重要な機能に投資をすることで優先度の高い機能開発をすることができる
- ビジネスモデルをアップデートし続けるプロダクト開発に柔軟に対応をしていくことができる

# ドメインモデルを活用することでサービスの規模が大きくなってもActiveRecordの肥大化と凝集度の低下を防止する開発ができる

サービスの規模が大きくなるにつれてサービスの中心的なテーブルのActiveRecordがいろんなドメイン(機能)で使用されるため、特定のドメインだけしか使用しない実装が含まれてしまうことになってしまい、それが積み重なっていき肥大化していき保守をすることが困難になってしまいます。

それをさけるために、ドメインごとにドメインモデルのクラスを作成していき、そのドメインモデルにドメイン特有の実装をしていくことで肥大化を防ぎ凝集度を高くしていくことができます。

それにより、サービスの規模が大きくなってもサービスの中心となるテーブルのActiveRecord(ORM)が肥大化をすることを避けることができ

保守がしやすい状態を保つことができます。

具体例

CREW Expressでは配達を依頼するときに作成するDeliveryRequest(配達依頼)というActiveRecordが存在します。

DeliveryRequestは、配達依頼、配達、配達依頼の管理、配達員への報酬振込みという4つのドメインで使用されます。

- 配達依頼: 配達員にどこに配達をしてもらいたいかの依頼をするドメイン
- 配達: 配達依頼を受け取った配達員が配達するドメイン
- 配達依頼の管理: 配達依頼をした人が配達したものを管理するドメイン
- 配達員への報酬振込み: 配達してくれた配達員に報酬を振り込むドメイン

この中でも配達依頼のドメインは機能が多くかつ複雑であるためDeliveryRequestには、配達依頼のドメインの実装がおおくあります。

さらに、他のドメインの実装もあるためDeliveryRequestが理解しづらいのと他のドメインの実装が原因でバグになってしまうなどの問題が発生する原因になってしてしまうことになります。

![名称未設定ファイル.drawio (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46364/0c3ec5d4-8d1e-82c2-1701-4f34fe2c462e.png)



そのため、DeliveryRequestのActiveRecordにはドメイン特有の実装をしない方針をとり、ドメインモデルクラスにDeliveryRequestのインスタンスをもたせドメイン特有の実装をしていくという実装にしています。

これにより、DeliveryRequestは肥大化をしないですむようになり、各ドメインのドメインモデルは凝集度が高くなります。

また、ドメインモデルをみることでドメインについて知る事ができるようになります。

リファクタのイメージ図

![名称未設定ファイル.drawio (1) (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46364/53860469-f440-4239-836b-e2de9b5ba784.png)



# コンテキストマップを作成することで重要なドメインをみきわめ優先度の整理をすることができる

## どのようなドメインがあるのかを理解することが見極めの第一歩

ある程度規模のあるシステムを開発する場合は、整理されていないとシステムにどのようなドメインが存在してどのような機能があるかのかは理解することは難しいです。

とくにtoBプロダクトはtoCプロダクトのように日常から使用できるサービスとはちがい、どのようなドメインや機能が存在するのかはわかりづらいです。

CREW Expressは配達を依頼したい人と配達をする人のためのシステムです。
そのため、開発者は日常で使用しないプロダクトについて理解をする必要があります。
その理解をするためにはどのようなドメインがあるのかを理解したほうがいいです。
そのためには、コンテキストマップを作成するのがいいと思います。
以下の図が作成したコンテキストマップです。

これにより、システム内にどのようなドメインについて理解をする事ができます。

![スクリーンショット 2022-12-06 12.30.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46364/a1755931-ad94-04c3-3e76-a202e55ec695.png)



## モブワークでコンテキストマップを作成するとメリットが多くある

一人でコンテキストマップを作成することも効果はありますが、その効果をより高めるためにモブワークをしてチームで一緒にドメインモデリングをしながら話し合いながらコンテキストマップを作成しました。

これにより、すでにシステムを長い間開発していた人から新しくチームに参加した人にドメインについての説明をしていくことができたり、新しくチームに参加した人が既存のメンバーに質問をすることでコンテキストマップ内で記述が必要な部分を話すことができ、コンテキストマップをアップデートをしていくことができます。

コンテキストマップを作成していきながらドメインについて理解を深めていくことで、競合他社との差別化ができシステムにとっても最も重要な機能であるコアドメインをみつけることができます。
また、コンテキストマップを作成するときはモブで作業をしているためチーム全体でコアドメインであることの話し合いができているため、ここにリファクタリングの工数を使っていくというチームの認識もできます。

## コンテキストマップは新機能を開発するときに必ずアップデートをするようにする

普段の開発からコンテキストマップをアップデートをしていかないと、コンテキストマップが放置されてしまいコンテキストマップを作成した時と現状が違ってしまいコンテキストマップを見た人が間違った認識をしてしまうということになり、コンテキストマップが存在しないほうがましという状態にもなってしまう可能性があります。

私達のチームでは新機能を開発するときはDesign Docを作成するようにしています。
Design Docを書いていくときはドメインモデリングをするようにしています。
そのドメインモデリングの最初にコンテキストマップレベルでの変更がないかを確認して、新しいドメインやコンテキストがあったり、変更がある場合はコンテキストマップを変更します。
これによりコンテキストマップが放置されてしまうことを防ぐことができます。

# ビジネスモデルをアップデートし続けるプロダクト開発に柔軟に対応をしていくことができる

CREW Expressではコアドメインである配達員の募集のドメインが大きく変わりました。

上述した、ドメインモデルを作成した設計やコンテキストマップでのサービスの理解などをしていたため、どのように機能追加をすればいいかなどを事前に話しながら対応をしていくことができたので他のドメインに影響をあたえずにすみました。

もし、ドメインモデルを作成していなかったらActiveRecordのコードを大きく変更する必要があり、関係ないドメインに影響をあたえてしまいActiveRecordの保守が困難になってしまい、大きな技術負債を抱えてしまうことも考えられました。

また、コンテキストマップを作成していなかったらドメイン同士の関連を考えることができずに、機能追加後にシステムがどのようなドメイン間の連携をしていけばいいかを理解をするのが難しくなってしまったと思います。

# 最後に

今回のようにコアドメインが大きく変わる必要があるのは発展途中のサービスには多くあると思いますが、同じテーブルを使用しているドメインへの影響をしないですむようにドメインモデルクラスを作成していき、コンテキストマップをアップデートしていきドメイン間の連携を考えることができたら、変更していくサービスに対応をし続けるシステムを作成していくときに役に立つと思います。