План и действие: как я заставил Claude Code работать предсказуемо

План и действие: как я заставил Claude Code работать предсказуемо AI-Assisted

Два месяца работы с Claude Code научили меня одной простой истине: AI-ассистент, которому дали задачу «добавь OAuth авторизацию», выдаст код за 10 минут. Но этот код придётся переписывать несколько раз, потому что он не учитывает существующую архитектуру, забывает про edge cases и оптимизирует выдачу результата под скорость ответа, а не под качество решения.

Проблема не в возможностях модели. Проблема в том, как мы её используем. Мы делегируем AI одновременно два принципиально разных процесса: придумать архитектурное решение и написать код. Это как просить джуна сразу спроектировать систему и закодить её, не задавая уточняющих вопросов. Результат предсказуем — быстрый, но очень хрупкий код, как наверное многие заметили, начав использовать такого монстра как Claude Code.

Решение оказалось банальным: разделить планирование и исполнение (именно для этого существует специальный режим в Claude Code). Сначала Claude должен помогать спроектировать решение и только потом приступить к реализации готового плана (в идеале разделив выполнение различных задач по различным компетентным AI агентам). Звучит очевидно, но именно детали делают всю разницу.

Анатомия хаоса: почему традиционный подход ломается

Типичный сценарий работы с Claude Code выглядит так: открываешь редактор, пишешь «добавь real-time уведомления», ждешь... Claude начинает генерировать код — создаёт WebSocket connection, правит компоненты, добавляет event listeners. Ты сидишь такой важный, видишь diff'ы, киваешь головой, одобряешь. Потом, х😜якс, запускаешь dev, а оказывается что половина не работает.

Что пошло не так? Claude выбрал Socket.IO, хотя в твоём стеке уже был поднят Laravel Reverb. Создал новую систему событий, вместо того чтобы использовать existing Laravel events. Забыл про аутентификацию для WebSocket connections. Результат технически корректен, но архитектурно несовместим с кодовой базой.

И ты начинаешь написывать ему: «Это не работает с Reverb, переделай». Claude рефакторит, теперь использует Reverb, но сломал existing notification logic для email. Исправляем дальше email, ломается что-то ещё. Час работы превращается в четыре часа отладки.

Корень проблемы: AI-модель принимает архитектурные решения в условиях дефицита контекста. Она видит задачу «добавь real-time уведомления», но не понимает, как это должно интегрироваться с existing инфраструктурой. Поэтому выбирает самое популярное решение из training data (Socket.IO), а не самое подходящее для конкретного проекта (Reverb).

Традиционный подход оптимизирует time-to-first-code, а не time-to-working-solution. Мы получаем код быстро, но тратим в три раза больше времени на исправления.

Фаза планирования: архитектура до первой строки кода

Двухфазная методология начинается с жёсткого правила: запретить Claude трогать код до утверждения плана. Звучит радикально, но работает.

Когда мне нужна новая фича, я открываю чат и пишу примерно так:

Read-only mode. НЕ пиши код, НЕ создавай файлы.

Задача: добавить OAuth авторизацию (Google, GitHub).

1. Проанализируй существующую систему auth
2. Найди, где хранятся user credentials, как устроены sessions
3. Выяви потенциальные конфликты с OAuth flow
4. Предложи план интеграции с минимальными изменениями

Ключевая фраза — «Read-only mode». Это явная инструкция Claude не генерировать код, только исследовать и планировать.

Claude заводит свою шайтан машину и начинает работать. Читает мою модельку пользователей User, находит Laravel native auth, смотрит middleware, проверяет существующие роуты. Через пару минут выдаёт структурированный план:

ТЕКУЩЕЕ СОСТОЯНИЕ:
- Auth через Laravel\Fortify
- Users хранятся в таблице `users` (email, password_hash)
- Session middleware активен

ПРЕДЛОЖЕНИЕ:
1. Подключить Laravel Socialite
2. Создать OAuthController для callback handling
3. Добавить миграцию: поля `oauth_provider`, `oauth_id` в `users`
4. Middleware для merge существующих аккаунтов по email
5. Update LoginManager component для OAuth buttons

ПОТЕНЦИАЛЬНЫЕ ПРОБЛЕМЫ:
- Конфликт: user с email X регистрируется через форму, 
  потом пытается войти через Google с тем же email
- Решение: проверка существования email, автоматический merge

Это уже другой уровень, как вы понимаете. План конкретный, учитывает мою архитектуру, предупреждает о edge cases. Я читаю, нахожу, что забыли про users без email (возможный кейс для GitHub OAuth с приватным email). Дополняю план:

Добавь обработку случая, когда OAuth provider не возвращает email.
Опция: запросить email через отдельную форму после успешного OAuth.

Claude обновляет план, добавляет раздел про fallback flow. Я одобряю финальную версию: «План утверждён, реализуй step-by-step».

На этом планирование заканчивается. У меня есть документ с архитектурными решениями, который я сохраняю в PLANS.md для future reference. Теперь можно писать код.

Фаза исполнения: код как реализация готовой спецификации

Когда план готов, Claude переходит в режим исполнения. Но не хаотичной генерации, а последовательной реализации пунктов плана.

Я даю команду: «Реализуй план. Комментируй каждый шаг». Ключевое слово — step-by-step. Это заставляет Claude двигаться методично:

[Claude]: Шаг 1/5: Создаю миграцию для добавления OAuth полей
[Создаёт файл migrations/add_oauth_fields_to_users.php]

[Claude]: Шаг 2/5: Обновляю модель User
[Правит app/Models/User.php, добавляет fillable fields]

[Claude]: Шаг 3/5: Создаю OAuthController
[Создаёт app/Http/Controllers/OAuthController.php]

Почему это работает лучше? Потому что каждый шаг строится на результате предыдущего. Claude не пытается угадать финальное состояние кода, он пошагово трансформирует существующую систему согласно плану.

Если на этапе исполнения всплывает проблема (например, версия Socialite несовместима с Laravel 12), я не паникую. Останавливаю исполнение, возвращаюсь в режим планирования:

Проблема: Socialite 5.x не поддерживает Laravel 12.

Read-only mode: предложи альтернативные решения.

Claude изучает альтернативы, предлагает использовать fork или написать собственный OAuth adapter поверх League/OAuth2-client. Мы обновляем план, возобновляем исполнение. Никакого рефакторинга наполовину написанного кода.

По завершении всех шагов я запускаю финальный review:

Сравни реализованный код с планом. 
Всё ли пункты выполнены? Есть ли отклонения?

Claude делает self-audit, находит забытый TODO (логирование OAuth errors), дописывает. Готово.

Практические приёмы и реальные кейсы

Приём 1: Отдельные чаты для планирования и исполнения

Это психологический трюк. Когда всё в одном чате, легко соскользнуть в режим «а давай быстренько допишем». Отдельные чаты создают ментальный барьер. План обсуждается в одном месте, код пишется в другом. Разделение контекстов помогает сохранить фокус.

Приём 2: PLANS.md как архитектурная документация

Все утверждённые планы сохраняю в PLANS.md в корне проекта. Через месяц, когда захочу расширить OAuth (добавить VK provider), я открою файл и вспомню, почему merge аккаунтов работает именно так. Планы — это living documentation, которая пишется автоматически.

Приём 3: Не бойтесь отменять планы

Иногда в процессе планирования понимаю, что задача сформулирована неправильно. Или есть более простое решение (оказывается, нужная библиотека уже подключена). Или вообще не стоит этого делать. Лучше потратить 20 минут на планирование и отказаться, чем час на код, который потом удалишь.

Реальный кейс: система онлайн-курсов

Мне нужно было добавить полноценную LMS (learning management system) в приложение на October CMS. Большая задача: модели для курсов, модулей, уроков, прогресса студентов, enrollment, backend контроллеры с FormController/ListController behaviors, frontend компоненты, видео-плеер.

Неправильный подход: сказать Claude «создай плагин для курсов» и получить кашу из недопродуманных связей и странной архитектуры.

Правильный подход: два часа планирования. Попросил Claude проанализировать структуру плагинов October CMS, изучить мои существующие плагины (для консистентности стиля), составить план:

  1. Схема БД с обоснованием связей (Course hasMany Module, Module hasMany Lesson, User belongsToMany Course through Enrollment)
  2. Структура плагина (Plugin.php, models/, controllers/, components/)
  3. Backend контроллеры с правильным использованием behaviors
  4. Frontend компоненты с учётом моей темы (Bootstrap 5, кастомные partial)
  5. Integration points с системой авторизации (frukt/users)

План на 15 пунктов. Обсудили, уточнили детали (как хранить прогресс: отдельная таблица или JSON в enrollment?), утвердили.

Дал команду: «Реализуй план». Claude потратил час, создал плагин. Я запустил миграции, открыл админку — всё работает. Формы настроены, relation widgets корректно отображают связи, компоненты рендерятся. Потребовалась одна правка: забыли scope для фильтрации только опубликованных курсов. Но это мелочь, которую поймал на review.

Итого: 2 часа планирования + 1 час реализации + 10 минут фиксов = 3 часа. Раньше такая задача заняла бы день с отладкой.

Когда методология НЕ работает

Для быстрых экспериментов двухфазный подход избыточен. Если я хочу за 5 минут проверить идею, я точно не буду тратить время на планирование. Скажу Claude: «Накидай прототип feature X». Получу грязный код, проверю концепцию, выкину. По идее это throwaway code, планирование не нужно.

Для trivial задач тоже overkill. Если нужно добавить одно поле в форму, я не составляю план на полчаса. Просто говорю: «Добавь поле phone в User model и форму регистрации».

Но для production features, рефакторингов, интеграций — двухфазный подход экономит время и нервы.

Вывод: AI как архитектурный партнёр, а не code monkey

AI-ассистент — это не замена разработчику. Это усилитель. Но усилитель работает эффективно, только если есть что усиливать. Если подаёте на вход хаос и неопределённость, на выходе получите усиленный хаос. Если подаёте чёткий план — получаете чёткую реализацию.

Разделение планирования и исполнения делает меня лучшим разработчиком. Потому что на этапе планирования я вынужден думать об архитектуре, о последствиях решений, о trade-offs. Раньше мог делегировать это мышление Claude и получать suboptimal решения. Теперь я думаю, а Claude материализует мысли в код.

Конкретные шаги для внедрения:

  1. Завтра, когда начнёте новую задачу, не спешите писать код
  2. Откройте чат с Claude: «Read-only mode. Проанализируй задачу X, предложи план»
  3. Потратьте 15-20 минут на ревью плана, дополните своими идеями
  4. Когда план готов: «План утверждён, реализуй step-by-step»
  5. Засеките время, сравните с обычным подходом

Уверен, вы увидите разницу. И больше не захотите возвращаться к хаотичной генерации кода.