Перейти к основному содержимому

Легаси-код — итоги

Разработчику Аналитику Тестировщику Архитектору Инженеру
Теория данных (раздел 3)

Эта страница собирает раздел "Легаси-код" в одну картину. Если отдельная тема кажется туманной — откройте указанную главу или оглавление. Итоги удобно перечитать после статей 1–4 и перед чек-листом. Определения для самопроверки — в чек-листе.


FAQ — Часто задаваемые вопросы

Ситуации, с которыми сталкиваются на первом проекте с "наследием" — страх править, ночные хотфиксы, давление "переписать всё". Здесь — практические ответы; формулировки для зачёта — в чек-листе.

Вопрос. Мне сказали "не трогай этот модуль" — но задача именно там. Как действовать?

Ответ. Уточните причину запрета (инцидент, нет тестов, комплаенс). Минимальная правка с characterization-тестом и согласованием с автором/тимлидом безопаснее, чем обход через копипасту в соседний файл. Подробнее здесь — глава 3.

Вопрос. Код работает 10 лет — зачем вообще называть его легаси?

Ответ. "Легаси" про риск изменения, а не про возраст: нет тестов, потеряны знания, устаревший стек. Работающий модуль без страховки — всё равно дорогой в сопровождении. Подробнее здесь — глава 1.

Вопрос. В проде всё стабильно, но разработчики боятся деплоя — что это?

Ответ. Типичное "тихое" легаси: снаружи тишина, внутри команды — скрытый техдолг. Пока не случится крупный сбой, менеджмент может не выделять время на тесты. Подробнее здесь — глава 1.

Вопрос. Автор модуля уволился, документации нет — с чего начать задачу?

Ответ. Цепочка: git log/blame, старые тикеты, интервью с поддержкой, один сквозной сценарий в логах, простая диаграмма вызовов. Зафиксируйте гипотезу в доке до правки. Подробнее здесь — глава 2.

Вопрос. Есть только .jar без исходников — можно ли что-то менять?

Ответ. Прямо в бинарник — почти нет; работают через обёртки, интеграции, логи, декомпиляцию для понимания (с юридическими ограничениями). Критический случай — оценка rewrite или замены поставщика. Подробнее здесь — глава 2.

Вопрос. Комментарий в коде противоречит тому, что делает метод — кому верить?

Ответ. Верьте поведению в проде, пока не доказано обратное: напишите characterization-тест, потом обновите комментарий или код. Подробнее здесь — глава 3.

Вопрос. "Странный" if с датой 1998 — удалить при рефакторинге?

Ответ. Сначала выясните бизнес-историю: контракт, закон, баг старого API. Уважайте работающий код; удаление без контекста — частая причина регресса. Подробнее здесь — глава 1, глава 3.

Вопрос. Начальник требует "переписать на микросервисы за квартал".

Ответ. Полный rewrite редко укладывается в срок: нужен параллельный контур и бюджет. Предложите Strangler Fig — вынос по одной функции с маршрутизацией. Подробнее здесь — глава 4.

Вопрос. Хотфикс ночью без тестов "спас" релиз — молодец?

Ответ. Краткосрочно да, но вы увеличили страх перед следующей правкой. На следующий день — тест на поведение и разбор инцидента, иначе легаси усугубится. Подробнее здесь — глава 3.

Вопрос. Тесты есть, но их никто не запускает в CI — это "управляемое" легаси?

Ответ. Тесты без CI — слабая страховка: их обойдут под дедлайном. Первый шаг — зелёный pipeline на критичных сценариях. Подробнее здесь — глава 1.

Вопрос. Не понимаю, как протестировать метод с десятью внешними API.

Ответ. Ищите шов (seam): обёртка над HTTP-клиентом, injection зависимости, тест на уровне API-контракта. Подробнее здесь — глава 3.

Вопрос. Рефакторинг на 3000 строк в одном PR — отклонять?

Ответ. Да, если нет крайней необходимости: серия малых PR с зелёным CI и понятным риском. Большой diff в легаси почти гарантирует скрытый регресс. Подробнее здесь — глава 3.

Вопрос. Новый сервис тянет типы и таблицы из старой БД напрямую — нормально?

Ответ. Это протекание модели легаси. Поставьте Anti-Corruption Layer — свой домен и адаптер к старому миру. Подробнее здесь — глава 4.

Вопрос. Mikado-граф зависимостей разрастается — не проще переписать?

Ответ. Mikado как раз показывает, где корень клубка. Если граф на сотни узлов без бизнес-ценности — тогда обсуждайте rewrite с цифрами, а не "на глаз". Подробнее здесь — глава 3.

Вопрос. CVE в старой библиотеке — обновить одним днём?

Ответ. Оцените breaking changes, покройте интеграционным тестом, обновляйте поэтапно. В легаси "просто bump версии" часто ломает пол-прода. Подробнее здесь — глава 1.

Вопрос. Прод и тестовая база разъехались — тесты "зелёные", прод падает.

Ответ. Характерно для легаси без дисциплины данных: нужны репрезентативные фикстуры, маскирование PII, регулярный refresh test из prod (если политика позволяет). Подробнее здесь — глава 2.

Вопрос. Sprout vs Wrap — когда что применять?

Ответ. Sprout — новая логика рядом со старым вызовом; Wrap — обёртка вокруг legacy-метода с новым интерфейсом. Оба сохраняют старое поведение до полной замены. Подробнее здесь — глава 3.

Вопрос. Менеджер не даёт время на тесты — только "фичи".

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

Вопрос. Два монолита делают одно и то же — с чего начать слияние?

Ответ. Карта источника правды по данным и процессам, затем Strangler на один поток (например, только чтение). Параллельный rewrite обоих — крайний случай. Подробнее здесь — глава 4.

Вопрос. Clean room — это "переписать, глядя на старый код"?

Ответ. Наоборот: новая реализация по спецификации, без копипасты исходников (важно и для лицензий). Старое — только как чёрный ящик для сравнения поведения. Подробнее здесь — глава 4.

Вопрос. Flaky-тест в легаси — удалить, чтобы CI был зелёный?

Ответ. Удаление без замены усиливает страх. Почините или пометьте quarantine с владельцем и сроком; flaky хуже отсутствия теста. Подробнее здесь — глава 3.

Вопрос. Как объяснить бизнесу, почему "маленькая правка" стоит две недели?

Ответ. Покажите цепочку: понимание → тест → правка → регресс → деплой. В критическом легаси неопределённость — главный драйвер срока. Подробнее здесь — глава 2.

Вопрос. ADR — не "лишняя бюрократия" для маленькой команды?

Ответ. Короткая запись "почему выбрали Strangler, а не rewrite" через год сэкономит недели споров. Формат может быть одной страницей в wiki. Подробнее здесь — глава 4.

Вопрос. Я новичок — меня посадили только на баги в легаси. Это карьерный тупик?

Ответ. Это типичный вход: навыки чтения чужого кода, тестов и безопасных правок ценятся выше, чем кажется. Фиксируйте победы (тест + док), просите наставника на первых PR. Подробнее здесь — глава 2.

Вопрос. После рефакторинга упала смежная система — кто виноват?

Ответ. Фокус на процессе: не хватило контрактного/интеграционного теста, не знали скрытую зависимость. Blameless postmortem и новый тест на регресс. Подробнее здесь — глава 3.

Вопрос. Можно ли "улучшать" легаси без согласования с архитектором?

Ответ. Локальный рефакторинг в рамках задачи — да; смена границ модулей или вынос сервиса — согласуйте, иначе получите два несовместимых плана модернизации. Подробнее здесь — глава 4.

Вопрос. Git history обрезан — как восстановить контекст?

Ответ. Тикеты, релизные notes, бэкапы репозитория, люди (support, ex-authors), логи деплоев. Документируйте найденное — вы создаёте новую память команды. Подробнее здесь — глава 2.


FAQ — Поисковые запросы

Краткие ответы на формулировки, которые часто вводят в Google и Yandex.

Вопрос. Что такое legacy code (легаси код)?

Ответ. Наследие: старый или чужой код без тестов и знаний, где страшно менять одну строку. По Фезерсу легаси — код без автотестов на изменение. Подробнее здесь — что такое легаси.

Вопрос. Как работать с легаси кодом на первой работе?

Ответ. Понять → зафиксировать тестом → маленькая правка → CI. Не "улучшать всё" одним PR. Подробнее здесь — безопасные изменения.

Вопрос. Рефакторинг legacy code — с чего начать?

Ответ. С characterization test на текущее поведение, затем швы (seams) и микрошаги. Подробнее здесь — глава 3.

Вопрос. Переписать систему с нуля или рефакторить — что выбрать?

Ответ. По умолчанию — Strangler Fig (постепенная замена); rewrite — при тупике стека, лицензии или потере исходников. Подробнее здесь — стратегии модернизации.

Вопрос. Strangler Fig pattern — что это простыми словами?

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

Вопрос. Working Effectively with Legacy Code — о чём книга Фезерса?

Ответ. О тестах, швах, безопасном рефакторинге без переписывания всего. Ключ: сначала страховка, потом правка. Подробнее здесь — глава 1, глава 3.

Вопрос. Characterization test — что это и зачем?

Ответ. Тест фиксирует как работает сейчас, даже если поведение "странное" — страховка от регресса при рефакторинге. Подробнее здесь — глава 3.

Вопрос. Seam (шов) в legacy code — примеры.

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

Вопрос. Anti-Corruption Layer — что это в DDD и миграции?

Ответ. Адаптер между вашим доменом и легаси, чтобы не тащить чужие типы и таблицы в новый код. Подробнее здесь — глава 4.

Вопрос. Mikado method refactoring — как работает?

Ответ. Граф зависимостей: пробуете изменение, откатываете, помечаете блокеры, идёте от листьев к корню. Подробнее здесь — глава 3.

Вопрос. Старый код без тестов — как не сломать production?

Ответ. Минимальная правка, characterization test, staging, feature flag, откат, мониторинг. Подробнее здесь — глава 3.

Вопрос. Как понять чужой код без документации?

Ответ. git log/blame, тикеты, интервью, логи, один сквозной сценарий, диаграмма вызовов. Подробнее здесь — понимание системы.

Вопрос. Реверс-инжиниринг Java jar без исходников.

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

Вопрос. Миграция монолита на микросервисы с legacy.

Ответ. Strangler, ACL, маршрутизация трафика, параллельный контур; не big bang rewrite. Подробнее здесь — глава 4.

Вопрос. Технический долг и легаси — одно и то же?

Ответ. Техдолг — упрощения в прошлом; легаси — часто его следствие плюс потеря знаний и стека. Связаны, но не синонимы. Подробнее здесь — глава 1.

Вопрос. Clean room rewrite — что значит?

Ответ. Новая реализация по спецификации без копипасты старых исходников; сравнение поведения с чёрным ящиком. Подробнее здесь — глава 4.

Вопрос. ADR (Architecture Decision Record) — зачем в легаси-проекте?

Ответ. Запись "почему так решили" — чтобы через год не спорить заново. Подробнее здесь — глава 4, итоги.

Вопрос. Sprout и Wrap — приёмы Фезерса, в чём разница?

Ответ. Sprout — новый код рядом со старым вызовом; Wrap — обёртка с новым интерфейсом вокруг legacy-метода. Подробнее здесь — глава 3.

Вопрос. Git blame и git log — как читать историю legacy файла?

Ответ. Кто менял, когда, в каком тикете; ищите первопричину "странного" if. Подробнее здесь — глава 2.

Вопрос. Легаси 1С и ERP — особенности сопровождения.

Ответ. Конфигурация + доработки, длинная история данных, ключевые пользователи; те же принципы тестов и постепенной замены. Подробнее здесь — внедрение ERP, глава 1.

Вопрос. Big bang migration vs incremental migration.

Ответ. Big bang — один cut-over, высокий риск; incremental/Strangler — по модулям, дольше, но откатываемо. Подробнее здесь — глава 4.

Вопрос. Как junior developer начать с legacy project?

Ответ. Мелкие баги, чтение с git log, тест на поведение, ментор на ревью — нормальный вход в индустрию. Подробнее здесь — глава 2.

Вопрос. Регрессионное тестирование legacy системы.

Ответ. Unit на критичные расчёты, integration/API, smoke после деплоя; characterization на "странное" поведение. Подробнее здесь — глава 3, тестирование.


Главная мысль раздела

Легаси — нормальное состояние зрелых систем. Банки, госуслуги, ERP и крупные интернет-сервисы живут на коде, которому 10–20 лет. Проблема для новичка обычно в другом: неопределённость — вы не знаете, что сломается от одной строчки.

Хорошая новость: с легаси работают системно — понять → безопасно менять → модернизировать по плану. "Героизм" (ночной фикс без тестов) иногда спасает дедлайн, но увеличивает страх перед следующей правкой.


Главные определения

Легаси как наследие

Наследие (legacy) — код, конфигурация, база, процессы, которые вы или ваша команда не создавали (или создавали давно и забыли). Риски:

  • устаревший стек (язык без поддержки, старая ОС);
  • потеря знаний (автор уволился, документации нет);
  • скрытые бизнес-правила ("так исторически");
  • безопасность и комплаенс (старые библиотеки с CVE).

Легаси по Фезерсу

Майкл Фезерс в книге Working Effectively with Legacy Code называет легаси код без автотестов, которые дают уверенность при изменении. Для него главный риск — регресс — вы "починили" одно, сломали другое, и узнали об этом от пользователей.


Оба смысла вместе

На практике старое и без тестов часто идут рядом — это самый дорогой для сопровождения вариант. Но бывает и молодой код без тестов (уже легаси по Фезерсу) и старый код с хорошими тестами (управляемое наследие).


Как узнать, с чем имеете дело

Типы помогают выбрать первый шаг, а не ярлык "всё плохо".

ТипПризнакиЧто это значит для новичкаПервый ответ
Управляемоеесть границы модулей, тесты на критичных путях, воспроизводимый деплойМожно учиться и править по книжке Фезерсаэволюция, локальный рефакторинг (Безопасные изменения в легаси)
Тихоев проде редко падает, но в команде боятся менятьРиск скрытый — инцидент "внезапный"карта зависимостей, characterization-тесты (Понимание легаси-системы, Безопасные изменения в легаси)
Кричащеечастые сбои, ручные обходы, "знаем обходной путь"Техдолг уже бьёт по бизнесунаблюдаемость + защитные тесты срочно
Критическоенет исходников/истории, всё связано со всемОдна правка = лотереяреверс, ACL, Strangler или rewrite после оценки (Понимание легаси-системы, Стратегии модернизации легаси)

Тихое легаси опасно тем, что менеджмент видит "всё работает" и не выделяет время на тесты — пока не случится крупный сбой.


Три опоры работы

Раздел построен как три навыка, которые дополняют друг друга.


1. Понять (статья 2)

Прежде чем менять, нужна модель в голове (и в документе):

  • откуда пришёл код (git log, старые тикеты);
  • кого спросить (поддержка, бывший автор);
  • какие диаграммы нарисовать (компоненты, последовательность вызовов);
  • что делать, если есть только .jar или бинарник (декомпиляция, логи).

Ошибка новичка: сразу "улучшать" непонятный метод. Лучше: зафиксировать поведение тестом, потом рефакторить.


2. Безопасно менять (статья 3)

Инструменты Фезерса:

  • characterization tests — "как работает сейчас";
  • швы (seams) — точки подмены зависимостей в тесте;
  • Sprout / Wrap — добавить новое рядом, не ломая старое;
  • Mikado — разорвать клубок зависимостей мелкими шагами.

Ошибка новичка: один PR на 3000 строк "привёл в порядок". Лучше: серия маленьких PR с зелёным CI.


3. Модернизировать осознанно (статья 4)

Когда меняется архитектура целиком:

  • Strangler Fig — выносить функции в новые сервисы по частям;
  • Anti-Corruption Layer — не тащить модель легаси в новый код;
  • clean room — новая реализация по спецификации, без копипасты старых исходников;
  • rewrite — только при жёстких критериях (тупик стека, лицензия, потеря знаний).

Правила для команды (с пояснениями)

  1. Сначала тест на поведение, потом рефакторинг.
    Тест — страховка. Без неё "красивый" рефакторинг может изменить сумму заказа.

  2. Сначала гипотеза и фиксация в доке — потом правка.
    Запишите: "думаем, скидка считается здесь". Если ошиблись — дешевле, чем неделя отладки в проде.

  3. Маленькие PR с понятным риском лучше месяца в одной ветке.
    Ревьюеру проще; откат проще; blame в git понятнее.

  4. Уважать работающий код.
    "Странный" if может быть требованием закона или контрактом с партнёром. Спросите, прежде чем удалять.

  5. Переписывание с нуля — исключение.
    По умолчанию — Strangler и постепенный вынос. Rewrite требует бюджета на два контура (старое + новое) параллельно.

  6. Фиксировать решения (ADR).
    "Почему вынесли биллинг в сервис X" — подарок себе через год.


Мини-словарь раздела

ТерминКратко
РегрессСломалось то, что раньше работало
Characterization testТест на текущее поведение, даже если оно "странное"
Seam (шов)Место, где можно подменить зависимость
StranglerПостепенная замена старой системы новой
ACLАдаптер между вашим доменом и легаси
ADRArchitecture Decision Record — запись архитектурного решения
ТехдолгУпрощения в прошлом, за которые платите временем сейчас

Куда смотреть дальше

Полный маршрут по разделу — на странице о разделе.