境界づけられたコンテキストとコンテキストマッピング
大規模なドメインを、安全に連携できる境界づけられたコンテキストへ分割します。
「境界づけられたコンテキストとコンテキストマッピング」はCoddyKit上の無料PHP Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPHP Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 PHP Academyコースには全4レッスンが含まれています。
戦略的DDD
戦術的パターンはドメイン内のオブジェクトをモデル化します。一方、戦略的DDDは、大規模なシステムを独立して進化できる複数の部分にどう分割するかを決めます。中心となる概念は境界づけられたコンテキストです。これは、ドメインモデルとその言語に一貫性が保たれる明確な境界です。コンテキストマッピングは、そうしたコンテキスト同士の関係を記述します。これは、単一のクラス設計よりも大きな影響を及ぼすことがよくあります。
ユビキタス言語
境界づけられたコンテキストの内部では、チームがユビキタス言語を共有します。会話、コード、モデルで同じ用語を使うのです。ただし、同じ単語でもコンテキストが違えば意味も異なります。営業における顧客(見込み客、割引)と、サポートにおける顧客(チケット、SLA)は同じものではありません。境界づけられたコンテキストによってその境界を明確にし、肥大化した共有モデルを無理に作らずに済みます。
同じ言葉、異なるモデル
同じビジネス上の概念でも、コンテキストごとにモデルが異なります。CatalogのProductは説明とメディアを重視しますが、Inventoryでは在庫と場所を重視します。各コンテキストは必要なものだけを定義します。
<?php
namespace Catalog;
final class Product {
public function __construct(
public readonly string $sku,
public readonly string $description
) {}
}
namespace Inventory;
final class Product {
public function __construct(
public readonly string $sku,
public readonly int $onHand
) {}
}
namespace App;
$c = new \Catalog\Product('A1', 'Blue mug');
$i = new \Inventory\Product('A1', 42);
echo $c->description, ' / ', $i->onHand, PHP_EOL;
大きな1つのモデルにしない理由
すべてのチームで使う単一の標準的なCustomerを作ろうとすると、要件が衝突する神クラス、チーム間の競合、変更に弱い構造が生まれます。境界づけられたコンテキストを使えば、各チームが自分のモデルと言語を所有し、独立してデプロイし、境界で変換できます。境界では小さな統合コストを支払うことで、大きな結合コストを避けられます。
コンテキストマップ
コンテキストマップは、境界づけられたコンテキストと、それらの間の関係を高いレベルで示す図です。技術的な統合だけでなく、チーム間/政治的な関係(誰が誰に依存するか、誰が変更を指示できるか)も記録します。DDDでは、繰り返し現れる関係パターンがいくつか定義されており、次に見ていきます。
コードにおけるコンフォーミスト
関係には方向性があることが多く、上流コンテキストが下流コンテキストに影響を与えます(顧客/供給者、コンフォーミスト、腐敗防止層)。下流のコンフォーミストには交渉力がないため、上流のモデルをそのまま採用します。つまり、外部の形を直接利用し、結合を受け入れます。
<?php
// Upstream's shape, used verbatim downstream (Conformist)
final class UpstreamUser {
public function __construct(public readonly int $userId, public readonly string $login) {}
}
final class Greeter { // conforms: depends directly on upstream type
public function greet(UpstreamUser $u): string {
return "Hello {$u->login} (#{$u->userId})";
}
}
echo (new Greeter())->greet(new UpstreamUser(7, 'jane')), PHP_EOL;
腐敗防止層
ACLは外部またはレガシーのモデルを、コンテキスト内のクリーンなモデルに変換します。そのため、外部の概念が内部に漏れ出すことはありません。これはコンテキストの境界に適用したAdapterパターンであり、ユビキタス言語を守ります。
<?php
// Our clean domain model
final class Customer {
public function __construct(public readonly string $id, public readonly string $name) {}
}
// Legacy/external shape we must not let leak in
$legacy = ['CUST_NO' => '0042', 'FULL_NM' => 'Jane Doe'];
final class LegacyCustomerAcl {
public function toDomain(array $row): Customer {
return new Customer($row['CUST_NO'], $row['FULL_NM']);
}
}
$customer = (new LegacyCustomerAcl())->toDomain($legacy);
echo $customer->id, ' ', $customer->name, PHP_EOL;
コードにおける共有カーネル
- 共有カーネル:2つのコンテキストが、小さく共同所有する部分(以下の共通
Money型など)を共有します。変更は合意を得たうえで行います。 - パートナーシップ:2つのチームがともに成功するか、ともに失敗します。
- 別々の道:統合にかかるコストに見合う価値がありません。
- オープンホストサービス/公開言語:上流が、多数の利用者に向けて安定した文書化済みのプロトコルを提供します。
<?php
namespace Shared; // small, jointly-owned kernel
final class Money {
public function __construct(public readonly int $cents, public readonly string $cur) {}
public function format(): string { return number_format($this->cents / 100, 2) . ' ' . $this->cur; }
}
namespace Billing; // depends on the shared kernel
use Shared\Money;
function invoiceTotal(): Money { return new Money(4999, 'USD'); }
namespace Payroll; // also depends on the SAME shared kernel
use Shared\Money;
function salary(): Money { return new Money(500000, 'USD'); }
PHPでコンテキストを統合する
具体的には、コンテキストは明確に定義された契約を通じて統合します。変換用メソッド、公開言語をラップするAPIクライアント、またはメッセージなどです。受信側が外部のDTOを自分のモデルにマッピングするため、結合は境界で止まります。
<?php
// Published Language DTO from an upstream Open Host Service
final class PricingDto {
public function __construct(public readonly string $sku, public readonly int $cents) {}
}
// Our downstream model
final class CatalogPrice {
public function __construct(public readonly string $sku, public readonly float $amount) {}
}
final class PricingTranslator {
public function translate(PricingDto $dto): CatalogPrice {
return new CatalogPrice($dto->sku, $dto->cents / 100);
}
}
$p = (new PricingTranslator())->translate(new PricingDto('A1', 1599));
echo $p->amount, PHP_EOL; // 15.99
コンテキストとアーキテクチャ
境界づけられたコンテキストは、デプロイ単位に自然に対応します。明確なモジュール境界を持つモジュラーモノリスや、独立したマイクロサービスなどです。境界は技術レイヤーではなく、ビジネスケイパビリティを中心に引くべきです。密結合した1つのコンテキストを分割するマイクロサービスは分散モノリスを生みます。一方、適切に整合したコンテキスト境界によって、サービスを独立して変更できるようになります。
接点としてのイベント
実際には、モデルを共有せずにコンテキストを統合するためのクリーンな方法は、イベントを交換することです。上流が小さく安定したイベント(公開言語)を公開し、下流がそれを購読して自分のモデルにマッピングします。上流のクラスをインポートすることは決してありません。
<?php
// Published Language: a minimal stable contract
final class OrderPlacedEvent {
public function __construct(public readonly string $orderId, public readonly int $cents) {}
}
// Downstream (Shipping context) maps it to its own model
final class Shipment {
public function __construct(public readonly string $forOrder) {}
}
final class ShippingListener {
public function on(OrderPlacedEvent $e): Shipment {
return new Shipment($e->orderId); // ignores fields it doesn't need
}
}
$shipment = (new ShippingListener())->on(new OrderPlacedEvent('o1', 1300));
echo 'shipment for ', $shipment->forOrder, PHP_EOL;
クイックチェック
コンテキスト間の関係です。
まとめ
戦術的DDDから戦略的DDDへ進みました。境界づけられたコンテキストは、モデルとそのユビキタス言語の一貫性を保つ境界です。これにより、チームは肥大化した1つの共有モデルから解放されます。コンテキストマップには、顧客/供給者、コンフォーミスト、腐敗防止層、共有カーネル、パートナーシップ、別々の道、オープンホストサービス/公開言語といった関係が記録され、技術的な統合とチーム間の力学の両方が示されます。ビジネスケイパビリティを中心に境界を引き、境界で変換すれば、システムを独立してデプロイできる部分へ進化させられます。
よくある質問
「境界づけられたコンテキストとコンテキストマッピング」レッスンは無料ですか?
はい。「境界づけられたコンテキストとコンテキストマッピング」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、PHP Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 PHP Academyコースには全4レッスンが含まれています。
「境界づけられたコンテキストとコンテキストマッピング」で何を学びますか?
大規模なドメインを、安全に連携できる境界づけられたコンテキストへ分割します。 ブラウザで直接実行するハンズオンコードでPHP Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
PHP Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのPHP Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「境界づけられたコンテキストとコンテキストマッピング」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このPHP Academyレッスンでコードを書いて実行できますか?
はい。すべてのPHP Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- DDDの構成要素:エンティティと値オブジェクト
- 集約、リポジトリ、ファクトリ
- ドメインイベントとドメインサービス
- 境界づけられたコンテキストとコンテキストマッピング