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

  • C4,

  • ArchiMate,

  • SysML,

  • 4+1,

  • AADL.

В этой статье я хочу сфокусироваться на нотации моделирования архитектуры C4. Моя цель — показать практические примеры её применения, который вы сможете использовать как ориентир в своей работе, а также инструменты для её создания.

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

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

Теория по нотации C4

Нотация моделирования C4 — это метод визуализации архитектуры программного обеспечения, разработанный Саймоном Брауном. Она используется для создания диаграмм, описывающих архитектуру систем.

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

Название "C4" расшифровывается как:

  • Context - Контекст, 

  • Containers - Конейнеры,

  • Components - Компоненты,

  • Code - Код.

Эти четыре "C" представляют четыре уровня абстракции (представления), которые используются в этой нотации для визуализации архитектуры.

Уровни представления архитектуры в нотации C4 в примерах

Краткое и наглядное описание для одного проета: схема C4 в Miro c примером проекта.

Для этой статьи визуализацию сделаю с помощью кода и инструмента https://www.structurizr.com/dsl.

???? Context

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

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

Элементы:
- системы,
- пользователи,
- взаимосвязи.

Пример проекта:
Сервис-агрегатор
GetDelivery из моего канала для системных аналитиков, где я разбираю на практике задачи по проектированию систем.

Context - код для https://www.structurizr.com/dsl

workspace {

model {
    user = person "Клиент" "Использует приложение GetDelivery."
    admin = person "Администратор" "Управляет приложением GetDelivery."

    GetDelivery = softwareSystem "GetDelivery" "Сервис доставки." {
        webApp = container "Web-приложение" "Интерфейс для клиентов." "Web Application"
        mobileAppiOS = container "Mobile App iOS" "iOS приложение для клиентов." "iOS"
        mobileAppAndroid = container "Mobile App Android" "Android приложение для клиентов." "Android"
        adminWebApp = container "Web App Admin" "Интерфейс для администраторов." "Web Application"
        backend = container "Backend" "Обрабатывает бизнес-логику." "Server-side Application"
        database = container "База данных" "Хранит информацию о заказах, пользователях и т.д." "Database"
        userDatabase = container "База данных пользователей" "Хранит данные пользователей." "Database"
        reportStorage = container "Файловое хранилище отчетов" "Хранит PDF отчеты." "File Storage"
        logicService = container "Сервис основной логики" "Обрабатывает основные функции системы." "Server-side Application"
        deliveryIntegrationService = container "Сервис интеграций с сервисами доставки" "Интеграция с СДЭК, Возовоз, Деловые Линии." "Server-side Application"
        authService = container "Сервис авторизации и регистрации пользователей" "Управляет авторизацией и регистрацией." "Server-side Application"
        reportService = container "Сервис генерации отчетов" "Генерирует PDF отчеты." "Server-side Application"
    }

    cdek = softwareSystem "СДЭК" "Система доставки."
    vozovoz = softwareSystem "Возовоз" "Система доставки."
    delovieLinii = softwareSystem "Деловые Линии" "Система доставки."

    user -> webApp "Использует"
    user -> mobileAppiOS "Использует"
    user -> mobileAppAndroid "Использует"
    admin -> adminWebApp "Использует"
    webApp -> backend "Взаимодействует"
    mobileAppiOS -> backend "Взаимодействует"
    mobileAppAndroid -> backend "Взаимодействует"
    adminWebApp -> backend "Взаимодействует"
    backend -> database "Использует"
    backend -> userDatabase "Использует"
    backend -> logicService "Использует"
    backend -> deliveryIntegrationService "Использует"
    backend -> authService "Использует"
    backend -> reportService "Использует"
    logicService -> reportStorage "Сохраняет отчеты"
    reportService -> reportStorage "Сохраняет отчеты"
    deliveryIntegrationService -> cdek "Интеграция"
    deliveryIntegrationService -> vozovoz "Интеграция"
    deliveryIntegrationService -> delovieLinii "Интеграция"
}

views {
    systemContext GetDelivery {
        include *
        autolayout lr
    }

    theme default
}
}

Пример проекта сервис-агрегатор для расчета наиболее выгодной стоимости доставки GetDelivery.

???? Container

Описывает верхнеуровневую архитектуру и технологии. Используется для понимания технологического стека и разделения зон ответственности.

Элементы:
- контейнеры (например, веб-приложения, базы данных),
- взаимосвязи,
- технологии.

Пример проекта: Сервис-агрегатор GetDelivery из моего канала для системных аналитиков, где я разбираю на практике задачи по проектированию систем.

Container - код для https://www.structurizr.com/dsl
workspace {

    model {
        user = person "Клиент" "Использует приложение GetDelivery."
        admin = person "Администратор" "Управляет приложением GetDelivery."

        GetDelivery = softwareSystem "GetDelivery" "Сервис доставки." {
            webApp = container "Web-приложение" "Интерфейс для клиентов." "Web Application"
            mobileAppiOS = container "Mobile App iOS" "iOS приложение для клиентов." "iOS"
            mobileAppAndroid = container "Mobile App Android" "Android приложение для клиентов." "Android"
            adminWebApp = container "Web App Admin" "Интерфейс для администраторов." "Web Application"
            backend = container "Backend" "Обрабатывает бизнес-логику, содержит сервисы и базы данных." "Server-side Application"
        }

        cdek = softwareSystem "СДЭК" "Система доставки." 
        vozovoz = softwareSystem "Возовоз" "Система доставки."
        delovieLinii = softwareSystem "Деловые Линии" "Система доставки."

        user -> webApp "Использует"
        user -> mobileAppiOS "Использует"
        user -> mobileAppAndroid "Использует"
        admin -> adminWebApp "Использует"
        webApp -> backend "API"
        mobileAppiOS -> backend "API"
        mobileAppAndroid -> backend "API"
        adminWebApp -> backend "API"
        backend -> cdek "HTTPS/JSON"
        backend -> vozovoz "HTTPS/JSON"
        backend -> delovieLinii "HTTPS/JSON"
    }

    views {
        container GetDelivery {
            include *
            autolayout lr
        }

        theme default
    }
}

???? Component

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

Используется для проектирования и документирования внутренней структуры компонентов системы.

Элементы:
- компоненты,
- взаимосвязи,
- технологии,
- зависимости.

Пример проекта: Сервис-агрегатор GetDelivery из моего канала для системных аналитиков, где я разбираю на практике задачи по проектированию систем.

Реализована в Draw.io
Реализована в Draw.io

Про возможности Structurizr

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

Пример кода диаграммы Component и других уровней

/*
 * This is a combined version of the following workspaces, with automatic layout enabled:
 *
 * - "Big Bank plc - System Landscape" (https://structurizr.com/share/28201/)
 * - "Big Bank plc - Internet Banking System" (https://structurizr.com/share/36141/)
*/
workspace "Big Bank plc" "This is an example workspace to illustrate the key features of Structurizr, via the DSL, based around a fictional online banking system." {

    model {
        customer = person "Personal Banking Customer" "A customer of the bank, with personal bank accounts." "Customer"

        group "Big Bank plc" {
            supportStaff = person "Customer Service Staff" "Customer service staff within the bank." "Bank Staff"
            backoffice = person "Back Office Staff" "Administration and support staff within the bank." "Bank Staff"

            mainframe = softwaresystem "Mainframe Banking System" "Stores all of the core banking information about customers, accounts, transactions, etc." "Existing System"
            email = softwaresystem "E-mail System" "The internal Microsoft Exchange e-mail system." "Existing System"
            atm = softwaresystem "ATM" "Allows customers to withdraw cash." "Existing System"

            internetBankingSystem = softwaresystem "Internet Banking System" "Allows customers to view information about their bank accounts, and make payments." {
                singlePageApplication = container "Single-Page Application" "Provides all of the Internet banking functionality to customers via their web browser." "JavaScript and Angular" "Web Browser"
                mobileApp = container "Mobile App" "Provides a limited subset of the Internet banking functionality to customers via their mobile device." "Xamarin" "Mobile App"
                webApplication = container "Web Application" "Delivers the static content and the Internet banking single page application." "Java and Spring MVC"
                apiApplication = container "API Application" "Provides Internet banking functionality via a JSON/HTTPS API." "Java and Spring MVC" {
                    signinController = component "Sign In Controller" "Allows users to sign in to the Internet Banking System." "Spring MVC Rest Controller"
                    accountsSummaryController = component "Accounts Summary Controller" "Provides customers with a summary of their bank accounts." "Spring MVC Rest Controller"
                    resetPasswordController = component "Reset Password Controller" "Allows users to reset their passwords with a single use URL." "Spring MVC Rest Controller"
                    securityComponent = component "Security Component" "Provides functionality related to signing in, changing passwords, etc." "Spring Bean"
                    mainframeBankingSystemFacade = component "Mainframe Banking System Facade" "A facade onto the mainframe banking system." "Spring Bean"
                    emailComponent = component "E-mail Component" "Sends e-mails to users." "Spring Bean"
                }
                database = container "Database" "Stores user registration information, hashed authentication credentials, access logs, etc." "Oracle Database Schema" "Database"
            }
        }

        # relationships between people and software systems
        customer -> internetBankingSystem "Views account balances, and makes payments using"
        internetBankingSystem -> mainframe "Gets account information from, and makes payments using"
        internetBankingSystem -> email "Sends e-mail using"
        email -> customer "Sends e-mails to"
        customer -> supportStaff "Asks questions to" "Telephone"
        supportStaff -> mainframe "Uses"
        customer -> atm "Withdraws cash using"
        atm -> mainframe "Uses"
        backoffice -> mainframe "Uses"

        # relationships to/from containers
        customer -> webApplication "Visits bigbank.com/ib using" "HTTPS"
        customer -> singlePageApplication "Views account balances, and makes payments using"
        customer -> mobileApp "Views account balances, and makes payments using"
        webApplication -> singlePageApplication "Delivers to the customer's web browser"

        # relationships to/from components
        singlePageApplication -> signinController "Makes API calls to" "JSON/HTTPS"
        singlePageApplication -> accountsSummaryController "Makes API calls to" "JSON/HTTPS"
        singlePageApplication -> resetPasswordController "Makes API calls to" "JSON/HTTPS"
        mobileApp -> signinController "Makes API calls to" "JSON/HTTPS"
        mobileApp -> accountsSummaryController "Makes API calls to" "JSON/HTTPS"
        mobileApp -> resetPasswordController "Makes API calls to" "JSON/HTTPS"
        signinController -> securityComponent "Uses"
        accountsSummaryController -> mainframeBankingSystemFacade "Uses"
        resetPasswordController -> securityComponent "Uses"
        resetPasswordController -> emailComponent "Uses"
        securityComponent -> database "Reads from and writes to" "SQL/TCP"
        mainframeBankingSystemFacade -> mainframe "Makes API calls to" "XML/HTTPS"
        emailComponent -> email "Sends e-mail using"

        deploymentEnvironment "Development" {
            deploymentNode "Developer Laptop" "" "Microsoft Windows 10 or Apple macOS" {
                deploymentNode "Web Browser" "" "Chrome, Firefox, Safari, or Edge" {
                    developerSinglePageApplicationInstance = containerInstance singlePageApplication
                }
                deploymentNode "Docker Container - Web Server" "" "Docker" {
                    deploymentNode "Apache Tomcat" "" "Apache Tomcat 8.x" {
                        developerWebApplicationInstance = containerInstance webApplication
                        developerApiApplicationInstance = containerInstance apiApplication
                    }
                }
                deploymentNode "Docker Container - Database Server" "" "Docker" {
                    deploymentNode "Database Server" "" "Oracle 12c" {
                        developerDatabaseInstance = containerInstance database
                    }
                }
            }
            deploymentNode "Big Bank plc" "" "Big Bank plc data center" "" {
                deploymentNode "bigbank-dev001" "" "" "" {
                    softwareSystemInstance mainframe
                }
            }

        }

        deploymentEnvironment "Live" {
            deploymentNode "Customer's mobile device" "" "Apple iOS or Android" {
                liveMobileAppInstance = containerInstance mobileApp
            }
            deploymentNode "Customer's computer" "" "Microsoft Windows or Apple macOS" {
                deploymentNode "Web Browser" "" "Chrome, Firefox, Safari, or Edge" {
                    liveSinglePageApplicationInstance = containerInstance singlePageApplication
                }
            }

            deploymentNode "Big Bank plc" "" "Big Bank plc data center" {
                deploymentNode "bigbank-web***" "" "Ubuntu 16.04 LTS" "" 4 {
                    deploymentNode "Apache Tomcat" "" "Apache Tomcat 8.x" {
                        liveWebApplicationInstance = containerInstance webApplication
                    }
                }
                deploymentNode "bigbank-api***" "" "Ubuntu 16.04 LTS" "" 8 {
                    deploymentNode "Apache Tomcat" "" "Apache Tomcat 8.x" {
                        liveApiApplicationInstance = containerInstance apiApplication
                    }
                }

                deploymentNode "bigbank-db01" "" "Ubuntu 16.04 LTS" {
                    primaryDatabaseServer = deploymentNode "Oracle - Primary" "" "Oracle 12c" {
                        livePrimaryDatabaseInstance = containerInstance database
                    }
                }
                deploymentNode "bigbank-db02" "" "Ubuntu 16.04 LTS" "Failover" {
                    secondaryDatabaseServer = deploymentNode "Oracle - Secondary" "" "Oracle 12c" "Failover" {
                        liveSecondaryDatabaseInstance = containerInstance database "Failover"
                    }
                }
                deploymentNode "bigbank-prod001" "" "" "" {
                    softwareSystemInstance mainframe
                }
            }

            primaryDatabaseServer -> secondaryDatabaseServer "Replicates data to"
        }
    }

    views {
        systemlandscape "SystemLandscape" {
            include *
            autoLayout
        }

        systemcontext internetBankingSystem "SystemContext" {
            include *
            animation {
                internetBankingSystem
                customer
                mainframe
                email
            }
            autoLayout
            description "The system context diagram for the Internet Banking System."
            properties {
                structurizr.groups false
            }
        }

        container internetBankingSystem "Containers" {
            include *
            animation {
                customer mainframe email
                webApplication
                singlePageApplication
                mobileApp
                apiApplication
                database
            }
            autoLayout
            description "The container diagram for the Internet Banking System."
        }

        component apiApplication "Components" {
            include *
            animation {
                singlePageApplication mobileApp database email mainframe
                signinController securityComponent
                accountsSummaryController mainframeBankingSystemFacade
                resetPasswordController emailComponent
            }
            autoLayout
            description "The component diagram for the API Application."
        }

        image mainframeBankingSystemFacade "MainframeBankingSystemFacade" {
            image https://raw.githubusercontent.com/structurizr/examples/main/dsl/big-bank-plc/internet-banking-system/mainframe-banking-system-facade.png
            title "[Code] Mainframe Banking System Facade"
        }

        dynamic apiApplication "SignIn" "Summarises how the sign in feature works in the single-page application." {
            singlePageApplication -> signinController "Submits credentials to"
            signinController -> securityComponent "Validates credentials using"
            securityComponent -> database "select * from users where username = ?"
            database -> securityComponent "Returns user data to"
            securityComponent -> signinController "Returns true if the hashed password matches"
            signinController -> singlePageApplication "Sends back an authentication token to"
            autoLayout
            description "Summarises how the sign in feature works in the single-page application."
        }

        deployment internetBankingSystem "Development" "DevelopmentDeployment" {
            include *
            animation {
                developerSinglePageApplicationInstance
                developerWebApplicationInstance developerApiApplicationInstance
                developerDatabaseInstance
            }
            autoLayout
            description "An example development deployment scenario for the Internet Banking System."
        }

        deployment internetBankingSystem "Live" "LiveDeployment" {
            include *
            animation {
                liveSinglePageApplicationInstance
                liveMobileAppInstance
                liveWebApplicationInstance liveApiApplicationInstance
                livePrimaryDatabaseInstance
                liveSecondaryDatabaseInstance
            }
            autoLayout
            description "An example live deployment scenario for the Internet Banking System."
        }

        styles {
            element "Person" {
                color #ffffff
                fontSize 22
                shape Person
            }
            element "Customer" {
                background #08427b
            }
            element "Bank Staff" {
                background #999999
            }
            element "Software System" {
                background #1168bd
                color #ffffff
            }
            element "Existing System" {
                background #999999
                color #ffffff
            }
            element "Container" {
                background #438dd5
                color #ffffff
            }
            element "Web Browser" {
                shape WebBrowser
            }
            element "Mobile App" {
                shape MobileDeviceLandscape
            }
            element "Database" {
                shape Cylinder
            }
            element "Component" {
                background #85bbf0
                color #000000
            }
            element "Failover" {
                opacity 25
            }
        }
    }
}

Источник: https://github.com/structurizr/examples/tree/main/dsl (big-bank-pic)

Если скопируете код и вставите в https://www.structurizr.com/dsl, то увидете следующее:

Дополнительный пример уровня Component из Miro для проекта Зоомагазина:

???? Code

Показывает детали реализации отдельных компонентов.

Используется для документирования структуры кода. На практике не используется, т.к. разработчикам это не надо. Это как диаграмма классов UML: вроде полезно понимать, а по факту не нужна.

Элементы:
- классы,
- интерфейсы,
- отношения между ними.

Пример можно посмотреть на сайте автора нотации - Саймона Брауна по банковскому проекту.

Где создавать схемы C4 - инструменты

Для создания схем в нотации C4 можно использовать:

  • графические инструменты,

  • инструменты визуализации через код (+ ChatGPT).

Использование инструментов, которые позволяют описывать C4 через код, позволяют ускорить процесс за счет использования искусственного интеллекта - ChatGPT или аналог.

1. Draw.io — графический инструмент

Draw.io (diagrams.net) — это бесплатный онлайн-инструмент, который подходит для создания различных видов диаграмм, включая C4. Он предоставляет широкий набор элементов дизайна, что делает его удобным для быстрого создания диаграмм.

Есть минусы в редактировании, когда на диаграмме много элементов: бывает, что перемещаешь не то что хотел, или не так, как хотел.

Плюсы:
+ Бесплатный;
+ Есть все виды диаграмм;
+ Есть интеграция с Confluence, Google Drive и другими постоянно используемыми программами.

Минусы:
- Большие схемы приводят к страданиями при редактировании. Это проблема всех графических редакторов.

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

Как включить C4 в Draw.io
Добавление элементов С4 в Draw.io
Добавление элементов С4 в Draw.io

Пример C4 в Draw.io
Пример C4 в Draw.io

2. Miro — графический инструмент

Miro — это онлайн-платформа для визуального создания и обсуждения проектов на электронных досках, которая также может быть использована для создания C4 диаграмм.

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

Плюсы:
+ Есть интеграция с Confluence, Google Drive и другими постоянно используемыми программами.
+ Приятный и удобный интерфейс, более современно выглядит, чем Draw.io.

Минусы:
- Ограничение на количество бесплатных досок, поэтому условно платный.
- Большие схемы приводят к страданиями при редактировании.
- Элементы C4 не стандартные для Miro, что может приводить к проблемам при редактировании.

Заключение:
При сравнении опыта работы с Miro и Draw.io, я остаюсь сторонником более простого и удобного Draw.io, так как для Miro возможность отрисовки C4 скорее неожиданная опция, чем удобная фича.

Шаблон Miro с элементами C4
Шаблон Miro с элементами C4

3. Microsoft Visio — графический инструмент

Microsoft Visio от Microsoft — это профессиональное решение для создания сложных диаграмм. Аналогичен по функциональности Draw.io, и скорее всего шаблоны элементов C4 придётся сначала создать, как в Miro.

Плюсы:
+ Распространен в IT-компаниях.

Минусы:
- Платный.
- Работа в оффлайн, хотя для кого-то это может быть и плюсом.
- Не предназначен для C4.

Заключение:
Я выберу draw.io, так как несколько лет не открывала Visio и у меня уже больше года не Windows.

4. Structurizr — инструмент визуализации через код

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

Чтобы использовать Structurizr для описания архитектуры в нотации C4:

  1. Используйте онлайн-интерфейс с редактором DSL: https://www.structurizr.com/dsl.

  2. Напишите или вставьте приведенный ниже код в редактор Structurizr.

  3. Нажмите "Render" справа сверху, над панелью с кодом, чтобы увидеть вашу диаграмму.

Плюсы:
+ Бесплатный.
+ Удобный в использовании.
+ Понятный язык разметки, которым "рисовать".
+ Поддерживает генерацию кода через искусственный интеллект (ChatGPT).
+ Визуально простой и понятный.
+ Чистый интерфейс - нет мусорной рекламы.
+ Можно даже писать на Java код для визуализации.
+ Потрясающая база знаний с примерами на английском языке.

Минусы:
- Могут быть сложности с визуализацией больших диаграмм.

Заключение:
Брать и использовать.

Примеры кода для Structurizr - Context

Код для диаграммы на уровне Context:

workspace {

    model {
        user = person "Пользователь" "Описание пользователя."
        bankingSystem = softwareSystem "Банковская Система" "Описание банковской системы."

        user -> bankingSystem "Использует" "HTTPS"
    }

    views {
        systemContext bankingSystem {
            include *
            autoLayout lr
        }

        theme default
    }
}

Этот код создает диаграмму контекста с двумя элементами:

  1. "Пользователь" (отображается как Person в PlantUML), который взаимодействует с системой.

  2. "Банковская Система" (отображается как System), которая представляет собой внешнюю систему, с которой взаимодействует пользователь.

Между этими элементами устанавливается связь с описанием "Использует" и протоколом "HTTPS".

Примеры кода для Structurizr - Container

Код для уровня Container:

workspace {

    model {
        user = person "Пользователь" "Описание пользователя."

        bankingSystem = softwareSystem "Банковская Система" {
            webApp = container "Веб-приложение" "Предоставляет банковские услуги онлайн." "Java"
            db = container "База Данных" "Хранит данные о счетах и транзакциях." "MySQL"
            api = container "API" "Предоставляет API для доступа к данным." "RESTful"
        }

        user -> webApp "Использует" "HTTPS"
        webApp -> db "Читает/записывает" "JDBC"
        api -> db "Запрашивает" "JDBC"
    }

    views {
        container bankingSystem {
            include *
            autoLayout lr
        }

        theme default
    }
}

Этот код создаёт диаграмму контейнеров внутри системы "Банковская Система". Здесь мы видим:

  1. Пользователь, который взаимодействует с веб-приложением.

  2. В Банковской Системе теперь определены три контейнера:

    • Веб-приложение: Представляет собой пользовательский интерфейс, написанный на Java.

    • База Данных: MySQL база данных, хранящая информацию.

    • API: RESTful API для доступа к данным базы.

Примеры кода для Structurizr - Component

Детализирует контейнер "Веб-приложение" из предыдущего примера.

В этом примере мы фокусируемся на компонентах внутри "Веб-приложения":

Также показаны связи между этими компонентами, а также их взаимодействие с внешними контейнерами, такими как "API" и физическая "База Данных".

Код для уровня Component:

workspace {

    model {
        user = person "Пользователь" "Описание пользователя."
        
        
        bankingSystem = softwareSystem "Банковская Система" {
        webApp = container "Веб-приложение" {
            ui = component "Пользовательский Интерфейс" "Angular, Предоставляет веб-интерфейс для пользователей."
            server = component "Серверная Логика" "Spring Boot, Обрабатывает запросы от пользовательского интерфейса."
            databaseComponent = component "Компонент Базы Данных" "JPA/Hibernate, Обеспечивает доступ к данным."
        }

        api = container "API" "RESTful, Предоставляет API для доступа к данным."
        db = container "База Данных" "MySQL, Хранит данные о счетах и транзакциях."

        user -> ui "Использует" "HTTPS"
        ui -> server "Вызывает" "JSON/HTTP"
        server -> databaseComponent "Использует" "JDBC"
        server -> api "Делает запросы" "JSON/HTTP"
        databaseComponent -> db "Читает/Записывает" "JDBC"
        }
    }

    views {
        component webApp {
            include *
            autoLayout lr
        }

        theme default
    }
}

5. PlantUML — инструмент визуализации через код

PlantUML — это инструмент, который позволяет создавать UML-диаграммы из текстового описания. Он поддерживает синтаксис для создания диаграмм C4, но работает с перебоями - периодически не поддерживает загрузку визуализатора по ссылке и выдаёт ошибку. Поэтому рекомендую использовать только от большой любви к PlantUML.

Плюсы:
+ Можно аккуратно визуализировать диаграммы через код.

Минусы:
- Работает нестабильно.

Заключение:
Structurizr лучше подходит для создания C4-диаграмм через код.

Чтобы использовать PlantUML для описания архитектуры в нотации C4:

  1. Используйте онлайн-интерфейс PlantUML, такой как PlantText или онлайн-редактор PlantUML на сайте plantuml.com.

  2. Напишите или вставьте приведенный ниже код в редактор PlantUML.

  3. Диаграмма будет автоматически сгенерирована на основе этого текстового описания. Либо нажмите "Submit".

*В случае проблем с отображением из-за недоступности URL https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml внутри PlantUML смените браузер или переключитесь несколько раз между дневным и ночным режимами (переключатель справа от кнопки "Submit").

Примеры кода для PlantUML

Context

Пример кода на PlantUML для диаграммы на уровне Context:

@startuml C4_Example
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml

LAYOUT_WITH_LEGEND()

Person(user, "Пользователь", "Описание пользователя.")
System(bankingSystem, "Банковская Система", "Описание банковской системы.")

Rel(user, bankingSystem, "Использует", "HTTPS")
@enduml

*Если не увидете диаграмму сразу, переключитесь в темную/светлую тему или смените браузер. Бывают проблемы с установкой соединения.

Куча рекламы вокруг печалит.
Куча рекламы вокруг печалит.

Container

Код для уровня Container:

@startuml C4_Containers
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

LAYOUT_WITH_LEGEND()

Person(user, "Пользователь", "Описание пользователя.")

System_Boundary(bankingSys, "Банковская Система") {
    Container(webApp, "Веб-приложение", "Java", "Предоставляет банковские услуги онлайн.")
    Container(db, "База Данных", "MySQL", "Хранит данные о счетах и транзакциях.")
    Container(api, "API", "RESTful", "Предоставляет API для доступа к данным.")
}

Rel(user, webApp, "Использует", "HTTPS")
Rel(webApp, db, "Читает/записывает", "JDBC")
Rel(api, db, "Запрашивает", "JDBC")
@enduml

Component

Детализируем "Веб-приложение" из предыдущего примера. Код для уровня Component:

@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml

LAYOUT_WITH_LEGEND()

Container_Boundary(webApp, "Веб-приложение") {
    Component(ui, "Пользовательский Интерфейс", "Angular", "Предоставляет веб-интерфейс для пользователей.")
    Component(server, "Серверная Логика", "Spring Boot", "Обрабатывает запросы от пользовательского интерфейса.")
    Component(database, "База Данных", "JPA/Hibernate", "Обеспечивает доступ к данным.")
}

Container(api, "API", "RESTful", "Предоставляет API для доступа к данным.")
Container(db, "База Данных", "MySQL", "Хранит данные о счетах и транзакциях.")

Person(user, "Пользователь", "Описание пользователя.")
Rel(user, ui, "Использует", "HTTPS")

Rel(ui, server, "Вызывает", "JSON/HTTP")
Rel(server, database, "Использует", "JDBC")
Rel(server, api, "Делает запросы", "JSON/HTTP")
Rel(database, db, "Читает/Записывает", "JDBC")
@enduml

Выводы

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

Я рекомендую для создания диаграммы C4 инструменты Draw.io и Structurizr.

Заключение

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

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

Наиболее полезные уровни:

  • Context — общее представление, полезен для понимания внешних взаимодействий с системой - интеграций.

  • Container — устройство системы внутри, подходит для понимания какие есть веб-, мобильные, серверные, и другие виды приложений.

  • Component — идеально подходит для документирования архитектуры Backend, основной уровень описания архитектуры, который требует внимания на проекте.

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

Дополнительно примеры схем архитектуры в можно посмотреть в моем канале в этом посте, и сверху-снизу от него.

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

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

Дополнительная информация

Теория и примеры

  1. The C4 model for visualising software architecture
    The C4 model and this website were created by Simon Brown
    Первоисточник с теорией по нотации, где можно искать ответы на вопросы "как правильно...".

  2. Примеры архитектуры для интеграционных проектов:

    1. Зоо-магазин онлайн.

    2. Логистический сервис: от монолита до микросервисов.

  3. Еще одна хорошая статья на Habr с аккуратным примером и теорией.
    Как описать большую систему в нотации С4.

Инструменты

  1. Пример схемы архитектуры проекта в Miro - интернет-зоомагазин
    Екатерина Ананьева
    Пример схемы архитектуры в нотации С4, на основе которого можно изучать нотацию и из которого можно переносить шаблоны элементов в свой собственный Miro.

  2. C4 Model with PlantUML (англ)
    Huseyin Kutluca
    Статья про возможность использования PlantUML для создания диаграмм в нотации C4. В ней можно взять дополнительные примеры для изучения и лучше понять подход к написанию кода.

  3. https://github.com/structurizr/examples/tree/main/dsl
    База данных с примерами для инструмента structurizr, с помощью которого можно описывать диаграммы C4 через код.

Комментарии (4)


  1. Foxcool
    08.12.2023 03:01
    +1

    Недавно открыл для себя mermaid как доступный способ кодом "рисовать" диаграммы. Поддерживаются различные виды, в том числе в бете поддреживаются С4 диаграммы. Автоматически рендерится в схемы на гитлабе, обсидиане. В вскод тоже работает, как минимум с установкой расширения (точно не помню). Т.е. можно без каких-либо отдельных инструментов вести ту же документацию сразу в гит-репозиториях в маркдауне и при этом не надо тащить картинками схемы - все изменения будут фиксироваться, как и изменения другого текста.


  1. Fred_Chou
    08.12.2023 03:01

    В Visio нет наборов элементов для рисования C4


  1. notffirk
    08.12.2023 03:01
    +1

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

    Тогда на помощь приходят системы для управления корпоративной архитектуры, такие как iserver и leanix и другие


  1. Dmitriys88
    08.12.2023 03:01

    Описание диаграмм кодом это пока очень грустно, так как autolayout пока что умеет работать с 4-5 квадратами и 8-10 стрелками. Когда их становится больше, а их всегда больше в реальных диаграммах реальных систем, то ты сначала вынужден тратить кучу времени на написание кода (это всегда дольше, чем в графическом редакторе из готового набора элементов drag'n'drop'ом вытянуть квадратик или стрелочку), а потом еще в 10 раз больше времени на то, чтобы потом все расставить так, чтобы это было хоть сколько-нибудь читаемо.

    Также в вашем примере с GetDelivery на С2 и С3 все перемешалось в кучу. Поизучайте, что есть Container и что есть Component и как эти абстракции вкладываются друг в друга на диаграммах. Половина ваших компонент на уровне С3 это на самом деле контейнеры с уровня С2 (если не все вообще). Просто попробуйте запихнуть это в тот же structurizr, поймете о чем я????