Памятка архитектору
Я работаю архитектором (Solution Architect если быть точным) в аутсорсинговой компании. В ходе работы я занимаюсь такими активностями как: дизайн и внедрение архитектурных решений, аудит систем заказчика и разного рода консультации вокруг архитектуры систем.
Иногда в разговоре с коллегами я говорю «спокойно, действуем ровно по учебнику». Но тут есть большая доля лукавства, т.к. одной книги где были бы собраны базовые принципы я так с ходу назвать не могу. По большей части это сборная солянка из разных книг, личного опыта и историй, рассказанных коллегами. Что-то освещено в одной из книг Фаулера, что-то есть в курсах от AWS.
В статье я решил собрать вместе список общих принципов, которых я стараюсь придерживаться, приступая к очередной задаче.
Сгенерированно нейросетью https://midjourney.gitbook.io/docs/
Идите от проблемы
Это немного смешной пункт, он должен идти под номером ноль. Я бы его не писал если бы не видел так много случаев, когда дизайн решения делался без понимания проблем, которые этот дизайн решает.
Грубо говоря, есть типовые архитектуры для разных случаев (например «трехзвенка с SPA для веб приложений»), их не так много. Если вы видите, что задача решается одной из типовых архитектур и никаких проблем или специфических особенностей нет, но на этом с дизайном архитектуры стоит остановиться.
Для лучшего понимая, приведу пример. Обсуждаю с cloud architect заказчика некую подсистему, опуская подробности, все на 100% сводится к классической архитектуре с микросервисом и синхронной записью/чтением записей в/из РСУБД. Вот буквально ничто из нефункциональных требований не указывает на то, что надо что-то изобретать более сложное. Более того есть жесткое требования синхронности. Архитектор — «нам нужна Кафка. Кафка — это круто». Я интересуюсь — «зачем тут Кафка т.е. что она такого добавит, что без нее не сделать (так сказать задаю вопрос — Чтобы что?)». Получаю в ответ «Кафка — это очень хорошая технология у меня экспертный опыт с Кафкой». Я полностью согласен с тем, что Кафка крута, но сюда то она каким боком? Можно, конечно, придумать решение с Кафкой, но зачем?
Короче не будьте как он. Если нет проблемы которую типовая архитектура не решает — не надо ничего изобретать.
Предупреждая возможные комментарии «Может быть было требование использовать крутую модную технологию для привлечения разработчиков». Да такое бывает. Это объективный фактор, о таком надо знать, но тут такого не было.
Всегда решать конкретную проблему
Предыдущий пункт на несколько другой лад. Решать надо всегда конкретную проблему, сформулированную в деталях. Нельзя сделать всех людей счастливыми, но можно попытаться помочь конкретному человеку с конкретной проблемой. Также и с системами. Строя дизайн системы надо точно понимать какие у нас конкретные проблемы, в конкретных подробностях и сколько у нас всего проблем. Т.е. желательно иметь полный список, а не решать каждую из проблем по отдельности, по мере их появления. Внезапно, на кануне релиза.
Говоря о конкретных деталях, я имею в виду, например такое: «система должна справляться с большим количеством одновременных пользователей». Это хорошее не функциональное требования, но оно бесполезно без понимания в цифрах «много это сколько конкретно» и говорим ли мы тут о спайках в несколько минут или о постоянной нагрузке часами. Опять же, что значит «справляться» — это скажем показывать latency < 3 сек для 95% пользователей или не выдавать 500-ю ошибку чаще чем раз в 5 запросов. Все это имеет большое значение при дизайне.
Приведу пример, на AMA сессии архитектурного борда был вопрос «как лучше подходить к инвалидации кэша». Без понимания конкретики ответить на вопрос нереально. Для начала надо хотя бы понимать, что это за кэш — кэш статических ассетов веб приложения или кэш пула соединений с базой данных в Apache Tomcat.
Другой способ подумать о конкретике это то, что называется «KPI & metrics of success». Иначе говоря, надо постараться понять, как выражается успешность вашего решения в как можно более четко квантифицируемых терминах
Типовая архитектура — это здорово
За десятки календарных лет и миллиарды человеко-лет, индустрия выработала типовые решения для типовых задач. Чем типовые решения хороши.
1. В них как правило нет серьезных сюрпризов. Все типовые грабли за вас уже собрали сотни миллионов людей, которые шли по этой дороге перед вами.
2. Их знает большинство разработчиков, шанс, что вашу задумку неправильно поймут заметно снижается.
3. Когда через 3 года команда полностью сменится и другие люди будут пытаться понять, что тут происходит — они не увидят ничего принципиально нового для себя. Что означает что они смогут легко включиться в работу и приносить пользу заказчику.
Знайте и любите типовые архитектуры. Каждая строчка там это боль и протраченные деньги миллионов людей, которые пробовали разные другие варианты.
Так нейросетка видит типовые решения
Есть конечно у типовых решений недостаток — они типовые, несколько скучные, сюрпризов там нет и развлечься с ними как правило не получается. Впрочем заказчку лучше этот аргумент не приводить.
Проблему всегда надо решать в контексте организации
Закон Конвея гласит «Организации проектируют системы, которые копируют структуру коммуникаций в этой организации». На самом деле в наше время это не совсем так хотя бы потому, что в компаниях чей бизнес строится вокруг информационных продуктов все может быть устроено наоборот — орг структура частично копирует структуру системы.
Более широко я бы сформулировал бы так — при проектировании решения надо учитывать с какими орг структурами заказчика надо будет взаимодействовать в процессе разработки и эксплуатации решения.
Особенно если заказчик — это крупная энтерпрайз компания — изучение SDLC и PDLC процессов может принести вам много интересных открытий. Для начала надо иметь ответы на вопросы
· Как устроены стандартные PDLC & SDLC практики
· С какими орг структурами внутри заказчика ваше решение будет взаимодействовать
· Каковы интересы и modus of operandi ключевых стейкхолдеров этих структур.
· В рамках чьих бюджетов ваше решение будет развиваться и существовать.
Последние пункты сильно залезают на поле психологии, бюджетирования и тому подобных не инженерных вещей далеких от архитектуры. Но если есть возможность это прояснить — лучше всегда как можно четче понимать за чей счет весь этот банкет и сколько этот человек еще готов/рассчитывает потратить денег. Предлагать решение за 10+ млн тому, кто готов потратить не больше двух в принципе — так себе идея.
Есть мнение, что система всегда делается для конечных пользователей. Что в целом верно. Но по факту в корпоративном окружении от конечного пользователя конкретно вас иногда отделяет столько слоев, что этим можно пренебречь. К сожалению. Грубо говоря тут все сложно, старайтесь в каждом конкретном случае в этой сложности разобраться.
Нельзя решить проблему просто нарисовав/документировав решение
Можно написать хорошую документацию, которую один черт никто не читает. Никто не читает документацию, а те, что читают все равно делают не так, как было написано, оправдываясь тем, что они же понимают, что вот эта стрелка RPC вызова на диаграмме от Сервиса А к Сервису Б это метафора (реальный случай, они так и сказали — метафора). А на самом деле надо было делать совсем по другом, и они так и сделали. Документировать безусловно надо, но не стоит документацию переоценивать.
Имплементацию архитектуры надо лидировать. «Держать команду за руку», объяснять тонкие моменты (а тонким может неожиданно оказаться что угодно), проверять как сделано и давать советы в мутных случаях. Особенно на начальном этапе. По-другому это, к сожалению, не работает.
Это не значит, что архитектор должен заменять собой тимлида, но строить взаимодействие с командой (командами) надо. И надо делать это хорошо. Обязательно надо периодически щупать решение руками от заглядывая в код слева, на право по SDLC от требования до мониторинга приложения, развернутого на рабочем окружении (если prod не доступен, то надо смотреть на самое старшее из доступных окружений).
Крайне желательно раз в несколько месяцев делать руками полный цикл изменения кода. Обычно это выглядит так:
· Взять в спринте маленькую задачу на час-другой работы
· Написать код, протестировать, создать PR, пройти ревью, смерджить в релизную ветку
· Пройтись по процессу деплоя. Тут все сильно зависит от того как этот процесс устроен- важно пробежаться по всем шагам и понять как ваше конкретное изменение по ним бежит.
Это часто позволяет идентифицировать пробелы в дизайне, которые с высоты птичьего полета разглядеть невозможно.
Уточню, для чего это нужно. У вас может быть сколь угодно прекрасная архитектура на верхнем уровне, но если для того, чтобы все работало вместе, людям с лопатами на местах надо соединять две либы при помощи проволоки, лома и не скажу, чего еще, пытаясь впихнуть невпихуемое и другого варианта объективно нет, то проблема конкретно у вас в архитектуре, а не в совместимости компонентов. При этом, к сожалению, бывает так, что понять это можно только взяв лопату в руки и поработав ей хотя бы с полдня.
Дьявол в деталях
Прежде чем предлагать решение, основанное на каких-то технологиях, надо убедиться, что они работают вместе именно так как было вами задумано. Часто недостаточно сказать «возьмите библиотеку X, протокол Y и запустите на платформе P». Прежде чем делать большую ставку на какое-то решение, надо убедиться, что все компоненты работают друг с другом.
Бывает так, что у вас есть опыт и понимание как каждый из кубиков работает по отдельности, но, когда вы их собираете вместе могут быть неожиданные побочные эффекты. Для решения таких проблем есть концепция скелетного прототипа. Это скелет системы, который содержит все ее части и прокидывает один самый простой запрос (часто это «сложить, а и б») через все компоненты системы с самого верха до самого низа.
Приведу пример. Меня просят помочь с интеграцией нашей команды в проект заказчика. У заказчика есть довольно подробно нарисованная система на базе BPML, GraphQL и т.д. (подробнее писать не буду вдруг они эту статью прочитают). В идеале все должно работать хорошо. Уже 4 месяца несколько команд работают над реализацией разных частей большой системы. Я начинаю задавать вопросы, выясняю, что все вместе «в сборе» никто не запускал. В центре всего находится сервер, который должен преобразовывать GraphQL в SQL. Этот сервер надо конфигурировать. Но как будет выглядеть процесс сохранение в git конфигурационных файлов 5-ю разными командами для сотен таблиц никто не думал. За две недели мы выяснили что часть библиотек работают не так как мы думали и в принципе не поддерживают ряд функций, которые нам нужны и часть кода, написанного другими командами, надо переписать.
Дьявол еще более в деталях
Когда я говорил о проблемах, которые архитектор решает, а нашей повседневной жизни где мы не строим ИТ системы Марсианских куполов-хабитатов, большинство проблем лежит в области не функциональных требований. Не все, но точно больше половины.
Сюда входит:
· Latency
· Max throughput
· Контракт на сохранность данных/Транзакционность/Атомарность операций
· Отказоустойчивость/SLA/Возможность работы в multi-DC режиме
· И многое другое, например ограничение по количеству ключей/таблиц/коллекций для конкретного сервиса и т.д.
Надо все эти вещи понимать и уметь относительно них валидировать компоненты придуманного вами решения.
Простой пример — мы придумали сохранять электронные чеки покупок в Redis, ключ — UUID чека, значение — сам чек, Json структура размером скажем в 3 килобайта в среднем. Вопрос в какие не функциональные ограничения Redis в какой момент мы упремся? Поможет ли нам кластер? А что делать если не поможет? А если нам нужна отказоустойчивость на случай падения одного из дата центров?
Проблему надо решать на том уровне, на котором она решается
Бывает так, что запрос, с которым заказчик к вам приходит выполнить не реально. Скажем у заказчик хочет настроить Multi-Master репликацию в кластере из 20 PostgreSQL серверов и спрашивает совета — как это сделать. Сделать это скорее всего нормально нельзя никак. Но можно попытаться узнать, зачем ему такое понадобилось и подумать — нельзя ли решить проблему другим образом.
Собственно, в любом случае, даже когда решение очевидно имеет смысл, стоит отступить на шаг и подумать, а нет ли другого, более простого решения и нужно ли проблему решать в принципе.
Самый забавный случай иллюстрирующий этот аспект произошел лет 10 назад. Заказчик обсуждал с нами создание системы для решения определенной бизнес-функции. Все шло к подписанию договора и началу разработки, пока на одном из звонков наш архитектор не спросил — «а почему вы вот так вот не поменяете бизнес процесс?», на что заказчик завис на пару минут и ответил «а точно, мне тогда система и не нужна вовсе», на чем все обсуждения закончились, нам сказали «спасибо». Но проект не случился.
Знать альтернативные варианты
Мир IT объемен и разнообразен. Одну и ту же проблему часто можно решить десятком разных способов. Причем из этого десятка три штуки откровенно плохие, три суперклассные, но каждый имеет свои плюсы и минусу. Остальные «решения идентичные настоящим», при определенных обстоятельствах работают, при определенных разрывают систему в клочья.
Часто заказчик приходит с вопросом «У меня не работает X c Y» и работа архитектора сводится к вопросу «А вы пробовали N вместо Y?» на что заказчик отвечает «N? Никогда не слышал, какая клевая шутка!»
Важно про каждый компонент решения понимать — какие есть альтернативы и какие у альтернатив достоинства, и недостатки.
Что дальше?
Чтение этой статьи не сделает из вас архитектора. Это скорее шпаргалка, на что обратить внимание работая с конкретной задачей. В качестве дальнейшего шага бы порекомендовал почитать например «The 6 Pillars of the AWS Well-Architected Framework» (https://aws.amazon.com/ru/blogs/apn/the-6-pillars-of-the-aws-well-architected-framework/) это тоже чеклист, но под другим углом.
Ну и в целом полезно время от времени сверяться с
рекомендациями по построению архитектуры от крупных облачных провайдеров. Я
лично эти рекомендации воспринимаю некоторой долей скепсиса, но и совсем
вредных вещей там тоже не посоветуют.