0Pricing
PHP Academy · Урок

Ограниченные контексты и контекстное отображение

Разделяйте крупные предметные области на ограниченные контексты, которые безопасно взаимодействуют

«Ограниченные контексты и контекстное отображение» — бесплатный урок PHP Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения 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 выделяет несколько часто встречающихся шаблонов отношений; далее мы рассмотрим их.

Конформист в коде

Отношения часто имеют направленность: вышестоящий контекст влияет на нижестоящий (Заказчик/Поставщик, Конформист, Антикоррупционный слой). Нижестоящий контекст-конформист не может влиять на ситуацию, поэтому просто принимает модель вышестоящего контекста как есть: напрямую использует чужую структуру, соглашаясь на связанность.

<?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, оборачивающий опубликованный язык, или сообщения. Принимающая сторона преобразует чужой объект передачи данных в собственную модель, поэтому связанность останавливается на границе.

<?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. Ограниченный контекст — это граница, внутри которой модель и её единый язык предметной области остаются согласованными, освобождая команды от одной раздутой общей модели. Карта контекстов документирует отношения — Заказчик/Поставщик, Конформист, Антикоррупционный слой, Общее ядро, Партнёрство, Отдельные пути, Открытый сервис/опубликованный язык — и отражает как техническую интеграцию, так и динамику команд. Проводите границы вокруг бизнес-возможностей, преобразуйте данные на границах — и система сможет развиваться в виде независимо разворачиваемых частей.

Часто задаваемые вопросы

Урок «Ограниченные контексты и контекстное отображение» бесплатный?

Да — полный текст урока «Ограниченные контексты и контекстное отображение» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс PHP Academy, подпишись на CoddyKit PRO. Курс PHP Academy содержит 4 уроков всего.

Чему я научусь в уроке «Ограниченные контексты и контекстное отображение»?

Разделяйте крупные предметные области на ограниченные контексты, которые безопасно взаимодействуют Ты практикуешь PHP Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать PHP Academy?

Предыдущий опыт не требуется. PHP Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Ограниченные контексты и контекстное отображение»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке PHP Academy?

Да. Каждый урок PHP Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Строительные блоки DDD: сущности и объекты-значения
  2. Агрегаты, репозитории и фабрики
  3. Доменные события и доменные службы
  4. Ограниченные контексты и контекстное отображение
← Назад к PHP Academy