Рефакторинг Python без паники: 10 промтов, которые превращают легаси в поддерживаемый код и не ломают прод

Рефакторинг Python без паники: 10 промтов, которые превращают легаси в поддерживаемый код и не ломают прод

Легаси-код на Python редко выглядит как катастрофа в первый день. Проблема накапливается: модуль на 2000 строк, где бизнес-логика перемешана с SQL, утечки памяти в долгоживущих воркерах, эндпоинт FastAPI, который отвечает 3 секунды вместо 200 мс. По данным Google Engineering Practices и многолетних наблюдений в индустрии, стоимость поддержки кода превышает стоимость его написания в разы — и именно рефакторинг становится узким местом.

ChatGPT и другие LLM здесь работают как ускоритель: они не заменяют инженера, но снимают рутину — разбор функций, поиск N+1, генерацию тестов-«страховки» перед изменениями. Главный риск — сломать прод. Поэтому в подборке ниже каждый промт строится вокруг принципа «сначала контракт и тесты, потом изменения». Промты проверены на реальных сценариях: медленный FastAPI, раздутый модуль, дублирование логики, утечки памяти.

1. Карта легаси-модуля перед любыми правками

Задача: понять, что вообще делает файл на 2000 строк, прежде чем что-то менять.

Промт:

Ты — senior Python-инженер. Проанализируй модуль ниже и составь карту:
1) список публичных функций/классов с одной строкой назначения;
2) скрытые зависимости (глобальные переменные, синглтоны, побочные эффекты);
3) места, где смешаны слои (I/O, бизнес-логика, форматирование);
4) функции длиннее 50 строк и с цикломатической сложностью выше 10;
5) предложи порядок рефакторинга от самого безопасного к самому рискованному.
Не пиши код, только анализ в виде таблицы.

```python
<вставь код модуля>

**Пример:** модуль `orders.py` на 1800 строк. LLM выделяет 12 функций, 4 из которых пишут в БД внутри цикла, и предлагает сначала вынести чистые хелперы, потом трогать I/O.

**Ожидаемый результат:** таблица с рисками и планом. Это ваш чек-лист и защита от «рефакторинга вслепую».

## 2. Тесты-страховка до изменений

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

**Промт:**

Напиши pytest-тесты, которые фиксируют ТЕКУЩЕЕ поведение функции, включая странности и баги. Используй parametrize, mock для внешних вызовов (requests, БД) через unittest.mock. Не исправляй логику — только зафиксируй.

<вставь функцию>

**Пример:** функция `calculate_discount`, которая при отрицательной сумме возвращает `None`. Тест фиксирует это как ожидаемое поведение — потом вы осознанно решите, баг это или фича.

**Совет:** запустите тесты на старом коде — они должны пройти. Это ваша страховочная сетка.

## 3. Разбиение «функции-монстра»

**Задача:** функция на 300 строк с вложенными `if`.

**Промт:**

Разбей функцию на маленькие с сохранением поведения. Требования:
- каждая новая функция ≤ 20 строк и делает одну вещь;
- без изменения публичного контракта;
- выдели чистые функции отдельно от I/O;
- покажи diff-подобно: было/стало.

<вставь функцию>

**Пример:** `process_order` разбивается на `validate_order`, `apply_discounts`, `persist_order`, `send_notification`. Тесты из промта №2 проходят без изменений — значит, поведение сохранено.

## 4. Поиск N+1 в SQLAlchemy

**Задача:** эндпоинт делает сотни запросов незаметно.

**Промт:**

Проанализируй код SQLAlchemy ниже. Найди N+1-запросы: обращения к relationship внутри циклов, ленивую загрузку там, где нужна жадная. Предложи фикс через selectinload/joinedload. Покажи, как проверить количество запросов через event.listen на engine (before_cursor_execute).

<вставь код>

**Пример:** `for user in users: print(user.orders)` генерирует N+1. Фикс: `select(User).options(selectinload(User.orders))`.

**Проверка:**
```python
from sqlalchemy import event
@event.listens_for(engine, "before_cursor_execute")
def count(conn, cursor, statement, params, context, executemany):
    print(statement)

5. Профилирование вместо догадок

Задача: найти реальное узкое место, а не то, что «кажется медленным».

Промт:

Помоги найти узкое место. Предложи план профилирования:
1) cProfile для CPU-bound;
2) tracemalloc для памяти;
3) py-spy для прода без остановки процесса.
Напиши готовые команды и как читать вывод (cumtime vs tottime).

```python
<вставь подозрительный код>

**Пример:** `python -m cProfile -s cumtime app.py`. Если `tottime` высокий у функции — она сама тормозит; если высокий `cumtime` — тормозят её вызовы.

**Важно:** `py-spy top --pid <PID>` работает на проде без перезапуска — читайте документацию на github.com/benfred/py-spy.

## 6. Перевод синхронного кода на async

**Задача:** FastAPI-эндпоинт блокирует event loop синхронными вызовами.

**Промт:**

Переведи код на async/await. Требования:
- замени блокирующие requests/psycopg2 на httpx/asyncpg;
- отметь места, где нужен run_in_executor для CPU-bound;
- не делай await внутри list comprehension без asyncio.gather;
- покажи до/после и предупреди о типичных ловушках (блокировка loop, забытый await).

<вставь код>

**Пример:** `requests.get` → `httpx.AsyncClient().get`. Параллельные вызовы — через `asyncio.gather`.

## 7. Code review как второй пилот

**Задача:** быстрая проверка PR перед merge.

**Промт:**

Сделай code review как строгий тимлид. Проверь:
- обработку исключений (не глотает ли ошибки);
- утечки ресурсов (файлы, соединения — есть ли with/context manager);
- изменяемые дефолтные аргументы;
- SQL-инъекции и валидацию входа;
- гонки в многопоточном коде.
Формат: критично / желательно / nitpick. Без воды.

<вставь diff или файл>

## 8. Кеширование без боли

**Задача:** ускорить повторные дорогие вычисления.

**Промт:**

Предложи стратегию кеширования для функции. Варианты: functools.lru_cache, cachetools.TTLCache, Redis. Объясни выбор по критериям: размер данных, TTL, распределённость, инвалидация. Покажи код с корректной инвалидацией и предупреди о мемоизации нечистых функций.

<вставь функцию>

**Пример:** `lru_cache(maxsize=128)` для чистых вычислений; Redis с TTL для данных, общих между воркерами. Не кешируйте функции, зависящие от текущего времени или сессии.

## 9. Поиск утечек памяти

**Задача:** воркер растёт в памяти часами.

**Промт:**

Помоги найти утечку памяти. Проверь: циклические ссылки, растущие глобальные списки/словари, незакрытые генераторы, кеши без ограничения, слушатели событий без отписки. Предложи диагностику через tracemalloc и gc, покажи снимки до/после.

<вставь код воркера>

**Пример:**
```python
import tracemalloc
tracemalloc.start()
# ... работа ...
snapshot = tracemalloc.take_snapshot()
for stat in snapshot.statistics('lineno')[:10]:
    print(stat)

10. Удаление дублирования логики

Задача: одна и та же валидация в 6 местах.

Промт:

Найди дублирование логики в файлах ниже. Предложи единую абстракцию: функцию, декоратор или базовый класс — что уместнее. Покажи рефакторинг и объясни, почему не переусложнил (избегай преждевременных абстракций).

```python
<вставь 2-3 файла>

```

Таблица: какой промт под какой сценарий

Сценарий Промт
Незнакомый легаси-модуль №1 Карта модуля
Перед любыми правками №2 Тесты-страховка
Функция на 300 строк №3 Разбиение
Медленный эндпоинт с ORM №4 N+1
«Кажется, тормозит» №5 Профилирование
Блокирующий FastAPI №6 Async
Проверка PR №7 Code review
Повторные вычисления №8 Кеш
Рост памяти воркера №9 Утечки
Копипаста в 6 местах №10 Дублирование

Как не сломать прод

Три правила, которые работают независимо от промтов. Первое: никогда не рефакторите без тестов — промт №2 идёт всегда первым. Второе: маленькие коммиты, каждый — отдельный смысловой шаг, чтобы git bisect находил проблему за минуты. Третье: фича-флаги для рискованных изменений — включили на 1% трафика, посмотрели метрики, откатили при аномалии.

Полезные источники: официальная документация Python по cProfile и tracemalloc (docs.python.org), руководство SQLAlchemy по загрузке связей (docs.sqlalchemy.org/en/20/orm/queryguide/relationships.html), репозиторий py-spy. Эти материалы — база, на которой промты дают точный результат, а не галлюцинации.

Промты — это не кнопка «сделать хорошо». Это ускоритель для инженера, который понимает, что делает. Начните с карты модуля и тестов, прогоните профилировщик, и только потом меняйте код. Так легаси превращается в поддерживаемый проект без ночных откатов.

← Все статьи

Комментарии

Читайте также

12 промтов, которые заменяют рутину продакт-менеджера: от roadmap до постмортема

29 сентября 2026

30 промтов для геймдизайна в Unity и Unreal: тренды 2025 года для инди-разработки с AI без бюджета студии

29 сентября 2026

12 промтов, которые превратили мой копирайтинг в A/B-конвейер на 40 гипотез в неделю

29 сентября 2026

11 промтов, которые превратили мою подготовку к собеседованию в инженерный пайплайн — от LeetCode до System Design

29 сентября 2026

Как тренировать алгоритмическое мышление в 2026: 11 промтов для LeetCode, оценки сложности и system design интервью

29 сентября 2026

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

29 сентября 2026

Google Cloud Architect — Professional (ACE + PCA): от VPC до BigQuery — путь к сертификации через реальные проекты

28 сентября 2026

Курс «Трудовое право РФ»: как разобраться в удалённой работе, дистанционных договорах и электронном документообороте

28 сентября 2026

10 промтов для Notion и Trello: как продакту и тимлиду разгрузить бэклог, ретро и стейкхолдеров с помощью AI

28 сентября 2026