Опытный разработчик не так давно зашёл в .Net и поставил цель получить сертификат Microsoft. Свой ежедневный прогресс он описывает на канале .Net Разработчик. Заметки об изученном материале, советы по повышению производительности и поддержке мотивации, ин
День 1332. #ЗаметкиНаПолях#DDD
Всегда Валидная Модель Домена
Инвариант — это условие, которое всегда должно выполняться. Например, треугольник имеет 3 стороны. Условие edges.Count == 3 по своей сути верно для всех треугольников.
Другое важное свойство инвариантов состоит в том, что они определяют класс предметной области: благодаря им этот класс является тем, чем он является. Следовательно, вы не можете нарушить эти инварианты. Если вы это сделаете, доменный класс просто перестанет быть тем, что вы от него ожидаете, а станет чем-то другим. Например, если вы добавите четвёртую сторону к треугольнику, он станет четырёхугольником.
Наличие инвариантов — это то, что требует введения правил валидации. Без таких инвариантов, как edges.Count == 3, вам не нужно было бы проверять входные данные от внешних клиентов.
Таким образом, разница между валидацией и инвариантами — это просто вопрос точки зрения. Одни и те же бизнес-правила рассматриваются как инварианты моделью предметной области и как правила валидации сервисами приложений.
Это различие приводит к различному обращению с нарушениями этих бизнес-правил. Нарушение инварианта в модели предметной области — это исключительная ситуация, и на неё следует генерировать исключение и полностью останавливать текущую операцию (принцип отказоустойчивости).
С другой стороны, нет ничего исключительного в том, что внешний ввод неверен. Для этого и нужны прикладные сервисы: они разделяют (фильтруют) правильные и неправильные запросы. Вы не должны генерировать исключения в таких случаях и вместо этого должны использовать класс Result со статусом операции.
Можно предположить, что разница между валидациями и инвариантами в том, что валидации могут меняться в зависимости от бизнес-правил. Например, треугольник имеет 2 инварианта:
- ровно 3 стороны,
- каждая сторона больше нуля.
Но в нашей модели предметной области есть ещё условие:
- каждая сторона долна быть больше 10 см.
Это правило валидации (в отличие от инвариантов) можно изменить или удалить из нашей модели предметной области.
Действительно, интуитивно эти два условия не кажутся одинаковыми: наличие 3 сторон и требование, чтобы все стороны были больше 10 см. Одно условие необходимо для треугольников, а другое явно нет. Но это только потому, что мы привносим наш реальный опыт в область моделирования предметной области.
Какова цель моделирования предметной области? Максимально приблизиться к физическому миру? Сделать модель максимально реалистичной?
Нет.
Цель в том, чтобы построить модель, полезную для нашей конкретной проблемы. Не для всех возможных областей проблем и определённо не для какой-то сферической проблемы в вакууме. Для нашей конкретной.
Следовательно, если нашему приложению необходимо, чтобы все треугольники имели стороны больше 10 см, если работа с треугольниками меньших размеров не помогает нам достичь наших целей, то эти меньшие треугольники могут просто не существовать для целей нашего приложения. Т.е., если концепция бесполезна для модели, вы вообще не должны включать её в модель.
Да, треугольники со сторонами меньше 10 см могут существовать в других доменах, но в нашем конкретном их нет. Так же, как и четырёхугольники, пятиугольники и другие фигуры (при условии, что наше приложение работает только с треугольниками). Поэтому между этими условиями наличия ровно 3 сторон и всех сторон больше 10 см нет разницы. Оба являются инвариантами, составляющими понятие треугольника в нашем конкретном приложении.
Конечно, требования могут измениться, и условие 10 см может превратиться в 5 или 20 (или даже стать настраиваемым), но это регулярный процесс уточнения, когда вы лучше понимаете домен по мере продвижения проекта. Это не означает, что исходное условие не было инвариантом. Было. Так же, как новое является инвариантом сейчас.
Источник: https://khorikov.org/posts/2022-06-06-validation-vs-invariants/