Всем привет! С вами Женя, разработчик Dodo Engineering и один из ведущих подкаста «Читаем вместе». Он посвящен IT-книгам. В каждом сезоне мы планируем читать и разбирать одну книгу. Уже подходит к концу первый сезон, который мы посвятили книге Fundamentals of Software Architecture. Она написана архитекторами для архитекторов, но разработчикам, особенно тем, которые интересуются, как создавать работающие системы, тоже может быть очень интересна и полезна.

Глава про архитектурные решения сильно нас зацепила, потому что в своей работе мы напрямую столкнулись с описанными проблемами. 

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

Знакомо? Нам тоже. Но мы смогли победить эти проблемы. Дальше расскажу, как нам это удалось.

Антипаттерны поведения архитектора

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

В книге описываются три антипаттерна в поведении архитектора, которые сводят на нет его работу.

Первый антипаттерн — Covering your assets, по-русски дословно «прикрыть свою задницу». Этот антипаттерн проявляется, когда архитектор не принимает никаких значимых решений или принимает их в последний момент, потому что боится изменений, а главное — ответственности за эти изменения. В итоге команда не может продолжать работу, потому что ждёт решения от архитектора.

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

Сергей Зарубин, Dodo Engineering

Ещё одно проявление этого антипаттерна — «аналитический паралич». В этом случае архитектор начинает искать оптимальное решение среди всех возможных, накапливает всё больше и больше информации, ему кажется, что не хватает требований, что вот ещё чуть-чуть, ещё какой-нибудь proof of concept запилить и только потом принять То Самое Решение. Это тоже приводит к тому, что команда ждёт, при этом ничего полезного не делает, случаются простои, а То Самое Решение так и не находится.

Как следствие — команда теряет доверие к архитектору и веру в его решения, потому что он не в состоянии выполнять те задачи, которые должен.

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

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

Евгений Пешков, Циан

Второй антипаттерн — Groundhog Day, т.е. «день сурка». С этим антипаттерном мы раньше часто сталкивались в своей компании. В этом случае проблем с принятием решений у архитектора нет. Но каждый день приходит кто-то и задает один и тот же вопрос: «Почему мы делаем X именно так?». И каждый день нужно разным людям давать одинаковый ответ.

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

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

Третий антипаттерн — Email-Driven Architecture. Архитектору надоело объяснять устно каждому человеку, почему принято то или иное решение, и он решает делать это с помощью электронной почты. Но письма теряются, а в рассылке могут быть люди, которые вообще не имеют отношения к решению. По большому счёту, здесь речь может идти не только об электронной почте, но и любом корпоративном мессенджере. Например, мы используем Slack, однако, он не спасает, потому что решения публикуются в каналах или тредах, которые со временем архивируются и теряются, а новые люди уже с трудом могут найти какую-то информацию. 

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

Тут на сцену выходит практика ADR (Architecture decision records). Или, по-русски, «запись архитектурных решений», но я всё-таки буду использовать ADR, потому что так привычнее и короче.

Ниже расскажу, как мы внедрили эту практику в Dodo Engineering и как это вообще работает в реальности.

Что такое ADR

Итак, ADR — это документ, в котором фиксируется нечто «архитектурно важное», т.е. решение, которое влияет на:

  • структуру ПО;

  • функциональные характеристики ПО;

  • зависимости между компонентами (где мы допускаем сильное связывание, а где его не должно случиться);

  • интерфейсы и API (как наши компоненты, модули и прочее будут взаимодействовать друг с другом);

  • используемые технологии (платформы, фреймворки, тулы и так далее).

Если в решении есть что-то из этих пяти составляющих, его надо фиксировать.

Структура ADR

Меня порой пугают трёхбуквенные аббревиатуры и новые практики. Обычно это достаточно сложно, занимает много времени и получается не с первого раза. 

Так вот, ADR — вообще не про эти опасения. Несмотря на «страшное» название и назначение, его структура весьма простая. 

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

  • У документа должен быть статус. Авторы книги предлагают использовать три: proposed (предложен), accepted (принят) и superseded (замещён). Первые два статуса нужны, чтобы не попасть в ситуацию «мы посовещались и я решил». По сути, ADR в статусе proposed — это своего рода RFC, request for comments. После того, как мы учтём и разберём все комментарии по решению, мы принимаем его, и ADR переходит в статус accepted.

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

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

  • Следом идёт непосредственно «тело» решения. Тут есть один интересный момент: в книге предлагается использовать утвердительные предложения. Не размышления в духе «Я думаю, что лучше сделать вот так», а утверждения «Мы будем делать вот так». То есть все сомнения и мысли мы оставляем для комментариев, но после обсуждения и принятия уже не должно быть фраз с «Я думаю, что...».

  • Причины принятия решения. Здесь предлагается сфокусироваться на том, почему мы будем что-то делать, а не как мы будем это делать. Кстати, именно «почему», а не «как» является вторым важным вопросом архитектуры.

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

  • Комплаенс (проверка соответствия). Это раздел про то, как мы будем проверять, что решению следует. Про комплаенс можно написать отдельную статью, а то и не одну. В качестве примера: если принято решение о  разделении кода сервисов на слои, то можно воспользоваться специальной автоматизированной тулой (например, ArchUnit или NetArchTest), которая сможет проверить, что код соответствует принятому решению.

  • Заметки. Тут указывается автор, дата принятия, кем принято. Чаще всего в обсуждении принимает участие более широкий круг разработчиков, но аппрувить могут только определённые люди. Это может быть вышестоящий архитектор или же архитектурное комьюнити.

Где хранить

Важный вопрос: где хранить ADR? Можно использовать Сonfluence или Notion. Ещё один вариант — хранить в Git, но порой к нему нет доступа у бизнес-стейкхолдеров. В любом случае, это должна быть система, где хорошо работает поиск, есть навигация и кросс-ссылки.

RFC в Dodo Engineering

Мы в Dodo Engineering в качестве аналога ADR используем RFC (request for comments). Так сложилось по историческим причинам, потому что сама практика у нас возникла чуть раньше, чем мы прочитали Fundamental of Software Architecture.

Вот наш список критериев, когда нужно писать RFC:

  • делаем что-то новое: сервис, библиотеку, нагруженный эндпоинт, компонент;

  • нужно что-то переписать с нуля;

  • изменения затронут 2+ команд или 1+ систему;

  • изменения невозможно или очень дорого откатить;

  • делаем контракт между системами;

  • добавляем или убираем что-то из стека;

  • есть сомнения, что нужно написать RFC.

Если выполняется хотя бы один из критериев, нужно писать RFC. Этот процесс у нас расписан по шагам:

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

  2. Публикуем в канал #architecture.

  3. Собираем возражения в RFC(пункт Комментарии).

  4. Если есть несогласные, устраиваем встречи:

    1. Встречи ограничены 7 участниками, длятся не больше часа.

    2. Количество слушателей не ограничено. Встречи записываются.

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

    4. Иногда пользуемся принципом disagree&commit, чтобы неделями не мусолить решения.

    5. В случае очень активной дискуссии можно сделать канал в слаке.

  5. После обсуждения и принятия RFC, считаем комментарии законченными и переносим его в History. Затем из RFC делаем ADR (architecture decision record) — краткую выжимку договорённостей. Если RFC написан кратко и ёмко, менять ничего не нужно.

  6. После переноса в History публикуем сообщение в #architecture об этом.

То есть как это работает у нас: человек пишет RFC, а потом скидывает в Slack, что есть такой-то RFC, у него устанавливается дедлайн, например, неделя-две. Все заинтересованные и причастные могут написать  возражения и комментарии. Это как на свадьбе какой-нибудь протестантской, как в фильмах показывают. Если кому-то есть что сказать — говорите сейчас или больше не говорите никогда. Тут даётся время на то, чтобы сказать, где ты не согласен с автором. После того, как RFC принят, ты уже ничего сделать не можешь с этим. 

Евгений Биккинин, Dodo Engineering

Необязательно писать RFC, если решение не вызывает споров, касается одной команды или же откатываемое. Таким образом мы снижаем поток RFC, которые необходимо отслеживать, потому что тогда на всех разработчиков ложится нагрузка: надо прочитать внимательно, прокомментировать, вступить в диалог. Потому что если ты сейчас за  две недели промолчишь, то всё, без тебя решение примут.

Заключение

С появлением в нашей компании практики RFC и ADR процесс принятия сложных решений стал проще и структурнее. Практически исчезли бесполезные и бесконечные споры, в результате которых каждый оставался при своём мнении.

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

Пишите в комментариях, как принимаются решения в вашей компании, читали ли вы эту книгу и какие практики из неё применяете.

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

Комментарии (5)


  1. Starche
    22.09.2021 00:36

    вступает в силу второй закон архитектуры: любое решение является компромиссом, у которого есть сильные и слабые стороны

    А какой первый? А лучше огласите весь список, пожалуйста


    1. komgbu
      22.09.2021 08:03
      +2

      Первый: любое решение в архитектуре - это компромисс.

      С плюсами всегда в наборе получаешь минусы. Нужно понять, какие архитектурно-значимые функциональные требования критичны и какие нефункциональные требования порождают. Далее - ранжирование по критичности (требования могут быть диаметрально противоположными: хочу чтобы система выдерживала 1млн запросов/сек - high throughput и задержка ответа составляла не более 10мс - low latency) и подбор паттерна, который лучше подходит для выполнения критичных требований.

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


    1. Xneg Автор
      22.09.2021 08:26
      +6

      @komgbu прав, а вот я в статье слегка напутал

      В книжке выводится всего два закона архитектуры.

      Первый закон:

      Everything in software architecture is a trade-off.

      Любое решение является компромиссом (о чём @komgbu чётко расписал).

      Второй закон:

      Why is more important than how.

      Вопрос "почему" является важнее вопроса "как". Для меня это стало тоже очень ценным подспорьем в спорах с коллегами, которые слишком рано уходят в детали имплементации, не рассматривая картину целиком.


  1. LeshiyUrban
    23.09.2021 07:07
    +1

    Ещё бывают ситуации, что архитектуру детально прописываешь, согласовываешь, создаёшь RFC, рисуешь диаграммы разного уровня детализации, составляешь секцию FAQ, а потом приходит человек и начинает спрашивать вопросы которые в явном виде уже описаны в документе. Просто ему/ей лень читать.????


    1. Xneg Автор
      23.09.2021 09:43
      +1

      Бывают такие люди, сам сталкивался. В таком случае помогает задать вопрос себе (да и ему/ей), настолько ли это уникальный человек в компании, что вам необходимо тратить на него время дважды. Потому что первый раз вы уже потратили время, детально всё описывая.