- Введение
- Get started
- Инструмент structurizr
- Объекты structurizr
- Структура репозитория
- Правила работы в репозитории
- Правила работы с git
- Работа со structurizr-lite
В компании для описания архитектуры используется подход architecture as a code. Такой подход позволяет гибко управлять архитектурными артефактами и описывать требуемые изменения по архитектуре по проектам. Описание в виде кода освобождает от нужды "рисовать схемы" и описывать уровни модели С4 по отдельности.
git clone https://github.com/Nikolo/arch-as-code-template arch-as-code
cd arch-as-code
make init ARGS="-n MyCompanyName"
make ss_group ARGS="-n Widget"
make ss_group ARGS="-n Backoffice"
make ss_group ARGS="-n Core"
git remote rename origin origin-template
git remote add origin git@......
git add .
git commit -m'Initial project'
git push origin
git checkout -b TASK-123_MyNewProject
make proj ARGS='-s backoffice_fetcher'
#edit files
make run
# open 127.0.0.1:8080 in browser
# check results
git add .
git commit -m'My new project purpose'
git push origin TASK123-MyNewProject
# create merge or pull request for review
Structurizr - это инструмент для визуализации и документирования архитектуры, основанный на модели С4. В качестве языка используется собственный DSL structurizr, официальная документация
В данной модели используется единый workspace на все пространство. Таким образом описывается общий архитектурный ландшафт компании.
Персона представляет собой одного из пользователей вашей программной системы (например, актеров, роли, персоны и т.д.).
Software System - это самый высокий уровень абстракции, описывающий то, что приносит пользу (value) своим пользователям, независимо от того, являются ли они людьми или нет. Описываются не только те программные системы (Software System), которую вы моделируете, но и другие программные системы, от которых зависит ваша программная система (или наоборот).
Это система ограниченная одновременно:
- группой людей (команда разработки)
- предметной областью (блокчейн/игры/мессенджер/...) или технологическим стеком (мобильная разработка/WEB/...)
- особенностями производственного процесса
Для удобства Software system могут быть сгруппированы, что бы на диаграммах легко считывалась зона ответственности по каждому проекту.
Создать новую группу можно при помощи вызова:
make ss_group ARGS='-n GROUP_NAME'
Контейнеры представляют собой некое приложение, хранилище данных. Под хранилищем данных вы можете подразумевать файл, файловую систему или базу данных и т.д.
Контейнеру принято:
- Давать понятное название;
- Указывать общий список используемых технологий. К примеру для разрабатываемого вами ПО вы можете указать название, версию языка и основного фреймворка. Для СУБД вы можете просто указать название СУБД и её версию, например, Postgres 13;
- Необходимо давать краткое описание контейнера и описывать его основную ответственность.
Связи описываются в отдельных файлах с названием элемента-потребителя _rel.dsl и располагаются в отдельных папках rel в описании контейнеров
В модели используются 3 уровня представлений и представления под проект
Диаграмма уровня 0, описывает весь архитектурный ландшафт на уровне компании
Диаграмма уровня 1. Диаграмма контекста подходит для бизнес-пользователей, которым не нужно погружаться в технические нюансы. Диаграмма на уровне контекста систем отвечает на вопросы:
- Какую систему мы разрабатываем?
- Кто использует систему?
- Как она вписывается в текущую среду? Основной фокус на этом уровне должен быть на акторах и на системах, а не на технологиях, протоколах и прочих низкоуровневых деталях.
Диаграмма на уровне систем позволяет:
- Увидеть какая система добавляется в текущую среду;
- Без опасений непонимания показывать её коллегам с меньшим уровнем технического погружения;
- Понять, с кем вам вероятно нужно пойти переговорить для того, чтобы договориться о межсистемных взаимодействиях.
Диаграмма 2 уровня, описывает состав конкретной SoftwareSystem (из каких контейнеров состоит) и при описании проектов на уровне контейнеров.
Диаграмма контейнеров подходит для пользователей, которым нужно понять архитектуру приложения без глубокого погружения в техническую часть. Это наиболее полезная и обязательная абстракция при документировании системы.
Цели диаграммы – ответить на следующие вопросы:
- Какие технологии использует система?
- Из каких контейнеров состоит система?
- Как контейнеры взаимодействую между собой?
- Как контейнеры взаимодействую с внешними системами?
- Как пользователи взаимодействуют с документируемой системой?
Корневой файл репозитория workspace.dsl, в который импортируются другие файлы через ключевое слово !import Таким образом строится общая модель описания на основании древовидной структуры файлов. Репозиторий состоит из модели (model) и представлений (views) и стилей (styles)
workspace "Project architect landscape" "The architectural landscape of project" {
model {
!include model/person.dsl
!include model/software_system_group.dsl
!include model/relationship.dsl
}
views {
!include views
!include style/styles.dsl
}
}
Модель содержит описание систем (software system), контейнеров внутри систем (container) Связи между элементами описываются в отдельных dsl файлах, которые добавляются также иерархически через include после описания модели самих элементов. Такой подход позволяет избежать ошибки, что в рамках описания связей сам элемент еще не был объявлен В представлениях существует :
- Общие диаграммы System landscape и System context под системы и диаграммы по задачам/проектам (views на context и container)
- Файл со стилями styles.dsl содержит описание внешнего представления объектов на схемах.
Для инициализации правильной структуры каталогов можно воспользоваться командой
make init ARGS='-n COMPANY_NAME'
Используем правило $_{name} - наименование для создаваемой сущности.
- group_{name} - group
- s_{name} - softwareSystem
- c_{name} - container
- p_{name} - person
Описываются в /model/person.dsl
p_b2b_customer = person "B2B Customer" {
tags "TASK-123, SuperFeature"
}
Из атрибутов указываются тэги по проектам, в рамках которых участвуют данные акторы. Новые тэги добавляются в начало списка тегов.
Основные группы систем уже заведены в репозитории в файле /model/software_system_group.dsl
Системы описываются в рамках групп отдельными файлами /model/software_system_group/{group_name}/software_system/{software_system_name}.dsl
s_super_feature = softwaresystem "Super feature service" {
tags "Context: System"
tags "TASK-123, SuperFeature"
// описание контейнеров
}
Из атрибутов указываются тэг стиля (все значения можно посмотреть в файле styles.dsl) и тэги по проектам, в рамках которых участвуют данные системы. Новые тэги добавляются в начало списка.
Контейнеры описываются в рамках систем (в том же файле, что и система)
s_mysoftware = softwaresystem "My software" {
tags "Context: System" "My software"
c_mysoftware_api = container "Mysoftware API" {
technology "Java"
tags "Container: Backend Service", "Mysoftware"
}
c_mysoftware_pgsql_db = container "Mysoftware DB" {
technology "PostgreSQL"
tags "Container: Database" "Mysoftware"
}
c_mysoftware_redis = container "Mysoftware Redis" {
technology "Redis"
tags "Container: Database" "Mysoftware"
}
}
Из атрибутов указываются тэг стиля (все значения можно посмотреть в файле styles.dsl) и тэги по проектам, в рамках которых участвуют данные контейнеры. Новые тэги добавляются в начало списка.
Описываются в рамках систем и контейнеров. В рамках описания связей нужно дублировать связи для систем и для контейнеров. Это сделано осознанно для упрощения фильтрации потоков на диаграммах. Подход следующий:
- В рамках проработки задачи или описания текущих процессов описывается логическая связь между системами (связь SoftwareSystem -> SoftwareSystem), которая обязательно помечается тэгом Relation: SoftwareSystem
- В рамках детальной проработки или детального уточнения процессов описывается логическая связь между системами и контейнерами (связи SoftwareSystem -> Container или Container -> SoftwareSystem) , которая обязательно помечается тэгом Relation: Container
- В рамках детальной проработки или детального уточнения процессов описывается логическая или физическая связь между контейнерами (связи Container -> Container) , которая обязательно помечается тэгом Relation: Container Связи необходимо описывать именно в такой последовательности для корректного импорта и отображения на всех диаграммах.
Связи описываются от системы/контейнера потребителя и внутри самой системы между контейнерами в одном файле, название которого совпадает с названием системы {softwareSystemName}_rel.dsl
сами файлы располагаются в папка /software_system/{systemName}/rel
s_mysoftware -> s_newsoftware "" "gRPC" {
tags "Relation: Synchronous, Relation: SoftwareSystem"
tags "TASK-123, SuperFeature"
}
s_mysoftware -> c_newsoftware_api "GetThings" "gRPC" {
tags "Relation: Synchronous, Relation: Container"
tags "TASK-123, SuperFeature"
}
Из атрибутов кроме тэга по типу связи (синхронный или асинхронный поток) указываются тэг стиля (все значения можно посмотреть в файле styles.dsl) и тэги по проектам, в рамках которых участвуют данные системы/контейнеры. Новые тэги добавляются в начало списка.
Договоренность по взаимодействию систем и контейнеров через kafka следующая:
- На уровне software system указывается асинхронное взаимодействие между системами (тэг Relation: Asynchronous), элемент kafka как softwareSystem не отображается
- На уровне container отражается отдельный container kafka внутри системы-consumer-a, отражаются потоки между системой источником (producer), контейнером в системе источнике. Внутри системы-consumer взаимодействие контейнера kafka с контейнером/контейнерами consumer-ами
Представления описываются в рамках раздела /views
Уже описано в system_landscape.dsl, модификация не требуется
systemlandscape "SystemLandscape" {
include *
exclude "relationship.tag==Relation: Container"
autoLayout
}
Для детализации схем по системам может быть добавлено описание в system_context.dsl по аналогии, название представления == название SoftwareSystem
systemContext s_mysoftware "s_mysoftware" {
include *
exclude "relationship.tag==Relation: Container"
autoLayout
}
Через exclude исключаем из представления связи между контейнерами
Контейнерные диаграммы описываются в container.dsl
container s_mysoftware "My_Software_Container" {
include *
autoLayout
exclude "relationship.tag==Relation: SoftwareSystem"
}
Через exclude исключаем из представления связи между системами
Представления по проектам расположены в отдельной папке /views/PROJ/{Project-folder}
, который в корне папки проекта содержит файл .dsl
с представлениями по проекту и папку .sequences
с набором plantuml диаграмм с описанием sequence диаграмм по проекту. Файл .dsl
с представлениями требуется называть согласно коду проекта/задачи в jira.
Так как основным требованием является расстановка тэгов на всех элементах, которые участвуют в проекте, то описание схемы под проект строится по шаблону (для тэга TASK-XXX
):
За основу для диаграммы выбирается система {softwareSystemName}
, реализующая основную бизнес-логику в проекте
Скрипт который позволяет автоматически создать все необходимые файлы запускается следующим образом:
make proj ARGS='-p "TASK-XXX_Business_name" -s softwareSystemName'
В результате его работы создаются следующие файлы (из шаблона template/proj.tmpl
):
systemContext {softwareSystemName} "TASK-XXX_ctx" {
include "element.tag==TASK-XXX"
exclude "relationship.tag==Relation: Container"
exclude "relationship.tag!=TASK-XXX"
autoLayout
}
container {softwareSystemName} "TASK-XXX" {
include element.type==person
include element.type==container
exclude "element.tag!=TASK-XXX"
include element.type==softwaresystem
exclude "element.tag!=TASK-XXX"
exclude "relationship.tag!=TASK-XXX"
autoLayout
}
Если использовать structurizr on premise то в веб-интерфейсе structurizr при двойном клике на системе откроется выпадающий список со всеми контейнерными диаграммами, в т.ч. и по проектам.
Например, для проекта Task-123
:
systemContext s_super_feature "TASK-123_Super_Feature_ctx" {
include "element.tag==TASK-123"
exclude "relationship.tag==Relation: Container"
autoLayout
}
container s_super_feature "TASK-123_Super_Feature_ctx" {
include element.type==person
include element.type==container
exclude "element.tag!=TASK-123"
include element.type==softwaresystem
exclude "element.tag!=TASK-123"
exclude "relationship.tag!=TASK-123"
autoLayout
}
Дополнительно есть возможность убрать признак autoLayout и расставить локально (используя structurizr lite) элементы более специфически, но в репозитории все диаграммы пока храним с признаком autoLayout
В данный момент для цветовой дифференциации изменений используется groovy скрипт, который на основании тегов добавляет стили к элементам и связям. Тег для раскраски задаётся именем ветки в git. Для все элементов и связей у которых присутствует тег совпадающий с именем тега из названия ветки и это:
- единственный или последний тег в списке тегов - добавляется тег "NEW"
- не единственный и не последний в списке тегов - добавляется тег "MOD"
Теги "NEW" и "MOD" содержат оформления позволяющие идентифицировать тип изменений.
Исключением длЯ автоматического выставления тегов является:
- элементы типа Person
- элементы типа Component
- присутствие тега "NOT_MODIFIED" в группе с проектным тегом (используется в случае когда элемент в этом проекте используется но не модифицировался и не добавлялся).
Важно!
- При переключении ветки необходимо перезапускать structurizr-lite.
- При запуске необходимо передавать env с именем тега для раскраски (делается автоматически при make run)
Structurizr позволяет в интерфейсе отображать архитектурные решения в виде списка. В текущем репозитории предлагается оформлять ADR в виде markdown файлов в папке adrs. Правила следующие:
- ADR ведутся по проектам и описывают основные решения, которые были приняты по архитектуре проектов
- Название файла в формате xxxx-adr-name где xxxx - порядковое число по возрастанию
- Заголовок описывает название ADR
- Обязательно указывается Status (Статус) по adr, для принятых решений указывается Accepted
- Context (Контекст) объясняет, почему нам нужно принять решение. В нем также описаны альтернативы, а также плюсы и минусы.
- Decision (Решение) В решении описывается обоснование того, почему было принято конкретное решение. В нем больше внимания уделяется "почему", а не "как". Решение включает в себя набор альтернатив, аргументов и последствия принятия этой альтернативы.
- Consequences (Последствия) Указывается опционально, раздел последствий содержит информацию об общем воздействии архитектурного решения. У каждого решения есть компромиссы и их нужно указать. Также если архитектурное решение предполагает декомпозицию (например, если описывается верхне-уровневая архитектура интеграции, а затем дорабатываются отдельные документы по технологиям и протоколам для взаимодействия внутренних систем).
Structurizr также позволяет вести ADR и отображать их в веб интерфейсе в разделе Decisions на уровне SoftwareSystem и Containers
Название веток должно начинаться с номера таска по которому делается проект, например "TASK-123_SuperFeature"
Это важно потому, что на основании имени ветки будет производиться раскраска компонентов
На данный момент запуск structurizr-lite
производится при помощи make run
.
Важно! При запуске анализируется текущая ветка в git
и на основании её названия производится раскраска элементов. При переключении ветки необходимо перезапускать structurizr-lite
!