Как стать автором
Обновить

Покрытие архитектуры as Code тестами

Уровень сложностиПростой
Время на прочтение16 мин
Количество просмотров7.5K

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

Архитектура as Code

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

Возьмём определение, приведённое в стандарте ANSI/IEEE Std 1471-2000:

Фундаментальная организация системы, реализованная в её компонентах, их взаимоотношениях друг с другом и средой и принципах, определяющих её конструкцию и развитие

Отдельно в этом определении хочется выделить, что архитектура — это не только «организация системы», но и «принципы, определяющие её конструкцию и развитие».

То есть архитектура — это не только «что», но и «почему». Это важно.

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

У визуализированной в виде картинки архитектуры есть один несомненный и самый главный плюс — она наглядна!

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

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

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

Итак, идея формата схем as Code очень проста — объединяем все плюсы картинки и кода, избавляясь от всех недостатков :) По сути, нам нужно описать схему кодом, по которому можно однозначно сгенерировать визуализацию. Как это выглядит, можно посмотреть на гифке: слева мы печатаем код, по которому справа тут же онлайн генерируется схема:

На гифке представлен пример на PlantUml (точнее, на PlantUml с подключённым C4 форматом архитектур), на нём же мы и рассмотрим сегодня примеры. Инструментов для описания различных схем кодом уже достаточно много, из открытых могу посоветовать ещё, к примеру, Structurizr.

💬 Не стоит пугаться незнакомых инструментов, форматов и кучи ссылок — по ним вовсе не обязательно переходить для дальнейшего чтения и понимания статьи 🙂

Для описания микросервисной архитектуры нам потребуется всего три элемента:

  • System_Ext — внешняя для нашего проекта система, с которой мы проинтегрированы.

  • Container — собственно микросервис (или докер-контейнер с микросервисом внутри).

  • Rel — связь чего угодно с чем угодно (первых двух пунктов выше в любой комбинации).

На PlantUml это выглядит примерно так:

System_Ext(goods, “Goods Repo")
System_Ext(stock, “Stock")

Container(bff, “BFF", "NestJS")
Container(task_repository, “Task Repo", "NestJS”)

Rel(bff, goods, "Get products", “API Gateway")
Rel(task_repository, stock, “Send task", $tags="async")
Rel(bff, task_repository, "Get task", “REST")

Проблемы архитектурных схем

Прежде чем перейти к тестам, давайте сформулируем проблемы, которые хотим решить, иначе зачем это всё?! 🙂

Сталкиваясь как ИТ-архитектор с множеством проектов различных компаний, я выделил три основные широко распространённые и ощутимые проблемы архитектурных схем:

  1. Неактуальность.

  2. Декларативность.

  3. Отсутствие контроля над исполнением.

Неактуальность

Архитектурная схема — это та же документация. А кто не встречался с проблемой неактуальной документации? 🙂

Бывает, смотришь на ИТ-архитектуру, там всё чётко, стройно и красиво. А на самом деле на проде… ну, не совсем так:

Знакомо? 🙂

Бывает и чуть иная ситуация:

Актуальна ли здесь архитектурная схема? Ну, может, и актуальна, только есть ли в этом смысл? 🙂 Неуверенность или незнание статуса актуальности приводит к тому, что даже наличие этой самой актуальности не приносит пользы.

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

Под декларативностью на архитектурных схемах я понимаю как раз отсутствие на ней принципов, по которой она спроектирована. То есть схема как раз и показывает, «что» сделано, не отвечая на вопрос «Почему именно так?» Давайте покажу на простеньком примере:

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

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

Отсутствие контроля над исполнением

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

Итак, у нас есть проблемы с архитектурой, которую мы теперь можем описывать в коде (as Code), а значит, у нас есть проблемы в коде!

А если у нас есть проблема в коде — надо написать тест!

Покрытие архитектуры тестами

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

Для наглядности возьмём микросервисную архитектуру, в которой есть внутренние (между контейнерами) и внешние (интеграции со сторонними системами, обозначенными серым цветом) взаимодействия. Взаимодействия (или зависимости) есть прямые (например, REST) и асинхронные (например, подключения к Kafka). Это всё, что стоит знать про наш пример архитектуры, подробно её разбирать нам не потребуется:

Напомню, что архитектура у нас описана в PlantUml при помощи трёх элементов:

System_Ext(goods, “Goods Repo")
System_Ext(stock, “Stock")

Container(bff, “BFF", "NestJS")
Container(task_repository, “Task Repo", "NestJS”)

Rel(bff, goods, "Get products", “API Gateway")
Rel(task_repository, stock, “Send task", $tags="async")
Rel(bff, task_repository, "Get task", “REST")

Откуда брать данные?

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

ServiceMesh

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

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

Также в обоих вариантах мы получаем достаточно долгую обратную связь. Чтобы по трафику получить граф взаимосвязей, с которым мы сравним архитектуру для проверки актуальности, нам понадобится как минимум прогнать все интеграционные тесты, а лучше дождаться выкладки новой версии на прод и исполнения на проде всех сценариев, включая «редкие». А мы-то хотели аналогичный работе с кодом процесс, чтобы хотя бы на этапе PullRequest’а в develop тесты автоматом говорили, всё ок или не ок 😅

А если не ServiceMesh, то что?

IaC

Вспомним, что у нас Infrastructure as Code уже практически является стандартом в отрасли, теперь у нас появляется и Architecture as Code, так почему бы два этих подхода не поженить?!

Если взять конфигурации микросервисов (их контейнеров) для kubernetes, получим сразу всё необходимое для нашей задачи практически без каких-то трудностей.

В таком конфиге мы явно прописываем все возможные взаимодействия микросервиса: исходящие REST-запросы, доступ к очередям и базам данных. Что касается скорости обратной связи: если я как разработчик добавляю новый REST-вызов из сервиса A к сервису Z, то я пропишу в конфиге микросервиса доступ A→Z на уровне инфраструктуры, чтобы проверить работоспособность кода на feature-окружении. То есть мы получаем обратную связь и можем запустить тест на архитектуру уже на этапе развёртывания задачи в feature-окружении, до какого-либо слияния веток и ревью PullRequest’а.

Для деплоя мы используем helm-чарты, для которых конфигурация каждого микросервиса лежит в yaml-файлах. Приведу упрощённый пример такой конфигурации, который содержит всё необходимое для проверки архитектурных связей этого микросервиса:

environment:
  GOODS_REPO_BASE_URL:
    default: https://gateway.int.com:443/goods/v1
  TASK_REPO_BASE_URL:
    default: http://tasks-repository:8080
  KAFKA_TASKS_BROKERS:
    default: msg-q8s.int.cloud:9092
  KAFKA_TASKS_TOPIC:
    default: stock-tasks-q8s-v1

Конфиг говорит, что наш микросервис шлёт REST-запросы к внешней системе (Goods_Repo) и к другому микросервису внутри нашего периметра (Task_Repo), а также подписан на топик кафки.

Тесты на актуальность

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

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

Для построения таких массивов нам понадобятся два парсера исходных источников данных и общий маппер приведения к единой структуре данных, по которой мы уже сможем писать обычные тесты (unit-тесты):

Код реализации, а также пример архитектуры, инфраструктуры и тестов можно посмотреть и взять себе на вооружение в нашем опенсорсе: https://github.com/Byndyusoft/aact Welcome! =)

💬 Далее по тексту статьи я буду приводить прямые ссылки на конкретные примеры в этом репозитории.

Простой тест на сопоставление списков микросервисов может выглядеть примерно так: 

it("finds diff in configs and uml containers", () => {
  const namesFromDeploy = deployConfigs.map((x) => x.name);
  const containerNamesFromPuml = containersFromPuml
    .filter((x) => x.type == "Container")
    .map((x) => x.name);

   expect(namesFromDeploy).toEqual(containerNamesFromPuml);
});

github.com/byndyusoft/aact/blob/ac05e3217ac4bc8d621ebbd1323ac9c86a828956/test/architecture.test.ts#L43

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

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

Для проверки актуальности архитектурной схемы помимо списка имён как минимум нужно проверить все связи каждого из микросервисов. При первом запуске такого теста на достаточно развесистой архитектуре, как правило, выявляются как недостающие, так и лишние связи. Пример output’а такого теста:

Container name bff ✅
Container name task_repository❌
Container name invoice_acl ✅
 --------------------------------------------------------
First failed container name task_repository
--------------------------------------------------------
FAIL test/architecture.spec.ts
● Architecture › finds diff in configs and uml dependencies
expect(received).toEqual(expected) // deep equality
- Expected - 1
+ Received + 1
Array [
“bff",
- “stock",
+ “goods",
“invoice", 

github.com/byndyusoft/aact/actions/runs/6603088421/job/17935846325#step:5:67

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

  • Типы и параметры связей — протоколы взаимодействия, указание конкретных REST API и очередей, настройки прав доступа и т. д.

  • Параметры контейнеров — количество реплик, параметры CPU и RAM, настройки autoscaling и т. д.

  • Форматирование и конвенции именования — файлов конфигураций и архитектур, именование переменных окружения и т. д.

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

Тесты на соблюдение архитектурных принципов

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

1. ACL (Anti-corruption Layer) Pattern

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

Рассмотрим на примере нашей учебной архитектуры, где ✅ помечены валидные связи (принцип соблюдён); ❌ помечены связи, нарушающие принцип (так как внешняя интеграция идёт напрямую из внутреннего микросервиса, не являющегося адаптером (не стоящего на периметре)); сами микросервисы-адаптеры выделены зелёным.

Чтобы написать тест, на архитектуре в PlantUml помечаем соответствующие микросервисы признаком Adapter:

Container(goods_adapter, “Goods ACL", "NestJS", $tags="adapter")

В тесте проверяем, что связи с внешними системами имеют только сервисы с таким признаком. Помним, что для внешних систем в PlantUml используем отдельный элемент System_Ext (визуально он влияет только на заливку такого элемента серым цветом).

Таким образом, если на архитектуре у нас будет представленная выше связь от контейнера Camunda, не помеченного тегом adapter, к внешней системе Stock: 

System_Ext(stock, "Stock")
Container(camunda, "Camunda")
Rel(camunda, stock, "")

то тест на ACL принцип упадёт.

2. Пассивные репозитории

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

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

Для возможности тестирования применяем всё тот же подход с тегом: помечаем микросервисы-репозитории (их ещё иногда называют CRUD API) спецпризнаком:

Container(task_repository, “Task Repository", "NestJS", $tags="repository")

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

Rel(task_repository, task_db, "")
Rel(camunda, task_repository, "")
Rel(task_repository, invoice_acl, "")

3. Внешние REST-вызовы должны идти через API-Gateway

Договорённость говорит о том, что внутри периметра мы ходим между микросервисами (контейнерами) напрямую через service кубера, а вовне периметра — через отдельно развёрнутый API Gateway. В конфигах инфраструктуры это можно отследить по формату URL:

GOODS_REPO_BASE_URL:
  default: https://gateway.int.com:443/goods/v1
TASK_REPO_BASE_URL:
  default: http://tasks-repository:8080

Раз нам важны URL для REST-интеграций, то отобразим их и на архитектуре подписью к связям:

Rel(goods_acl, goods_repository, "", "https://gateway.int.com:443/goods/v1")

⚠️ Важно при этом не забыть добавить проверку соответствия URL в конфиге и на архитектуре в тесты проверки актуальности. То есть проверять не только наличие связи, но и её параметры.

В тесте на использование API Gateway проверяем все исходящие связи к внешним системам, например, на соответствие формату URL: https://gateway.int.com:443/*. Такой тест в нашем примере упадёт на строке:

Rel(stock_acl, stock, "", "http://stock:8080")

так как элемент stock является внешней системой (System_Ext), а значение параметра "http://stock:8080" не соответствует паттерну URL API Gateway’я.

4. Операции записи идут только через оркестратор бизнес-процессов

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

В нашем примере оркестратором распределённых транзакций является Camunda:

Такое разделение на уровне инфраструктуры приведёт к тому, что в конфигурации права только на чтение и на чтение и запись будут различаться (например, по X-API-Key или иным другим способом). Также уровень доступа у связи разделим и на архитектуре знакомыми нам тегами, только теперь это будут атрибуты не элементов, а собственно связи:

Rel(invoice_acl, invoice_repository, "", $tags="rw")

Вновь не забываем добавить проверку на соответствие атрибутов прав записи в тесты на актуальность. В тесте на соблюдение правил обработки распределённой транзакции проверяем, что тегом rw к репозиториям обладают только исходящие из Camunda (микросервиса с тегом оркестратора) связи.

И другие принципы

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

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

  • Разделение сервисов по хостам и дата-центрам.
    Часто на архитектуре важно отразить распределение системы по «железу» и по хостингу в том или ином дата-центре. Так как данные для сверки мы черпаем из инфраструктуры as Code, проверить на актуальность не составит труда. Помимо актуальности можно проверить и выполнение различных правил, к примеру, что инстансы критичных микросервисов запущены на разных хостах или дата-центрах.

  • Наличие DLQ (dead letter queue) для критичных потоков асинхронных данных. Для проверки этого правила также всё у нас есть 🙂

  • И так далее…

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

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

Решение архитектурных проблем

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

Актуальность

Архитектурная схема поддерживается в актуальном состоянии из-за автоматического прогона тестов при сборке очередной версии на CI/CD. Если разработчик добавляет новую связь между микросервисами, без добавления в конфиг она физически нигде не заработает (не будет доступно сетевое взаимодействие), а при добавлении в конфиг все связи автоматически свалидируются с архитектурной схемой. То есть в случае несоответствия схеме очередной билд попросту не соберётся, да и автоматические проверки при создании PullRequest’а также не пройдут из-за упавшего теста.

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

Тесты описывают императивность архитектуры

Архитектурная схема явно ничего не говорит о заложенных при её проектировании принципах. Схема только фиксирует текущие параметры, наличие или отсутствие определённых связей между микросервисами и другую информацию, не уточняя причин принятых решений проектирования и «принципов, определяющих её конструкцию и развитие» (см. определение архитектуры в начале статьи 🙂).

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

Тесты описывают и фиксируют принципы и договорённости проектирования и автоматически проверяют схему на соответствие им.

Контроль изменений в архитектуре

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

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

Личный опыт

На рисёрч, разработку и внедрение идеи с нуля на первом проекте в сумме у нас ушло около трёх человеко-недель. На последующих проектах, если полностью совпадали по стеку, для внедрения требовалось только взять готовый код и примеры тестов из OpenSource, без дополнительных трудозатрат. На некоторых проектах отличалась инфраструктура или форматы и подходы к её хранению as Code, в таких случаях командам требовалось лишь добавить свою прослойку для парсинга инфраструктуры, сохранив при этом всю остальную структуру и код из примера:

Конкретно в проекте, который стал первым для апробации подхода, помимо решения заранее сформулированных и обозначенных выше проблем тесты на архитектуру выявили ещё ряд техдолгов, о части из которых команда даже не догадывалась. К примеру, тесты показали наличие в системе топиков кафки, у которых были продьюсеры, но не было ни одного подписчика 😅, оказалось, что год назад не полностью удалили код устаревшей функциональности. Также выяснилось, что не только архитектура бывает неактуальной, но и код с конфигурацией! Тесты показали наличие в конфигурациях REST-зависимостей, которые ну никак не ложились на текущую работу системы, при проверке оказалось, что и в конфигах, и в коде микросервисов присутствовали никем и никогда не используемые методы API.

Не знаю, как вам, а мне доставляет отдельное удовольствие исправлять техдолг, удаляя неиспользуемый код :) Вдвойне приятно, когда после этого ещё и тест из красного становится зелёным 😀

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

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

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

Что дальше?

Советую и вам покрывать архитектуру ваших проектов тестами, возможно, и вашей команде это даст даже больше пользы, чем вы изначально будете ожидать 🙂

Буду рад новым контрибьюторам в opensource-репозиторий с кодом и примерами архитектурных тестов, да и просто звёздочкам на гитхабе. В ближайшее время надеюсь доделать и опубликовать roadmap развития проекта, и мне очень интересны примеры ваших архитектур и принципов — закидывайте в репозиторий (можно в Issues), даже если не знаете, как протестировать тот или иной принцип или договорённость, будем вместе думать и развивать количество покрытых тестами примеров паттернов проектирования!
Ещё раз ссылка на публичный репозиторий: https://github.com/Byndyusoft/aact.
Репозиторий также доступен и на российской площадке: https://gitverse.ru/Byndyusoft/aact, репозитории синхронизированы.

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

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

Кого заинтриговал, подписывайтесь на мой канал: Архитектура распределённых систем.

Материал этой статьи в формате доклада:

И пара слов обо мне:

Руслан Сафин

Соучредитель, технический директор и архитектор в «Бындюсофт».
Автор и преподаватель курса по микросервисной архитектуре в ИТМО.
Член программных комитетов конференций CodeFest и TechLeadConf.

❤️

Теги:
Хабы:
Всего голосов 24: ↑22 и ↓2+22
Комментарии8

Публикации

Истории

Работа

DevOps инженер
51 вакансия

Ближайшие события

19 августа – 20 октября
RuCode.Финал. Чемпионат по алгоритмическому программированию и ИИ
МоскваНижний НовгородЕкатеринбургСтавропольНовосибрискКалининградПермьВладивостокЧитаКраснорскТомскИжевскПетрозаводскКазаньКурскТюменьВолгоградУфаМурманскБишкекСочиУльяновскСаратовИркутскДолгопрудныйОнлайн
3 – 18 октября
Kokoc Hackathon 2024
Онлайн
24 – 25 октября
One Day Offer для AQA Engineer и Developers
Онлайн
25 октября
Конференция по росту продуктов EGC’24
МоскваОнлайн
7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань