Егор Урванов

Спеки по агрегатамRFC-требования и ограниченные контексты вместо спеки на каждую фичу

Spec-driven development без разрастания спек: как держать их в одном словаре агрегатов, чтобы их не становилось больше с каждой фичей: уровни требований, карточка агрегата и границы контекстов.

· 4 мин · · Спеки и контекст

Почему спек становится много

Спека на фичупонятие описано в каждой фиче
12 файлов«Бронь» — в 7
растёт с фичами
Словарь агрегатовпонятие описано один раз
Reservation
Room
TimeSlot
Member
4 записи«Бронь» — в 1
растёт с доменом
Фича 13→[booking::Reservation]+1 MUST→тест+1

Числа условные. Как спеки и изменения раскладывает OpenSpec: папки specs/ и changes/, изменения уходят в архив.

Вывод
В этом примереДвенадцать фич дали двенадцать спек, и бронь описана в семи из них по-разному. В словаре те же фичи дописали строки в четыре записи агрегатов.
В общем случаеЕсли спека привязана к изменению или фиче, файлов становится больше с каждой задачей, а одно понятие расходится по нескольким местам. Если единица — агрегат, число записей ограничено самим доменом, а фича только добавляет в запись требования.
Что сделатьВыпишите понятия, которые встречаются в трёх и больше спеках, и заведите каждому одну запись в словаре. Спеки фич пусть ссылаются на запись, а не пересказывают её.

Уровни требований RFC 2119

СловоЗначениеСилаПроверка
MUSTобязательноавтотестблокирует
MUST NOTзапрещеноавтотестблокирует
SHOULDпо умолчанию, отступ с причинойревьюпредупреждает
MAYдопустимонетне проверяется
MUST = SHALL

Слова и их смысл — по RFC 2119. Каждому слову соответствует своя проверка.

Вывод
В этом примереВ записи брони правило «интервалы не пересекаются» стоит как MUST и проверяется тестом, а «подтверждение в тот же канал» — как SHOULD и смотрится на ревью.
В общем случаеСлово требования сразу говорит, чем его проверять и что делать при нарушении. Агент читает MUST как границу, а SHOULD как умолчание, и не путает одно с другим.
Что сделатьПерепишите требования своей спеки с этими четырьмя словами и рядом с каждым MUST укажите тест, который его проверяет.

Карточка агрегата

Пример выдуман. Термины — по Martin Fowler: DDD Aggregate.

Вывод
В этом примереВся бронь — одна карточка: адрес, четыре требования, три команды, права, связи и ссылка на фичу, из которой она появилась.
В общем случаеАгрегат — граница, внутри которой требования всегда соблюдаются, а менять его можно только его командами. Поэтому в карточке рядом стоят и правила, и единственные способы их нарушить.
Что сделатьДля каждого агрегата заведите карточку из шести полей. Если требование нельзя приписать ни одному агрегату, скорее всего, агрегат ещё не назван.

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

booking
ReservationRoomTimeSlot
billing
InvoiceTariff
access
PassLevel
связи между контекстами — только по idbilling::Invoice→ id →booking::Reservationaccess::Pass→ id →booking::Reservation
«Уровень»
booking::Room.floorЭтаж
access::LevelДопуск
одно слово — два термина, разные подписи
термин = одна записьссылка [[ctx::Name]]совпало слово — разные записисловарь меняется вместе со спекой

Подход — Bounded Context и Ubiquitous Language.

Вывод
В этом примереСчёт и пропуск ссылаются на бронь по id и не знают её устройства. Слово «уровень» в бронях значит этаж, а в доступе — допуск, и это две разные записи.
В общем случаеКонтекст — область, внутри которой у каждого слова один смысл. Когда слово совпало в двух контекстах, заводят два термина с разными подписями, иначе агент перенесёт правило из одного в другой.
Что сделатьРазложите агрегаты по контекстам и найдите слова, которые встречаются в двух. Для каждого такого слова заведите отдельные записи и разные подписи в интерфейсе.

Дальше по теме

ПродолжениеПетля сверки для спеккак в Kubernetes: желаемое, замер и среда агента
Пример с бронированием выдуман. Термины — по источникам в подписях под схемами.
  • AI
  • spec-driven development
  • спеки
  • DDD
  • агенты
© 2026 Егор Урванов