? На самом деле, моя идея написания тестов на архитектуру настолько проста, легко реализуема и при этом полезна, что я до сих пор толком не понимаю, почему я не встречал материалов на эту тему, и сама тема всё ещё не используется повсеместно ?
Статья написана по следам моих докладов на трёх крупных ИТ-конференциях, на каждой из которых ко мне подходили архитекторы и разработчики российских бигтехов, говорили, что я очень точно попал в их боли и предложил суперпрактику, которую они теперь будут внедрять. На всех трёх конференциях я получил высшие оценки от аудитории, а на двух из них доклад был признан лучшим в своей секции. В конце статьи приведена ссылка на видео доклада с одной из конференций.
В статье я поделюсь своей идеей и 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")
Проблемы архитектурных схем
Прежде чем перейти к тестам, давайте сформулируем проблемы, которые хотим решить, иначе зачем это всё?! ?
Сталкиваясь как ИТ-архитектор с множеством проектов различных компаний, я выделил три основные широко распространённые и ощутимые проблемы архитектурных схем:
Неактуальность.
Декларативность.
Отсутствие контроля над исполнением.
Неактуальность
Архитектурная схема — это та же документация. А кто не встречался с проблемой неактуальной документации? ?
Бывает, смотришь на ИТ-архитектуру, там всё чётко, стройно и красиво. А на самом деле на проде… ну, не совсем так:

Знакомо? ?
Бывает и чуть иная ситуация:

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

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

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

Итак, у нас есть проблемы с архитектурой, которую мы теперь можем описывать в коде (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); });
Берём имена всех микросервисов из конфигов (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.
❤️
