Прямой ответ
Anti-Corruption Layer (ACL) — слой изоляции между доменной моделью и внешними/legacy системами (ACL — «защита от коррупции» — ACL — «внешняя модель не портит доменную» — ACL — микросервисы — «legacy не влияет на домен» — ACL); проблема, которую решает: внешние модели портят доменную (ACL — «legacy-модель в домене» — ACL — техдолг — «legacy-поля в доменной модели» — техдолг — ACL — «домен зависит от legacy» — ACL — техдолг); механика: изоляция (ACL — «ACL между доменом и legacy» — ACL — микросервисы — «домен не знает о legacy» — ACL — техдолг — «legacy-модель преобразуется в доменную» — ACL); реализация: (1) Адаптер (ACL — «адаптер legacy → домен» — ACL — микросервисы — «адаптер преобразует» — ACL — техдолг); (2) Фасад (ACL — «фасад для legacy» — ACL — микросервисы — «фасад скрывает legacy» — ACL — техдолг); (3) Транслятор (ACL — «транслятор legacy-модель → доменная» — ACL — микросервисы — «транслятор преобразует» — ACL — техдолг); когда ACL: legacy-системы (ACL — «legacy — ACL» — ACL — техдолг — strangler fig — «legacy — ACL + Strangler Fig» — strangler fig), внешние API (ACL — «внешний API — ACL» — ACL — микросервисы — «внешний API — своя модель» — ACL), интеграции (ACL — «интеграция с другой системой» — ACL — микросервисы — «другая система — своя модель» — ACL); когда НЕ ACL: одна система (ACL — «одна система — ACL не нужен» — ACL — техдолг — «ACL для одной системы» — оверхед — техдолг), простая интеграция (ACL — «простая интеграция — ACL не нужен» — ACL — техдолг — «ACL оверхед» — техдолг); антипаттерны: ACL без адаптера (ACL — «без адаптера» — ACL — «legacy-модель в домене» — техдолг — адаптер обязателен — ACL), ACL для всего (ACL — «ACL для всего» — ACL — «оверхед» — техдолг — «ACL только для legacy/внешних» — ACL), ACL без мониторинга (метрики — «ACL преобразует» — метрики — алерты — алерты — «ACL сломан» — incident).
Практика: ACL для legacy-системы
Адаптер (ACL — legacy → домен (ACL — class LegacyUserAdapter: def to_domain(self, legacy_user: LegacyUser) -> User: return User(id=legacy_user.user_id, name=legacy_user.full_name) (ACL — «адаптер legacy → домен» — ACL — техдолг); Фасад (ACL — legacy API (ACL — class LegacyAPIFacade: def get_user(self, user_id: str) -> User: legacy_user = legacy_api.get_user(user_id) return LegacyUserAdapter().to_domain(legacy_user) (ACL — «фасад скрывает legacy» — ACL — техдолг); Транслятор (ACL — legacy-модель → доменная (ACL — def translate(legacy_data: dict) -> User: return User(id=legacy_data["user_id"], name=legacy_data["full_name"]) (ACL — «транслятор преобразует» — ACL — техдолг); Мониторинг (метрики: «ACL translations», «ACL errors» — метрики — алерты — алерты — «ACL сломан» — incident).
Практический сценарий: интеграция с legacy CRM через ACL
Контекст: новый сервис (микросервисы), интеграция с legacy CRM (ACL — «legacy CRM» — ACL — strangler fig), боль: legacy-модель портит доменную (ACL — «legacy-поля в домене» — техдолг — ACL — «домен зависит от legacy» — техдолг); решение — ACL: (1) Адаптер (ACL — class CRMUserAdapter: def to_domain(self, crm_user: CRMUser) -> User: return User(id=crm_user.user_id, name=crm_user.full_name) (ACL — «адаптер CRM → домен» — ACL — техдолг); (2) Фасад (ACL — class CRMFacade: def get_user(self, user_id: str) -> User: crm_user = crm_api.get_user(user_id) return CRMUserAdapter().to_domain(crm_user) (ACL — «фасад скрывает CRM» — ACL — техдолг); (3) Домен (ACL — class User: def __init__(self, id: str, name: str): self.id = id self.name = name (ACL — «домен не знает о CRM» — ACL — техдолг); (4) Мониторинг (метрики — «ACL translations» — метрики — алерты — алерты — «ACL сломан» — incident); результат: legacy CRM (ACL — домен не знает о CRM (ACL — «домен чистый» — ACL — техдолг — legacy-модель изолирована (ACL — «legacy не влияет на домен» — ACL — техдолг); вывод: ACL решили задачу (legacy изолирован — ACL — ADR — «ACL без адаптера» — антипаттерн — техдолг).
FAQ
Anti-Corruption Layer против адаптера — в чём разница? Anti-Corruption Layer (ACL — слой изоляции (ACL — «слой между доменом и legacy» — ACL — микросервисы — «слой защищает домен» — ACL); Адаптер (ACL — паттерн внутри ACL (ACL — «адаптер — часть ACL» — ACL — микросервисы — «адаптер преобразует» — ACL); разница: ACL — слой (ACL — «слой изоляции» — ACL, адаптер — паттерн (ACL — «паттерн внутри ACL» — ACL); «ACL вместо адаптера» — нет (ACL включает адаптер — ACL — ADR — техдолг).
Когда использовать Anti-Corruption Layer? Legacy-системы (ACL — «legacy — ACL» — ACL — техдолг — strangler fig — «legacy — ACL + Strangler Fig» — strangler fig), внешние API (ACL — «внешний API — ACL» — ACL — микросервисы — «внешний API — своя модель» — ACL), интеграции (ACL — «интеграция с другой системой» — ACL — микросервисы — «другая система — своя модель» — ACL); когда НЕ ACL: одна система (ACL — «одна система — ACL не нужен» — ACL — техдолг, простая интеграция (ACL — «простая интеграция — ACL не нужен» — ACL — техдолг); «ACL для всего» — антипаттерн (оверхед — техдолг — «ACL только для legacy/внешних» — ACL — ADR — техдолг).
Как реализовать Anti-Corruption Layer?
Адаптер (ACL — legacy → домен (ACL — class LegacyUserAdapter: def to_domain(self, legacy_user: LegacyUser) -> User: return User(id=legacy_user.user_id, name=legacy_user.full_name) (ACL — «адаптер legacy → домен» — ACL); Фасад (ACL — legacy API (ACL — class LegacyAPIFacade: def get_user(self, user_id: str) -> User: legacy_user = legacy_api.get_user(user_id) return LegacyUserAdapter().to_domain(legacy_user) (ACL — «фасад скрывает legacy» — ACL); Транслятор (ACL — legacy-модель → доменная (ACL — def translate(legacy_data: dict) -> User: return User(id=legacy_data["user_id"], name=legacy_data["full_name"]) (ACL — «транслятор преобразует» — ACL); «ACL без адаптера» — антипаттерн (legacy-модель в домене — техдолг — адаптер обязателен — ACL — ADR — техдолг).
Anti-Corruption Layer и Strangler Fig — как связаны? Anti-Corruption Layer (ACL — изоляция (ACL — «ACL изолирует legacy» — ACL — техдолг), Strangler Fig (strangler fig — миграция (strangler fig — «Strangler Fig мигрирует legacy» — strangler fig — техдолг); связь: часто вместе (ACL — ACL + Strangler Fig (ACL — strangler fig — «ACL изолирует, Strangler Fig мигрирует» — ACL — strangler fig); когда вместе: legacy-миграция (ACL — «legacy — ACL + Strangler Fig» — ACL — strangler fig — техдолг); «ACL вместо Strangler Fig» — нет (разные паттерны — ACL — strangler fig — часто вместе — ADR — техдолг).
Источники: Microsoft Azure patterns (ACL), Martin Fowler (ACL), Domain-Driven Design — ссылки в шапке.