Привет, меня зовут Алексей, я системный архитектор e-commerce платформы Lamoda, и в этом посте — мое представление о том, чем на самом деле занимается ИТ-архитектор, какие вопросы решает в ежедневной работе и за что несет ответственность.

Сцена из фильма "Начало"
Сцена из фильма "Начало"

С начала 90-х ИТ-сфера сильно эволюционировала, и роль архитектора (я не буду говорить о профессии, потому что считаю, что как таковой ее у нас нет) развивалась вместе с ней. В 2021-ом перед ним стоит задача куда шире, чем проектирование. Он как архитектор зданий, которому нужно не просто построить условный дом, но и вписать его в окружающий контекст, включить в существующую экосистему. Архитектор принимает решения о важных вещах, выступает катализатором изменений, которые нужны проекту. Он использует нарративы, описывая, как должны выглядеть системы и какие паттерны использовать, чтобы команда могла их одобрить и реализовать.

«Чем мы вообще тут занимаемся?»

Этот риторический вопрос я иногда задаю своей команде, выдергивая их из привычного потока мыслей и рутинных задач. «А занимаемся мы перекладыванием JSON-ов, вот чем!» — сам же и отвечаю. Выражения лиц меняются с задумчивых на изумленные. Этой «провокацией» я делаю акцент на том, что происходит в программах, если убрать удобные абстракции привычных фреймворков и библиотек. Именно передача и координация являются нетривиальными задачами, хотя часто разработчики видят сложность совсем в других местах.

Мы разрабатываем приложения, которые выступают отдельными независимыми агентами в мультиагентной среде и обмениваются между собой сообщениями. Агентами могут выступать люди, которые взаимодействуют с приложениями, и другие системы, которые разрабатываются другими отделами, но также обмениваются с нашими приложениями сообщениями. JSON в данном случае выступает как условность, формат и протокол в действительности могут быть какими угодно.

JSON-ы принято обрабатывать: сериализовывать для передачи по сети и десериализовывать в модели для удобства обработки. Модели принято хранить в структурах данных в памяти и на диске для оптимизации операций записи и чтения. Все становится интереснее, когда мы хотим обрабатывать одновременно не один, а два JSON-а. Тут придется озаботиться, чтобы они друг другу не мешали и не нарушали задуманный порядок вещей. Задача перекладывания JSON-ов не является тривиальной, но должна оставаться простой.

Что важнее: доступность или согласованность

Опытные инженеры, среди которых есть и архитекторы, ежедневно работают для того, чтобы круглосуточно на отправленный запрос в нашу систему выдавался верный JSON за приемлемое время. Например, создание заказа. Для e-commerce это критичное место: нужно провалидировать соответствие всех условий, корректно зарезервировать товары и оповестить все заинтересованные стороны о новом успешном заказе. Все это должно происходить за доли секунды и отвечать ожиданиям кастомера.

Между кликом и созданием заказа проходит меньше секунды. Клиент получает уведомление, что всё прошло успешно.  И менее, чем через минуту, заказ уже собирается в фулфилмент центре Lamoda.
Между кликом и созданием заказа проходит меньше секунды. Клиент получает уведомление, что всё прошло успешно. И менее, чем через минуту, заказ уже собирается в фулфилмент центре Lamoda.

В распределенной системе, когда у нас множество сервисов общаются между собой по сети, нужно выбирать между доступностью и согласованностью. Невозможно обеспечить одновременно и то, и другое, необходим компромисс. Более того, в каждом конкретном случае нужно адекватно выбирать модель согласованности. Да и доступность тоже не ограничивается числом успешных ответов.

Расширим круг действующих лиц. Добавим во взаимодействия команды разработки, которые постоянно вносят изменения, а также бизнес, который требует улучшений и развития.

Еще один пример. В Lamoda, как и в любой крупной e-commerce компании, существует большая система обработки заказов. За более чем 10 лет домен нашей системы вырос и многократно усложнился, как и ее ответственность за все ту же согласованность и доступность. Сама система и ее сложность появилась не просто так и не была результатом проектирования архитектора-маньяка. Ее создали люди, которые приняли сотни решений, а эти решения привели к тем результатам, которые мы видим сейчас. Нужно отдать должное этим людям, так как система выполняет возложенные на нее требования. Проблема только в одном — вносить изменения стало крайне проблематично. И решение этой проблемы нельзя назвать тривиальным, но оно должно быть простым. Как и в задаче с обработкой JSON-ов.

Какую задачу решает архитектор

У меня есть задача: построить систему взаимодействующих между собой сервисов. Они должны работать как единое целое, обеспечивать бесперебойную работоспособность большого и сложного e-commerce, который растет и развивается. При этом я должен учитывать десятилетний опыт legacy системы.

Отсутствие понимания, что делают существующие системы и как должны быть спроектированы будущие, является основной причиной того, что инициативы по глобальному рефакторингу слишком затягиваются, слишком дороги и иногда просто терпят неудачу.

Другими словами, моя задача — управлять сложностью поддержки и развития. Не уменьшить, не препятствовать росту, а именно управлять. Настроить разработку в домене обработки заказов так, чтобы она была понятной, предсказуемой и стабильной.

Чтобы построить такую работающую систему, нужны технологии и практики, инструменты и компетенции. Опыт внутренней разработки в виде инструментов и инженеров, которые используют и развивают эти инструменты.

Как развивалось понимание архитектуры и обязанностей архитектора

В 1990-х годах архитектура рассматривалась как «набор структур, которые представляют собой абстракцию поставляемой системы, необходимых для работы с растущей сложностью типичных программных систем». С этой точки зрения, основные обязанности архитектора заключались в создании (визуальных) моделей системы и их использовании для проверки архитектуры.

В начале 2000-х фокус ответственности сместился: архитекторам нужно было принимать важные решения, чтобы создавать правильные модели («правильные» означают, что они удовлетворяют потребности заинтересованных сторон). Если «абстракция» и «структуры» описывают то, что создает архитектор, то принятие решения относится к тому, как они создаются.

Примерно в 2010 году, отчасти из-за стремления фокусироваться на ценностях бизнеса, к что и как добавляется для чего. Цель архитектуры — улучшить контроль над рисками и стоимостью, поэтому архитектор отвечает за это не только на стадии проектирования, но в процессе реализации своего решения.

Но есть условие, без которого архитектор не может выполнять свои обязанности правильно — это понимание контекста, т.е. знание заинтересованных сторон, их потребностей и окружения, в котором нужно реализовать решение.

За что отвечает современный архитектор

Таким образом, обязанности архитектора заключаются в том, чтобы:

  • понимать контекст;

  • принимать решения;

  • создавать модели;

  • валидировать дизайн;

  • реализовывать и поставлять решения.

При этом одни пункты из этого списка влияют на выполнение других. Например:

  • моделирование и принятие решений без понимания контекста приводит к построению неадекватных моделей; 

  • моделирование фактически подразумевает принятие решений (о декомпозиции, взаимосвязях);

  • без моделирования и решений нечего валидировать;

  • реализация и поставка не валидированных решений приводит к проблемам.

Т.е. самого по себе выполнения описанных обязанностей недостаточно. Они должны выполняться согласованно между собой.

В зависимости от ситуации, каждому пункту нужно уделять внимание. Пропуск одного из них приводит к антипаттернам роли архитектора, которые все мы периодически наблюдаем по статьям и обсуждениям в сообществе.

Один из ярких примеров — The Waterfall Wasteland, когда архитектурная команда занимается дизайном в отрыве от проектной и не вовлекается в ежедневные активности, в результате чего растет время между проектированием и доставкой в продакшен. Совместная работа с проектной командой дает важную обратную связь, без которой легко оказаться в «Башне из слоновой кости» (The Ivory Tower Architect).

С другой стороны, есть пример The Agile Outback, когда в страхе перед Ivory Tower проектирование считается излишней практикой или даже контрпродуктивной. Вместо этого команда получает фидбэк от реализованных ошибок. Такой подход может быть выгодным в начале, но вскоре приводит к серьезным затруднениям.

Как я решаю свою задачу через призму этих обязанностей

Напомню, что мне и моей команде нужно построить систему взаимодействующих между собой сервисов, которые должны бесперебойно работать как единое целое.

Раз архитектура — это принятие решений о важных вещах, то в первую очередь нужно выстроить прочный скелет, на который можно уверенно наращивать все остальное. В нашем случае это согласованность и доступность JSON-ов, о которых я говорил в начале. Ко всему прочему, в распределенных системах невозможно избежать ошибок, поэтому мы проектируем с учетом того, что ошибки будут всегда. И мы должны свести их влияние к минимуму, обеспечить доставку сообщений, целостность локального состояния и достоверность глобального.

Например, однажды мы решили не использовать для обработки отложенных задач по событию внешний брокер. На тот момент существовало ограничение на использование внешних зависимостей, и нужно было по возможности переиспользовать уже имеющиеся зависимости. Мы использовали возможности баз данных. В скором времени разные типы событий и их количество стали расти пропорционально новым фичам. Текущее решение не позволяло масштабироваться должным образом, обработка отложенных задач деградировала по времени исполнения. И в конечном счете это привело к дополнительным затратам на реализацию конвейеров обработки уже далеко после запуска.

Следующий момент — разграничение контекстов и маппинг опыта в новые сервисы, ведь мы говорим про работу в домене, который 10 лет развивался и рос. Нельзя с нуля написать новый сервис, поставить его рядом с работающей системой и заменить одно на другое. Только качественное моделирование контекста и его коммуникаций дает ответ, как корректно интегрировать новый сервис в отлаженную систему.

Я большой фанат подходов Domain Driven Design и того, как они развиваются последние несколько лет (DDD Europe, etc). В частности bounded contexts, поскольку именно они помогают определить транзакционные границы сервиса и то, как лучше настроить оркестрацию взаимодействий. Чтобы избежать единой точки отказа, оркестраторы у нас являются частью сервиса и контекста соответственно. Т.е. исполнением саги занимается исключительно ответственный за это сервис внутри контекста, а не отдельный инфраструктурный сервис, который исполняет саги по запросу.

a) исполнение саги локальным оркестратором; b) использование отдельного сервиса оркестратора для исполнения саги; с) вариант хореографии событий;
a) исполнение саги локальным оркестратором; b) использование отдельного сервиса оркестратора для исполнения саги; с) вариант хореографии событий;

И если оркестрация находится внутри очерченного контекста, то для распространения изменений между более широкими контекстами используется уже хореография. Т.е. тут речь про обмен доменными событиями через шину данных (events-bus).

Еще один важный пункт — валидация и поставка решений. Для его выполнения архитектору нужна команда. Никто не в силах в одиночку адекватно и за разумное время «перемаппить» контексты, которые формировались целое десятилетие. На самом деле никто такого поведения и не ждет. Но именно архитектор должен задуматься и сформировать рабочие группы с нужными компетенциями и настроить их совместную работу.

Как формируем команды

У нас есть большая система, которая занимается хранением и процессингом комплексных состояний. При этом происходят нетривиальные взаимодействия со множеством других внутренних систем: изменение состояния по запросу, реакция на ответ, координация нескольких запросов и т.п. У нас также есть технологическая база и практики, как все растащить на контексты и наладить взаимную коммуникацию.

Исходя из этого мы формируем команды, которые должны:

  • погрузиться в контекст;

  • иметь экспертизу в легаси-стеке;

  • иметь возможность адаптироваться к новому стеку;

  • принять необходимые технологии и практики;

  • получить экспертизу в домене;

  • принимать решения самостоятельно.

Следующая важная задача — найти баланс сложности для команды. В нашем случае сложность лежит в плоскости домена и в плоскости решения. Чтобы инженеры не испытывали когнитивных перегрузок, этот момент прорабатываем изначально и возвращаемся в процессе для тонкой настройки.

Поэтому используем эмпирический подход и формируем команды в среднем из трех инженеров, один из которых — техлид. Он выступает дизайнером выделенного контекста и совместно с еще двумя инженерами прорабатывает решение. В команде может присутствовать аналитик, доменный эксперт от бизнеса, продакт. Если команда смогла спроектировать решение и имплементировать его самостоятельно, значит, баланс сложности решения и домена соблюден.

Выстраиваем взаимодействия через единый нарратив

Каждый раз я рассказываю своей команде историю жизненного цикла заказа. Заказ для нас — это не монолитная сущность с вариативным набором параметров, а прежде всего последовательность событий, распределенных во времени.

Событийная архитектура определяется наличием описанных событий — фактов о состоянии системы, дальнейший их процессинг и построение релевантных проекций-отражений. Она выступает публичной схемой взаимодействия между сервисами.

Каждое событие изменяет состояние одного или более независимых сервисов. Нужно ли транслировать изменение вовне или оно затрагивает исключительно локальное состояние? Можно ли принять решение об изменении, используя локальное состояние, или требуется координация нескольких сервисов? Отвечая на вопросы, мы приходим к пониманию того, как корректно организовать коммуникацию и в какой момент времени фиксировать изменения.

При моделировании наших систем мы перестаем беспокоиться о тяжелом монолитном стейте. Теперь нам нужно распространять изменения, коммуницируя между сервисами по сети. Сместить фокус со структур и их состояний на дизайн взаимодействий и коммуникацию.

Всю работу над проектом, каким бы сложным и громоздким он не казался, должен пронизывать единый нарратив. Каждый техлид контекста-сервиса, каждый инженер в группе должен считывать и понимать смысл, который стоит за всей работой. Как в плоскости решения, так и в плоскости домена. Задача архитектора — сформировать целостный и воспроизводимый нарратив для своей команды.


Выполняя свою задачу, архитектор в проекте играет режиссерскую роль. Как командообразующий игрок, он настраивает части, создавая целое. Иначе композиция не получится, а значит, впереди будет непредсказуемость, риски и потери.

Что еще почитать