Что такое Архитектура? Чем Архитектура отличается от Дизайна? Где граница между Архитектурой и Реализацией? Можно ли увидеть Архитектуру? Можно ли тестировать Архитектуру? Чем отличаются Инженерный и Эволюционный подходы к Архитектуре? Что такое Хорошая Архитектура? В чем состоит работа Архитектора? Чем она отличается от работы Разработчика? Какие инструменты доступны Архитектору? Можно ли менять Архитектуру отдельно от Реализации? Есть ли у Архитектуры ДНК?



Изображение из блога tomaszjaniak

Покажите нам вашу Архитектуру


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

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

Как же сделать все правильно? Нужно нарисовать диаграммы, описать фичи в документах, а потом все это поддерживать в актуальном состоянии. Вот тогда это будет Архитектура. Но, представив объем работ, быстро приходит понимание, что это все не стоит потраченного времени. Вот же код — все понятно. А если придет другой клиент, то еще за час можно будет нарисовать новую диаграмму.

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

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

Может быть, все так и должно быть. Может быть, Архитектура — это и есть Бюрократия вокруг спекулятивных документов, оторванных от реальности? Но интуиция подсказывает, что все-таки нет. Так что же тогда такое «Архитектура»?

Архитектура это...


Что будет, если задать вопрос «Что такое Архитектура?» десяти профессиональным разработчикам? Если не подглядывать в Википедию, дадут ли они один и тот же ответ?

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

А еще Архитектура — это то, каким образом приложение выполняет свое предназначение.

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

Можно ли считать все это ответом на вопрос «Что такое Архитектура?» — пожалуй, да. Вроде бы все правильно, вроде бы все понятно. Но является ли этот ответ практически полезным, тем, что можно использовать в реальном рабочем процессе? Не совсем.

Как понять, что решение важное или фундаментальное? Что такое глобальные задачи? Что значит дорого или дешево? Как оценить сложность? Где граница между высокоуровневым и низкоуровневым? Что такое порядок? В чем состоит предназначение системы?

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

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

С другой стороны, если спросить «Что такое Реализация?» — ответ, вероятно, будет однозначным: «Вот ссылка на репозиторий с кодом!». И ведь с этим не поспоришь. И каких-то сомнений или двусмысленности трактовки этого ответа не возникает. 1+1=2, Реализация — это код.

А с кодом работать очень просто. Если хочется разобраться в реализации — можно открыть проект в среде разработки. Если изменения в коде нужно ревьювить — на то есть ветки в репозитории. Если пришло время релизить новую версию приложения — запускаются тесты.

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

Но что если Архитектура выражалась бы кодом, так же, как и Реализация?

Декларативность и Императивность


В современной разработке используется множество мейнстримных языков программирования. Большинство из них появились давно или очень давно. И несмотря на то, что они все еще хороши, все же они понемногу устаревают. Это слабо типизированные языки: JavaScript, Python, PHP, Ruby, и языки со строгой типизацией: Java, C/Objective-C/C++, C#. Им на смену приходят новые языки, которые в рамках той же платформы пытаются решить застарелые проблемы, посыпая их синтаксическим сахаром, но не внося принципиально новых концепций, если смотреть глобально: Swift, Kotlin, TypeScript, Go. Все это языки, построенные на Объектно-Ориентированной парадигме. Также, зрелую популярность приобрел и Функциональный подход к программированию, который как реализуем на перечисленных языках, так и представлен в языках специализированных, но менее популярных: Erlang, F#. Начинают набирать популярность и языки, реализующие существенно новые концепции: Rust, Haskell.

Все это разнообразие объединяет одно: все это языки Реализации. Ни один из перечисленных языков программирования не является выражением Архитектуры. Но есть одно исключение — SQL.

SQL — это единственный мейнстримный язык программирования, который является Декларативным. Он построен на модели реляционной алгебры и имеет узкую специализацию — работа с хранимыми данными. Но все же, почему SQL можно считать языком Архитектуры?

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

Во вторых, SQL предоставляет язык запросов к данным, который позволяет клиенту запрашивать любые комбинации данных, описанных в схеме. Если бы языка запросов не было, то на каждую модель данных, требуемую клиенту, пришлось бы либо реализовывать отдельный API метод, либо клиент был бы вынужден выполнить несколько API-вызовов к различным частям схемы данных и скомбинировать требуемую модель на своей стороне. Наличие языка запросов позволяет исключить из описания Архитектуры детали реализации, связанные с перечислением API методов на получение конкретных моделей данных по общей схеме. Язык запросов исключает детали реализации из описания Архитектуры.

SQL предоставляет три ключевых свойства важных для описания Архитектуры:

  1. Декларативность — SQL позволяет отделить описание Архитектуры от ее Реализации.
  2. Анализируемость — SQL предоставляет доступ к мета-информации схемы данных, что позволяет визуализировать, документировать и анализировать ее представления.
  3. Корректность — SQL позволяет определить ограничения модели данных, что дает возможность предотвратить разнообразные нарушения целостности данных со стороны Реализации.

Пожалуй, SQL можно назвать инструментом описания Архитектуры в терминах хранения данных, но для описания полной Архитектуры продукта его явно недостаточно.

Другие средства описания Архитектуры


Прямым аналогом SQL является GraphQL, который также позволяет определить схему данных и предоставляет доступ к ней через язык запросов. При этом GraphQL строится на теории графов, а не на модели реляционной алгебры. Это дает возможность работать с иерархическими моделями данных более естественным способом, в отличие от SQL, где работа с иерархиями бывает затруднительной.

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

Если SQL является средством описания Архитектуры схемы хранения данных, то GraphQL позволяет описать Архитектуры схемы данных уже на бизнес-уровне, в терминах конкретной прикладной области. В этом смысле GraphQL позволяет определить Архитектуру на более высоком уровне, ближе к реальной прикладной области продукта.

Модули кода и микросервисы, совместно с их API и зависимостями, также являются средствами выражения Архитектуры в терминах структуры и связей.

Архитектура и Реализация


Для небольшого проекта, над которым работает десяток разработчиков, какого-то отдельного описания Архитектуры часто не требуется. Если код проекта написан аккуратно и хорошо структурирован, этого может быть вполне достаточно для понимания общей картины и направлений развития.

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

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

Конечно, в Бюрократии как таковой нет ничего плохого. В любой работе важна ее организация. Проблема заключается в количестве Бюрократии на единицу полезной работы. Если для того, чтобы сделать Раз, нужно провести еще Два, Три, Четыре, Пять митингов, — это уже никуда не годится.

Даже простой вопрос, какое изменение разработчик может сделать сам, потому что это Реализация, а по какому нужно сделать запрос на ревью, потому что это Архитектура, — начинает вызывать трудности. Приходится придумывать разнообразные Архитектурные триггеры, что, если вы меняете схему данных или затрагиваете вопросы криптографии и безопасности — это нужно ревьювить Архитектурно, а другие темы вроде бы нет, но это не точно. Все это нужно не только сформулировать и объяснить сотням разработчиков, но и следить за тем, чтобы описанные правила соблюдались. Такой процесс постоянно будет давать сбои.

Все эти проблемы связаны с отсутствием четкого определения Архитектуры.

Так же, как изменение «.java» файла в репозитории однозначно говорит об изменении реализации, изменение «.architecture» файла может говорит об изменении архитектуры. Конечно, «.architecture» файлов в природе не существует. Но для каждого проекта можно определить, какие конкретно его аспекты относятся к его архитектуре, и сделать это явным.

Если изменение схемы данных считается изменением Архитектуры — значит файлы содержащие SQL-миграции должны относится к Архитектуре. Если API — это тоже часть Архитектуры, можно определить API в виде тех же swagger файлов, и полагаться на них. Если структура модулей — Архитектур, тогда изменение описания модулей — это Архитектурное изменение. И так далее.

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

Формальное представление Архитектуры в коде возможно, и только оно дает четкое определение того, что такое Архитектура. Такое представление дает возможность анализировать Архитектуру и автоматически генерировать по ней документацию, которая всегда будет актуальной. Все остальные: документы, схемы и диаграммы составленные вручную — Бюрократия.

У Архитектуры может быть формальное выражение в коде, и только оно задает четкую границу между Архитектурой и Реализаций. И такая граница нужна.

Инженерный и Эволюционный подходы в Архитектуре


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

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

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

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

Пропалывать сорняки необходимо. Но каков будет сад, если заниматься только этим? Цветочные клумбы завянут в тени фруктовых деревьев, клубника и морковь будут расти вперемежку, и все это окажется пересечено бесчисленным количеством тропинок, впустую расходующих доступное пространство. Здесь трудно говорить о какой-либо Архитектуре.

Чтобы Архитектура появилась, архитектор должен выполнять хотя бы работу садовника. Ягоды и овощи стоит растить отдельно — структура, а там, где люди ходят чаще всего, нужно проложить дорожки — связи. Наблюдая за частностями, архитектор может действовать проактивно, организуя и систематизируя в единую структуру частные особенности возникающие в процессе Реализации. Как и ландшафтный дизайн, архитектор может оформлять естественное развитие событий, закрепляя позитивные тенденции и предотвращая негативные.

И тут уже нужно четкое определение Архитектуры в коде. Схемы данных, структуры модулей и сервисов, их API и правила взаимодействия. Без определения этих инструментов архитектор либо погрязнет в ревью реализации, либо будет наивно надеяться, что разработчики действительно будут следовать правилам, описанным в каких-то там документах, чего, конечно же, не случится.

Если есть формальное представление Архитектуры и правила ее изменений, это уже можно назвать Эволюционным подходом к развитию Архитектуры. И это уже неплохо. Но стоит ли этим ограничиваться?

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

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

Формальное определение Архитектуры конкретного проекта не обязательно должно быть статичным. Устаревшие методы API можно объявлять как Deprecated, а недостающие декларировать как Not Implemented. Осмысленные части кода можно отмечать для вынесения в отдельные модули. Можно планировать разделение таблицы на две, или перенос их в другую базу данных. И так далее. Архитектуру можно менять, не меняя реализации. Реализация догонит. А чтобы догоняла быстрее, процесс можно немного автоматизировать, сделав автоматические напоминания в командные чаты. Точно так же, как изменения разработчиков в Архитектурных файлах могут автоматически попадать в чат архитектурной команды.

Инженерный подход к развитию Архитектуры возможен.

При этом не стоит считать, что работа архитектора чем-то принципиально лучше или хуже работы разработчика. Она просто другая. Разработчик, в первую очередь, работает в Императивном стиле, тогда как работа архитектора — больше Декларативная. Бывает, что проработать Архитектуру сложно, а Реализация —- рутина. Бывает и наоборот.

Архитектура и Дизайн


Термины Архитектура и Дизайн часто употребляют как синонимы. Можно сказать: Архитектура системы или Дизайн системы. По большому счету, понятно, о чем речь. Но все же в этих терминах можно найти существенные отличия.

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

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

Конечно, и то, и другое важно.

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

Если Архитектура включает в себя схему данных — должно быть и ее визуальное представление. У модулей есть зависимости — их тоже нужно визуализировать. Если есть API — по нему должна быть документация, напрямую связанная со структурой сервисов. И так далее. Дизайн — это визуальное представление Архитектуры.

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

Заключение


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

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

Многие инструменты существуют уже десятки лет, например SQL, нужно просто научиться их правильно использовать. Новые технологии, такие как GraphQL, начинают набирать популярность, и они дают надежду на то, что задачи описания бизнес-домена со временем станут столь же рутинными, сколь и описание домена хранения данных. Доступны средства документации и визуализации структуры приложения и API, в том числе Swagger. Для тестирования Архитектуры можно использовать те же фреймворки и инструменты интеграции, что и для тестирования Реализации.

Архитектура — Декларативна. Вероятно, Бюрократия работы с документами никогда полностью не исчезнет из работы архитектора, но уже сейчас ее объем можно существенно сократить. Архитектура — это тоже код, и со временем доступный инструментарий для работы над Архитектурой может стать столь же развитым, как и инструментарий для работы над Реализацией. Посмотрим.


Дмитрий Мамонов,
Wrike


P.S. Я начинал статью со списка философских вопросов на которые, надеюсь, мне удалось дать вполне конкретные ответы. По крайней мере, такова моя точка зрения. Нашли ли вы в статье что-то полезное или новое? Как вы сами отвечаете на поставленные вопросы? Пишите в комментариях.