本章では、大規模業務システム開発で広く採用されている「ドメイン駆動設計(Domain Driven Design:DDD)」について学習します。
多くの業務システムでは、仕様変更が繰り返される中で業務ルールが画面、SQL、共通クラス、ストアドプロシージャなどに散らばり、保守性が低下していきます。 DDDは、このような問題を解決するために生まれた設計思想であり、「業務そのもの」を中心にシステムを設計することを目的としています。
本章では、Entity、Value Object、Aggregate、Repository、Domain Service、Application Service、Bounded Context、ユビキタス言語などの主要概念をVB.NETを例に実践的に解説します。
本章のゴールは、データベース中心の設計ではなく、「業務ルールを中心にした設計」ができるようになることです。
1. ドメイン駆動設計(DDD)とは
DDDとは、ソフトウェアをデータ中心ではなく「業務知識(ドメイン)」を中心に設計するアプローチです。
ここでいうドメインとは、企業や組織が扱う業務領域を指します。 例えば以下のようなものがドメインになります。
- 販売管理
- 在庫管理
- 受発注管理
- 人事管理
- 銀行業務
- 保険契約管理
- 物流管理
DDDでは、「データを保存するためのクラス」を作るのではなく、「業務ルールを持ったモデル」を設計します。
2. なぜDDDが必要なのか
業務システムは開発よりも保守期間の方が圧倒的に長くなります。 そのため、変更しやすい設計が重要です。
DDDを導入しない場合の問題
- 業務ルールが画面に書かれている
- SQLに業務判断が含まれている
- 共通クラスが巨大化する
- 同じルールが複数箇所に存在する
- 仕様変更時に修正箇所が分からない
- テストが難しい
DDDでは、業務ルールをDomainモデルへ集約し、変更に強い構造を実現します。
3. ユビキタス言語(Ubiquitous Language)
DDDでは、開発者だけでなく業務担当者とも共通の言葉を使います。 これをユビキタス言語と呼びます。
悪い例
- Flg1
- Status2
- CheckData()
- MasterData()
良い例
- Order
- Invoice
- Approve()
- Cancel()
- ShippingDate
- PaymentStatus
クラス名・メソッド名・変数名を業務用語に合わせることで、コードそのものが仕様書になります。
4. Entity
Entityは、一意の識別子(ID)を持つ業務オブジェクトです。
Public Class Customer
Public ReadOnly Property CustomerId As Integer
Public Property Name As String
Public Property Email As String
End Class
EntityではIDが同じであれば同じ業務上の存在として扱います。
Entityの特徴
- IDを持つ
- ライフサイクルがある
- 状態が変化する
- 業務ルールを持つ
5. Value Object
Value Objectは識別子を持たない値オブジェクトです。
例えば金額・メールアドレス・電話番号・郵便番号などはValue Objectとして設計できます。
Public Class Money
Public ReadOnly Property Amount As Decimal
Public Sub New(amount As Decimal)
If amount < 0 Then
Throw New BusinessException("金額は0以上です。")
End If
Me.Amount = amount
End Sub
End Class
Value Objectは生成時に妥当性を保証することで、不正な値をシステムへ持ち込ませません。
6. Aggregate
Aggregateは、複数のEntityやValue Objectをまとめる単位です。
例えば注文管理ではOrderがAggregate Rootになります。
Order
├ Customer
├ OrderDetail
├ Payment
└ ShippingAddress
外部から直接OrderDetailを変更するのではなく、Order経由で操作します。
メリット
- 整合性を維持しやすい
- 責務が明確になる
- 業務ルールを集中管理できる
7. Repository
Repositoryは、永続化を抽象化するためのインターフェースです。
Public Interface ICustomerRepository
Function Find(id As Integer) As Customer
Sub Save(customer As Customer)
End Interface
Application層はRepositoryを通してデータを取得・保存します。 DB実装はInfrastructure層が担当します。
8. Domain Service
Entityに属さない業務ルールはDomain Serviceへ配置します。
Public Class TransferService
Public Sub Transfer(fromAccount As Account,
toAccount As Account,
amount As Money)
fromAccount.Withdraw(amount)
toAccount.Deposit(amount)
End Sub
End Class
複数Entityをまたぐ業務ルールはDomain Serviceが担当します。
9. Application Service
Application Serviceはユースケースを実現する層です。
- 入力DTOを受け取る
- RepositoryからEntity取得
- Domain呼び出し
- 保存
- DTO返却
業務判断はApplication ServiceではなくDomainへ配置します。
10. Bounded Context
大規模システムでは同じ言葉でも意味が異なることがあります。
| コンテキスト | Customerの意味 |
|---|---|
| 営業 | 商談相手 |
| 請求 | 請求先 |
| 配送 | 配送先 |
DDDでは意味の違うものは別のBounded Contextとして管理します。
11. ドメインイベント
重要な業務イベントをモデル化する設計です。
- 注文が確定した
- 請求書が発行された
- 商品が発送された
- 会員登録が完了した
イベントを利用することでシステム同士の結合度を下げられます。
12. CQRSの考え方
更新処理と参照処理を分離する設計手法です。
| Command | Query |
|---|---|
| 登録 | 検索 |
| 更新 | 一覧表示 |
| 削除 | 集計 |
検索専用DTOを作ることでパフォーマンス向上や保守性向上につながります。
13. DDDを既存VBシステムへ導入する方法
- 画面から業務ロジックを分離する
- Service層を作る
- Repositoryを導入する
- 重要EntityからDomainモデル化する
- Value Objectへ置き換える
- Bounded Contextを整理する
- 新機能からDDDを適用する
全面改修ではなく、段階的な導入が現実的です。
14. DDD導入でありがちな失敗
- 小規模システムに過剰適用する
- EntityをDTO化してしまう
- Repositoryが巨大化する
- Serviceへロジックを書きすぎる
- ユビキタス言語が統一されない
- DB中心設計から抜けられない
15. 演習課題
- 販売管理システムのEntityを設計する
- Money・EmailをValue Object化する
- 注文管理のAggregateを設計する
- Repositoryを実装する
- Domain Serviceを設計する
- Application Serviceを作成する
- Bounded Contextを整理する
- 既存VBシステムへDDDを段階導入する計画を作成する
16. まとめ
本章では、VB.NET業務システムにおけるドメイン駆動設計(DDD)の考え方を学習しました。
DDDは、データではなく業務ルールを中心に設計することで、長期保守・仕様変更・テスト・再利用に強いシステムを実現する設計思想です。
Entity、Value Object、Aggregate、Repository、Domain Service、Application Serviceなどを適切に設計することで、業務知識をコードへ自然に反映できます。
また、ユビキタス言語やBounded Contextを活用することで、開発者と業務担当者が共通認識を持ちやすくなり、大規模プロジェクトでも保守性を維持できます。
DDDはすべてのシステムに適用するものではありませんが、長期間運用されるVB.NET業務システムでは非常に強力な設計手法です。 本章で学んだ内容を活用し、業務そのものを正しく表現できるエンタープライズアプリケーションを設計できるようになりましょう。