- BrainTools - https://www.braintools.ru -
Это продолжение первой статьи [2] про взрослый вайб-код для тех разработчиков, которые уже перешли на тёмную сторону. Ради неё, на самом деле, писалась первая часть: меня очень попросили опубликовать свой ИИ-фреймворк, в котором сейчас производится 99% моего кода, поэтому делюсь тут.
Меня зовут Саша Раковский. Работаю техлидом в расчётном центре одного из крупнейших банков РФ, где ежедневно проводятся миллионы платежей, а ошибка [3] может стоить банку сотни миллионов рублей. Законченный фанат экстремального программирования, а значит и DDD, TDD, и вот этого всего. Штуки редкие, крутые, так мало кто умеет — для этого я здесь, делюсь опытом [4]. Если стало интересно, добро пожаловать в мой блог [5].
В прошлой части я разобрал базу по ИИ-разработке для начинающих и накинул несколько тезисов от себя:
На голых промптах далеко не уедешь. В ИИ-разработке необходим системный подход к решению повторяющихся задач, исправлении повторяющихся ошибок, в управлении контекстом. Без ИИ-фреймворка – никак.
Без автотестов хоть сколько-то адекватная ИИ-разработка невозможна. Именно автотесты должны быть центральным элементом ИИ-разработки. Если софт – это совокупность поведения [6] системы, то зелёный автотест – это единица поведения [7], фундаментальная частица, из которой построен этот софт.
Автономная ИИ-разработка – это пока фантастика. Даже самые лучшие модели чудят так, что никакими тестами не предугадаешь все их возможные косяки. Человеческое ревью необходимо обязательно.
В общем, нужен фреймворк, построенный вокруг автотестов и частого ревью. Чем больше кода необходимо отсмотреть, тем выше вероятность пропустить какой-то косяк. Поэтому чем чаще ревью, чем меньше смотреть за раз, тем лучше.
Из опенсорсных TDD-фреймворков мне известен только один – Superpowers. И это вполне годная штука, если вы предпочитаете легковесные подходы в дизайне и автотестах, но при этом хотите поддерживать высокую дисциплину разработки.
Однако, именно поэтому мне, например, superpowers не очень подходит – слишком уж легковесный. Он практически противоречит ATDD и плохо встраивается в более структурированные процессы разработки. В то же время, в процессе разработки у меня как-то само по себе родилось своё решение, заточенное под принятый в нашей команде “книжный подход”.
И раз получилось неплохо, то почему бы, по просьбам подписчиков своего канала, и не поделиться прогрессом на текущий момент. Фреймворк проверен на 3,5 месяцах работы, 4к коммитов, 1500 тестов, ~350 — e2e, 25к строк продакшн-кода (12k java back, 12k ts/tsx front). И столько же тест-кода.
Начнем с концепции. Любой софт – это совокупность поведения системы. Каждая единица поведения должна иметь свой тест-кейс. Зелёный, то есть подтвержденный. Поэтому хороший софт – это совокупность зелёных тест-кейсов. Именно вокруг этой идеи построены процессы разработки в нашей команде. И именно она легла в основу самого фреймворка.
Верхнеуровнево фреймворк проходит следующую последовательность шагов:
краткое описание продукта + перечисление историй
история 1
этап спецификации
интервью
… (проектирование требований на основе интервью и описания продукта)
генерация кейсов на основе требований
этап реализации сгенерированных кейсов:
кейс 1
красный тест
… (реализация)
зелёный тест
кейс 2
… (остальные кейсы)
история 2
этап спецификации
…
этап реализации
Вся работа разбита на истории – минимально зависимые друг от друга фичи, каждая из которых поставляет свою рбособленную ценность. Как говорил Кент Бек пользакам: “Tell me your story”. История должна покрывать какой-то один аспект пользовательского опыта. Например, “однажды я забыл пароль” – вполне себе подобная история, которая превращается в фичу “Сброс пароля”.
Разработка истории начинается с постановки требований: описания истории, критериев приёмки, проектирования апи, макетов. Эти требования необходимы для составления списка тест-кейсов – главного артефакта для каждой истории.
После того, как тест-план готов, фреймворк проходит по списку кейсов в TDD-стиле, реализуя тесты один за другим, прерываясь лишь на ревью. После того, как все тест-кейсы позеленены, история считается реализованной.
Центральным элементом фреймворка является скилл /continue, который, опираясь на текущее состояние проекта – список историй и их прогресс-файлы, определяет, какой дальнейший шаг необходимо сделать.
По ссылке [8], я специально сделал демо-пример классического бэк+фронт приложения – Kanban-доски с 3 запланированными к разработке историями в stories.md [9]:
Создать таску.
Передвинуть таску в другую колонку.
Изменить/удалить таску.
Пройдёмся по ним в обратном порядке:
К истории #3 я намеренно не приступал, поэтому /continue 3 начнет проектирование с самого первого шага – написания спецификации:
проведёт и запротоколирует интервью;
составит описание истории;
построит макеты интерфейса;
определит используемое апи и спроектирует новое, если надо;
сгенерирует тест-кейсы, необходимые для реализации.
В истории #2 спека уже есть, но разработка еще не начата, поэтому “/continue 2” начнет уже с разработки бэка: найдет первый кейс, прочитает спеку, напишет красный приёмочный тест и побежит шаг за шагом его зеленить в коротких red-green-refactor TDD-циклах, прерываясь на ревью после каждого шага.
В истории #1 уже сделаны все кейсы на бэке и даже начат фронт, поэтому вызов скилла “/continue 1” приведёт к тому, что разработка продолжится с фронтового кейса – с последнего шага, который отмечен в progress.md [9]истории, как выполненный.
Но, как видите, тут мы встречаем первое ограничение: фреймворк был разработан мной для своих задач – разработки серверного приложения. Чтобы использовать фреймворк для мобильного, десктопного приложения, embedded, игр или для еще какого-то софта, может понадобиться доработка фреймворка через специально придуманный для этого скилл /prompt-update.
В каждой истории есть свой progress.md, который фиксирует, на чем остановилась работа над историей в прошлый раз. Это длинный чек-лист, разбитый на несколько фаз:
спецификация
реализация:
бэкенд
внешние интеграции
фронтенд
безопасность
нагрузка
инфраструктура.
Спецификация состоит, как я уже говорил, из нескольких шагов: интервью, описания, макетов, апи и тест-плана.
После каждого шага /continue, отмечает шаг сделанным в чеклисте, делает коммит и встает на паузу, ожидая ревью от человека. После запуска /continue переходит к следующему шагу.
Все остальные фазы состоят из кейсов, сгенерированных, в первой фазе.
В свою очередь, каждый кейс разбивается на отдельные TDD-шаги. Тут уже фреймворк очень сильно начинает навязывать свой подход к разработке – а именно ATDD, процесс в котором большой TDD-цикл оборачивает внутри несколько маленьких.
Например, для бэка это выглядит так:
красный приёмочный (e2e, acceptance) тест;
красный usecase-тест;
зелёный usecase-тест;
красный адаптер-тест (например, контроллер);
зелёный адаптер-тест;
… такие же мини-циклы для других адаптеров
зелёный приёмочный тест;
После каждого шага следует коммит, чтобы можно было посмотреть изолированные изменения, сделанные в рамках отдельного шага.
Как видим, тут навязана Clean Architecture с общепринятым в гексагональной архитектуре ATDD. Этот подход к тестированию описан, например, в “Get Your Hands Dirty on Clean Architecture”, Tom Hombergs и “Hexagonal Architecture Explained” от самого автора гексагоналки, Alistair Cockburn. Если вы предпочитаете иную архитектуру или иной тестовый подход, то тут потребуется доработать фреймворк под себя с помощью /prompt-update, о котором я уже упоминал, но подробнее расскажу чуть позже.
Одно из больных мест любой LLM – это качество кода, на котором она обучается. Поэтому для исправления типовых косяков LLM, мне пришлось добавить еще несколько гейтов, чтобы исправлять типовые ошибки:
на красном шаге это ревью строгости тестов и соблюдения тестовой архитектуры + рефакторинг;
на зелёном шаге это рефакторинг + проверка покрытия тестами.
Каждый гейт содержит обязательный чеклист, по каждому пункту которого LLM должна отписаться, есть ли нарушение или нет.
После всех гейтов следует коммит, и в дело вступаем мы, отсматривая diff коммита и высказывая замечания. Если замечаний нет или они устранены, мы сбрасываем контекст и делаем /continue. Фреймворк молотит дальше, а мы идем в другое окно IDE разруливать другой добежавший до конца /continue.
Каждый шаг реализации разбит на 2 этапа: написание теста/кода и последующие гейты (ревью, рефакторинг, coverage). Чтобы эти активности друг на друга не влияли, все подшаги запускаются в отдельных агентах.
Другой приём управления контекстом – этот тот самый progress.md [10], позволяющий сбрасывать контекст после каждого шага, и начинать с пустого контекста, загружая туда только самое необходимое, повышая надежность вывода.
Если я сталкиваюсь с каким-то косяком не в первый раз, я вызываю /prompt-update с описанием проблемы. После исправления фреймворка, я отсматриваю изменения, откатываю последний коммит, сбрасываю контекст, и проверяю, что в этот раз проблема решена.
В итоге, день за днём фреймворк обрастает всё новыми и новыми правилами, становясь всё более эффективным… и, порой, все менее послушным. Потому что чем больше правил, тем больше шансов, что какое-то из них нейросеть простодушно забудет.
Сейчас я пишу код только с этим фреймворком и без него уже вряд ли захочу. Если хотите прикоснуться ко всем тем книжным процессам, которые работают у нас в команде, и повертеть в руках не хаотичный вайб-кодинг, а полноценный взрослый продакшн процесс ИИ-разработки, то я специально приготовил 2 репозитория:
Независимо от родного языка и типа проектируемых систем я бы рекомендовал сначала всё же скачать первую репу и поиграться с ней.
Я предполагаю, что у вас есть подписка на клод или на клод-совместимую LLM (например, GLM5 от Z.ai или вы умеете запускать Claude-конфигурацию в Codex).
Склонируйте репу с Канбан доской. Рекомендую склонировать 3 раза и открыть каждую репу в отдельной IDE. Ну или используйте worktrees, если так привычнее.
В каждой из IDE откройте терминал, зайдите в клод, и введите /continue 1, /continue 2, /continue 3 соответственно.
В первой ide клод приступит к написанию selenium-теста для фронтового кейса, на котором остановилась разработка.
Во второй ide начнёт разработку с того места, где остановилась вторая история – с acceptance-теста для первого бэкенд-кейса.
В третьей ide клод увидит, что третья история ещё не начата и приступит к разработке с самого первого шага – интервью.
Почему 3 ide?
Пока /continue делает все свои необходимые шаги, легко может пройти от 5 до 20 минут. Иногда, если клод столкнулся с какой-то непростой для него проблемой и по много раз перезапускает долго исполняющиеся тесты, чтобы проверить ту или иную гипотезу, время одного запуска может затянуться на сорок минут и даже час.
Это один из недостатков получившегося фреймворка – цикл, на который Claude уходит в работу, очень долгий. Впрочем, если дефицита задач нет, то параллелизация работы позволяет все равно двигаться именно с той скоростью, с которой вы способны ревьюить изменения. Каждая фича будет ехать примерно, как если бы она была написана руками, но одновременно с ней будут ехать еще 3-4 минимум.
Впрочем, уже сейчас многие модели переходят на заметно более высокие скорости ответа. Так что в ближайшие полгода-год, вероятно, этот недостаток уйдет в прошлое.
Почему не worktree?
Можно и worktree, конечно. Но я использую отдельные репозитории, потому они чуточку удобнее и позволяют чуточку больше.
Как у меня
Мой типовой поток состоит из 6 параллельно запущенных IDE, в которых 4-5 молотят /continue или обрабатывают замечания по результатам работы этого скилла, а в оставшихся я занимаюсь какими-то техдолгами: планирую рефакторинги, ищу проблемы в коде, оптимизирую пайп.
Про порты
Поскольку параллельно запущенные агенты начинают одновременно запускать приложение, чтобы погонять тесты, то тут происходит конфликт [13] портов и общей инфраструктуры. Чтобы этого не происходило, предусмотрены скрипты, определяющие порты на основе имени директории репозитория.
Если папка будет иметь на конце индекс: “continue-example1”, “continue-example2”, “continue-example3”, то это позволит фреймворку забить для каждого репозитория порты так, чтобы при запуске приложений и инфраструктуры разные потоки друг другу не мешали.
Альтернативный вариант – пустая репа [12] с голым фреймворком. Я запарился и потратил кучу времени на отладку и тестирование фреймворка, чтобы он, независимо от выбранных технологий, мог доехать от пустой репы, до простенького mvp на одних лишь только вызовах /continue и небольших корректирующих усилиях по причесыванию каких-то заскоков.
Что делать?
Клонируете пустой фреймворк [12].
Прописываете:
описание продукта в BriefProductDescription.md [14]
ожидаемую нагрузку/производительность в ExpectedLoad.md [15]
технологии в technology.md [16]
генерите вместе с клодом список историй и просите его записать их в stories.md [17]
И дальше /continue без остановки.
У меня отняло несколько вечеров, чтобы отвязать фреймворк от этой своей джавы и сделать его более-менее рабочим на других языках. Я сделал несколько шаблонов под 90% основных технологий и языков. И оно даже работает на всех из них плюс-минус так, как я ожидаю. Но если вы с другого языка, то вы, вероятно, можете испытать некую форму культурного шока от того, как результат не похож на то, что принято в вашем языке. Так что /prompt-update вам в помощь.
Помимо /continue и саб-скиллов, которые он оркестрирует, есть еще парочка полезных скиллов, которые вызываются вне основного потока /continue.
Этот скилл используется для любого исправления поведения фреймворка. В том числе, для самых серьезных переделок фреймворка. Этот скилл один из самых вызываемых – я его использую по несколько раз в день.
Рядом с ним еще живёт /prompt-refactor, который предназначен для поиска проблемных мест во фреймворке. Но этот скилл я вызываю нечасто: порой он предлагает ерунду всякую, поэтому может использоваться только в условиях глубокого понимания работы фреймворка и контекста. Например, чтобы оценить последние изменения: /prompt-refactor last commit.
Не всё то история, что надо кодить в tdd-стиле, итерируясь по прогресс-файлу. А потому довольно скоро у меня появился скилл, предназначенный для багфиксов, рефакторинга, работы над инфраструктурой, промптами и иных задач, требующих продолжительной работы. Концептуально, таска близка к истории, но содержит гораздо меньше церемонии, подразумевая только описание задачи и прогресс-файл, содержащий исключительно необходимые для реализации задачи шаги.
Скилл /continue умеет итерироваться по задачам так же, как и по историям. Таски хранятся в своей папочке и после реализации мигрируют в папочку /done. Я в своей разработке использую его не реже раза в день.
Одно из не самых очевидных применений агентских систем – аналитика. Клод замечательно справляется с гуглежом документации, исследованием апишек, их проверкой с помощью курла. Клод может может сделать полную локальную копию больших объемов текстовых данных. И даже может скрейпить сайты, хитро обходя всякие антибот системы сайтов, чтобы собирать оттуда необходимую информацию.
Также Клод неплохо справляется с аналитическими задачами на больших данных – делегируя вычисления в код, оставляя за собой только формулировку правил, верхнеуровневый поиск каких-то закономерностей и формат отображения.
Всё это очень сильно упрощает и ускоряет аналитику. Но вот проблема: результаты этой аналитики потеряются вместе с сессией, а контекст сессии с каждым запросом к ней будет засоряться. Поэтому для фиксации всех своих находок может быть полезен скилл /doc.
У фреймворка есть много ограничений:
он был разработан под конкретный технологический стек;
под определенные подходы к разработке – Clean Architecture + DDD + OOP + Martin Fowler’s Refactoring Book;
под определенный подход к тестированию, ATDD – Acceptance Tests (Continuous Delivery book) + hexagonal architecture testing (adapter tests + application tests);
под бэк + фронт веб-приложение;
для экономии токенов используется английский язык.
В целом, если от технологии я его как-то отвязать смог, то ни от Clean Architecture, ни от ATDD даже пока не планировал. Поэтому, если Clean Architecture и ATDD для вас чужды, то, возможно, проще будет попытаться под себя адаптировать SuperPowers.
Но, если уж вам понравилось решение, то для редактирования фреймворка под свои задачи, вам потребуется часик-другой доработать его напильником скиллом /prompt-update.
Ну и, как обычно, в завершении техника безопасности:
ни ИИ, ни фреймворк не заменит разработчика: если на ревью не будет замечен баг, то он уедет в прод и все сломает;
фреймворк работает по принципу “железо дешевле людей” и предпочитает сэкономить человеческое время, потратив токены, поэтому мне не всегда даже $200 подписки Claude хватает для 5 часового окна при работе в несколько потоков;
фреймворк исполняется ллмкой, ллмки нарушают правила, поэтому иногда фреймворк будет сходить с рельс, и надо его подправлять (самое частое – иногда требуется повторно дёрнуть скилл /refactor или /test-review на чистом контексте);
фреймворк был разработан под один конкретный проект; он может показать себя заметно хуже на другом языке, на другой архитектуре, для других задач и в другом подходе к тестированию;
фреймворк разработан под вкусовые [18] предпочтения автора, если у вас другие – /prompt-update или superpowers;
фреймворк молодой, не учитывает и не может учитывать всего, поэтому он нуждается в постоянной доработке с помощью /prompt-update.
В общем, приятной эксплуатации. За обновлениями – в мой канал.
Автор: RakovskyAlexander
Источник [19]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/28876
URLs in this post:
[1] внимания: http://www.braintools.ru/article/7595
[2] первой статьи: https://habr.com/ru/articles/1023094/
[3] ошибка: http://www.braintools.ru/article/4192
[4] опытом: http://www.braintools.ru/article/6952
[5] блог: https://t.me/RakovskyXP
[6] поведения: http://www.braintools.ru/article/9372
[7] поведения: http://www.braintools.ru/article/5593
[8] ссылке: https://github.com/rakovi4/continue-example
[9] stories.md: https://github.com/rakovi4/continue-example/blob/main/ProductSpecification/stories.md
[10] progress.md: http://progress.md
[11] репа: https://github.com/rakovi4/continue-example/tree/main
[12] репа: https://github.com/rakovi4/continue-framework/tree/main
[13] конфликт: http://www.braintools.ru/article/7708
[14] BriefProductDescription.md: https://github.com/rakovi4/continue-framework/blob/main/ProductSpecification/BriefProductDescription.md
[15] ExpectedLoad.md: https://github.com/rakovi4/continue-framework/blob/main/ProductSpecification/ExpectedLoad.md
[16] technology.md: https://github.com/rakovi4/continue-framework/blob/main/ProductSpecification/technology.md
[17] stories.md: https://github.com/rakovi4/continue-framework/blob/main/ProductSpecification/stories.md
[18] вкусовые: http://www.braintools.ru/article/6291
[19] Источник: https://habr.com/ru/articles/1023998/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1023998
Нажмите здесь для печати.