Сценарий 05: Рефакторинг

Старший разработчик выявляет возможности для улучшения кода с помощью анализа на основе CPG.

Содержание

Быстрый старт

# Выберите сценарий рефакторинга
/select 05

Как это работает

Классификация запросов

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

Тип запроса Ключевые слова (RU) Ключевые слова (EN) Маршрутизация
dead_code мёртвый код, неиспользуемый, недостижимый dead code, unused, unreachable DeadCodeDetector
duplicates дубликат, клон, копирование duplicate, clone, copy-paste ASTCloneDetector
complexity сложность, цикломатическая complexity, cyclomatic, nesting TechnicalDebtDetector
general рефакторинг, улучшить, запах кода refactor, improve, code smell Полный конвейер

Классификацию выполняет detect_refactoring_query_type(), анализирующий ключевые слова запроса и направляющий к наиболее подходящему детектору.

Двухфазная архитектура

Сценарий рефакторинга использует двухфазный конвейер обработки:

Запрос пользователя
    |
    v
[Фаза 1] На основе обработчиков (шаблонные ответы, без LLM)
    |-- CodeCloneHandler   → структурированный отчёт о клонах
    |-- DeadCodeHandler     → структурированный отчёт о мёртвом коде
    |-- CodeSmellHandler    → структурированный отчёт о запахах
    |
    v (если обработчик не может ответить)
[Фаза 2] Полный конвейер с LLM
    |-- TechnicalDebtDetector.detect_all_smells()
    |-- ImpactAnalyzer.analyze_bulk_impact()
    |-- RefactoringPlanner.create_refactoring_plan()
    |-- LLM генерирует ответ на естественном языке

Фаза 1 (handler-based) выдаёт мгновенные структурированные ответы на типовые запросы — без вызова LLM. Фаза 2 (LLM fallback) обрабатывает сложные или неоднозначные запросы, требующие синтеза на естественном языке.

Три режима работы

Режим Описание Применение
code_smells Обнаружение запахов кода, мёртвого кода, анализ сложности (по умолчанию) Повседневное качество кода
large_scale Массовый рефакторинг с ROI-анализом и приоритизацией Планирование спринтов
mass_migration Миграция символов/API, автоматическое переименование Обновление фреймворков

Режим mass_migration направляет обработку в mass_migration_workflow() — специализированный конвейер для переименования символов по всей кодовой базе. См. Массовый рефакторинг (S13) для операций массового переименования.

Обнаружение мёртвого кода

10 паттернов обнаружения

DeadCodeDetector выявляет мёртвый код через 10 специализированных паттернов, каждый с оценкой достоверности, отражающей надёжность обнаружения:

Паттерн Достоверность Описание
DEPRECATED_MARKER 0.95 Функции с явными маркерами устаревания
UNREACHABLE_AFTER_RETURN 0.85 Код после безусловного return/break/continue
INVARIANT_DEAD_CODE 0.80 Условия, которые всегда истинны или всегда ложны
DEAD_CODE 0.70 Функции без вызывающих в графе вызовов
EMPTY_STUB 0.65 Функции с пустым телом или заглушкой
UNUSED_VARIABLE 0.60 Переменные, объявленные, но не используемые
DEAD_CALLBACK 0.55 Функции обратного вызова, которые нигде не зарегистрированы
SINGLE_CALLER_FUNCTION 0.50 Функции с единственным вызывающим (кандидаты на встраивание)
ORPHAN_COMPONENT 0.45 Компоненты, отключённые от основного графа вызовов
TEST_ONLY_FUNCTION 0.40 Нетестовые функции, вызываемые только из тестового кода

Находки ранжируются по достоверности — паттерны с высокой достоверностью с большей вероятностью являются истинными срабатываниями и безопаснее для действий.

Фильтрация по намерению

Система определяет намерение по ключевым словам запроса и запускает только релевантные паттерны:

"Найти устаревшие функции"      → DEPRECATED_MARKER
"Найти неиспользуемый код"      → DEAD_CODE + UNUSED_VARIABLE + SINGLE_CALLER_FUNCTION
"Найти недостижимый код"        → UNREACHABLE_AFTER_RETURN + INVARIANT_DEAD_CODE
"Найти мёртвый код"             → Все паттерны по умолчанию

Английские запросы работают аналогично:

"Find deprecated functions"     → DEPRECATED_MARKER only
"Find unused static functions"  → DEAD_CODE + SINGLE_CALLER_FUNCTION
"Find unreachable code"         → UNREACHABLE_AFTER_RETURN + INVARIANT_DEAD_CODE

Примеры обнаружения мёртвого кода

> Найти неиспользуемые статические функции

╭─────────────── Анализ мёртвого кода ────────────────────────╮
│                                                              │
│  Неиспользуемые статические функции (вызовы не найдены):     │
│                                                              │
│  src/backend/utils/misc/help.c:                              │
│    - old_format_help()         Строки: 45-89                 │
│    - legacy_usage_message()    Строки: 123-156               │
│                                                              │
│  src/backend/catalog/pg_type.c:                              │
│    - deprecated_type_check()   Строки: 789-834               │
│                                                              │
│  Достоверность: ВЫСОКАЯ (статические функции, нет внешних ссылок) │
│  Рекомендация: Можно безопасно удалить после проверки        │
│                                                              │
╰──────────────────────────────────────────────────────────────╯

Дублирование кода

Обнаружение клонов через AST

ASTCloneDetector (src/analysis/clone_detector.py) выявляет дублированный код, сравнивая абстрактные синтаксические деревья, а не сырой текст. Это позволяет находить семантические клоны даже при различии имён переменных.

CodeCloneHandler (Фаза 1) выдаёт структурированные отчёты о клонах без LLM:

> Найти повторяющиеся фрагменты кода

╭─────────────── Обнаружение клонов ──────────────────────────╮
│                                                              │
│  Кластеры дублирующегося кода:                               │
│                                                              │
│  Кластер №1 (сходство 95%, 34 строки):                       │
│    - src/backend/access/heap/heapam.c:1234-1267              │
│    - src/backend/access/heap/heapam.c:1890-1923              │
│    Рекомендация: Выделить общую логику во вспомогательную     │
│    функцию                                                   │
│                                                              │
│  Кластер №2 (сходство 88%, 22 строки):                       │
│    - src/backend/executor/nodeSeqscan.c:45-66                │
│    - src/backend/executor/nodeIndexscan.c:78-99              │
│    - src/backend/executor/nodeBitmapscan.c:89-110            │
│    Рекомендация: Создать общую подпрограмму инициализации    │
│                                                              │
│  Всего клонов: 15 кластеров                                  │
│  Дублируемых строк: ~450                                     │
│                                                              │
╰──────────────────────────────────────────────────────────────╯

Анализ сложности

TechnicalDebtDetector выявляет функции с чрезмерной цикломатической и когнитивной сложностью:

> Найти функции с цикломатической сложностью выше 20

╭─────────────── Анализ сложности ────────────────────────────╮
│                                                              │
│  Функции, превышающие порог (сложность > 20):                │
│                                                              │
│  exec_simple_query()        сложность: 47                    │
│     Расположение: src/backend/tcop/postgres.c:890            │
│     Рекомендация: Выделить аутентификацию, разбор            │
│                 и выполнение в отдельные функции             │
│                                                              │
│  ExecInitNode()             сложность: 32                    │
│     Расположение: src/backend/executor/execProcnode.c:156    │
│     Рекомендация: Использовать таблицу диспетчеризации       │
│                 вместо оператора switch                      │
│                                                              │
│  Всего: 23 функции превышают порог                           │
│                                                              │
╰──────────────────────────────────────────────────────────────╯

Анализ влияния

Влияние через граф вызовов

ImpactAnalyzer использует CallGraphAnalyzer для определения радиуса поражения любого рефакторинга — количество вызывающих, транзитивных зависимых и затронутых подсистем:

> Какие компоненты затронет рефакторинг heap_insert?

╭─────────────── Анализ влияния ──────────────────────────────╮
│                                                              │
│  Целевая функция: heap_insert()                              │
│  Прямые вызывающие: 23                                       │
│  Транзитивные вызывающие: 156                                │
│                                                              │
│  Затрагиваемые подсистемы:                                   │
│    - Исполнитель (12 вызовов)                                │
│    - Команда COPY (3 вызова)                                 │
│    - Выполнение триггеров (4 вызова)                         │
│    - Обёртка внешних данных (4 вызова)                       │
│                                                              │
│  Радиус поражения: ВЫСОКИЙ (156 транзитивных зависимых)      │
│  Безопасных рефакторингов: 3 (функции с ≤5 вызывающими)      │
│                                                              │
╰──────────────────────────────────────────────────────────────╯

Центральность по посредничеству

DependencyAnalyzer вычисляет центральность по посредничеству (betweenness centrality) для каждой функции в графе вызовов — выявляя архитектурные узкие места, через которые проходит множество путей вызовов. Функции с высокой центральностью — рискованные цели для рефакторинга, так как изменения распространяются широко:

Оценка рисков по центральности:
  - ExecProcNode()    процентиль: 98%  риск: КРИТИЧЕСКИЙ
  - heap_insert()     процентиль: 92%  риск: ВЫСОКИЙ
  - ExecScan()        процентиль: 87%  риск: ВЫСОКИЙ
  - pg_parse_query()  процентиль: 45%  риск: НИЗКИЙ

Высокий процентиль центральности = через функцию проходит много кратчайших путей. Её рефакторинг затрагивает много подсистем.

Метрики технического долга

TechnicalDebtDetector.calculate_debt_metrics() вычисляет количественные метрики долга:

Метрика Описание
total_effort_hours Оценка часов на исправление всех обнаруженных запахов
debt_ratio Технический долг как доля от общего объёма кодовой базы
estimated_value Денежная оценка стоимости устранения долга
by_severity Разбивка: критический / высокий / средний / низкий
by_category Разбивка: dead_code / complexity / duplication / …

Эти метрики включаются в metadata каждого ответа по рефакторингу, позволяя отслеживать тренды по спринтам.

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

Возможности выделения методов

> Найти возможности выделения методов в exec_simple_query

╭─────────────── Анализ выделения методов ────────────────────╮
│                                                              │
│  Функция: exec_simple_query()                                │
│  Текущее количество строк: 234                               │
│                                                              │
│  Предлагаемые выделения:                                     │
│                                                              │
│  1. Строки 45-78: Обработка аутентификации                    │
│     Предлагаемое имя: check_query_authorization()            │
│     Параметры: query_string, session_state                   │
│                                                              │
│  2. Строки 89-134: Разбор запроса                             │
│     Предлагаемое имя: parse_and_analyze_query()              │
│     Параметры: query_string                                  │
│     Возвращает: ParsedQuery                                  │
│                                                              │
│  3. Строки 156-198: Генерация плана                           │
│     Предлагаемое имя: generate_query_plan()                  │
│     Параметры: analyzed_query                                │
│     Возвращает: PlannedQuery                                 │
│                                                              │
│  Эффект: Снижение сложности с 47 до ~12 на функцию           │
│                                                              │
╰──────────────────────────────────────────────────────────────╯

Приоритизированный список задач

RefactoringPlanner генерирует приоритизированный список задач из всех находок:

Задачи рефакторинга (по приоритету):
  1. [ВЫСОКИЙ] Удалить deprecated_type_check() — 0 вызывающих, безопасно удалить
  2. [ВЫСОКИЙ] Выделить 3 метода из exec_simple_query() — сложность 47→12
  3. [СРЕДНИЙ] Объединить дублирующие подпрограммы инициализации сканирования — 3 файла, 66 строк экономии
  4. [НИЗКИЙ] Встроить вспомогательную handle_auth_step() — 1 вызывающий

Каждая задача включает оценку трудозатрат, уровень риска и ожидаемое улучшение.

Использование CLI

# Анализ рефакторинга через запрос
python -m src.cli query "Найти неиспользуемые функции в модуле executor"

# Глубокий анализ через промпт
python -m src.cli exec --prompt "Предложи возможности рефакторинга для функций с высокой сложностью"

# Обнаружение мёртвого кода
python -m src.cli query "Найти устаревший и недостижимый код"

# Обнаружение клонов
python -m src.cli query "Найти дублирующиеся фрагменты кода"

Примеры запросов

Мёртвый код: - «Найти неиспользуемые статические функции» - «Найти устаревшие функции» - «Найти недостижимый код после return» - «Найти пустые заглушки» - «Найти компоненты-сироты»

Дублирование: - «Показать повторяющиеся фрагменты кода» - «Найти скопированный код в executor»

Сложность: - «Найти функции с высокой цикломатической сложностью» - «Найти длинные функции, которые следует разбить» - «Найти классы-монолиты»

Анализ влияния: - «Какие компоненты затронет изменение heap_insert?» - «Предложи рефакторинг для exec_simple_query» - «Показать радиус поражения изменений ExecProcNode»

Связанные сценарии