Контракты, а не задачи
Я замерил, куда на самом деле уходит моя неделя. Декомпозиция одной фичи на точные задачи — какие файлы, какие методы, в каком порядке — стоит мне часов. Потом я посмотрел, что разработчик сделал с моей декомпозицией.
Он вставил её в Claude.
Задержись на этом на секунду — мне понадобилось стыдно долго. Подробный список задач — это, по функции, промпт. Я руками писал промпты самыми дорогими часами в команде — для модели, которая сидит рядом с кодом и перегенерирует тот же план за минуты.
Дубль
У репозитория, из которого релизится моя команда, есть собственный агентный тулинг: по хорошо оформленному требованию он в порядке вещей выдаёт план имплементации — файлы, слои, порядок.
Так что каждая моя пофайловая задача была дублем: моей догадкой о плане имплементации, произведённой дальше от кода, чем инструмент, который всё равно его переделает.
Два прохода по одной работе. И из двух дорогим был мой.
Математика горлышка
Вот почему это не косметическая неэффективность:
| Шаг | Кто платит | Типичная цена |
|---|---|---|
| Мелкозернистая декомпозиция | владелец | часы на фичу |
| Реализация по ней | разработчик + агент | часто меньше |
Когда постановка стоит дороже производства, очередь выстраивается перед владельцем. Не изредка — структурно. Фичи перестают ждать рук и начинают ждать моей писанины.
И у ловушки жестокий поворот: чем я усерднее — чем мельче декомпозирую, — тем хуже. Каждый лишний час прожёвывания ложится на дорогую сторону баланса и ничего не снимает с дешёвой. Усердие копает яму глубже.
Значит, лечение не может быть «декомпозируй лучше». Оно обязано быть «декомпозируй меньше — и всё равно оставайся в безопасности». Вот как это выглядит.
Одна фича, две передачи
Как список задач: добавь колонку, поправь хэндлер, расширь валидацию, не забудь миграцию, обнови вызов на клиенте. Пять прогнозов о том, как, — каждый из них тулинг рядом с кодом выведет заново, и ни один я не могу проверить.
Как контракт: операция переименования существует; дубль имени отклоняется отдельной ошибкой; вызвать может только владелец scope; когда родительский объект умирает, запись умирает с ним; «готово» — это три проходящие проверки.
Пять обещаний о том, что должно стать истинным, — каждое проверяемо, и ни одно не является моей догадкой о чужом файле.
В этом вся замена. Единица передачи — больше не изменение, которое надо сделать, а обещание, которое надо сдержать. Из чего оно состоит:
| Секция | На какой вопрос отвечает | Почему переживает встречу с реальностью |
|---|---|---|
| Интерфейс | Что существует, когда ты закончил? | Абстрактная схема, именованная конвенциями самого API — ничего выдуманного |
| Поведение | Что происходит при успехе, при отказе, на границах? | Текстом, не кодом — перевод берёт на себя имплементатор |
| Доступ | Кто может вызвать, под какой привилегией и в каком scope? | Включая случаи, о которых забывают: обход админа, машинная идентичность |
| Жизненный цикл | Что происходит при удалении / обновлении / отвязке родителя? | «Мы забыли про каскад» — самый скучный продакшн-инцидент на свете |
| Приёмка | Что значит «готово»? | Прогоняемо без вопросов автору, что он имел в виду |
| Радар воздействия | Что нельзя сломать и что от этого зависит? | Порядок становится данными, а не племенным знанием |
Что контракт намеренно опускает: пути к файлам, имена методов, SQL, пошаговые инструкции. Это юрисдикция имплементатора, это лучше перегенерируется ближе к коду — и каждая такая строка в спеке — строка, за которую я заплатил дважды.
Страх — и закон, который на него отвечает
Отдать крупное обещание вместо пяти прожёванных шагов — страшно, похоже на безрассудство. Страх легитимен — и у него есть точный ответ:
Гранулярность декомпозиции должна быть обратно пропорциональна силе твоего приёмочного gate.
Если gate исполнителя силён — ревью против контракта, тесты, которые пишет автор как норму, скрипт, проверяющий саму структуру контракта, — крупные единицы безопасны: один контракт упаковывает то, что было бы шестью задачами, а gate ловит, что пошло не так.
Если gate слаб, крупные куски и правда безрассудство. Приходится мельчить — не навсегда, а пока gate не вырастет.
Я гоняю оба режима одновременно, поэтому и знаю, что закон держится:
| Трек | Gate сегодня | Размер единицы сегодня |
|---|---|---|
| Backend | Силён: сеньор ревьюит против контракта, автор пишет тесты, скрипт проверяет структуру | Крупный — один контракт вместо шести задач |
| Frontend | Слабее, ещё растёт | Мелкозернистый, послойный |
Backend-контракты со временем стали жёстче, а не мягче: сеньор, который их потребляет, раз за разом возвращал их — недостающий пункт жизненного цикла, имя поля, уплывшее от API-дока, строка доступа без админского случая. Каждый его рулинг становился постоянной проверкой. Это gate буквально усиливается — и каждый раз, когда это происходило, я мог позволить себе отдать кусок чуть крупнее.
Frontend остаётся мелкозернистым не потому, что фронтенд сложнее, а потому, что тот gate моложе. Тот же закон, другой конец шкалы.
Куда делись часы
Выигрыш замыкает петлю, с которой этот текст начался:
| Было | Стало | |
|---|---|---|
| Мои часы на фичу | прожёвывание плана имплементации | написание обещаний + суждение по приёмке |
| Разработчик получает | мой прогноз, чтобы вставить его в модель | право владеть «как» — с gate, который ловит провал |
| Очередь | выстраивается передо мной | выстраивается перед gate — а он масштабируется |
Два контракта, делящие граничный интерфейс, могут даже идти параллельно — фронтенд против схемы, бэкенд против поведения, — потому что источник истины на границе — контракт, а не совещание. Прожёванные задачи так не умеют: они сериализуются на общих файлах, даже когда обещания независимы.
Честный prior art, с датой: design-by-contract существует сорок лет — предусловия и постусловия принадлежат Мейеру, не мне, — а работы 2026-го оживляют его под задачной декомпозицией, чтобы верифицировать кодогенерацию. Ход здесь другой: контракт заменяет задачу как единицу передачи на границе человек↔агент, и приходящего с ним закона гранулярности я нигде сформулированным не видел. По состоянию на середину июля 2026-го — сверься с датой, прежде чем цитировать.
Неуютное следствие — дальше в серии возьмусь за него всерьёз: если гранулярность — функция силы gate, то улучшение твоих gate — а не промптов и не моделей — самая рычажная инвестиция в команде, работающей с AI. Gate — это и есть продукт.
Владелец перестаёт быть горлышком в тот день, когда единица передачи — обещание, которое может проверить gate исполнителя, а не план, который владелец был вынужден написать дважды.
Дальше: The Two-Layer Compiler — почему тупой процедурный слой плюс обучающийся слой компаундятся, а ручная сообразительность — нет.