Архитектура Архитектуры. Шаг 10. Это конец
Знаете, как называется система, которая приносит постоянную прибыль, работает без особых проблем и обслуживается маленькой командой? Продукт с заканчивающимся сроком обслуживания!
End of Life
Как в ресторане перед закрытием. Клиентам сообщают, что кухня скоро закроется. Можно еще что-то заказать напоследок, но дальше только бар. Вроде никто их не гонит, и они продолжают трапезу, но столы вокруг начинают освобождать. И вскоре становиться тихо и одиноко. Есть вариант перейти на дорогие и замысловатые коктейли, персональный аккаунт-бармен поможет со вкусом потерять сбережения или сознание. Так что на следующий день у клиента возникает резонный вопрос: «Стоит ли идти в тот же ресторан или же заглянуть в другой?». Но не будем бежать вперёд крыс с камбуза. Пока клиент у вас — горшочек варит.
Уводить на пенсию свои проекты мне еще не доводилось. Однако накопился опыт эвтаназии других продуктов. Чем же славна эпоха заката империи? Конечно же роскошью и развратом! Первое легко приводит ко второму. Период обслуживания славен тем, что клиент платит сбор за поддержу или операционные затраты. Ну, а ваша компания, обычно, тратит много сил на уменьшение затрат. Так что через несколько лет проект начинает приносить чистую прибыль. В довесок к этим деньгам, добавляются заказы на дополнительные функции и всевозможные изменения. Я не встречал ни одного проекта, который к 10–15 годам жизни не превратился в плешивую и хромую курицу, несущую золотые яйца. Именно благодаря этим яйцам (и не важно, что говорит сам сюзерен) ваш директор решается озвучить мечту об некстгене на ежегодном замере харизмы. Следующая версия продукта должна стать следующей курицей и ядра — чистый изумруд!
Важно обратить внимание на то, что это «следующая версия». Не новый продукт. Новое — риск. Начальство риски не любит, потому что никто не умеет их готовить. Рецепт идеального продукта — взять старый и продать еще раз. А значит, что от вас, в первую очередь, ожидают доработанный старый дизайн, но блэкджеком и API-ками! Круг замыкается, и вы опять начинаете слинии и иконостаса. Но, позвольте, ведь старую курицу еще не закопали, так что за ней тоже надо следить. И в идеале, когда кура всё же откинет копыта (а за долгий срок мутаций и не такое вырастет) незаметно подменить на новую, ещё более лучшую, чтоб с урожаями и надоями.
Вот этот самый этап подмены — колдовство архитектора! Так что расчехляем волшебную палочку, и айда ей бить по рукам! За что бить — всегда найдётся. Проект на вольных хлебах и накатанных рельсах. В первое время за ним следили. Ведь в начале были подписаны кучи SLA, а значит в них нужно было укладываться, чтоб не ложиться под… По мере накопления мутаций: изменения законов и регуляций, стандартов и технологий, принципов работы и сливания бизнес-направлений — все принимают факт, что это уже не тот же самый ванильный рожок с добавками. А прямо-таки новое нечто, со своим вкусом и рогами. Поэтому рамки начинают двигать и в конце вообще опускают. Поэтому основой разработки становится клятва Гиппократа. Не навреди! Неважно, как впихнуть очередное изменение и продуктовую деталь, лишь бы не сломалось нажитое непосильным трудом. Сейчас, наверное, уже сложно представить продукт без автоматических тестов, но в легаси такое сплошь и рядом. Ведь если б можно было продолжать эволюционировать, то никакая следующая новая система не нужна.
Из опыта:
Старые системы не так уж и плохи. Они служат верой и прибылью. Нужно понимать, что ваш легаси продукт — является стандартом де-факто для ваших клиентов. Всё, что будет предложено, будет сравниваться с этим стандартом. Победить конкурента бывает легче, чем самого себя. Против вас играет ваше же тесная связь с клиентом и понимание его бизнес процессов. Память всегда защищает нас от тревожных и драматичных моментов прошлого. Ваш клиент будет помнить лишь успехи. И придавать ценность количеством страданий. Тем более, что начальство, ходившее по мукам разработки прошлого продукта, скорее всего уже на других местах. А новички пришли уже в работающую экосистему. Так что первые же упоминания о том, что ваша компания будет разрабатывать что-то новое — вызовет восторженные аплодисменты публично и ноту недоверия за кулисами. Архитектору будут противостоять: низкие требования к железу (чтобы с этих пор по-новому, оставалось все по-старому), большой (очень большой, накопившийся за 10 лет) набор функций и быстродействие (как следствие примитивности). Тут работает знакомое всем определение безумия, с легким капиталистическим штрихом: делать абсолютно другую систему и ожидать того же результата. Эти препятствия не преодолеть технически, так что стоит сразу начать политические баталии. В качестве оружия нужны простые и понятные факты и цифры. Основная идея — за всё нужно платить. Красивая картинка и устойчивое шифрование — больше локальных ресурсов, облачные сервисы — задержка из-за удалённых вызовов, детальные логи и сбор больших данных — больше хранилища и шире каналы, доступ из любого места — больше уровней и периметров безопасности.
Миром правят деньги. И время. И нет, я не про то, что время — деньги. Как в конвенциональной политике, так и в корпоративной, каждый преследует личные цели, прикрываясь лозунгами и заботой об остальных. А значит важно только то время, когда господин на каденции. Так что деньги сейчас. Пусть потом будет меньше, но это уже проблемы тех, кто придёт после. Поэтому волевыми решениями и близким горизонтом начальство продавит «сейчас заделиверим, а тесты никогда потом». Тут ведь как работают с Гиппократом: не пойман — не баг! Поймать что-то в ручном режиме в системе с тысячами сценариев… В конечном итоге и клиент тоже будет проверять так же, поэтому то, что всплывет потом в проде, просто назовут новой проблемой. Отсюда и странное явление старых энтерпрайз продуктов: со временем объем разработки падает, а количество ошибок увеличивается. Технический долг будет расти башней из кубиков, пока не превратит всех в трупиков. Но каждый новый босс, а в легаси проектах они меняются где-то раз в год-два (после того как уйдёт тот, кто курировал проект с начала), будет надеяться, что последний кубик будет не в его смену. Такое отношение порождает два смертных врага архитектуры (и других удивительных тварей):
Золотые шестёрки.
Years of Gears
Любимчики системы. Они делают быстро и точно. Вот как сказали, так и сделают. Золотые руки. И работать руками они любят. Никакой автоматизации. Проверяют вручную, деплоят вручную и думают тоже как-то так. А раз автоматизация им не нужна, то они первые соглашаются на «тесты потом» (последнее читать два раза с ударением на разный слог). И с тем же рвением и удовольствием будут убивать и то, что заскриптили и затестили раньше. Ведь новых фишек не было в старых тестах, а «менять их долго, я лучше ручками». Пик популяции приходится на середину жизненного цикла системы. Когда уже не следят за изначальными обязательствами по контракту, а требования от заказчика всё поступают и поступают. Деньги начинают звенеть прибылью, а не отбиванием расходов на разработку платформы и прототипов. У начальства и других недальновидных участников процесса возникает ощущение свободы действий.
— Клиент уже никуда не денется.
— Архитектура нужна была в платформе, а у нас конкретный проект.
— Мы допиливаем, а не строим.
И всё в духе «Après moi le déluge». Поэтому чувствуя, что дом уже стоит, и нужно только обустроиться внутри, эффективные люди начинают оптимизировать пространство, снося стены. Пока архитектор будет пытаться защитить несущие конструкции и указать, где проходит вода и электропроводка, начальство примет «непростое решение» отказаться от его услуг в этом проекте и направить энергию и опыт в другое русло. И сцену займут те, кто не спорит. Когда в руках только кувалды — что стены, что гвозди…
Дабы не быть голословным:
Как я упоминал, в уходящие проекты я приходил в конце. И чтоб хоть как-то ознакомиться с происходившим, делал код ревью. В последний этап больших изменений почти нет. Собственно, отказываются от легаси именно потому, что изменения почти невозможны. Так что мне хватало день-два, на то, чтоб просмотреть весь прошлый спринт. И тут было так много интересных историй, что я даже сделал дайджест и раз в месяц слал в группу подборку знатных кусков шоколадного кода.
Есть лёгкие глупости типа:
Log.Debug(string.Format("starting visitor: {0}", visitor.GetType().Name);
Раньше было больше параметров, но потом золотые руки добрались и убрали лишнее. Оставив при этом ставшее неуместным форматирование.
А есть и хардкор с использованием цикла с одного элемента:
var promoConditionTypes = GetPromotionConditionTypes(promotionRequest)
.FirstOrDefault();
foreach (var promoConditionType in promoConditionTypes)
{
SetThreshold(promoConditionType);
return;
}
Если посмотреть коммит, то видно, что последний разработчик просто добавил .FirstOrDefault(); Не утруждаясь изменить следующую строку — он же её не писал, а читать явно не в его стиле.
Так получаются подобные шедевры:
_stringBuilder.Append(
String.Join(" ",
description.Select(c =>c.Culture+" "+c.Value+" "+c.Type+" ")
.OrderBy(descriptionStr => descriptionStr)));
Заметьте, что код писали опытные разработчики, с парой лет опыта в этом проекте.
Откуда растут руки-ноги? Я не менеджер и точно не психолог, но у большинства наблюдаемых похожий симптом: «чукча — не читатель, чукча — писатель». Проект долгий и большой, так что разработчики сидят в своих командах и постоянно варятся в собственных соках. Им дают задания и баги, связанные с этими заданиями. Всё время у них своя экспертиза, предметная область и удобное болото из кода, который они пишут. Родное. Теплое. И почти не пахнет. А потом, вдруг, продуктовый бэклог тает, возникают новые проекты, и многие уходят туда. Но наши герои не любят перемен. Так что, вместо 5 команд остаются 2, почти полностью из заложников зоны комфорта. И тут их мир рушиться. Они оставались, чтоб дальше сидеть в своём тёплиньком, а их объединили и перемешали, сделав ответственными за всю кодовую базу. Поэтому сознательно или нет, они работают так, чтоб писать как можно больше своего и меньше разбираться с существующим. Отсюда и желание пробить новый проход, чтоб не искать ключ от двери. И пристраивать балкон для нового холодильника, чтоб не дай бог не двигать мебель на кухне. Конечно, старый холодильник тоже оставим. Максимум — отключим от сети и повесим записку «Балкон ходить».
Расцвет Николаев.
символ верховной власти
И раз уж вокруг так много костылей, то никак не обойтись без тех, кто может заставить это чудо ходить. Поэтому даже в плодоносящем продукте есть настоящие часовщики и механики — отличные инженеры, знающие весь код и бизнес, с историями и сплетнями. Такие вот титаны, держащие на плечах менеджеров с шестёрками и шестерёнками. Такие люди — единственный шанс увеличить производительность или разработать всё необходимое для новой сертификации в старом проекте. Решения могут быть сложными костылями, но всегда работают, не ломая продукт. Если вам уже стало интересно, почему же солидные доны сидят в старом проекте, а не строят новый ракетный двигатель? Обычно ответ прост. Потому что доны, хоть и ушлые, но токсичные и душные. Никто с ними работать не может. Да и им самим не очень-то и хотелось. Так что остаться в болоте среди тех, кто не хочет понимать продукт — выбор стратегов. Может нелюдимых гениев и сторонятся, но все понимают, что без них накроются медным тазом все должности, где хотелось бы золотой парашют. Как-то раз пришлось писать фасад драйвера спец. клавиатуры (что-то типа программируемого Numpad для монитора), так как оригинальные уже не выпускали. А на месте могли быть и старые и новые устройства. Никто из любимчиков начальства такую задачу взять не согласился. А вот нелюдимый дядя с сигаретой сказал, что это звучит интересно. И осилил несмотря на отсутствие документации у китайских девайсов. Возможно, осознание собственной незаменимости приводит к самокоронации. А любая попытка понять, вмешаться или подправить работу — в агрессию против института самодержавия, либо, что еще хуже, попыткой занять кремниевый трон!
Игры престолов:
В процессе разработки нового продукта возникла необходимость создание адаптера для лёгкого перехода от легаси системы к новому решению. Сама задача не сложная: в новой системе один вызов API, а в старой необходима последовательность двух. Во время параллельной работы (когда на одной точке одновременно работают и новая и старая версия) следует избегать двухголового управления. Если процесс начинает система А, то система Б пассивно исполняет указания. И наоборот. Таким образом в сложной цепочке узлов процесса не возникает разногласий и всяких проблем конкуренции. Как часть установки нового продукта, нужен был патч (upward compatibility) старого контроллера. Что то, что помогло бы создать согласованность действий. Пусть даже не транзактивность, но хотя бы возможность отката команды 1, если команда 2 не прошла. Так вот этот софтверный контроллер уже лет 5 в одиночку поддерживает Николай — последний из первоначальной команды разработчиков. Специалист в предметной области и технологии. Я посылаю ему имейл с парой тройкой вариантов решения и просьбой присоединиться к обсуждению. В ответ получаю просто: «Нет». Я пытаюсь дозвониться — три дня полный игнор по всем каналам. Я подключаю его менеджера и своего (CTO) в придачу. Через пару дней согласовали встречу. На ней Николай сказал, что эти две команды его устраивают в том виде, в котором они есть. А если мы хотим заменить его контроллер, то можем идти и писать свой. Чтоб осознать абсурдность, стоить сказать пару слов о самих командах. В новой системе есть команда «Открыть», а в старой «Открыть замок» и «Открыть крышку». То есть всё что нужно — закрыть замок, если крышка не открылась по какой-то причине. Никаких физических или логических ограничений в ходе обсуждения не выявили. Просто Николай не занимается «ерундой», которая только «портит» его продукт, который «уже 10 лет без нареканий», ради какой-то «новой херни». Я немного опешил, но в конце концов, я архитектор и никем не управляю. Пусть этим занимается начальство. СТО идёт к генеральному. Гендир присылает гневное письмо с вызовом Николая на ковёр и обещанием нашей команде, что всё уладят. Через пару дней всё тот же Великий Завоеватель Рынков, Даймё разработчиков и Отец продажи, уважаемый Ген Дир пишет, что, пожалуй, нам надо как-то продумать альтернативы и обойтись без изменений старого софта…
Остатки развитой цивилизации.
Так как особо ценные сотрудники не особо ценят всех остальных, то в потоках их гениальности и презрения, обветшалый кораблик начинает кидать из стороны в сторону. Пара корабельных мастеров и матросов способны держать посудину на плаву. Но вот не задача — за фарватером никто не следит. Курс в основном прокладывают крысы — как только они начинают сбегать с корабля, значит пора разворачивать штурвал в другую сторону. Вокруг валяются карты и приборы, но вот кому и зачем они? Пока всё идёт хорошо, начальство видит только то, что штат команды «раздут». И вообще, то, что работает — лучше не трогать. А значит, чем меньше рук, тем меньше и риски. Ириски любят делить на всех. Людей переводят, они и сами уходят, а с ними и знания о не документированных особенностях и внутренних договорённостях. И каждый кусочек пазла приходится восстанавливать через болезненный опыт. Поменяли старый USB кабель и сожгли контроллер. Сменили операционку и не нашли драйвера. Обновили сторонний пакет программ и всё посыпалось. Граблелицевая археология как модель познания мира. Самый распространённый симптом проблемы — никто не говорит о проблемах. Чаще всего сменяются команды поддержки. Их любят аутсорсить там, где подешевле. Ганг не стоит на месте и текучка кадров большая. А вот конфигурацию, администрирование и техническое обслуживание остаётся близко к клиенту. И изменения в продакшине дело не сиюминутное. Через много месяцев выясняется, что система всё ещё шлёт алерты на какой-нибудь ящик, пользователя, который давно покинул компанию, а пароль от дублирующего/основного забыли/потеряли год назад и вообще работают без него. Поэтому обо всех ошибках и потенциальных проблемах никто не знает. Хуже всего, когда забывают узнать у уходящего сотрудника пароль от сертификатов или мастер пароль базы. К сожалению, этим страдают, как и молодые компании, в которых такие процессы еще не налажены, так и крупные компании со сложной иерархией — у семи нянек…
Воспоминания о боли.
Как я и говорил, свои проекты я ещё не увольнял. Но вот похожий казус пережить пришлось. Некстген славен широкой продажей. Куча потенциальных клиентов и демок. Кое где всё решается быстро, а кое где всё затягивается удавкой на шее. Но выбирать клиентов в начале не приходится. На рынок надо пробиться, так что продукт суют везде. Один из потенциальных «потенциальных покупателей» вообще не шибко то и подходил под профиль — мелковат и не богат. Но поморочили они нам голову с годик и дошли до пилотного запуска в паре мест. А потом отказались. Ну вроде бы и разошлись достойно, и головняка меньше. Проходит пару лет и новый менеджмент в увеличившемся бизнесе случайно обратил внимание, что есть более удобная система и в плане отчётов, и в возможностях управления (правильно, мнение работников их вообще не волновало). И вот они приходят с большим чеком и требуют продолжения банкета. Кто ж будет спрашивать архитекторов при таком раскладе? Ну, а продукт уже сильно изменился и по возможностям, и по стеку. Там уже никак нормально не замерджить или апгрейднуть не выйдет. Прошла волна крупных и содержательных бесед внутри компании. Так как деньги уже взяли, а мозгов, похоже, никогда и не было, нашли временное решение — взять с гита старый код и собрать ту версию, что еще работает у клиента. Это даст отсрочку и позволит сделать позже нормальный процесс апгрейда. Собрали, отдали, расширили пилот на пару сотен установок, но тут начались проблемы. База как-то быстро росла, локальные данные как-то расходились с центральными отчётами… После тщательного и сложного расследования выяснилось, что команда поддержки новая (и не местная), привыкшая к последней версии софта и другому стеку компонентов, не знала, что DLQ выполнен табличкой в базе данных, а не средствами очереди. Так что ни об ошибках синхронизации, ни об самой очереди недоставленных сообщений никто не заботился — эта часть знаний была утеряна в ходе естественной эволюции.
Я, в силу фокуса на софте, мало привожу примеры про железо, но там в плане магических артефактов всё еще круче. Градус понимания начальства давно ушёл в минус, причем в Кельвинах. Если эффективный менеджер смотрит в код, то обычно его понимание сводиться к чтению по-английски и прецедентному праву: «соседняя команда тоже делала routing и у них был всего 1 sprint в estimation, а вы мне тут в начале года про Q3 втираете!». А вот с периферийкой они же визуально знакомы. «Вот тут кабель HDMI дорогой, а мы у китайцев взяли за ⅓ цены! Представляешь какая экономия для компании с нашими то миллионами устройств!». Представляю. Ведь Мастер по Закупкам просмотрел все спецификации и в какой среде это будет использоваться, а теперь на глазок может определить какой из стандартов нам нужен. И это так мы выучили урок, что не все USB кабели одинаково полезны. Ну, видимо, чтоб научиться определять на глазок, да на зубок, малый совет нашего королевства решил начать с жопы. Так что не удивляйтесь, когда очередной выпускник MBA оповестит вас постфактум, что он решил поменять мониторы с тачем «с убого резистивного, на современный ёмкостный». Да еще за пол цены! А то ведь не возможно нормально пользоваться и презентации отталкивают инвесторов. Теперь у нас как яблоки из силиконовой долины! Большие, круглые и на ощупь не отличимы от настоящих! Особенно в защитных перчатках работника цеха, которому потом этим экраном пришлось бы пользоваться. И всё же у меня потребительское понимание устройств, а когда приходится общаться с нашим отделом разработки контроллеров, то те на комплименты модернизаторам не скупятся. Я быстро стал понимать, почему высадка на луну в 2020 — это разработка с нуля, а не «можем повторить 69-й».
Цикл жизни.
Процесс создания айфонов https://www.differencebetween.com/difference-between-vertical-and-vs-horizontal-gene-transfer/
В программном мире, как и в природном, жизнь кратковременна и поколения сменяют поколения, передавая в будущее гены — функции и признаки успеха. Экономическая эффективность же. Новую собаку всегда учат старым трюкам — все простые и грубые решения прошлого. Все как в жизни — низкий интеллект легко масштабируется. Так что, даже если технологически ваш свежий продукт будет совсем другим, все применимые практики перейдут в него из старого софта, всевозможных прототипов и того, что помогает подписывать договора. Ну и каждый клиент, работающий с легаси вашей компании, захочет вытащить из него как можно больше данных в новую систему. Экстракция, сама по себе, не сложная технически задача. И в этом кроется ошибка. Все стараются перевести это в русло чёрной работы — долгий, нудный процесс, но без особой мысли. Любой дурак справится. Наверное, похоже на управление проектом (no pun intended). Однако, несмотря на всю противоречивость моего заявления, советую к нему прислушаться: «экспорт старых данных имеет ценность лишь при возможности их импорта в новый продукт». А это значит, что задача должна перекочевать в продуктовую плоскость. Попытаетесь закопать голову в песок и на каждой стадии вас будут присыпать еще больше, пока окончательно не похоронят в пилотке. Причём продукта нового, так как именно там должны быть продуманны случаи несоответствия ожиданиям:
Не полные данные. Структура данных новых систем обычно сложнее, так как нынешние тенденции — это сбор информации и мультиканальность процессов. Иногда разница просто огромна. В таких вариантах выгрузка вообще имеет мало смысла и тогда используют агрегацию. Некоторым системам просто нужны какие-то стартовые значения. Так что либо последние (если говорим о допустим о позиции манипулятора), либо какие-то средние (когда речь о показателях прибыльности или производительности), а иногда и сумма (состояние сейфа).
Анонимность. В старых системах об обезличивании данных не думали, да и требований таких не было. В новой уже другие условия. Однако для клиента это будет выглядеть потерей функциональности или информации. Я столкнулся с этим в системах оплаты. Легаси тупо хранила номера кредиток и это позволяло проводить транзакции позже, повторить попытку или сделать возврат постфактум. В новой системе была PCI DSS сертификация (вместо номера был хэш и маска) и такая магия уже работала. Отдел продаж сразу поднял руки, так как у них была официальная LFL стратегия в подходе к существующим аккаунтам. Продакт же настаивал, что это ошибка проектирования.
Разная глубина истории. Исходит из первого пункта, но если перевести на язык таблиц, то первый пункт про столбцы, а этот про строки. В новой системе не может быть заказа без имейла. И все отчеты по импортированным транзакциям со вшитым join-ом по этому полю идут… Ну, в общем, к вам много кто придёт, после тестов — крайний тот, кто «раз такой умный то, чего же не предупредил?».
Регуляции. Особенно тут сложно с фискальными данными. Требование хранить их годами есть везде, где мне приходилось работать. И тут очень важно поднять вопрос о целесообразности импорта как такового. Почти всегда решение — отдельный монолитик со своей базой для листания и распечатки истории, как я и упомянул в предыдущем посте.
В идеале за год до конца службы продукта надо подготовить все инструменты и API. Конечно, никто не готовится заранее, только если это не было оговорено в контракте (ни разу не видел нормальных требований). Но, если вы должны предоставить доступ сторонним участникам, то лучше заранее считать их врагами. Убедитесь, что везде есть авторизация и доступ только на чтение (иногда внутренние инструменты делают без подобающей защиты, а добрый delivery менеджер делиться ими с клиентом и партнерами). Ограничивайте количество данных и запросов, чтоб не нагружать систему. Миграцию обычно отдают джунам-арджунам, а те предпочитают учиться наживую. Лишние стрессы вам не нужны, так что с одной стороны выгрузка должна быть свободно доступна, просто по талонам, а с другой стороны пулемет на вышке пока снимать не стоит. То же самое и к импорту. Мы же не хотим, чтоб после удачной проверки на системе тестировщика, где данных было лишь на пару недель, кто-то бы положил прод попытавшись впихнуть туда базу за годы. А значит не рассчитывайте, что импорт удастся за раз.
Процесс стоит сделать асинхронным и прозрачным (показывать статус, давать возможность прервать или притормозить).
Хорошо бы сделать импорт сегментированым. С возможностью выбора периода и/или типов данных.
Обязательно делать импорт обратимым. Если что-то сорвалось — мы не хотим отравить систему.
И это все, что я могу сказать о войне во Вьетнаме. На правах послесловия:
Кадр из фильма Equilibrium и томик Йейтса
Но я бедняк и у меня лишь память о некотором дерьме,
Я простираю этот опыт свой тебе под ноги,
Ступай же по нему легко, теперь говно топтать тебе.