«1. Введение

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

Structurizr отказывается от традиционных подходов перетаскивания в редакторах архитектурных диаграмм, таких как UML, и позволяет нам описывать наши архитектурные артефакты с помощью инструмента, который мы знаем лучше всего: Java.

2. Начало работы

Для начала давайте добавим зависимость structurizr-core в наш pom.xml:

<dependency>
    <groupId>com.structurizr</groupId>
    <artifactId>structurizr-core</artifactId>
    <version>1.0.0</version>
</dependency>

3. Системы

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

Во-первых, нам нужно создать рабочее пространство и модель:

Workspace workspace = new Workspace("Payment Gateway", "Payment Gateway");
Model model = workspace.getModel();

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

Person user = model.addPerson("Merchant", "Merchant");
SoftwareSystem paymentTerminal = model.addSoftwareSystem(
  "Payment Terminal", "Payment Terminal");
user.uses(paymentTerminal, "Makes payment");
SoftwareSystem fraudDetector = model.addSoftwareSystem(
  "Fraud Detector", "Fraud Detector");
paymentTerminal.uses(fraudDetector, "Obtains fraud score");

Теперь, когда наша система определена, мы можем создать представление:

ViewSet viewSet = workspace.getViews();

SystemContextView contextView = viewSet.createSystemContextView(
  paymentTerminal, "context", "Payment Gateway Diagram");
contextView.addAllSoftwareSystems();
contextView.addAllPeople();

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

4. Просмотр через PlantUML

В предыдущем разделе мы создали представление простого платежного шлюза.

Следующий шаг — создать удобную для человека диаграмму. Вероятно, самым простым решением для организации, уже использующей PlantUML, было бы указание Structurizr выполнить экспорт PlantUML:

StringWriter stringWriter = new StringWriter();
PlantUMLWriter plantUMLWriter = new PlantUMLWriter();
plantUMLWriter.write(workspace, stringWriter);
System.out.println(stringWriter.toString());

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

5. Просмотр через веб-сайт Structurizr

Существует еще один вариант визуализации диаграмм. Архитектурный вид можно отправить на веб-сайт Structurizr через клиентский API. Затем диаграмма будет сгенерирована с использованием их богатого пользовательского интерфейса.

Давайте создадим клиент API:

StructurizrClient client = new StructurizrClient("key", "secret");

Параметры ключа и секрета получены из панели управления рабочей областью на их веб-сайте. Затем к рабочему пространству можно обратиться:

client.putWorkspace(1337, workspace);

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

6. Контейнеры

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

Во-первых, мы создаем несколько контейнеров для нашего платежного терминала:

Container f5 = paymentTerminal.addContainer(
  "Payment Load Balancer", "Payment Load Balancer", "F5");
Container jvm1 = paymentTerminal.addContainer(
  "JVM-1", "JVM-1", "Java Virtual Machine");
Container jvm2 = paymentTerminal.addContainer(
  "JVM-2", "JVM-2", "Java Virtual Machine");
Container jvm3 = paymentTerminal.addContainer(
  "JVM-3", "JVM-3", "Java Virtual Machine");
Container oracle = paymentTerminal.addContainer(
  "oracleDB", "Oracle Database", "RDBMS");

Затем мы определяем отношения между этими вновь созданными элементами:

f5.uses(jvm1, "route");
f5.uses(jvm2, "route");
f5.uses(jvm3, "route");

jvm1.uses(oracle, "storage");
jvm2.uses(oracle, "storage");
jvm3.uses(oracle, "storage");

Наконец, создаем представление контейнера, которое можно передать в средство визуализации :

ContainerView view = workspace.getViews()
  .createContainerView(paymentTerminal, "F5", "Container View");
view.addAllContainers();

Визуализация результирующей диаграммы с помощью PlantUML дает:

7. Компоненты

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

Во-первых, мы создаем некоторые компоненты в контейнере:

Component jaxrs = jvm1.addComponent("jaxrs-jersey", 
  "restful webservice implementation", "rest");
Component gemfire = jvm1.addComponent("gemfire", 
  "Clustered Cache Gemfire", "cache");
Component hibernate = jvm1.addComponent("hibernate", 
  "Data Access Layer", "jpa");

Затем давайте добавим некоторые отношения:

jaxrs.uses(gemfire, "");
gemfire.uses(hibernate, "");

Наконец, давайте создадим представление:

ComponentView componentView = workspace.getViews()
  .createComponentView(jvm1, JVM_COMPOSITION, "JVM Components");

componentView.addAllComponents();

Представление полученного Диаграмма с помощью PlantUML приводит к:

8. Извлечение компонентов

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

Чтобы использовать эту функцию, нам нужно добавить еще одну зависимость:

<dependency>
    <groupId>com.structurizr</groupId>
    <artifactId>structurizr-spring</artifactId>
    <version>1.0.0-RC5</version>
</dependency>

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

Мы даже можем подключить пользовательские стратегии разрешения:

ComponentFinder componentFinder = new ComponentFinder(
  jvm, "com.baeldung.structurizr",
  new SpringComponentFinderStrategy(
    new ReferencedTypesSupportingTypesStrategy()
  ),
  new SourceCodeComponentFinderStrategy(new File("/path/to/base"), 150));

Наконец, мы запускаем средство поиска:

componentFinder.findComponents();

Приведенный выше код сканирует пакет com.baeldung.structurizr на наличие bean-компонентов с аннотациями Spring и добавляет их в качестве компонентов в контейнер JVM. Излишне говорить, что мы можем реализовать свои собственные сканеры, аннотированные ресурсы JAX-RS и даже связыватели Google Guice.

Ниже приведен пример простой диаграммы из примера проекта:

9. Заключение

В этом кратком руководстве рассматриваются основы проекта Structurizr for Java.

И, как всегда, пример кода можно найти на GitHub.