10 промтов для рефакторинга legacy-кода: стратегии и примеры

Введение

Legacy-код — это как старый дом: вроде работает, но каждая перестановка мебели рискует обрушить стену. По данным Stripe (2023), разработчики тратят до 42% рабочего времени на технический долг. Рефакторинг устаревшего кода — одна из самых сложных задач в разработке, ведь нужно улучшить код, не сломав бизнес-логику. Здесь на помощь приходят AI-ассистенты и правильно составленные промты. В этой статье — 10 проверенных промтов, которые помогут вам провести рефакторинг безопасно, быстро и без головной боли.

Промт 1: Аудит общего состояния кода

Задача: Быстро оценить масштаб проблем и получить структурированный отчёт о техническом долге.

Промт:

Проведи аудит качества кода в проекте. Изучи файлы: [список файлов]. Определи:
- Самые проблемные зоны (дублирование, длинные функции, сложные условия)
- Уровень связности и связанности (coupling/cohesion)
- Нарушения принципов SOLID и паттернов проектирования
- Признаки «двойной поддержки» (dead code, закомментированные блоки)
- Оценку рисков для рефакторинга (что можно трогать, а что лучше не стоит)
Выдай результат в виде Markdown-таблицы с приоритетами: критично, важно, желательно.

Пример использования: Вы копируете файлы с кодом или перечисляете имена файлов в репозитории, вставляете промт в ChatGPT/Claude. На выходе получаете таблицу:

Файл Проблема Приоритет Риск Рекомендация
order.js Дублирование расчёта налогов Важно Средний Вынести в утилиту
db.py Связанность с UI-логикой Критично Высокий Разделить слои

Промт 2: Декомпозиция божественного объекта

Задача: Разбить огромный класс на маленькие, ответственные за свои задачи.

Промт:

Проанализируй класс [имя класса] из файла [имя файла]. Это «божественный объект» (более 1000 строк, много несвязанных методов). Предложи:
- Какие классы можно выделить по принципу единственной ответственности (SRP)
- Какие методы стоит переместить в новые классы
- Как сохранить совместимость с внешним API (старые методы можно оставить как фасад)
- План миграции с шагами и тестами
Ответ представь в виде списка новых классов с описанием их методов.

Пример: Для класса OrderManager (1500 строк) промт выдал разбиение на OrderCalculator, OrderRepository, OrderNotifier и OrderManager (только координация). Это классический пример применения паттерна Facade.

Промт 3: Поиск и устранение дублирования

Задача: Найти повторяющиеся куски кода и предложить решение.

Промт:

Найди дублирование кода в следующих файлах: [список]. Для каждого фрагмента:
- Укажи файлы и строки, где встречается похожий код
- Определи тип дублирования (копипаст, дублирование логики, дублирование побочных эффектов)
- Предложи метод устранения: извлечение функции, наследование, композиция, шаблонный метод
- Покажи пример рефакторинга с кодом «до» и «после»
Приоритезируй фрагменты по частоте встречаемости и вероятности ошибки.

Пример: В трёх разных сервисах была одна и та же функция форматирования даты. Промт предложил вынести её в общий модуль date-utils.js и использовать его во всех местах. Код сократился на 40 строк, а риск расхождения в форматах исчез.

Промт 4: Улучшение читаемости сложных условий

Задача: Превратить «спагетти» из вложенных if-else в понятный код.

Промт:

Дан фрагмент кода с вложенными условиями: [вставь код]. Перепиши его так, чтобы:
- Каждое условие было выражено через именованную функцию с понятным названием
- Использовать паттерн Guard Clauses (ранний выход) если это уместно
- Убрать глубокую вложенность (< 3 уровней)
- Не изменить внешнее поведение
Полный ответ приведи в виде кода с комментариями, объясняющими каждое решение.

Пример: В legacy-коде была проверка в 6 уровней вложенности. Промт превратил её в набор функций isValidUser(), hasAccess(), isWithinWorkingHours() — код стал читаться как объяснение бизнес-правил.

Промт 5: Создание тестов для рефакторинга

Задача: Сгенерировать юнит-тесты, чтобы рефакторинг был безопасным.

Промт:

Придумай набор юнит-тестов для функции [имя функции] из файла [файл]. Учти:
- Нормальные сценарии, граничные случаи, негативные сценарии
- Тесты на зависимости (замокай внешние вызовы)
- Покрытие ветвлений (if/else, switch)
- Тесты на стабильность (идиомпостентность)
Напиши тесты в формате [Jest/pytest/другой фреймворк] по данному коду: [вставь код]

Пример: Для функции calculateDiscount() промт сгенерировал тесты, покрывающие случай нулевой суммы, отрицательных скидочных купонов и граничных дат. Это дало уверенность для дальнейшего изменения кода.

Промт 6: Обновление синтаксиса и deprecated-функций

Задача: Перевести legacy-код на современный стандарт.

Промт:

Список файлов: [файлы]. Найди в них устаревшие конструкции (deprecated) для версии [языка и версии, например, Python 3.9 → 3.12]. Замени их на современные аналоги:
- Используй официальную документацию и перечень изменений
- Обрати внимание на изменения синтаксиса, стандартной библиотеки, типов
- Не меняй поведение кода, только синтаксис
Приведи таблицу: файл, старая конструкция, новая конструкция.

Пример: Промт заменил typing.List на list, ф-строки вместо .format(), заменил os.path на pathlib. Код стал выглядеть чище и совместим с новыми версиями Python.

Промт 7: Рефакторинг SQL-запросов и работы с БД

Задача: Улучшить производительность и читаемость запросов, которые зарыты в коде.

Промт:

Найди в коде SQL-запросы (или ORM-запросы) в файлах [файлы]. Проанализируй:
- Используют ли они индексы (по плану запросов, если возможно)
- Есть ли запросы в цикле (N+1 проблема)
- Читаемость: большие JOIN, сложные WHERE
- Предложи оптимальный вариант с учётом типов данных
Выдай отчёт: таблицу с проблемами и рекомендациями.

Пример: Промт обнаружил, что в цикле вызывается запрос для каждого товара — 100 запросов на корзину. Он предложил один запрос с WHERE id IN (...). Время ответа API упало с 4 секунд до 200 мс.

Промт 8: Уменьшение связанности (decoupling) между модулями

Задача: Снизить взаимозависимость компонентов, чтобы их можно было заменять и тестировать отдельно.

Промт:

Проанализируй зависимости между модулями: [модули]. Построй граф зависимостей (текстом). Определи:
- Циклические зависимости
- Скрытые зависимости через глобальные переменные/состояние
- Нарушение Dependency Inversion
Предложи рефакторинг с использованием внедрения зависимостей, событийной модели или интерфейсов.
Покажи пример для одного модуля: как изменить его API, чтобы разорвать цикл.

Пример: Модуль auth импортировал user, а user импортировал auth. Промт предложил вынести общие типы в отдельный пакет и использовать события для обмена информацией. Циклическая зависимость исчезла.

Промт 9: Переработка глобального состояния и синглтонов

Задача: Устранить проблемы глобальных переменных, которые делают код непредсказуемым.

Промт:

Найди в проекте синглтоны, глобальные переменные, статические методы с состоянием. Код: [вставь релевантные классы]. Предложи:
- Как заменить синглтон на внедрение зависимости (DI)
- Как ограничить область видимости состояния (контекст выполнения)
- Как сделать код тестируемым: чтобы можно было подменять зависимости в тестах
- Приведи конкретные шаги миграции для одного из классов

Пример: API-клиент был синглтоном с настройками токенов. Промт показал, как переделать его на класс, создаваемый через фабрику, и передавать в конструкторы сервисов. Тесты легко стали подменять моки и настраивать тестовые токены.

Промт 10: Стратегия миграции с пошаговым планом

Задача: Получить поэтапный план рефакторинга большого модуля.

Промт:

Модуль [название] состоит из [количество] файлов, [строк кода]. Цель: рефакторинг без остановки разработки новых фич. Разработай стратегию, используя паттерн Strangler Fig или Branch by Abstraction.
- Разбей на итерации длительностью не более 2 недель
- Для каждой итерации: какие файлы трогаем, какие тесты нужны, какие риски, как откатывать
- Определи признаки готовности итерации (Definition of Done)
- Дай чек-лист для code review
Выведи в виде таблицы: Итерация

| Действия | Тесты | Риски | DoD.

Пример: Для модуля корзины (12 файлов, 3000 строк) промт предложил 5 итераций: выделить модель данных, вынести валидацию, заменить ORM, добавить кэш, убрать дублирование. Каждая итерация сопровождалась тестами и возможностью отката.

Промт 11: Комментирование и документация legacy-кода

Задача: Сгенерировать документацию на существующий код с минимумом изменений.

Промт:

Добавь комментарии и docstring-и к следующим файлам: [код]. Правила:
- Не изменяй логику, только добавляй комментарии
- Используй формат JSDoc/reST (по стандарту проекта)
- Комментируйте «зачем», а не «что» (что понятно из кода)
- Отметь подозрительные места TODO с объяснением, почему здесь может быть баг
- Сгенерируй итоговый README для модуля с кратким описанием, API и примерами.

Пример: Промт добавил docstring к старой функции расчёта скидок и объяснил, что «функция возвращает float, а не Decimal — отсюда возможны потери точности». Это сразу указало на потенциальный баг для денежных операций.

Промт 12: Анализ зависимостей от устаревших библиотек

Задача: Оценить риски использования старых версий библиотек и предложить обновление.

Промт:

Список зависимостей проекта: [вставьте содержимое package.json / requirements.txt / go.mod]. Проанализируй для каждой:
- Актуальная ли версия, и сколько ей лет
- Есть ли известные уязвимости (CVE)
- Совместима ли с текущей версией языка/рантайма
- Обновление мажорной версии: какие критические изменения (читай официальный changelog)
- Дай рекомендации: обновить, отложить, заменить аналогом
Выведи таблицу: Зависимость

| Текущая версия | Актуальная | Риски | Рекомендация.

Пример: Для JQuery 2.x промт указал на уязвимости XSS и рекомендовал перейти на современный фреймворк или хотя бы на 3.7+. Такой анализ позволил приоритизировать технический долг.

Промт 13: Переработка обработки ошибок

Задача: Сделать обработку исключений понятной и безопасной.

Промт:

Проанализируй код на предмет обработки ошибок: [файлы]. Найди:
- Пустые catch (catch {} или except: pass)
- Перехват слишком широких исключений (except Exception)
- Потеря стектрейсов (например, raise без from в Python)
- Отсутствие корректных кодов ошибок и сообщений для пользователя
- Предложи улучшения, сохранив поведение API. Покажи пример для одного места: как обработать ошибку правильно.

Пример: В Python-проекте был except Exception: pass, из-за которого ошибки молча глотались. Промт предложил логировать исключение и пробрасывать его с контекстом (from exc). Теперь ошибки видно в мониторинге.

Промт 14: Оптимизация производительности узких мест

Задача: Найти и исправить замедления в коде.

Промт:

Вот фрагменты кода, которые часто выполняются (циклы, обработчики событий): [код]. Проанализируй сложность алгоритмов и операции с памятью. Предложи:
- Улучшение алгоритма (например, замена O(n^2) на O(n log n))
- Кэширование дорогих вызовов (мемоизация)
- Использование генераторов вместо списков
- Правильные структуры данных (hash map, set)
- Не меняй поведение, сохрани результаты. Оцени примерный выигрыш в производительности (в процентах или на глаз).

Пример: Промт заменил поиск дубликатов в массиве через in (O(n^2)) на использование Set (O(n)). Время обработки списка из 1000 элементов сократилось в 100 раз.

Промт 15: Подготовка кода для перехода на другую архитектуру

Задача: Подготовить код к миграции на микросервисы или модульный монолит.

Промт:

Цель: перейти от монолита к [микросервисам/модульному монолиту]. Проанализируй текущий код: [перечислить модули]. Определи границы доменов (bounded contexts) и предложи:
- Какие части кода можно выделить в отдельные модули без больших изменений
- Какие скрытые зависимости между доменами существуют (вызовы функций, общие БД)
- Предложи интерфейсы между модулями (API, события)
- Разработай план поэтапной миграции, начиная с наименее связанных модулей
Выведи сводную таблицу: Модуль

| Зависимости | Риск | Приоритет миграции.

Пример: Промт выявил, что модуль «платежи» скрыто обращается к таблицам модуля «заказы» через SQL. Предложил сначала выделить общий сервис заказов и перевести платежи на вызов API. Это снизило риски до разрыва монолита.

Заключение

Рефакторинг legacy-кода — это не разовая акция, а постоянный процесс. Используя промты как помощники, вы можете:
- Быстро оценивать масштаб проблем
- Генерировать тесты для безопасности
- Получать готовые планы и примеры рефакторинга

Главное — помнить: промты не заменяют экспертизу разработчика, а лишь ускоряют рутинные задачи. Начните с малого — возьмите один из предложенных промтов и примените к своему коду. Уверен, вы почувствуете разницу. Хотите больше подобных материалов? Подпишитесь на блог asibiont.com/blog, и мы продолжим делиться практическими инструментами для разработчиков.

Ссылки и источники:
- Шаблон Strangler Fig описан в книге Мартина Фаулера «Рефакторинг» и его статье на martinfowler.com.
- Паттерн Branch by Abstraction — описан в статье на martinfowler.com.
- Данные о времени на техдолг: Stripe, 2023 — отчёт «Developer Coefficient» (по данным исследования).
- Документация по Python: Deprecation Warnings в официальной документации (python.org).

← Все статьи

Комментарии