1. 単一責任の原則 (SRP: Single Responsibility Principle)
「クラスは一つの変更理由だけを持つべきである」
✅ 適用ポイント
- 変更の理由が異なるものは、別のドメインやサービスとして分離する。
- 異なるユースケース や 異なるビジネスロジック を一緒にすると、不要な結合が発生し、変更時の影響範囲が広がる。
- 例)注文作成と注文履歴管理は異なる責務を持つため、分離が適切。
2. 共通閉鎖の原則 (CCP: Common Closure Principle)
「パッケージのクラスは同じ種類の変更に対して閉じているべきである」
「ある変更が影響する範囲は、そのパッケージ内に閉じ込めるべきである」
✅ 適用ポイント
- 変更が発生する際に、影響を受けるコンポーネントが同じなら、同じコンテキスト内で統合する。
- 逆に、変更の影響を受けないものは、独立して分離するのが適切。
- 例)決済のロジックが変わると影響を受けるのは決済関連の機能のみ → 決済ドメイン内で統合。
3. まとめ:SRP & CCP を考慮した分離基準
判断基準 | 分離のポイント |
---|---|
SRP(単一責任の原則) | 変更理由が異なる場合、分離する。 |
CCP(共通閉鎖の原則) | 同じ変更の影響を受ける場合、統合する。 |
イベント駆動アーキテクチャ | SRP で分離しつつ、CCP で統合すべき部分は イベントベースで疎結合にする。 |
💡 基本的には注文と決済を分離し、イベント駆動アーキテクチャ(SAGA など)を活用するのが最適!
注文・決済ドメインを例えした場合
1. Bounded Context を基準にした分離
注文(Order)と決済(Payment)は異なる Bounded Context を持っています。
-
注文(Order)Bounded Context
- ユーザーが商品をカートに追加し、注文を作成するプロセス
- 注文状態の管理(未決済、決済完了、配送中、キャンセルなど)
- 在庫管理や注文履歴の管理
-
決済(Payment)Bounded Context
- 決済処理(クレジットカード、銀行振込、電子決済など)
- 決済承認・精算処理
- 決済失敗・返金処理
これらのドメインは異なる責務を持つため、分離するのが適切です。
2. 単一責任の原則 (SRP: Single Responsibility Principle) による追加分離
各ドメイン内でも、変更の理由ごとにさらに細かく分離できます。
(1) 注文ドメイン(Order Domain)の内部分離
✅ 異なる変更理由を持つ場合、分離する
- Order Command Service → 注文の作成・キャンセル
- Order Query Service → 注文情報の取得
- Order History Service → 注文履歴の管理
💡 注文の作成と取得は異なる責務を持つため、分離が適切
(2) 決済ドメイン(Payment Domain)の内部分離
✅ 異なる変更理由を持つ場合、分離する
- Payment Processing Service → 決済の承認・キャンセル
- Payment Gateway Adapter → 外部決済システムとの連携
- Refund Service → 決済キャンセル・返金処理
💡 決済承認と返金処理は異なるビジネスプロセスを持つため、分離が適切
3. 共通閉鎖の原則 (CCP: Common Closure Principle) による統合の検討
-
「注文が変更されるたびに決済も変更されるべきか?」
- 例えば、注文が作成されるたびに決済情報も必ず作成される場合、統合する方が適切な場合もある。
-
「決済が失敗した場合、注文状態も変更されるべきか?」
- 決済失敗時に注文状態を変更する必要がある場合、注文と決済が密接に関連するが、
イベント駆動アーキテクチャ を活用して疎結合にするのが理想的。
- 決済失敗時に注文状態を変更する必要がある場合、注文と決済が密接に関連するが、
統合すべきケース
- 注文と決済のトランザクションが強く結びついている場合(SAGA パターンの適用)
- 変更の影響範囲がほぼ同じで、別々に管理すると複雑になる場合
分離すべきケース
- 注文と決済の変更理由が異なる場合
- 決済ロジックが外部決済システムと密接に関係する場合
- スケーラビリティや独立したデプロイが必要な場合
最適なアーキテクチャ(分離されたサービス構造)
1) 注文サービス(Order Service)
- 注文作成 (
Order Command Service
) - 注文情報取得 (
Order Query Service
) - 注文履歴 (
Order History Service
) - 注文イベント (
Order Event Publisher
)
2) 決済サービス(Payment Service)
- 決済承認 (
Payment Processing Service
) - 決済ゲートウェイ連携 (
Payment Gateway Adapter
) - 返金処理 (
Refund Service
) - 決済イベント (
Payment Event Publisher
)
結論:どこまで分離し、どこで統合すべきか?
1️⃣ Bounded Context を基準に分離
2️⃣ SRP に基づいて、異なる変更理由を持つコンポーネントを分離
3️⃣ CCP に基づいて、変更の影響範囲が同じなら統合を検討
4️⃣ イベント駆動アーキテクチャ(SAGA パターンなど)を活用し、適切に連携
基本的には注文と決済を分離し、イベント駆動アーキテクチャで疎結合にするのが理想的!