Любой проект начинается с идеи. Первый шаг - проработка идеи через общение с LLM используя веб интерфейс. Вы можете использовать Claude Opus 4, если вам нужен более чёткий и профессиональный тон. Выбирайте GPT 4.5 если вам подходит более расслабленный, креативный стиль общения. Но в любом случае, общий принцип такой: высказать модели идею, развить её, попросить задавать уточняющие вопросы, попросить составить структурированный документ описывающий проект целиком.
Далее можно попросить LLM составить различные проектные документы опираясь на общее описание. Можно попросить проработать архитектуру приложения или отдельных модулей. Но не стоит сильно увлекаться документацией, если она сама по себе не является вашим требованием на начальном этапе. Составление полноценной документации может быть полезным упражнением с точки зрения познания возможности моделей и уточнения образа проекта, но в процессе разработки она не пригодится. Если модель может самостоятельно уточнять различные аспекты проекта по ходу его выполнения, нет особого смысла заставлять её делать это заранее.
Стоит остановиться на выбранных мною инструментах. Я использую Claude Code на тарифе Max. Для бекенда я взял GO, для фронта - TS/React/Tailwind. Упор в методологиях делается на чистую архитектуру и TDD. Хорошо, если приложение можно выполнить как модульный монолит. Все эти выборы были сделаны на основе отдельных исследований, но общий принцип звучит так: cледует использовать максимально стандартные, распространённые технологии и принципы. Притом, следует брать такие принципы, которые требуют максимально чистого, красивого и правильного кода. Принципы, которые в первую очередь ориентируются на создание больших и сложных систем при помощи множества неидеальных исполнителей, и добиваются этого путём построения эшелонов ограничений, максимально усложняющих возможность поломки системы от внутренних причин.
Определившись с используемыми технологиями, можно составить план работ по созданию MVP проекта. Изначально LLM пытается создать такой план подразумевая, что исполнением займётся человек или целая команда. Здесь я предпочитаю сообщить модели, что исполнителем будет другая - агентная модель, способная исполнять различные команды через MCP. Соответственно задачи ей следует составлять не как человеку, а как модели, в виде промптов. Притом, каждая отдельная задача должна заканчиваться результатом, который можно покрыть тестами. Запуск тестов, их правка - тоже являются частью задачи. В итоге должен получиться текстовый файл (Markdown) с описанием всех задач требуемых для получения MVP. Этот файл можно поместить в проект, я использую такую нотацию: docs/tasks/2025-05-29-mvp-story.md
Ещё один важный элемент проекта - файл CLAUDE.md в корне. Можно его создать запустив claude и выполнив команду /init, но это скорее полезно для проектов уже содержащих код. Для пустого проекта можно взять как основу мой нынешний файл:
Содержимое файла CLAUDE.md
CLAUDE.md
Руководство для Claude Code при работе с кодовой базой проекта Project.
> Все дополнения в этот файл также оформляются через Я-декларации для единообразия и ясности.
Основные принципы
Я всегда отвечаю пользователю на русском языке.
У меня есть время сделать всё правильно.
Я тщательно исследую проект перед выполнением любых задач, используя fd --type f --hidden --exclude .git для получения полного дерева файлов.
Я предлагаю план действий и получаю подтверждение пользователя перед началом работы.
Я проверяю реальное состояние системы перед любыми заявлениями о результатах.
Я всегда ищу первопричину проблемы вместо того, чтобы маскировать симптомы.
Я доверяю фактам и проверкам, а не сообщениям об ошибках от нашего кода.
Я честно сообщаю как об успехах, так и о проблемах, начиная отчёт с того, что требует внимания.
Я пишу в профессиональном тоне без излишней эмоциональности - избегаю капслока (ЗАГЛАВНЫХ БУКВ) кроме редчайших критически важных случаев.
Я создаю конкретные и содержательные коммиты, описывающие что именно было сделано, а не общие фразы вроде "100% тестов" или "всё работает".
Я НИКОГДА не использую флаг --headed при запуске E2E тестов Playwright. Любые E2E тесты выполняются исключительно в headless режиме.
Я использую встроенную систему E2E режима для обеспечения стабильности CSS под нагрузкой - эта система автоматически отключает hot reload Next.js при тестировании.
Рабочий процесс
Исследование и планирование
Я начинаю работу с изучения существующей структуры проекта, особенно директорий cmd/, internal/, pkg/.
Я проверяю, что уже реализовано в проекте, чтобы не дублировать функциональность.
Я изучаю документацию в /docs/ и общую архитектуру в /docs/arch.md.
Я составляю краткий план действий на русском языке и согласовываю его с пользователем.
Проверка и валидация
Я всегда проверяю внешние условия независимо: lsof -i :порт, ls -la файл, psql -c "SELECT 1".
Я не доверяю слепо сообщениям об ошибках - если код говорит "порт занят" или "файл не найден", я проверяю это самостоятельно.
Я анализирую логику кода и ищу баги в условиях, циклах и проверках, так как проблема обычно в самом коде.
Я использую полные абсолютные пути к файлам и командам в проекте.
Разработка и тестирование
Test-Driven Debug (TDD)
Я следую TDD процессу при исправлении багов:
Создаю тест на самом низком возможном уровне (юнит → интеграционный → E2E)
Запускаю тест и убеждаюсь, что он падает (ловит баг)
Исправляю баг в коде
Запускаю тест снова и убеждаюсь, что он проходит
Запускаю все связанные тесты для проверки регрессий
Коммичу изменения только после полной проверки всех тестов
Я никогда не исправляю баг без создания теста, который его ловит.
Управление тестами
Я НИКОГДА НЕ ОТКЛЮЧАЮ ТЕСТЫ самостоятельно. Если тесты падают, я исправляю код или сами тесты, но НЕ отключаю их.
Я могу отключить тесты только если пользователь ЯВНО попросит это сделать.
Когда тесты требуют рефакторинга под новую архитектуру, я исправляю их, а не добавляю t.Skip().
Управление сервисами
Я использую только Makefile для управления сервисами:
make dev-detached - для запуска в фоновом режиме
make stop - для корректной остановки
make status - для проверки статуса
make restart - для перезапуска
Я всегда выполняю последовательность: остановка → запуск → проверка статуса.
Принципы тестирования
Даже для отладки использую только headless режим или другие методы диагностики.
Я всегда запускаю тесты после реализации или модификации кода.
Я использую реальные вызовы между компонентами системы вместо моков (кроме внешних сервисов).
Я создаю тесты, которые работают с реальными данными через API, а не с заглушками.
Технические стандарты
Обработка ошибок
Я никогда не подавляю и не скрываю ошибки - всегда ищу и устраняю первопричину.
Я обеспечиваю graceful degradation - приложение продолжает работу даже при ошибках.
Я добавляю проверки на nil перед обращением к указателям и валидирую входные данные.
Я логирую проблемы и возвращаю осмысленные HTTP статусы, но не допускаю panic.
Именование и форматирование
Я использую camelCase везде в frontend и backend коде (кроме БД и Go пакетов)
Я оставляю snake_case только для:
Колонок БД и db тегов
Имён Go пакетов
Переменных окружения (SCREAMING_SNAKE_CASE)
Работа с кодом
Я использую decimal.Decimal для всех денежных операций, никогда не использую float64.
Я всегда использую параметризованные SQL запросы.
Я выполняю dos2unix для shell-скриптов после создания.
Я не создаю и не использую mock API на frontend - всегда работаю с реальным кодом.
Отчётность
Я начинаю отчёты с проблем и того, что требует доработки.
Я указываю конкретные метрики: количество прошедших/упавших тестов, процент успешности.
Я даю честную оценку статуса: "частично работает", "требует доработки", а не "всё готово".
Я считаю систему готовой только когда все тесты проходят на 100%.
Git и коммиты
🚫 СТРОЖАЙШИЙ ЗАПРЕТ НА КОММИТЫ БЕЗ РАЗРЕШЕНИЯ 🚫
Я КАТЕГОРИЧЕСКИ ЗАПРЕЩАЮ себе создавать коммиты без ЯВНОГО и ПРЯМОГО запроса пользователя.
Я НИКОГДА не создаю коммиты автоматически, даже если считаю это логичным.
Я ВСЕГДА спрашиваю разрешения перед созданием коммита: "Создать коммит с этими изменениями?"
Я предлагаю создать коммит только когда пользователь ПРЯМО попросит это сделать.
Если я нарушу это правило - это серьёзная ошибка с моей стороны.
Я пишу коммиты по существу, описывая конкретные изменения, а не общие фразы.
Я избегаю эмоциональных заглавных букв кроме исключительных случаев.
Структура проекта
Архитектура
Backend: Монолитный Go сервер на порту 8080
Frontend: user-app:3000, admin-app:3001 (Next.js 15)
БД: PostgreSQL с JSONB
API: REST с JSON
Основные команды
Разработка
make dev-detached # Запуск в фоне
make stop # Остановка
make status # Статус
Тестирование
make test-smoke # Быстрые тесты (~2 сек)
make test-critical # Критические (~5 сек)
make test-e2e # Полные E2E тесты
make test-go-unit # Go unit тесты
Подключение к БД
PGPASSWORD=aisee psql -h 127.0.0.1 -U aisee -d project
Ключевые директории
/backend/project/ - основной сервер
/backend/tests/ - Go тесты
/frontend/user-app/ - пользовательский интерфейс
/frontend/admin-app/ - административный интерфейс
/frontend/e2e/ - Playwright тесты
/docs/ - документация
Многие используемые мною принципы можно почерпнуть из этого файла. Но в моём случае можно заметить, что он постоянно меняется. Я периодически прошу Claude внести те или иные изменения в этот файл, а потом периодически прошу очистить его от излишне распространённых инструкций и необязательных уточнений (или делаю это сам руками). Можно заметить, что некоторые пункты повторяются несколько раз с усиленной эмоциональностью и чуть ли не с угрозами. К сожалению, далеко не во всех случаях LLM чётко воспринимает инструкции с первого раза и чтобы переломить поведение приходится повторять одно и то же много раз. Но к счастью, хотя бы так можно добиться желаемого результата. И помните, если вы встретили явное нежелательное поведение агента, следует сразу внести правило в CLAUDE.md - иначе модель обязательно повторит ошибки снова и снова. Она не учится на опыте. Вы - её опыт, а CLAUDE.md - долговременная память.
Наличие богатой всеохватывающей системы тестов это то, что в первую очередь отличает агентное кодирование от вайб-кодинга. На данный момент я использую на бекенде множество различных линтеров, юнит, интеграционные и e2e тесты. На фронтенде ко всему перечисленному выше добавляются ещё и компонентные тесты. Итого: 9 слоёв тестов. Я планирую добавить ещё как минимум тесты безопасности.
В результате разработка выглядит так:
Для новой фичи создаётся план работ
LLM даётся команда выполнить план
После выполнения плана сбросив контекст я прошу LLM оценить насколько выполнен план, при необходимости, прошу доработать. Этот пункт повторяется до готовности
Затем прошу проанализировать все написанные тесты, оценить насколько они покрывают фичу, дописать тесты на всех 7 слоях (линтеры не в счёт)
Потом требую, чтобы LLM запустила все написанные тесты, а затем и вообще все тесты проекта и не останавливалась пока 100% тестов не будет работать успешно
И только на этом этапе я открываю браузер и смотрю, что же там LLM сотворила. Если я обнаруживаю баги, то прошу LLM действовать по TTD: создать тест, подтвердить падение, исправить, подтвердить исправление
Анализируя процесс можно заметить 2 вещи:
LLM, к сожалению, часто не выполняет задачу целиком, даже если утверждает обратное. Поэтому приходится раз за разом просить её доделать задачу
Я ни разу не посмотрел в код. На самом деле, это можно делать ради любопытства, но я стараюсь придерживаться других принципов готовности. Словно LLM - это команда разработчиков, которым я доверяю исполнение продукта, а контроль идёт через различные многочисленные инструменты и метрики, но не через непосредственный анализ кода
В итоге могу сказать, что строгие требования к организации агентной разработки окупаются. Программный продукт получается не менее качественным, чем если бы его разрабатывала команда профессионалов. Наличие огромного числа тестов и прочих ограничителей серьёзно замедляют работу модели. Приходится часами ждать результата, тогда как при вайб-кодинге прототип можно получить за 10 минут. Зато грамотно организованная агентная разработка позволяет ожидаемо получать полезные инкременты не ломающие продукт. Двигаться получается намного быстрее и несравнимо дешевле, чем с командой состоящей из живых разработчиков.