Многие используют подход API First в проектировании систем, но зачастую даже не задумываются, что порождают таким образом сервисы с анемичными доменными моделями, проектируя по сути REST-обертки над базой данных с отсутствием какой-либо бизнес-логики.
API First и Богатая доменная модель не являются взаимоисключающими понятиями, если правильно выстроить процесс и архитектуру.
Главная проблема: API First фокусируется на контрактах внешнего мира, что часто приводит к созданию DTO/Model классов, которые являются чистыми структурами данных без поведения (анемичная модель).
API First — это про контракты, а не про реализацию. Не позволяйте инструментам кодогенерации диктовать структуру вашей доменной модели!
Правильный workflow:
1. API Design First: Создайте/обновите OpenAPI спецификацию.
2. Генерация DTO: Сгенерируйте или создайте классы для API‑контрактов.
3. Projection First: Спроектируйте доменную модель независимо от DTO, фокусируясь на поведении и инвариантах.
4. Создание Mapping Layer: Напишите преобразователи между DTO и Domain Objects.
5. Реализация Application Service: Тонкий слой, который координирует работу домена.
Стек технологий, который помогает:
— MapStruct: Для автоматизации маппинга между DTO и Domain
— JUnit 5: Для тестирования доменной логики
— OpenAPI Generator: Для автоматической генерации DTO из спецификации
— ArchUnit: Для проверки архитектурных правил (например, запрет на анемичные модели)
// ArchUnit тест, проверяющий, что в доменных классах есть поведение
@ArchTest
static final ArchRule domain_models_should_have_business_methods =
classes()
.that().resideInPackage("..domain..")
.and().areAnnotatedWith(Entity.class)
.should().containAnyMethodsThat(
DescribedPredicate.describe(
"have business methods",
method -> !method.getName().startsWith("get") &&
!method.getName().startsWith("set")
)
);




