B2B SaaS, продукту семь лет, единственный разработчик ушёл. Продукт приносит деньги, но команда боится релизов и выкатывает раз в два месяца. Задача звучала как «перепишите нам всё». Мы предложили другое.
Почему не переписывать
Переписывание с нуля выглядит привлекательно ровно до того момента, когда выясняется, что в старом коде зашиты семь лет решений, о которых никто уже не помнит. Проверка контрагента, которая кажется бессмысленной, — реакция на инцидент трёхлетней давности. Странный формат выгрузки — требование партнёра.
Переписанная система обязана воспроизвести это всё, а список нигде не записан. Поэтому первым делом разбираются, как система устроена. Код позже.
Неделя 1: карта системы
Мы прошли репозиторий и историю коммитов и собрали схему: какие модули есть, кто кого вызывает, где точки входа, где данные пересекают границы.
Из истории коммитов вылезает то, чего нет в коде: файлы, которые правят чаще всего, — это либо зоны активного развития, либо зоны боли. Второе видно по сообщениям коммитов вида «fix», «hotfix», «ещё раз fix».
Результат недели — схема зависимостей, список зон риска и оценка по остальному. До этой оценки любой названный срок был бы выдумкой, и мы это проговорили на старте.
Отдельная находка: работающий тестовый стенд с копией боевой базы, открытый в интернет без авторизации. Он не имел отношения к задаче, но это была самая дорогая находка недели.
Неделя 2: сеть безопасности
Рефакторинг без тестов — это переписывание с надеждой. Поэтому вторая неделя ушла на характеризационные тесты.
Ключевое отличие от обычных тестов: характеризационный тест фиксирует не правильное поведение, а текущее. Даже если оно неправильное.
Мы нашли два таких случая. В одном округление в отчёте работало не по математическим правилам, и клиенты сверяли по нему свои цифры годами. Во втором API возвращал ошибку с кодом 200, и интеграции партнёров были написаны под это.
Оба поведения мы зафиксировали тестами и вынесли отдельным списком «это баги, но их чинить нельзя без предупреждения партнёров». Решение принимал клиент, не мы.
К концу недели критичные пути были покрыты на 71% — не идеально, но достаточно, чтобы изменения перестали быть прыжком в темноту.
Неделя 3: зависимости и релизы
Обновили библиотеки, которые не трогали четыре года. Закрыли 23 известные уязвимости. Мы их не искали, они закрылись сами вместе с обновлением версий.
Порядок здесь важен: сначала тесты, потом обновление. Обратный порядок означает, что при первой же поломке непонятно, сломало ли её обновление или оно просто проявило то, что было сломано раньше.
Подняли пайплайн: тесты, сборка, деплой на стенд, деплой в прод, откат одной командой. Полный цикл релиза — 12 минут вместо двух месяцев ожидания подходящего момента.
Что получилось
- 40 000 строк разобрано и описано схемой
- покрытие критичных путей — с 0 до 71%
- 23 закрытых уязвимости в зависимостях
- релиз 12 минут вместо «раз в два месяца, когда не страшно»
Кода при этом переписано мало. Задача была не «сделать красиво», а «сделать изменения безопасными». Красиво команда сделает сама — теперь у неё есть тесты, которые скажут, если стало хуже.
Что мы бы сделали иначе
Стенд с боевыми данными нашёлся на третий день. Если бы мы начинали заново, мы бы отдельным получасовым шагом в первый день проверяли: какие окружения существуют, что в них за данные и кто до них дотягивается. Это дёшево и иногда оказывается важнее всего остального.
Если вы в такой же ситуации
Первое, что нужно сделать, — не искать подрядчика на переписывание. Нужно получить карту: что есть, что связано, где опасно. Это неделя работы и после неё разговор о сроках и бюджете становится предметным.
Мы делаем такой аудит отдельно от разработки — в том числе для тех, кто потом уходит делать всё своими силами.