0Pricing
PHP Academy · 강의

바운디드 컨텍스트와 컨텍스트 매핑

큰 도메인을 안전하게 소통하는 바운디드 컨텍스트로 나눕니다.

바운디드 컨텍스트와 컨텍스트 매핑은(는) CoddyKit의 무료 PHP Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 PHP Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. PHP Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

전략적 DDD

전술적 패턴이 도메인 내부의 객체를 모델링한다면, 전략적 DDD는 큰 시스템을 독립적으로 발전할 수 있는 여러 부분으로 나누는 방법을 결정합니다. 핵심 개념은 경계 컨텍스트입니다. 이는 도메인 모델과 그 언어가 일관성을 유지하는 명시적인 경계입니다. 컨텍스트 매핑은 이러한 컨텍스트가 서로 어떻게 관계를 맺는지 설명합니다. 이는 단일 클래스 설계보다 더 큰 영향을 미치는 경우가 많습니다.

유비쿼터스 언어

경계 컨텍스트 내부에서 팀은 대화, 코드, 모델에서 동일하게 사용하는 유비쿼터스 언어를 공유합니다. 문제는 같은 단어도 컨텍스트에 따라 의미가 달라진다는 점입니다. 영업의 Customer(잠재 고객, 할인)와 지원의 Customer(문의 티켓, 서비스 수준 계약)는 같은 대상이 아닙니다. 경계 컨텍스트는 하나의 비대해진 공유 모델을 억지로 사용하지 않고 이러한 경계를 명시적으로 만듭니다.

같은 단어, 다른 모델

같은 비즈니스 개념도 컨텍스트에 맞는 모델을 갖습니다. 카탈로그의 Product는 설명과 미디어를 중요하게 여기지만, 재고에서는 재고 수량과 위치를 중요하게 여깁니다. 각 컨텍스트는 필요한 것만 정의합니다.

<?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;

하나의 거대한 모델을 사용하지 않는 이유

모든 팀이 사용할 하나의 표준 Customer를 만들려고 하면, 서로 충돌하는 요구 사항과 팀 간 경쟁, 변경에 취약한 구조를 가진 만능 클래스가 생깁니다. 경계 컨텍스트를 사용하면 각 팀이 자신의 모델과 언어를 소유하고, 독립적으로 배포하며, 경계에서 변환할 수 있습니다. 경계에서는 큰 결합 비용을 피하기 위해 작은 통합 비용을 지불합니다.

컨텍스트 맵

컨텍스트 맵은 경계 컨텍스트와 그 사이의 관계를 높은 수준에서 표현한 그림입니다. 기술적 통합뿐 아니라 팀/정치적 관계도 기록합니다. 즉, 누가 누구에게 의존하고 누가 변경을 지시할 수 있는지를 나타냅니다. DDD에는 반복해서 등장하는 여러 관계 패턴이 있으며, 다음에서 살펴보겠습니다.

코드에서의 순응자

관계는 대개 방향성을 가집니다. 상위 컨텍스트가 하위 컨텍스트에 영향을 줍니다(Customer/공급자, 순응자, 부패 방지 계층). 순응자인 하위 컨텍스트는 영향력을 행사할 수 없으므로 상위 컨텍스트의 모델을 그대로 받아들입니다. 외부 모델의 형태를 직접 사용하며 결합을 받아들이는 것입니다.

<?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은 외부 또는 레거시 모델을 해당 컨텍스트의 깔끔한 모델로 변환하여 외부 개념이 내부로 새어 들어오지 않게 합니다. 이는 컨텍스트 경계에 적용한 어댑터 패턴으로, 유비쿼터스 언어를 보호합니다.

<?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;

코드에서의 공유 커널

  • 공유 커널: 두 컨텍스트가 작고 공동으로 소유하는 일부를 공유합니다(아래의 공통 Money 형식). 합의가 있을 때만 변경해야 합니다.
  • 파트너십: 두 팀이 함께 성공하거나 함께 실패합니다.
  • 별도 경로: 통합에 드는 비용을 감수할 가치가 없습니다.
  • 공개 호스트 서비스 / 공개 언어: 상위 컨텍스트가 여러 소비자를 위해 안정적이고 문서화된 프로토콜을 제공합니다.
<?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

컨텍스트와 아키텍처

경계 컨텍스트는 배포 단위에 자연스럽게 대응합니다. 명확한 모듈 경계를 가진 모듈형 모놀리스나 별도의 마이크로서비스로 구성할 수 있습니다. 경계는 기술 계층이 아니라 비즈니스 역량을 중심으로 그어야 합니다. 하나의 긴밀하게 결합된 컨텍스트를 나누어 만든 마이크로서비스는 분산 모놀리스를 만듭니다. 반대로 잘 맞춰진 컨텍스트 경계는 독립적으로 변경되는 서비스를 만듭니다.

접점으로서의 이벤트

실제로 모델을 공유하지 않고 컨텍스트를 통합하는 깔끔한 방법은 이벤트를 주고받는 것입니다. 상위 컨텍스트는 작고 안정적인 이벤트(공개 언어)를 발행하고, 하위 컨텍스트는 이를 구독하여 자체 모델로 매핑합니다. 상위 컨텍스트의 클래스를 가져오는 일은 절대 하지 않습니다.

<?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로 나아왔습니다. 경계 컨텍스트는 모델과 유비쿼터스 언어가 일관성을 유지하는 경계이며, 팀이 하나의 비대해진 공유 모델에 얽매이지 않게 합니다. 컨텍스트 맵은 Customer/공급자, 순응자, 부패 방지 계층, 공유 커널, 파트너십, 별도 경로, 공개 호스트 서비스/공개 언어와 같은 관계를 문서화하고, 기술적 통합과 팀의 역학을 모두 담습니다. 비즈니스 역량을 중심으로 경계를 그리고, 경계에서 변환하면 시스템을 독립적으로 배포 가능한 부분으로 발전시킬 수 있습니다.

자주 묻는 질문

“바운디드 컨텍스트와 컨텍스트 매핑” 강의는 무료인가요?

네 — “바운디드 컨텍스트와 컨텍스트 매핑” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 PHP Academy 강의 전체를 잠금 해제할 수 있습니다. PHP Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“바운디드 컨텍스트와 컨텍스트 매핑”에서 뭘 배우나요?

큰 도메인을 안전하게 소통하는 바운디드 컨텍스트로 나눕니다. 브라우저에서 직접 실행하는 실습 코드로 PHP Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

PHP Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 PHP Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“바운디드 컨텍스트와 컨텍스트 매핑” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 PHP Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 PHP Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. DDD 구성 요소: 엔터티와 값 객체
  2. 애그리거트, 리포지터리 및 팩토리
  3. 도메인 이벤트와 도메인 서비스
  4. 바운디드 컨텍스트와 컨텍스트 매핑
← PHP Academy(으)로 돌아가기