1. この記事について
下記の本を読んで自分の理解が浅かったところなどを中心に今後のために残すためのものになります。
立場的にも似たような本を読むことが多いので、後輩などに相談された時に違いをもって説明できたらいいなと思ってます...。
2. 本の概要
オンライン書籍というのを題材にドメイン(ソフトウェアで解決したい問題領域)とは何なのか?を具体例を持ってDDDを説明する内容です。
この書籍では具体的にドメインをサブドメイン、境界付けられたコンテキスト、コンテキストマッピングへの細分化する考え方といった実装前に行う設計工程の指針が一段掘って説明してありました。
他の本ではドメインとは『こう』考えられるよね?じゃあこれで設計しました!!となり、フォーカス対象が、クリーンアーキテクチャなどの『アーキテクチャ』に沿ってどのように実装するべきであるか?を教えてくれるモノが多い印象なのでありがたかったです。
そのため、Part3以降でアーキテクチャも考えた実装に入った際、納得感が強く得られました。
3. この本を読もうとした動機について
また、いくつかのDDDに関する本を読み下記のようにChatGPTに問題を作ってもらい考える機会を作ったが、システムアーキテクトとしての成長の実感を得られにくい状態が続いていました。
今回、『つくりながら』という構成だったのでキーボードで入力しながら、本に書いてあることを確認するために読み戻って考えたりしました。
それが良かったのか、いつもより成長の実感は得られたように思います。
仕事上、効率的に業務をこなすためにすべてに対してAIを使うことが基本になり過ぎた結果、プライベートでもAIを使い過ぎるようになり、深く意味を理解し整理と出力する能力が衰えていること実感しています...。
問題①:Repositoryの責務分離
あなたのチームでは、以下のようなコードが存在します。
```python
# order_repository.py
class OrderRepository:
def __init__(self, db):
self.db = db
def save(self, order):
self.db.execute("INSERT INTO orders VALUES (?, ?, ?)", (order.id, order.customer, order.amount))
self.db.execute("INSERT INTO logs VALUES (?, ?)", (order.id, "Order created")) # ログ記録もここで実施
```
この OrderRepository は動作していますが、アーキテクチャ的に問題があります。
何が問題で、どう修正すべきか?
要点
Repositoryはドメインオブジェクトの永続化責務に限定すべき。
クロスカット関心事(例:ログ、監査)は別コンポーネントに委譲。
単一責務の原則(SRP)違反はテスト困難・変更波及を引き起こす。
模範解答
問題点:
OrderRepository が永続化+ログ記録という2つの責務を持っている。
結果として「DB構造変更」「ログ出力方針変更」どちらでもRepositoryが影響を受ける。
修正案:
Repositoryは「Orderを保存する」責務のみに限定。
ログ出力はApplication層で行う。
例:
```python
# application/usecases/place_order.py
class PlaceOrderUseCase:
def __init__(self, repo, logger):
self.repo = repo
self.logger = logger
def execute(self, dto):
order = Order.create(dto.customer, dto.amount)
self.repo.save(order)
self.logger.info(f"Order created: {order.id}")
```
👉 責務が明確になり、Repositoryをテストダブルに置き換えても副作用がなくなる。
---
問題②:層間依存の方向違反
次のような構造になっています。
/domain
order.py
/application
place_order_service.py
/infrastructure
db_connection.py
domain/order.py の中で、直接 `from infrastructure.db_connection import get_connection` が呼ばれています。
この設計上の問題を説明し、**DIP(依存関係逆転の原則)**に基づいてどう直すべきか述べてください。
要点
依存の方向は「外→内」でなければならない。
(UI → Application → Domain、Infrastructureは内層の抽象を実装)
Domainは技術に依存しない。逆転の原則で「抽象」に依存させる。
模範解答
問題点:
Domain層がInfrastructure層(DB技術)に依存している。
これにより、DB変更・技術差し替えのたびにDomainを改修する必要がある。
修正案:
Domain層には「抽象インターフェース」を定義。
Infrastructure層がそれを実装。
```python
# domain/repositories.py
from abc import ABC, abstractmethod
class OrderRepository(ABC):
@abstractmethod
def save(self, order): ...
```
```python
# infrastructure/order_repository_sql.py
from domain.repositories import OrderRepository
class SqlOrderRepository(OrderRepository):
def __init__(self, conn):
self.conn = conn
def save(self, order):
self.conn.execute(...)
```
```python
# application/place_order_service.py
class PlaceOrderService:
def __init__(self, order_repo):
self.repo = order_repo
def execute(self, dto):
...
```
👉 これで依存方向が**内向き(安定方向)**になり、DIP遵守。
---
問題③:DTOとテスト戦略
以下のようなコードが存在します。
```python
# adapters/controllers/order_controller.py
def create_order(request):
order = Order(
customer=request["customer"],
amount=request["amount"]
)
service.place_order(order)
```
この設計の問題と、DTOを導入した場合のテスト容易性の改善点を説明せよ。
要点
Controller層で直接Domainオブジェクトを生成するとUI変更がDomainへ波及。
DTOを導入して、境界の入力変換責務を明確化。
DTOは検証・マッピング・テストの単位を分離する。
模範解答
問題点:
Web入力(JSON)を直接Domainに詰めているため、バリデーションや形式変更がDomainに影響。
テストで「Web入力フォーマット」変更が「ドメインロジック」のテストにまで影響する。
改善案:
DTO(Data Transfer Object)を導入し、Controllerで変換責務を明示。
```python
# dto.py
from pydantic import BaseModel
class OrderDTO(BaseModel):
customer: str
amount: int
```
```python
# controller
def create_order(request):
dto = OrderDTO(**request)
service.place_order(dto)
```
→ Application層で `Order.create(dto.customer, dto.amount)` を行う。
テスト戦略の利点:
- DTO単体で入力検証テストが可能。
- Domainテストは純粋なロジック検証に集中できる。
- ControllerテストはI/O変換のみに限定される。
---
🔍 今日のまとめ
観点 | 守るべき原則 | 実務での効果
---|---|---
Repository | 単一責務 | テスト容易・副作用分離
層間依存 | DIP遵守(外→内) | 技術差し替え容易
DTO | 境界明示とテスト分離 | 入力検証とドメインを独立管理
4. 学びトップ3
まだまだ理解も浅い点があるので、実作業する際には手元に広げたいなと思った内容です。
一緒に本を広げて考えてくれる仲間が増えると嬉しいな...。
4.1 イベントストーミングからドメインモデリング
イベントストーミング : 関係者全員でビジネス全体像を把握し、サブドメイン群の洗い出しとその関連を明確にする
ドメインモデリング : イベントストーミングによって見えてきたサブドメインの関連からモデルを可視化する
イベントストーミング自体を知らなかったのですが、まずはドメインイベントというものを定義し、ドメインイベント間を繋ぎ、各ドメインイベントを別の要素を組み合わせて詳細化していくという流れの中でコンテキストとサブドメインが特定されていく手法は面白い手法だと感じました。
また、それを使ってコアとなるドメインをモデリングするというのもイベントストーミングの成果物を使って作成していくので非エンジニアともいかに連携していけばいいのかというアイデアにもなったので、何度か試したいですね
4.2 集約
「集約は小さくする」という原則をいかに実現するのか?ということが分かり易かった。
具体的にはアンチパターンとして紹介があったことを自分はやっていたのですが、メンバ変数に他の集約を持たせることしかアイデアを持っていませんでした。
解決法としてIDを持たせるというのが解説してあり衝撃がありました。(思いつけよと言われると、それはそうなのですが...。)
また、その際に生まれる結果整合性という課題にも具体的な実装例があり、読んでいて過去の実装コードが頭をよぎり、修正したくなりましたが無理だろうな(;'∀')
4.3 トランザクション
文章にすると下記のようにシンプルであり分かっていたつもりだったが、具体的な実装例をもって説明があったので今まで以上に理解は深まりました。
アプリ層のテストではMockに切り替えてテストもできる形になっていたので、これなら将来的にDB変更があっても問題が限定的であろうという実感も得られて良かったです。
本書では後でDIの導入やトランザクション後のイベント駆動、Outboxパターンなどと繋がっていくけど、概念だけでなく実コードがないと説明が難しいと思うのですが、あれこれと複雑に記載したくなる中で『トランザクション』機能に限定した分かり易い説明でした...すご...。
- アプリがトランザクションの責務を持つ
- アプリはリポジトリのデータベース仕様に依存しない
5. 注意点
この本の読み方、学習法になるが、この本は作業手順でない。
ドメイン駆動設計の用語の意味や工程、考え方をしっかりしてもらうものである。
ドメインとは?から分かり易く説明があり、3章の戦略的設計までで境界づけられたコンテキストで簡易のクラスがコードで表されている。
その時点で、自分は何かしらのルールで確定したのだと思ってしまった。
もちろん、そんなことはなく、後の4章の業務知識の獲得、5章のドメインモデルの可視化を通して明確になるモノであることが後から分かった。
3章の戦略的設計の中で話されている内容は事前に知っておくべき内容であるため、順番の変更はできないが、本の内容があまりに整理されていたために、開発の手順であると勘違いしました。
あと、19章のイベント駆動アーキテクチャについて、トランザクションとの関係が見えず、全体感が最後まで見えなかった。
20章のOutboxパターンに繋がるもって行き方で、読むだけであれば『なるほど!!』と感じたのですが、最初にコードを理解しながら進めると最後のシーケンス図に行きつくまでに迷子感が強かったですね。
最初にシーケンス図を見て全体をイメージしながら進めるといいと思います。
6. 読み方のおすすめ
読み手のスキルにもよりますが、基本的には最初からじっくり紙に書いたり、手を動かして読むのがいいと思いました。
今はAIに訊くと用語に対して詳しく教えてくれるので、その知見をもとにAIの話も疑いながら、本の内容と違和感がないかを確認して読み解くといいのかな?と思ってます。
ただ、経験則ですがDDD関連についてChatGPTは詳しくて、正確な印象があるので本領域についてはあまり疑うことなく、本書の不明点を相談しながら理解を深められると思っています。
7. 実務への適用案
本書のドメイン設計の考え方を中心に全て適応...というのは逆に何も考えていないのに等しいので、主方針としては使い捨てのツールにはこれらは不要です。
そうでない場合ですが、現在は要件定義書からの設計について、ユーザーストーリーからなんとなくドメインを抽出して設計を行っている。
これについてはAIと壁打ちを繰り返していき、それっぽくなったところで確定させるやり方になっていて疑問を持っていました。
これが間違いであるとは思ってないが、今後はイベントストーミングを取り入れていくことも極めて有用だなーと思ったので、うまく両方を使った効率的な仕組みを検討を進めたいですね
また、4で意識した集約の考え方も取り入れていけば、設計品質がさらに上がると自分に期待したいです...。
8. 総評
正直、自分のスキルレベル的にも良かったです。
いい意味で忘れた頃に読みたいですし、開発時にイベントストーミングなどを行ってみようとする際には手元に置いておきたいと感じました。
Kindle版を買って、会社に本を置く方がいいかも...?
9. 願望
本書においては、Outboxパターンやイベントソーシングなどの技術の仕組みだけでなく、採用の判断基準の考え方まで分かり易く教えてくれている。
ソフトウェアの第一法則だこれ!!と学びの深い内容であった。
なので、満足なのですが、例えばクライアントからパーセンタイル(p95/p99)やRTO/RPOという非機能の具体数値目標の話が合った際に次のスプリントでやること...みたいな話があれば嬉しいなと感じました。
いや、難しいなコレ...。
まずは対象のソフトウェアにおける理論値予測だけでな、動くハードウェアの調査・動作負荷テストからかな???