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

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

Разработчику Аналитику Тестировщику Архитектору Инженеру
Теория данных (раздел 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 — запись архитектурного решения
ТехдолгУпрощения в прошлом, за которые платите временем сейчас

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

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