Недавно я наткнулся на историю столь же удивительную, сколь и ужасную:
Один из моих клиентов занимался поддержкой нескольких пенсионных фондов, входящих в сотню лучших по миру. У него была еженочная пакетная задача, которая начала вылетать. Поначалу никто не мог понять, в чём дело. Насколько все помнили, эта пакетная задача никогда раньше не вылетала.
Написавший её человек умер уже 15 лет назад, да и ушёл из компании много десятков лет назад. Программа была не такой большой, однако оказалась непостижимой. Её писали в стиле, отдававшем приоритет вычислительной эффективности, а не простоте чтения. И, разумеется, у неё не было никаких тестов.
Как назло, днём ранее запушили изменение порядка выполнения скриптов, работающих в этом окружении. Все решили, что виновато это изменение. Инженеры откатили всё к предыдущему релизу. К сожалению, это только усугубило проблему.
…
Ещё одна программа, занимающаяся переводом прибыли, должна была уведомлять пользователей, что их вкладов недостаточно для прогнозирования дохода. Заметив, что из первой программы из-за её вылета нет выходных данных, она восприняла эту ситуацию как «все вклады равны 0». Разумеется, она должна была вести себя совершенно иначе. Но никто не знал, что она будет действовать так, поскольку первая программа никогда не вылетала.
…
Я получил от ИТ-директора неожиданное текстовое сообщение. «Простите за беспокойство, у нас огромная проблема. s1X. Можете прилететь сегодня во второй половине дня?» В их терминологии S1X обозначает «хуже, чем уровень серьёзности 1, потому что проблема распространилась на несвязанные с ней части бизнеса».
К счастью, все пенсии были спасены и история окончилась хэппи-эндом. Но нам вряд ли покажется нормальным, что критически важные финансовые системы зависят от древнего ПО, в котором не разбирается никто из ныне живущих людей.
Ещё одна история с менее счастливым финалом: в Англии потерялось 16 тысяч отчётов о случаях заболевания коронавирусом из-за того, что организация использовала устаревший 30-летний формат файлов.
Бизнес на слегка прогнивших системах
Оказывается, описанный выше пример не уникален. В 2012 году, когда я ушёл из Intel, чтобы устроиться в Sun, то осознал, насколько плоха ситуация с её линейкой продуктов SPARC. Бывшая когда-то «золотым гусем» доткомовской эпохи серверов, теперь она чрезвычайно далеко отстала от линейки продуктов Intel Xeon. Мой собственный руководитель в буквальном смысле сказал мне запускать симуляции на серверах Intel Xeon, а не на серверной ферме SPARC, потому что «она очень медленная». Хуже того, дело было не только в лучшей производительности процессоров Intel, но и в том, что благодаря технологическому отрыву они были значительно дешевле в изготовлении.
У меня возник логичный вопрос: зачем вообще клиенты покупают наши чипы SPARC, если они настолько отстали от конкурента? Полученный от ведущего архитектора ответ взорвал мой
Именно так — бизнес-модель всего нашего отдела основывалась на разлагающихся программных системах американских корпораций.
Сколько нужно ресурсов, чтобы лампочки никогда не гасли
Когда я впервые пришёл в Amazon, то очутился внутри идеального архетипа легаси-системы. Изначально она разрабатывалась с кучей технического долга… другой командой… которую уже давно распустили. Ответственность за проект перешла к нашей команде, и он оказался настолько непопулярным, что разработчики массово начали переходить в другие отделы. Из примерно десятка членов команды, к которым я присоединился, спустя год не осталось ни одного.
Внешне казалось, что система живёт и развивается. Она была написана на современном языке и техническом стеке (Java 8). Её ежедневно поддерживала целая команда разработчиков с шестизначной зарплатой. И её постоянно обновляли для устранения багов и/или добавления новых функций.
Тем не менее, несмотря на всё это, можно было с лёгкостью заметить, что передача ответственности отяготила систему. В результате смены ответственных лиц и команды огромное количество фундаментальных знаний о ней было утеряно. Я имею в виду такие знания, как общая структура кода, сквозная функциональность, оптимальные способы эксплуатации и техники отладки. Мы упорно трудились над тем, чтобы поддерживать систему на плаву. Но всё равно казалось, что мы увязаем в трясине, постоянно ставя под сомнение каждое изменение и находясь в тумане неизвестности.
Можете представить, насколько всё было бы хуже, если бы проект работал на Java 1, с полным отсутствием активной разработки и разработчиков, которых назначили ответственными?
Как предотвратить катастрофический провал
Мы, разработчики ПО, стремимся создавать надёжные системы без багов, которые можно просто оставить работать в одиночку на долгие годы без ручного вмешательства. И по этой метрике скрипт пенсионного фонда, безусловно, был огромным успехом.
Тем не менее, жестокая реальность заключается в том, что всё ломается… рано или поздно. Всё рано или поздно придётся обновлять.
- Может быть, ваша система использует оборудование, которое больше не производят
- Или имеет зависимости, которые уже прекратили своё существование
- Или имеет зависимости с серьёзными уязвимостями защиты, а единственные патчи выпущены только для версий без обратной совместимости
- Или приложение разработано на основании допущений, которые уже неверны
- Или мир просто изменился, и приложению нужно меняться вместе с ним.
Какова бы ни была причина, изменения неизбежны. Единственный вопрос заключается в том, насколько болезненны они будут, когда настанет их время.
Если над вашей системой активно работают, то изменения могут и вовсе быть безболезненными. Но если систему игнорировали несколько лет или даже десятков лет, то катастрофическим провалом может закончиться слишком многое.
- Создавшие систему люди уже могли уйти из компании
- Мог потеряться исходный код
- Люди могут не знать, как правильно компилировать исходный код для сборки исполняемого файла
- Или как деплоить новый исполняемый файл
- Или правильно запускать исполняемый файл с нужной конфигурацией всех флагов
- Или разбираться в архитектуре и реализации кода
- Или какие инварианты и неявные допущения использует код для правильной работы
- Или как проводить автоматизированыне тесты
- Или как отлаживать выявленные тестами сбои
- Или как отлаживать сбои в продакшене
- Или как получить доступ к логам и метрикам продакшена.
Стремление к тщательному документированию всего вышеперечисленного может помочь. Однако документация всегда будет субоптимальной. В ней всегда будут пробелы. Подробная документация не может стать заменой кропотливому изучению системы.
Праздный мозг
Наличие отдельно разработчика, отвечающего за поддержку всего вышеизложенного определённо станет хорошим первым шагом. Но его недостаточно.
Люди будут «читать доки» очень много раз, а потом им это надоест. Они не получат тех знаний, которые можно приобрести только опытом. И решением настоящих проблем.
Если попросить их провести «аудит», то высока вероятность того, что они отнесутся к этому формально, а проблемы «заметут под ковёр», ведь им интереснее работать над более свежими и яркими проектами… или просто сачковать. При отсутствии настоящих результатов и сложностей многие пойдут пути наименьшего сопротивления.
Если вы действительно хотите избежать разложения ПО, то единственный способ гарантировать это — постоянное движение, даже если оно кажется необязательным и рискованным. Так получается просто потому, что лучший способ накопления, сохранения и проверки своих фундаментальных знаний и умений — постоянное внесение изменений с тестированием своей возможности успешной реализации таких изменений. День, когда вы прекратите движение, станет днём, когда начнут устаревать и разваливаться ваши фундаментальные знания.
Даже движение по кругу, как ни смешно это звучит, будет лучше, чем бездействие. Но если взглянуть реалистично, то специалисты по эксплуатации всегда могут делать что-то, способное двигать систему вперёд, пусть и маленькими шагами.
Можно обновить окружение, чтобы использовать последние версии зависимостей:
- Например, мигрировать с JDK 8 на 11
- Или обновить JVM, чтобы использовать сборщик мусора G1 вместо CMS
- Или обновить компилятор GCC с версии 5 до 7
- Или обновить базу данных с Postgres 9.5 до Postgres 11
- Или обновить AWS SDK с версии 1.10 до 1.11
- Или установить последний дистрибутив Linux на машины в продакшене
В особо серьёзных случаях, когда зависимости безнадёжно устарели, можно изучить возможность полной миграции на более новый стек:
- Например, мигрировать со SPARC на x86.
- Или с Solaris на Linux.
Можно поддерживать остроту знаний разработчиков, обновляя и ваше приложение:
- Например, устраняя любые давние баги или пограничные случаи
- Или совершенствуя набор автоматизированных тестов
- Или подчищая технический долг
- Или внося оптимизации производительности
- Или реализуя новые функции
- Или просто инкрементно рефакторизируя свой код, чтобы делать его более читаемым.
Описанные выше изменения привносят переходные риски и связаны с казалось бы «необязательными» затратами. Разработчики неизбежно будут делать ошибки и вносить баги. Когда узнаёшь о таких затратах, испытываешь искушение просто отступиться и не делать ничего. «Не чини то, что не сломано».
Если система обеспечивает минимальную ценность для бизнеса, то это может даже быть рационально. Однако если система критически важна, то вы меняете небольшой переходный риск на постоянный риск катастрофы. Риск того, что однажды вашу систему нужно будет срочно отлаживать или обновлять, но ваша организация окажется совершенно неспособной на это.
Для любой критически важной системы жизненно необходимо сохранять фундаментальные знания и навыки. А единственный способ их сохранения — постоянные тренировки.
На правах рекламы
Мощные VDS с защитой от DDoS-атак и новейшим железом. Всё это про наши эпичные серверы. Создайте собственный тариф в пару кликов, максимальная конфигурация — 128 ядер CPU, 512 ГБ RAM, 4000 ГБ NVMe.
Автор: Mikhail