Легаси-код — итоги
Миграция схем и CDC — Пакетная работа, опорные темы БД. Сверка — SQL для тестировщика.
Эта страница собирает раздел "Легаси-код" в одну картину. Если отдельная тема кажется туманной — откройте указанную главу или оглавление. Итоги удобно перечитать после статей 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 — только при жёстких критериях (тупик стека, лицензия, потеря знаний).
Правила для команды (с пояснениями)
-
Сначала тест на поведение, потом рефакторинг.
Тест — страховка. Без неё "красивый" рефакторинг может изменить сумму заказа. -
Сначала гипотеза и фиксация в доке — потом правка.
Запишите: "думаем, скидка считается здесь". Если ошиблись — дешевле, чем неделя отладки в проде. -
Маленькие PR с понятным риском лучше месяца в одной ветке.
Ревьюеру проще; откат проще; blame в git понятнее. -
Уважать работающий код.
"Странный"ifможет быть требованием закона или контрактом с партнёром. Спросите, прежде чем удалять. -
Переписывание с нуля — исключение.
По умолчанию — Strangler и постепенный вынос. Rewrite требует бюджета на два контура (старое + новое) параллельно. -
Фиксировать решения (ADR).
"Почему вынесли биллинг в сервис X" — подарок себе через год.
Мини-словарь раздела
| Термин | Кратко |
|---|---|
| Регресс | Сломалось то, что раньше работало |
| Characterization test | Тест на текущее поведение, даже если оно "странное" |
| Seam (шов) | Место, где можно подменить зависимость |
| Strangler | Постепенная замена старой системы новой |
| ACL | Адаптер между вашим доменом и легаси |
| ADR | Architecture Decision Record — запись архитектурного решения |
| Техдолг | Упрощения в прошлом, за которые платите временем сейчас |
Куда смотреть дальше
- Чек-лист самопроверки — вопросы перед merge или планом модернизации.
- Strangler Fig — миграция монолита.
- Юнит-тестирование — AAA, изоляция, структура тестов.
- Культура кода — как не усугублять легаси при каждой правке.
- О разделе — маршрут по материалам.
Полный маршрут по разделу — на странице о разделе.