Всем привет, меня зовут Сергей Прощаев. Я Tech Lead и руководитель направления Java / Kotlin разработки в FinTech, а также преподаю на курсах по архитектуре и бэкенд‑разработке в OTUS. В этой статье хочу разрушить один опасный миф: якобы скоро нейросети заменят разработчиков, и нам останется только пить кофе, пока ИИ пишет микросервисы.

Спойлер: это не так.

Сегодня мы перейдем к практике создания функционального узла системы. Мы не будем полагаться только на магию ИИ — мы совместим инженерный опыт, готовые архитектурные шаблоны и возможности автономных агентов. Это демонстрация реального процесса, где разработчик выступает в роли дирижера сложной технологической системы. Расскажу, как подготовить фундамент, как ставить задачи агентам и, что самое важное, где автоматика ошибается и требует твердой руки эксперта.

Агенты не пишут код. Они решают задачи

Когда я только начинал экспериментировать со связкой Kotlin + AI‑агенты, я думал, как и многие: «Сейчас объясню бизнес‑требование, и оно само превратится в Pull Request». На деле получил лапшу из классов, нарушающую все принципы SOLID. Потому что ИИ, будь то Copilot, Cursor с агентами или самописные воркеры на базе LangChain4j, отлично решает задачу «в лоб». Но плохо понимает контекст всей системы, если этот контекст ему не дать.

Можно потратить месяц, переписывая один модуль Ktor‑приложения, где ИИ‑агент генерировал эндпоинты без спецификации OpenAPI. Каждый новый метод будет работать, но вместе все это превращается в кашу. Именно тогда я и сформулировал правило: «Кодинг — это доставка. Архитектурный дизайн и контракты — рулевое управление». И рулить должен разработчик (рис. 1).

Рис. 1 Иллюстрация концепции: разработчик как дирижер ИИ-команды
Рис. 1 Иллюстрация концепции: разработчик как дирижер ИИ‑команды

Благодаря этому у меня сформировалось понимание того, что подход Agent‑Oriented Programming имеет место быть, но с жестким контролем. Весь входящий поток бизнес‑требований необходимо сначала «упаковывать» в строгую архитектурную схему, используя проверенные шаблоны. Только после этого даем волю ИИ‑команде.

Подготовка фундамента: не дайте агенту сойти с рельсов

Главная ошибка новичков — дать агенту промпт: «Создай CRUD для пользователей на Ktor с Exposed». Он создаст. Но как потом это поддерживать? Без абстракций, без Clean Architecture, без разделения на слои.

Мой Best Practice теперь выглядит так: шаблон решает всё. Я не стартую проект с пустого main.kt, а использую stage‑driven генерацию (пошаговое создание структуры).

Сначала необходимо вручную или с помощью второго агента‑архитектора создает каркас. Например, для типового микросервиса на Kotlin можно использовать следующий скелет:

  • domain — модели и чистые интерфейсы репозиториев (никаких фреймворков).

  • usecases — бизнес‑логика, которая дергает интерфейсы.

  • adapters — реализации репозиториев (Exposed, Ktor Client), контроллеры.

Я называю это «подготовкой загона». Агентам по разработке я разрешаю писать код только внутри контрактов, определенных интерфейсами. Если бизнес говорит: «Нужна авторизация через госключ», мы не просим ИИ сразу писать код. Мы просим:

  1. Агента‑аналитика: Проанализируй вводные и предложи модель данных и sequence‑диаграмму (Mermaid).

  2. Человека: Утверди диаграммы, добавь нефункциональные требования (NFR).

  3. Агента‑разработчика: Имплементируй строго по утвержденной спецификации в подготовленных файлах.

Работа с ИИ‑командой: декомпозиция под надзором

Перейдем к практике. Допустим, задача — сделать функциональный узел «Управление подписками пользователей» на Kotlin.

Стараюсь использовать автономных агентов для первичной декомпозиции, но с инженерным контролем.

Я даю агенту промпт: «Распиши Use Case „Оформление подписки“. Учти, что платеж проходит через внешний эквайринг, возможна задержка колбэка до 30 секунд, пользователь должен видеть актуальный статус в реальном времени».

Агент выдает:

  1. Сохранить запись в БД со статусом PENDING.

  2. Сходить в эквайринг.

  3. Обновить статус.

Как человек, смотрю на это и вижу фатальную дыру. А если эквайринг отвечает долго, а пользователь нажал кнопку 5 раз подряд? Идемпотентность! Агент часто игнорирует идемпотентность, если ему не напомнить.

Дальше подключаем второго агента для написания интеграционных тестов. Мы не пишем тесты руками. Мы скармливаем ему спецификацию в формате Gherkin (Given/When/Then), и он генерирует Kotlin‑код с использованием kotest и test containers. Человек на этом этапе следит только за одним: покрыты ли тестами те самые граничные условия, которые нашел архитектор.

Посмотрите на диаграмму последовательности ниже. Это результат работы связки «Человек‑Архитектор + ИИ‑аналитик». Мы специально развели синхронные и асинхронные вызовы, чтобы не связывать основной поток пользователя с внутренней кухней платежей (рис. 2).

Рис. 2 Диаграмма последовательности: идемпотентное оформление подписки с разделением на синхронный ответ и асинхронный callback
Рис. 2 Диаграмма последовательности: идемпотентное оформление подписки с разделением на синхронный ответ и асинхронный callback

Схема показывает, как мы развели синхронную и асинхронную ветки в сценарии оформления подписки. Пользователь получает моментальный ответ 202 Accepted и не ждёт, пока отработает платёж. В этот момент запись уже лежит в базе в статусе PENDING, а событие ушло в очередь. Дальше фоновый агент спокойно общается с эквайрингом (до 30 секунд) и обновляет статус, не нагружая основной пользовательский поток. Ключевой момент — insertOrIgnore с идемпотентным ключом, который предотвращает дублирование подписок при повторных запросах.

Таким образом, схема еще раз иллюстрирует центральную идею: архитектор‑дирижёр определяет, что делается синхронно, а что — асинхронно, какие контракты использовать, а ИИ‑команда исполняет в этих рамках. Без такого разделения мы бы получили хрупкий сервис, склонный к каскадным отказам!

Инженерный контроль: когда ИИ ошибается красиво и незаметно

Правило, которое я вывел: автоматика отлично справляется с happy path. Как только начинаются сетевые проблемы, гонки состояний или обратное давление (backpressure) — нужен инженерный контроль. ИИ сегодня — это мощный, но все еще Junior‑разработчик. А когда Junior пишет сложный многопоточный код в продакшен, за ним нужен Lead.

Чтобы минимизировать риски, можно использовать практику «Авто‑ревью». Один ИИ‑агент генерирует код, второй (с промптом «ты вредный сеньор‑проверяльщик») ищет типовые уязвимости: блокировки на уровне БД, утечки корутин, нарушения контрактов. И роль человека — принимать окончательное решение в спорных ситуациях между ними.

История одного рефакторинга: от хаоса к оркестру

Как‑то в сети мне попалась история, когда команда переводила легаси‑проект с Java на Kotlin и прикрутить умный поиск. Бизнес хотел «как в Google, но внутри ERP». Изначально команда пыталась просто писать промпты в ChatGPT и вставлять код. Закончилось это тем, что сервис поиска падал при любом запросе длиннее трех слов.

Но после применения коллаборативного подхода все взлетело. Был взят шаблон Ports and Adapters (Hexagonal Architecture):

  1. Разработчик спроектировал порт SearchEnginePort с одним методом.

  2. ИИ‑агент сгенерировал три адаптера: простой полнотекстовый поиск, поиск через векторную базу (pgvector) и гибридный с ранжированием.

  3. Архитектор (человек) написал фабрику, переключающую стратегии в зависимости от типа запроса без перезагрузки сервиса.

В итоге это решение стало обрабатывать 500 RPS на довольно скромных контейнерах. Но главное не цифры, а то, как быстро были перебраны гипотезы. Без агентов написание трех параллельных адаптеров заняло бы недели две. С ними команде удалось сделать прототип за 3 дня. Но дирижировал процессом человек. Именно он решил, что pgvector надо использовать не напрямую, а через обертку, чтобы избежать проблем с драйвером PostgreSQL!

Результат: пошаговое создание работающего функционала

Как это выглядит в итоге на проекте?

  1. Инициализация: берем готовый Gradle‑шаблон с Ktor, Exposed, Koin. (1 минута).

  2. Анализ: загружаем требования в NotebookLM или LangChain‑агента, получаем каркас Use Case и диаграмму (Рис. 2).

  3. Контракты: разработчик‑человек пишет 20–30 строк интерфейсов в domain и usecases. Это и есть границы дозволенного для ИИ.

  4. Реализация: агент генерирует DefaultSubscriptionUseCase и SubscriptionController. Код компилируется с первого раза, потому что контракты жестко заданы типами Kotlin.

  5. Проверка: второй агент генерирует property‑based тесты, проверяет на утечки по шаблонам. Человек проверяет критический сценарий с таймаутами.

Заключение: дирижер, а не исполнитель

Возвращаясь к началу статьи: стоит ли бояться ИИ? Нет. Стоит ли учиться с ним работать по‑новому? Однозначно да!

Мир уходит от ремесленного написания тысяч строк однотипного кода. Ценность разработчика смещается в область архитектурных решений, понимания компромиссов и настройки автономных агентов. Это как переход от ручного труда к работе оператора сложного станка с ЧПУ. Вроде бы работу делает станок, но без мастера, который его настроит и проконтролирует, он настрогает брака.

Если вам близок подход «ИИ не вместо разработчика, а как часть инженерной системы», тему можно разобрать глубже на курсе «Проектирование и разработка Kotlin‑бэкенда». Он подойдет тем, кто хочет не просто писать код на Kotlin, а проектировать backend‑сервисы с понятными контрактами, архитектурными границами, тестируемой бизнес‑логикой и устойчивостью к реальным продакшен‑сценариям.

Познакомиться с подходом можно на бесплатных открытых уроках курса. Их проводят преподаватели‑практики: можно увидеть реальные сценарии работы с Kotlin, архитектурными шаблонами и ИИ‑агентами, протестировать формат обучения и задать вопросы экспертам.

Комментарии (0)