Перейти к содержанию
Innovialabs

Запахи кода и как их рефакторить

Практика3 мин

Коротко

Запах кода — это сигнал, что структура мешает изменениям; лечится он маленькими шагами рефакторинга, каждый из которых защищён тестами.

Что такое запах кода и когда его лечить

Запах кода — это не баг, а признак того, что код трудно читать и менять. Программа работает, но каждая правка занимает больше времени и чаще ломает соседние места.

Рефакторинг — изменение структуры без изменения поведения. Главное правило: сначала тесты, потом правка. Если поведение не зафиксировано тестами, вы не узнаете, что что-то сломали.

Лечить запах стоит, когда вы всё равно трогаете этот код: добавляете фичу или чините баг. Переписывать «на всякий случай» модуль, который никто не меняет, обычно невыгодно.

Порядок безопасного рефакторинга

  1. Напишите или найдите тесты, которые покрывают текущее поведение.
  2. Сделайте одно маленькое изменение.
  3. Запустите тесты.
  4. Зафиксируйте коммит.
  5. Повторите.

Маленькие коммиты легко откатить и легко проверить на ревью. Не смешивайте рефакторинг и новую функциональность в одном коммите.

Каталог запахов и лекарство

ЗапахПризнакШаг рефакторинга
Длинный методФункция не помещается на экран, внутри комментарии-разделителиExtract Method
ДублированиеОдинаковый блок в нескольких местахВынести общую функцию
God objectКласс знает и делает всёExtract Class по ответственности
Магические числаif (status === 3)Именованная константа или enum
Feature envyМетод больше работает с чужими данными, чем со своимиMove Method к данным

Длинный метод

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

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

Прежде чем объединять, убедитесь, что код одинаков по смыслу, а не только по виду. Если два блока совпадают случайно и будут меняться по разным причинам, объединение создаст ложную связь. Если же это одно бизнес-правило — выносите в одну функцию.

God object

Признаки: сотни строк, десятки зависимостей, название вроде Manager или Helper. Сгруппируйте поля и методы по ответственности и вынесите каждую группу в отдельный класс. Исходный класс поначалу может просто делегировать вызовы — так внешний код не придётся менять сразу.

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

// было
if (order.status === 3) refund(order);

// стало
const OrderStatus = { Paid: 1, Shipped: 2, Cancelled: 3 } as const;
if (order.status === OrderStatus.Cancelled) refund(order);

Имя объясняет смысл и даёт одно место для изменения.

Feature envy

Если метод класса Invoice постоянно читает поля Customer, чтобы посчитать скидку, логика скидки, скорее всего, принадлежит Customer. Перенесите метод туда, где живут данные.

Частые ошибки

  • Рефакторинг без тестов. Начните хотя бы с характеризационных тестов, фиксирующих текущий вывод.
  • Большой взрыв. Переписать модуль целиком за одну ветку — рискованно и тяжело ревьюить.
  • Абстракции на будущее. Не выносите интерфейс, пока нет второго реального использования.
  • Ручное переименование. Используйте автоматические рефакторинги IDE — они надёжнее поиска и замены.

Частые вопросы

Чаще эффективнее рефакторить понемногу по ходу задач. Отдельное время оправдано, когда запах явно тормозит команду и это можно показать на конкретных задачах.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

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

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.