Что такое легаси в коде
Однажды, Симба, всё это будет твоим
Иногда программисты на вопрос, почему программа работает именно так, отвечают, что это «легаси» и исправить ничего нельзя. Разберёмся, что это значит, насколько это мешает разработке и что делают с легаси-кодом.
Что такое легаси
С английского legacy переводится как «наследие». Легаси-код — это код, который перешёл «по наследству» от предыдущих разработчиков. Чаще всего это происходит так:
👉 Проще говоря, легаси — это код, про который говорят: «Это ещё Михалыч писал 8 лет назад для синхронизации с сервером, он работает, мы его не трогаем, потому что иначе всё сломается». При этом Михалыча в компании давно нет, документации тоже нет, и проще этот код не трогать совсем.
Так как легаси — это старый код, то обычно на него завязаны многие важные вещи в программе. Получается замкнутый круг: отказаться от легаси нельзя, потому что без него всё сломается, но и поддерживать его в рабочем состоянии тоже сложно, потому что никто не хочет разбираться в старом коде.
Откуда берётся легаси
Причин появления легаси может быть несколько:
Легаси — это не какое-то преступление, а часть жизни любой живой ИТ-компании. Рано или поздно у любого продукта появится легаси. И чем крупнее проект, тем больше его будет. Например, в исходном коде Windows 10 до сих пор остаются фрагменты кода, написанные ещё 20 лет назад для Windows 3.1.
Легаси — это плохо?
Легаси — это просто старый код, который нужно поддерживать наравне с новым. Если он работает — отлично, пусть живёт. Другое дело, что команде, например, было бы удобнее, чтобы код был написан не на старом фреймворке, а на новом, который знают все.
Получается, главный минус легаси-кода не в том, что он работает плохо, а в том, что его неудобно поддерживать.
Что значит «поддерживать старый код»?
Например, в старом коде для запроса к серверу идёт сначала адрес, а потом номер запроса. Спустя 10 лет требования сервера изменились, поэтому сначала должен идти запрос, а потом уже адрес. Значит, нужно изменить порядок полей в коде.
Если старый код понятен и хорошо задокументирован, на эту задачу уйдёт две минуты. Если это старые пыльные легаси-кишки, то это может стать задачей на час.
Что делать с легаси-кодом
Если легаси-код работает и не требует вмешательства и поддержки — то можно пока ничего не делать, пусть работает. Будет время — перепишем на новый фреймворк, а если нет, то и так пока поработает.
А если нужно срочное вмешательство — пахнет бедой. Зовите менеджеров.
Legacy-сервисы в вашей инфраструктуре
Привет! Меня зовут Паша Черняк, я ведущий разработчик в QIWI, и сегодня я хочу поговорить о неизбежном. О Legacy.
Прежде чем переходить к тому, как мы в QIWI работаем с нашими Legacy-сервисами, я расскажу, как мы навели порядок с сервисами в Кошельке. Вот уже два года я отвечаю за его работоспособность. Если есть какая-то проблема, то всегда в первую очередь звонят мне. Мне обычно не хватает наглости в 11 часов вечера позвонить кому-то еще, поэтому приходилось садиться и разбираться во всех сервисах нашего домена.
Но я, как и любой человек, люблю спать по ночам, поэтому пытался разобраться с эксплуатацией: «Ребята, а почему вы мне звоните?». На что получил вполне лаконичный ответ вида «А кому еще?». Потому что я сервисы чиню, а еще ребята банально не знают, кому звонить.
Поэтому на одной из ретроспектив команды бекэнда Кошелька мы решили, что нужно составить табличку, на которой написан список наших сервисов, микросервисов и монолитов кошелька, и ответственных за них. Таблички это вообще полезно, в разумных пределах.
Кроме информации о том, кто за что отвечает, там были ответы на вопросы: кто владелец сервиса, кто отвечает за его развитие, за архитектуру и жизненный цикл. Люди, ответственные за этот сервис — люди, которые могут в случае чего его починить. Владелец сервиса имеет право оставить +2 в коммитах, ответственные тоже должны обязательно присутствовать на ревью, прежде чем этот сервис примет на себя новый коммит.
Время шло, начали применяться новые практики, например, миграция в Kubernetes, всякие checkstyle, spotbugs, ktlint, наличие логов в кибане, autodiscovery сервисов вместо указания напрямую адресов и прочие полезности. И везде наша таблица позволяла поддерживать актуальность наших сервисов. Для нас это некий чеклист, который говорит о том, что этот сервис вот это делать умеет, а вот этого пока еще нет Но мы шли дальше, понимая, что нам не хватает информации о наших сервисах, за которыми мы следим, где лежат исходники сервиса, где запускаются таски на сборку в TeamCity, как они деплоятся, где хранятся исходники end2end тестов, фотографии с грумингов про архитектуру, про принятые решения. В идеале хотелось, чтобы вся эта информация где-то лежала и была под рукой, когда нужно. Поэтому наша табличка стала пунктом отправления за поиском информации.
Но QIWI, хоть и сохраняет дух стартапа, является большой компанией. Нам уже 12 лет, и команды меняются: люди уходят, люди приходят, формируются новые команды. И мы обнаружили на своем домене несколько сервисов, доставшихся нам в наследство. Что-то пришло с разработчиками из других команд, что-то просто как-то опосредованно относилось к Кошельку, поэтому сервис у нас теперь на балансе. Разбираться с тем, что и как работает — зачем? Сервис же работает, и у нас есть продуктовые фичи, которые надо обязательно запилить.
Как бывает
Но в какой-то момент времени мы обнаруживаем, что сервис перестает выполнять свою функцию, что-то сломалось — как быть в такой ситуации? Сервис просто перестал работать. Совсем. А узнали мы об этом, во-первых, случайно, а во-вторых, через полгода. Так бывает. Единственное, что мы знали — на каких виртуалках развернут сервис, где лежат его исходники, и всё. Мы делаем git clone и погружаемся в мысли человека, который писал это несколько лет назад, но что мы видим? Никакого привычного для нас Spring Boot, хотя привыкли ко всему, у нас же full stack и все такое. Может, там есть Spring Framework? А вот и нет.
Парень, который все это писал, был суров и писал всё на чистой Java. Привычных инструментов для разработчика нет, и возникает идея — надо бы это все переписать. У нас же микросервисы есть, а из каждого тостера доносится привычное «Ребята, микросервисы — это то, что вам нужно!». Если вдруг что-то не так, вы спокойно возьмете любой язык и все будет отлично.
Штука в том, что сейчас у нас нет заказчика, который отвечает за этот сервис. Какие у него были бизнес-требования, что вообще должен делать этот сервис? А сервис плотно интегрирован в ваши бизнес-процессы.
А теперь скажите, насколько просто переписать сервис, не зная его бизнес-требований? Сервис непонятно как логируется, есть ли метрики — неизвестно. Какие они, если есть — тем более неизвестно. И при этом в сервисе огромное количество классов непонятной бизнес-логики. Что-то входит в какую-то базу данных, о которой мы тоже пока ничего не знаем.
С чего же начать?
С самого логичного — с наличия тестов. Там обычно написана хоть какая-то логика и можно сделать выводы о том, что происходит. Сейчас же модно TDD, но мы видим, что те же 5 лет назад все было практически так же, как сейчас: unit-тестов почти нет, да и не скажут они нам ровным счетом ничего. Ну кроме разве что какой-то проверки, как подписывается какой-нибудь xml с каким-нибудь кастомным сертификатом.
По коду ничего понять не удалось, и мы пошлить смотреть, чего тамна виртуалке. Открыли логи сервиса, нашли в них ошибку http-клиента, самоподписанный сертификат, который был вшит в ресурсы приложения, бессовестно протух. Мы связались с нашими аналитиками, они попросили новый сертификат, нам его выпустили и сервис снова работает. Казалось бы, что на этом все. Или нет? Все-таки сервис работает, он выполняет какую-то функцию, которая нужна нашему бизнесу. У нас есть некие стандарты разработки приложений, которые скорее всего есть и у вас. Например, не хранить логи на ноде в папке, а хранить в каком-то хранилище, типа эластика, смотреть на них в кибане. Можно вспомнить и золотые метрики. То есть нагрузка на сервис, количество запросов на сервис, жив он или нет, как у него HealthCheck проходит. По крайней мере, эти метрики помогут узнать, когда его со спокойной совестью можно вывести из эксплуатации и забыть как страшный сон.
Что делать
Поэтому мы добавляем такой старый сервис в табличку, а потом идем искать из числа разработчиков добровольцев, которые займутся сервисом и приведут его в порядок: напишут хоть какую-то информацию о сервисе, добавят ссылки на дашборды в графане, на таски сборки, поймут, как разворачивать приложение, не руками же накидывать с помощью ftp файлики.
Главное — сколько вся эта полезная добровольческая активность займет времени? Один спринт для более или менее опытного разработчика, например, во время 20%-го техдолга. А сколько времени ушло на то, чтобы понять всю закоренелую логику по общению с некой госсистемой, привести ее на более новые технологии? Я за это не ручаюсь, может, месяц, а может, и два работы команды. Это я говорю по опыту интеграции в текущее время с каким-нибудь новым сервисом.
При этом выхлопа бизнес-ценности — никакого. Совсем. Взять сервис на поддержку и потратить на это немного времени — нормально. Но после наших стандартных танцев с сервисом мы добавили его в таблицу, добавили информации о нем и, возможно, когда-нибудь перепишем. Но сейчас он отвечает нашим стандартам работы сервисов.
Как итог, хотелось бы подвести к некому плану, что делать с Legacy-сервисами.
Переписывать legacy с нуля — плохая затея
Серьезно, можно даже не думать об этом. Понятно, что хотелось бы, и видятся какие-то плюсы, но обычно это не нужно никому, включая вас самих.
Справочник
Откопайте исходные коды ваших приложений, сделайте справочник, в котором будет указано, что и где лежит и как работает, туда же впишите описание проекта (условный readme.md), чтобы быстро понимать, где лежат логи и метрики. Разработчик, который будет разбираться с этим после вас, только спасибо скажет.
Понимайте домен
Если вам принадлежит какой-то домен, старайтесь держать руку на пульсе. Звучит банально, да, но не все следят за тем, чтобы сервисы были в едином ключе. А ведь работать в одном стандарте на самом деле ощутимо проще.
Как работать с legacy-системами
На самом деле, по-хорошему статью следовало бы назвать так: «Как работать с legacy-системами и сохранять психическое здоровье». Любой, кто имеет с ними дело, меня поймет. Эта статья — попытка обобщения многолетнего опыта знакомства с legacy-системами в виде набора подходов и практических советов. Примеры буду приводить из собственного опыта — в частности, работы с унаследованной Java-системой.
Кстати, материалов о работе с legacy в структурированном виде почти нет — оба источника, посвященных именно ей, приведены в конце материала. И это при том, что на legacy приходится чуть ли не половина всего аутсорсинга.
Особенности legacy
Legacy — в переводе с английского «наследство», и наследственность эта тяжелая. Почти всем доводилось, придя в проект, получить код десятилетней давности, написанный кем-то другим. Это и есть унаследованный код — то есть код исто(е)рический, который часто бывает ужасен настолько, что оказывается вообще непонятно, как с ним работать. И если нам достается legacy-система, то мы, кроме старого кода, также имеем:
— устаревшие технологии;
— неоднородную архитектуру;
— недостаток или даже полное отсутствие документации.
Со всем этим нам нужно разбираться и как-то жить дальше. И тут без хорошего чувства юмора, пожалуй, не обойтись — те, кто воспринимают жизнь слишком серьезно, обычно сбегают сразу же, как только увидят настоящее legacy.
На самом деле, legacy-система — это не так уж страшно, и вот почему: если система жила все эти десять лет и до сих пор работает, значит, какой-то толк от нее есть. Может быть, она приносит хорошие деньги (в отличие от вашего последнего стартапа на новейших технологиях). Кроме того, код такой системы относительно надежен, если он смог так долго выживать в продакшне. Поэтому вносить в него изменения нужно с осторожностью.
Прежде всего, нужно понять две вещи:
1. Мы не можем неуважительно относиться к системе, которая зарабатывает миллионы, или к которой обращаются тысячи людей в день. Как бы плохо она ни была написана, этот отвратительный код дожил до продакшна и работает в режиме 24/7.
2. Раз эта система приносит реальные деньги, работа с ней сопряжена с большой ответственностью. С самого начала ясно, что это не стартап в стол, а то, с чем пользователи будут работать уже завтра. Это подразумевает и очень высокую цену ошибки, причем дело здесь не в претензиях клиента, а в реальном положении вещей.
Какие задачи нам придется решать, работая с такой системой? Во-первых, мы, очевидно, будем разрабатывать новую функциональность, раз система жива, а значит развивается. Во-вторых, мы будем исправлять ошибки, и это тоже очевидно. И наконец, хотя многие предпочитают про это забыть, мы будем заниматься оптимизацией и стабилизацией системы, даже если напрямую такой задачи перед нами в начале проекта никто не ставил.
Обратный инжиниринг

Прежде всего, нужно внимательно читать код, чтобы точно понимать, как именно он работает. Это обязательно — ведь достаточной документации у нас, скорее всего, не будет. Если мы не поймем хода мыслей автора, то будем делать изменения, последствия которых окажутся не вполне предсказуемыми. Чтобы обезопасить себя от этого, нужно вникать еще и в смежный код. И при этом двигаться не только вширь, но и вглубь, докапываясь до самого нутра. Откуда вызывается метод с ошибкой? Откуда вызывается вызывающий его код? В legacy-проекте «call hierarchy» и «type hierarchy» используется чаще, чем что бы то ни было другое.
Конечно, придется проводить много времени с отладчиком — во-первых, чтобы находить ошибки, и во-вторых, чтобы понять, как все работает — потому что логика обязательно будет такой, что по-человечески прочитать ее мы не сможем. Собственно говоря, дебажить нужно будет вообще все, в том числе и open source-библиотеки. Даже если проблема где-то в Spring, значит, придется отлаживать и, возможно, пересобирать Spring, если возможности его обновить не окажется. Именно так нам неоднократно приходилось делать, причем не только со Spring.
Что касается документации, не лишним будет прибегнуть к тому, что я бы назвал промышленной археологией. Очень полезно бывает откопать где-нибудь старую документацию и поговорить с теми, кто помнит, как писался доставшийся вам код. Возможно, где-то есть старый Confluence, возможно, хотя бы дамп его базы, где вы что-то, может быть, и найдете. Иногда это бывает проще, чем сидеть с дебаггером. Но нередко там окажутся только документы, не имеющие прямого отношения к коду, например, руководства по настройке серверов, которые все в принципе боятся трогать.
Используя эти приемы, рано или поздно вы начнете более или менее понимать код. Но чтобы ваши усилия не пошли прахом, вы должны обязательно сразу же документировать результаты своих изысканий — для этого я советую рисовать блок-схемы или диаграммы последовательности (sequence diagrams). Конечно, вам будет лень, но делать это точно нужно — через полгода без документации вы сами в этом коде будете копаться как в первый раз. А если через полгода с кодом будете работать уже не вы, ваши последователи будут очень благодарны вам за имеющуюся документацию.
Кстати, зачастую для себя и для бизнеса документацию нужно готовить разную: в вашей, рассчитанной на инженеров, представители бизнеса ничего не поймут. Им потребуется что-то понятное, описывающее функционирование системы на верхнем уровне. И наконец, нужно не забывать самим пользоваться этой документацией и читать ее. Однажды, решив проблему после двух дней героической борьбы, мы обнаружили собственный документ, подробно описывающий точно такой же случай.
Процесс разработки

— Не переписывать. Самое важное здесь — вовремя бить себя по рукам и не пытаться переписать весь код заново. Прикиньте, сколько человеко-лет для этого потребуется — вряд ли заказчик захочет потратить столько денег на переделывание того, что уже и так работает. Это касается не только системы в целом, но и любой ее части. Вам, конечно, могут дать неделю на то, чтобы во всем разобраться, и еще неделю на то, чтобы что-то исправить. Но вряд ли дадут два месяца на написание части системы заново.
Вместо этого реализуйте новый функционал в том же стиле, в каком написан остальной код. Другими словами, если код старый, не стоит поддаваться соблазну использовать новые красивые технологии — такой код потом будет очень тяжело читать. Например, вы можете столкнуться с ситуацией, которая была у нас — часть системы написана на Spring MVC, а часть — на голых сервлетах. И если в части, написанной на сервлетах, нужно дописать еще что-то, то дописываем мы это так же — на сервлетах.
— Соблюдать бизнес-интересы. Нужно всегда помнить, что любые задачи обусловлены прежде всего ценностью для бизнеса. Если вы не докажете заказчику необходимость тех или иных изменений с точки зрения бизнеса, этих изменений не будет. А для того, чтобы убедить заказчика, вы должны попробовать встать на его место и понять его интересы. В частности, если вам хочется провести рефакторинг только потому, что код плохо читается, вам не дадут этого сделать, и с этим нужно смириться. Если совсем уж невмоготу, реорганизовывать код можно по-тихому и понемногу, размазывая работу по бизнес-тикетам. Либо убедить заказчика в том, что это, например, сократит время, необходимое для поиска ошибок, а значит, в конечном итоге сократит расходы.
— Тестировать. Понятно, что тестирование необходимо в любом проекте. Но при работе с legacy-системами тестированию нужно уделять особое внимание еще и потому, что влияние вносимых изменений не всегда предсказуемо. Тестировщиков потребуется не меньше, чем разработчиков, в противном случае у вас должно быть все просто невероятно хорошо с автоматизацией.
В нашем проекте тестирование состояло из следующих фаз:
1. Верификация, когда реализованный функционал фичи проверяется в отдельной ветке.
2. Стабилизация, когда проверяется ветка релиза, в которой все фичи слиты вместе.
3. Сертификация, когда все то же самое прогоняется еще раз на немного других тест-кейсах в сертификационном окружении, максимально приближенном к продакшну по характеристикам железа и конфигурации.
И только после прохождения всех этих трех фаз мы можем делать релиз. Кто-то наверняка считает, что сертификация — лишняя фаза, так как на стадии стабилизации все уже выяснено, но наш опыт говорит о том, что это не так — иногда во время регрессионного теста, который прогоняется по второму кругу на другой машине, что-нибудь да вылезет.
— Формализовать DevOps и релиз. При работе с legacy-системой важно наладить все, что касается DevOps и прочих практик, напрямую не связанных с разработкой. В частности, очень хорошо совместно с девопсами на стороне заказчика прописать определенную процедуру релиза, каждый шаг которой будет строго документирован. Только тогда процесс становится предсказуемым и ясным для каждого из участников.
Релизная процедура может быть, например, следующей. Когда заканчивается разработка и пройдены две или три фазы тестирования, мы пишем письмо DevOps-команде за 36 часов до предполагаемого времени релиза. После этого созваниваемся с девопсами и обсуждаем все изменения окружений (мы сообщаем им обо всех изменениях в БД и конфигурации). На каждое изменение у нас есть документ (тикет в Jira). Затем во время релиза все причастные к этому собираются вместе, и каждый говорит, что он сейчас делает: «Мы залили базу», «Мы перезапустили такие-то серверы», «Мы пошли прогонять регрессионные тесты в рабочем окружении». Если же что-то идет не так, запускается процедура отката релиза, точно описанная в изначальном документе на релиз — без такого документа мы обязательно что-нибудь забудем или напутаем (вспомните, в какое время суток обычно происходят релизы).
— Выстроить branching strategy. Основные модели бренчинга давно описаны на сайте того же Atlassian, их можно адаптировать под ваши нужды. Главное — ни в коем случае не коммитить изменения сразу в транк: должны быть stable trunk и feature branches. Я советую делать релизы из релизных веток, а не из транка. То есть у вас есть транк, от которого отходят ветки на конкретные фичи, соответствующие тикетам в Jira. Когда вы закончили разработку в спринте, вы собираете отдельную релизную ветку из готовых фич и ее сертифицируете. Если же что-то пойдет не так, из такой ветки можно будет легко устранить то, что по какой-то причине из релиза в итоге выпадает. Когда же релиз произошел, релизная ветка вливается в stable trunk.
— Контролировать качество кода. И наконец, code review — это, казалось бы, достаточно очевидная практика, к которой прибегают почему-то далеко не во всех проектах. Очень хорошо, если каждая часть кода проверяется более чем одним человеком. Даже в очень сильной команде в процессе code review обязательно обнаруживаются какие-то косяки, а если смотрят несколько человек, количество выявленных косяков возрастает. Иногда самое страшное находит третий или четвертый reviewer. Но во избежание как саботажа, так и излишнего фанатизма, необходимо договориться, сколько review достаточно для того, чтобы считать фичу готовой.
Для проверки можно использовать пул-реквесты (конечно, если у вас Git), далее есть Crucible и FishEye — оба прикручиваются к Jira. И наконец существует очень удобный инструмент Review Board, который работает и с SVN, и с Git. Он позволяет послать запрос на проверку кода, который соберет в себе все изменения в данном feauture branch.
Управление проектом

Глупые вопросы. Тимлид не должен стесняться задавать команде «глупые» вопросы и напоминать обо всех вышеперечисленных приемах работы. «Я накатил свежий код, и теперь ничего не работает!» — «А какую ветку ты взял? А базу обновил? А что в логах? А дебажил?» Несмотря на всю свою простоту, такие диалоги — неотъемлемый элемент нашей работы, и в особенности с legacy-проектами. Нужно удерживать все в голове и не уставать снова и снова напоминать о каких-то очевидных и не очень очевидных вещах. Без этого, поверьте, не обойтись!
Процесс, или «здесь так принято». В силу американской текучки кадров новые менеджеры со стороны заказчика приходят в проект чаще, чем нам хотелось бы. И многие из них, еще не разобравшись в специфике legacy, пытаются внедрять практики и решения из своего предыдущего опыта. Им нужно терпеливо объяснять, почему здесь принято именно так, а не по книжке. Сначала такие вещи донести бывает трудно, но в конечном итоге либо заказчик согласится с вами, либо вы вместе придете к компромиссному решению.
В работе с legacy-системами действительно важен правильно выстроенный, понятный и прозрачный процесс: Jira (или аналог) обязательно должна отражать реальное положение дел в данный момент. Все требования должны быть ясно сформулированы, а процессы четко прописаны. Вся эта Jira-бюрократия точно окупится, сильно снизив степень энтропии в проекте. Так, когда к вам придет заказчик и потребует срочно сделать новую фичу, вы сможете просто показать заполненное расписание. Тогда он легче сможет понять, что чем-то придется пожертвовать.
Что касается эстимэйта (вы же используете Planning Poker, правда?), то оценивать всегда нужно с запасом, чтобы быть готовым к сюрпризам — как мы уже говорили, влияния в незнакомом нам коде зачастую неясны, и порой может вылезать что-то совершенно неожиданное и в неожиданных местах. Так, у нас в проекте был случай, когда изменения в простом CSS сломали часть бизнес-логики: кто-то поставил в JS проверку на цвет элемента интерфейса.
Бизнес, tech debt и SWAT. При работе с legacy-системами нужно стараться противостоять потоку бизнес-требований, которые заказчик будет вам непрерывно поставлять. Заказчик не всегда осознает риски, связанные со стабильностью системы, поэтому вам придется постоянно о них напоминать. Бороться с этими рисками можно двумя способами: балансированием бизнес и стабилизационных задач в каждом спринте или отдельными стабилизационными проектами. Оптимальным кажется баланс 70 на 30, когда 30% времени каждого спринта вы занимаетесь стабилизацией. Впрочем, заказчик скорее всего не даст вам сделать все, что вы хотите — поэтому записывайте технический долг по мере обнаружения. Из этого tech debt вы будете брать задачи на вышеупомянутые 30%. А может, заказчик согласится на стабилизационный проект, особенно если вы покажете ему tech debt в ответ на вопрос, почему все в очередной раз упало.
Примеры оптимизации
А теперь вкратце расскажу о способах оптимизации, которыми мы пользовались в разное время.
Во-первых, нужно уйти от традиции ежедневных перезапусков, если так было принято в проекте. Однако делать это нужно, конечно, с осторожностью — продолжать проверять логи и следить за всем, что может привести к падению системы, и бороться с этим. У нас была система, которые перезапускалась каждую ночь, так как не могла прожить и двух суток из-за memory и других leaks — теперь же она совершенно стабильно работает от релиза до релиза две-три недели (за редкими исключениями, о которых мы обычно узнаем в 4 утра).
А вот хороший пример того, как делать не нужно. У нас была система, несколько компонентов которой периодически отваливались. Тогда со стороны заказчика пришел девопс и написал скрипты, которые по логам анализируют активность этих компонентов, и если в логе три минуты нет записей, то эти службы перезапускаются. Это, конечно, сработало, но такие вещи должны однажды плохо кончиться.
Очень важный момент — проход по всем логам и составление отдельного эпика. Бывают, конечно, заказчики, которые долго не дают доступа к продакшн-логу. У нас, например, так продолжалось полгода, после чего случился переломный момент, когда нас самих попросили посмотреть логи продакшна. Просмотр затянулся на всю ночь. В системе, работавшей, как считалось, штатно и стабильно, нормальные логи попадались лишь иногда — в основном же записи были со сдвигом вправо и начинались с «at». Это были сплошные стектрейсы, и их набиралось на десятки мегабайт в сутки. Конечно, мы завели эпик в Jira и создали тикеты на отдельные exceptions. Затем нам пришлось несколько месяцев выбивать время на стабилизационный проект. В итоге мы исправили множество ошибок, о которых никто не догадывался, и сделали логи информативными. Теперь любой стектрейс в них — действительно признак нештатной ситуации.
Еще советую обращать внимание на третьесторонние зависимости как на front-end (Google Tag Manager, Adobe Tag Manager и т. п.), так и на back-end. Например, если у нас на странице есть JavaScript со сторонних ресурсов, нужно посмотреть, завернуты ли эти скрипты в try..catch блоки. У нас были случаи, когда сайт падал из-за того, что ломался какой-то скрипт на стороне. Также важно предусматривать возможность недоступности любых внешних ресурсов.
Ну и последнее: следите за всем, за чем только можно, и грамотно агрегируйте логи. Ведь у вас может быть 12 продакшн-серверов, и вас могут попросить их логи посмотреть, что точно нужно делать не через tail. Мы использовали ELK — связку Elastic search — Logstash — Kibana. Очень полезен мониторинг: мы навесили Java Melody на все серверы и получили огромное количество новой информации, на основании которой многое исправили, осчастливив заказчика.
P.S. Полезные ссылки:
— Виктор Полищук: «Legacy Projects. How To Win The Race» — доклад на русском о работе с унаследованными системами, основанный на конкретных примерах из опыта докладчика.
— Michael Feathers: «Working Effectively with Legacy Code» — книга по теме, которую я, честно говоря, не читал. В основном она про рефакторинг. В открытом доступе есть обширная презентация автора с тем же названием, по которой вы сможете понять, стоит ли вам покупать эту книгу.
Підписуйтеся на Telegram-канал редакції DOU, щоб не пропустити найважливіші статті.




