Рефакторинг AI кода: 4 стадии от хаоса до архитектуры | 2026 | AiManual
AiManual Logo Ai / Manual.
26 Фев 2026 Гайд

4 стадии рефакторинга AI-сгенерированного кода: от вайбкодинга до чистой архитектуры

Пошаговый гайд по превращению AI-кода в чистую архитектуру. Разбираем реальный кейс с конвертером JSON Telegram: от вайбкодинга до Dependency Injection.

Зелёный CI — это ловушка. Особенно с ИИ

Вы просите Claude 4.0 или его более нового коллегу из 2026 года написать конвертер JSON для Telegram API. Модель выдаёт 200 строк кода. Тесты проходят. CI зелёный. Вы чувствуете магию вайбкодинга — всё работает с первого раза.

А потом открываете код. И видите это: жёсткие зависимости, бизнес-логика в сервисном слое, пять разных способов обработки ошибок, импорты по кругу. Знакомо? Это не код. Это бомба замедленного действия, которая взорвётся на следующем спринте. Я прошёл через это десятки раз и вывел 4 чёткие стадии рефакторинга, которые превращают AI-хаос в работающую архитектуру.

ВАЖНО: Эта статья для тех, кто уже попал в ловушку «зелёного CI». Если вы только начинаете использовать AI-кодинг, сначала прочтите «Зелёный CI и пустая архитектура», чтобы понять механику проблемы.

Наш пациент: конвертер JSON Telegram от Claude

Давайте возьмём реальный пример. В 2025-2026 году многие используют AI-агенты для генерации кода быстрее, чем успевают его проверить. Результат — технический долг, в котором можно утонуть. Наш пример — конвертер, который трансформирует внутренние структуры данных в JSON для Telegram Bot API.

💡
Я не буду показывать весь изначальный код (он занимает 3 экрана). Но суть в том, что Claude 4.0 сгенерировал один гигантский класс TelegramJsonConverter, который делает всё: парсит данные, валидирует, форматирует JSON, логирует ошибки и даже отправляет метрики в Prometheus. Классический монолит в микросервисной одежде.

1 Стадия 0: Диагностика AI-хаоса (что мы имеем на старте)

Перед рефакторингом нужно понять, с чем имеем дело. AI-модели 2026 года (те же Claude 4.0, GPT-5, DeepSeek Coder V3) страдают одинаковыми болезнями:

  • Циклические зависимости: Модуль A импортирует B, B импортирует C, C импортирует A. CI молчит, пока не попробуешь собрать production-бандл.
  • Жёсткая связность: Бизнес-логика приклеена к фреймворку, к базе данных, к внешнему API.
  • Отсутствие абстракций: Вместо интерфейсов — конкретные реализации. Вместо dependency injection — оператор new в середине метода.
  • Разношёрстная обработка ошибок: В одном месте исключения, в другом возврат null, в третьем — кортеж (result, error).

Вот как выглядит типичный AI-сгенерированный код нашего конвертера:

# ТАК НЕ НАДО ДЕЛАТЬ (код от Claude 4.0)
class TelegramJsonConverter:
    def __init__(self):
        self.validator = DataValidator()  # Жёсткая зависимость
        self.metrics = PrometheusMetrics()  # Ещё одна
        self.logger = logging.getLogger(__name__)  # И ещё
    
    def convert_message(self, message_data):
        # 50 строк бизнес-логики, валидации и форматирования
        if not self.validator.validate(message_data):
            self.metrics.increment_error("validation_failed")
            self.logger.error(f"Validation failed: {message_data}")
            return None
        # ... ещё 40 строк кода
        return json.dumps(result)

Проблема не в том, что код не работает. Он работает. Проблема в том, что его невозможно тестировать, модифицировать и поддерживать. Это как дом, построенный на песке — выглядит нормально, пока не пойдёт дождь.

2 Стадия 1: Разделение ответственностей (выжимаем логику из сервиса)

Первое, что нужно сделать — вытащить бизнес-логику из сервисного класса. AI любит всё складывать в один класс, потому что в тренировочных данных так делают новички на Stack Overflow.

Шаги:

  1. Выделяем чистые функции для трансформации данных
  2. Создаём отдельные классы-валидаторы
  3. Выносим логирование и метрики в декораторы или aspect-ориентированный код

После рефакторинга:

# Чистые функции для бизнес-логики
def transform_message_content(content: str, options: dict) -> dict:
    """Преобразует контент сообщения в структуру Telegram."""
    # Только логика трансформации, без валидации, без логирования
    return {
        "text": content,
        "entities": parse_entities(content),
        "parse_mode": options.get("parse_mode", "HTML")
    }

# Валидатор как отдельный класс
class MessageDataValidator:
    def validate(self, data: dict) -> ValidationResult:
        # Только валидация
        pass

# Основной сервис становится тоньше
class TelegramJsonConverter:
    def __init__(self, validator: MessageDataValidator):
        self.validator = validator  # Зависимость через конструктор!

Почему это важно: Чистые функции легко тестировать. Вы можете написать unit-тесты без моков для базы данных, HTTP-клиентов или логгеров. Это сокращает время тестирования на 70%.

3 Стадия 2: Внедрение зависимостей (убиваем оператор new)

Самая частая ошибка AI-кода — создание зависимостей внутри методов. Класс сам создаёт валидаторы, клиенты БД, HTTP-сессии. Результат — невозможно подменить реализацию для тестов, невозможно использовать другой источник данных.

Решение: Dependency Injection (DI). Но не тот сложный фреймворк, который требует конфигурационных файлов на 100 строк. Простой, явный DI через конструктор.

# ПОСЛЕ рефакторинга
class TelegramJsonConverter:
    def __init__(
        self,
        validator: MessageDataValidator,
        metrics_client: Optional[MetricsClient] = None,
        logger: Optional[logging.Logger] = None
    ):
        self.validator = validator
        self.metrics = metrics_client or NoOpMetricsClient()
        self.logger = logger or logging.getLogger(__name__)
    
    def convert_message(self, message_data: dict) -> Optional[str]:
        # Теперь зависимости инжектятся, а не создаются внутри
        if not self.validator.validate(message_data):
            self.metrics.increment("validation_failed")
            self.logger.warning("Validation failed")
            return None
        # ... остальная логика

Теперь вы можете:

  • Передать Mock-валидатор в тестах
  • Использовать другой клиент метрик в production
  • Легко заменять реализации без изменения кода конвертера

Если вы думаете: «Это же очевидно!» — спросите у AI-агентов, которые генерируют код быстрее, чем вы успеваете его проверить. Они так не думают. ИИ обучен на коде с GitHub, а там DI используют в 20% проектов, если повезёт.

4 Стадия 3: Определение контрактов (интерфейсы вместо имплементаций)

Теперь, когда зависимости инжектятся, нужно определить контракты. AI редко генерирует интерфейсы, потому что в примерах кода в интернетах их почти нет.

Создаём абстракции:

from abc import ABC, abstractmethod
from typing import Protocol

# Контракт для валидатора
class DataValidator(Protocol):
    def validate(self, data: dict) -> ValidationResult:
        ...

# Контракт для клиента метрик
class MetricsClient(Protocol):
    def increment(self, metric_name: str, tags: dict = None):
        ...
    def timing(self, metric_name: str, value_ms: float):
        ...

# Рефакторенный конвертер с контрактами
class TelegramJsonConverter:
    def __init__(
        self,
        validator: DataValidator,  # Теперь интерфейс!
        metrics: MetricsClient,
        logger: logging.Logger
    ):
        self.validator = validator
        self.metrics = metrics
        self.logger = logger

Зачем это нужно? Если завтра потребуется валидация не в памяти, а через внешний сервис, вы создадите RemoteDataValidator, реализующий тот же протокол, и замените зависимость в DI-контейнере. Код конвертера не изменится ни на строчку.

💡
Интересный факт: новые мультимодальные модели вроде JanusCoder, которые учатся видеть код через SVG-представления, всё равно плохо генерируют интерфейсы. Они лучше понимают синтаксис, но архитектурные паттерны даются им тяжело. Подробнее в статье про JanusCoder.

5 Стадия 4: Чистая архитектура (собираем пазл)

Финальная стадия — организация кода по слоям. AI генерирует плоский код: всё в одной директории, всё импортирует всё. Мы создаём чёткие границы:

Слой Что содержит Зависимости
Domain (Ядро) Контракты, бизнес-модели, чистые функции Нет внешних зависимостей
Application (Приложение) Сервисы (наш конвертер), use cases Только Domain
Infrastructure (Инфраструктура) Реализации валидаторов, клиенты API, репозитории Может зависеть от Domain и Application

Структура проекта после рефакторинга:

telegram_converter/
├── domain/                    # Ядро
│   ├── contracts/            # Интерфейсы
│   │   ├── validators.py
│   │   └── metrics.py
│   └── models/               # Бизнес-модели
│       └── message.py
├── application/              # Слой приложения
│   └── services/
│       └── telegram_converter.py  # Наш главный сервис
└── infrastructure/           # Реализации
    ├── validators/
    │   └── message_validator.py
    └── metrics/
        └── prometheus_client.py

Теперь зависимости идут только в одну сторону: Infrastructure → Application → Domain. Никаких циклических импортов. Никаких неожиданных зависимостей от фреймворка в бизнес-логике.

Типичные ошибки при рефакторинге AI-кода

Даже зная теорию, можно наступить на грабли. Вот самые частые ошибки:

1. Рефакторинг без тестов

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

2. Слишком глубокие абстракции с первого дня

Создаёте интерфейс для класса, который используется только в одном месте. Это over-engineering. Добавляйте абстракции, когда появляется вторая реализация или необходимость мокинга для тестов.

3. Игнорирование существующей архитектуры

Рефакторите AI-код в вакууме, не учитывая общую архитектуру проекта. Получается островок чистого кода в море хаоса. Интегрируйте отрефакторенный код в существующую систему, даже если это требует адаптеров.

Инструменты 2026 года, которые реально помогают

Рефакторинг вручную — это долго. К счастью, к 2026 году появились инструменты, которые помогают:

  • Cursor IDE с AI-агентами для рефакторинга. Можете попросить: «Выдели валидацию в отдельный класс с интерфейсом» — и агент сделает это за 30 секунд.
  • ArchUnit для Python (аналог Java ArchUnit). Пишете тесты на архитектурные правила: «Слой domain не должен импортировать infrastructure» — и CI будет падать при нарушении.
  • CodeClimate с AI-движком — автоматически находит архитектурные проблемы в AI-сгенерированном коде.

Но помните: инструменты не заменяют понимания. Вы должны знать, какую архитектуру строите. Иначе получится вайб-кодинг на стероидах — быстрее, но так же бессмысленно.

Что делать, если нет времени на полный рефакторинг?

Бывает. Спринт горят, фичу нужно вчера. Минимальный план действий:

  1. Изолируйте AI-код: Оберните его в Facade или Adapter, чтобы грязный код не просачивался в чистую часть системы.
  2. Напишите интеграционные тесты: Хотя бы убедитесь, что текущая функциональность работает.
  3. Запланируйте рефакторинг в следующих спринтах: Добавьте технический долг в бэклог с конкретными шагами (те самые 4 стадии).

Самое опасное — оставить AI-код как есть, потому что «работает же». Через полгода вы не сможете его изменить, не сломав пол-системы. Это тот самый неосознанный вайб-кодинг, который кажется эффективным, пока не станет слишком поздно.

💡
Мой неочевидный совет: Используйте AI не для генерации кода с нуля, а для рефакторинга. Дайте ИИ задание: «Вот мой грязный класс, выдели из него чистые функции, создай интерфейсы для зависимостей, примени Dependency Injection». Современные модели (на 2026 год) справляются с этой задачей лучше, чем с генерацией с чистого листа. Потому что у них есть контекст — ваш существующий код.

AI-кодинг — это не магия. Это инструмент, который требует навыков и дисциплины. Четыре стадии рефакторинга — не догма, а карта, которая помогает не заблудиться в лесу AI-сгенерированного кода. Используйте её, и ваша архитектура выживет даже в эпоху, когда AI сжимает команды с 40 до 10 человек. Потому что код пишут люди. Даже если им помогает искусственный интеллект.

Подписаться на канал