Что такое легаси и как его узнать
Миграция схем и CDC — Пакетная работа, опорные темы БД. Сверка — SQL для тестировщика.
Вы открываете репозиторий — и видите модули, которые писали до вас — другая команда, другой стиль, иногда другой век технологий. Это обычная рабочая ситуация. Раздел помогает снизить страх перед таким кодом и не романтизировать переписывание с нуля.
Дальше: как понять систему → как менять безопасно → стратегии замены.
Два смысла слова "легаси"
В разговорах смешивают два определения. Оба правомерны — важно понимать, о каком говорит собеседник.
| Смысл | Обычно имеют в виду | Главный риск |
|---|---|---|
| Наследие | Старый стек, чужой стиль, "код не я писал" | найм, безопасность, лицензии, совместимость |
| По Фезерсу (Working Effectively with Legacy Code) | Любой код без автоматизированных тестов | любое изменение может сломать неочевидное поведение |
Наследие — про время и контекст — Java 8, монолит, модуль, который три года никто не трогал, но он держит расчёт зарплат. Код может быть аккуратным — и всё равно "легаси" для новичка в проекте.
По Фезерсу — про изменяемость: нет сетки тестов → нет быстрой обратной связи → каждая правка рискованна. Возраст тут ни при чём: вчерашний сервис без тестов уже легаси в инженерном смысле.
В остальных статьях раздела опора на оба смысла — сначала оцениваем стек и знания команды, затем строим защиту изменений (тесты, швы, наблюдаемость). Подробнее про тесты — в Юнит-тестирование; про читаемость и имена — в Культуре кода; про техдолг в коде — 4.06/115.
Почему легаси неизбежен
Легаси появляется из реальных ограничений, а не из "плохих программистов прошлого":
- смена команд и потеря устного контекста;
- сроки релиза и осознанные компромиссы (технический долг — в методологии PO);
- отсутствие или устаревание документации;
- естественное старение платформ и зависимостей.
Банки, логистика, госсектор, производство десятилетиями крутят системы, которые нельзя выключить на квартал ради rewrite. Переписывание с нуля часто рискованнее, чем эволюция — об этом в стратегиях модернизации.
Работа с легаси — дисциплина — реверс и контекст, маленькие шаги рефакторинга, защита от регресса, фиксация знаний для следующих людей.
"Тихое" и "кричащее" легаси
Удобная метафора для приоритизации:
- Тихое — работает, инциденты редки, но дорого сопровождать — долго разобраться, страшно менять, мало кто понимает.
- Кричащее — частые сбои, непредсказуемые баги, ручные обходы в проде, "магия" при деплое.
Оба типа могут быть без тестов. Разница в том, как срочно нужны наблюдаемость и защитный слой тестов: у "кричащего" — в первую очередь.
Признаки легаси-кода
Признаки накладываются — один модуль может попадать сразу в несколько пунктов.
- Нет тестов или покрытие формальное. Тесты "для галочки", не ловят регресс на бизнес-путях — по сути то же отсутствие защиты.
- Устаревший стек. Неподдерживаемые версии языка, фреймворка, ОС; библиотеки с известными CVE без патча.
- Документация врёт или отсутствует. Описан "идеальный" дизайн 2012 года, а в коде — пять слоёв заплаток.
- Архитектурная связанность. Всё дергает всё — глобальное состояние, циклы зависимостей модулей, БД из UI.
- Высокая когнитивная нагрузка. Непонятные имена, функции на сотни строк, неочевидные побочные эффекты. Отсутствие комментариев само по себе слабый признак — см. культуру кода. Опасны комментарии, противоречащие коду.
- Сборка и деплой вручную. "Только на машине Васи", скрипт из письма, секреты в конфиге без версионирования.
- Растущий техдолг. Каждая фича занимает всё больше времени; одни и те же места ломаются снова.
Критическое наследие (экстремальный случай)
Не всякий старый код одинаково болезненен. Критическое легаси — когда стоимость ошибки и неопределённость максимальны:
- бинарные
.dll/.soбез исходников; - история в VCS обрезана или отсутствует (один "initial commit" на весь зоопарк);
- в одной процедуре смешаны UI, бизнес-логика, SQL и сеть;
- "хаки" платформы: самописный SQL-конкатенацией, обходы багов ОС;
- привязка к железу или ОС, которую нельзя воспроизвести в CI;
- нет логов: падение без сообщения.
Тут нужны навыки разработки и расследования — реверс, интервью, песочница — см. Понимание системы.
Управляемое ("здоровое") легаси
Легаси может быть управляемым. Такое наследие может быть на старом стеке, но:
- понятные границы модулей;
- логика соответствует бизнес-правилам (пусть и не самым новым API);
- есть тесты на критичных путях или жёсткий ручной регресс с чек-листом;
- есть хотя бы схема архитектуры (C4, блок-схема в
/docs); - сборка и деплой воспроизводимы скриптом;
- имена и структура читаемы.
Такой код можно эволюционировать — без clean room и без "большого взрыва". Он может быть неидеален по модным метрикам, но предсказуем.
Мини-пример — один возраст — разная изменяемость
Старый, но понятный модуль с тестом:
# discounts.py — поведение зафиксировано
def legacy_vip_discount(base: int) -> int:
return int(base * 0.9) # исторически округление вниз
# test_discounts.py
from discounts import legacy_vip_discount
def test_vip_discount_unchanged():
assert legacy_vip_discount(100) == 90
Монолитная "простыня" без тестов (фрагмент):
function processOrder(order) {
// валидация, скидка, налог, SQL, email, аудит — 200+ строк
if (order.region === 'EU') { /* ... */ }
}
Первый случай — легаси по контексту, но изменяемый. Второй — легаси по Фезерсу до появления тестов и извлечения функций (безопасные изменения).
Технический долг и легаси
Технический долг — накопленные компромиссы (скорость вместо структуры, отложенные тесты, временные костыли). В легаси он проценты растут: правка в одном месте тянет цепочку неожиданных эффектов.
Долг неизбежен в agile-командах, если его не видят: нет реестра, нет слотов в спринте на погашение — через год "маленькая фича" превращается в неделю риска. Работа с легаси — это и погашение долга маленькими порциями, а не ожидание "когда-нибудь перепишем".
Культура отношения к наследию
Полезные установки в команде:
- Искать контекст (задача, срок, ограничение платформы), а не винить отсутствующих авторов.
- Фиксировать открытия в репозитории — ADR, комментарий к модулю, диаграмма — не только в чате.
- Менять узко: задача → тест → правка → ревью; без "попутного" переписывания соседнего модуля.
- Уважать то, что работает — странное поведение может быть требованием регулятора или контракта с партнёром.
Чек-лист по разделу — в конце; следующий шаг — как копать систему и восстанавливать контекст.