Автогенерация архитектуры �«as Code»
Руслан Сафин, Бындюсофт
Руслан Сафин
Технический директор и архитектор в Бындюсофт
Автор и преподаватель курса по микросервисной архитектуре в ИТМО
Член программных комитетов CodeFest, TechLeadConf и UWDC
2
Byndyusoft — 12 лет на рынке
Создаём IT-продукты для на заказ. Нам доверяют ключевые сервисы, от которых зависит бизнес.
3
Архитектура As Code
4
ИТ-архитектура
«Фундаментальная организация системы, реализованная в её компонентах, их взаимоотношениях друг с другом и средой и принципах, определяющих её конструкцию и развитие»
© стандарт ANSI/IEEE Std 1471-2000
5
5
5
Архитектура — картинка
6
Картинка
—
+
7
Код
+
—
8
Код → Картинка
+
9
Инструменты
10
Архитектура микросервисов в 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")
12
12
12
13
Преимущества архитектуры «as code»
14
Проблемы �архитектурных схем
0. Их отсутствие😅
15
Неактуальность архитектуры
16
Неактуальность архитектуры
17
Архитектуру теперь можно описывать кодом�↓�значит её можно сгенерировать!
18
19
Автогенерация архитектуры
20
На примере архитектуры микросервисов
21
21
21
Архитектура микросервисов в 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")
22
22
22
Откуда брать актуальные зависимости сервисов?
— Сложность извлечения данных
— Отсутствие инфраструктурных данных
Код сервисов
+ Первоисточник поведения сервисов
23
Откуда брать актуальные зависимости сервисов?
�— Нет «редких» связей
— Сложность симуляции на препроде
— Данные только после появления трафика
Service Mesh
�+ Реальный трафик
24
Ещё варианты? 🙂
25
26
Откуда брать актуальные зависимости сервисов?
k8s configs
�+ Все связи, включая «редкие»
+ Бóльшая информативность
+ Данные не требуют трафика
27
Конфиг сервиса
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
28
28
28
Берём данные из конфигов
[
Сервис1 {
[ связь1, связь2 ]
},
Сервис2 {
[ связь1, связь3 ]
},
...
]
29
29
Реализация
30
30
Результат генерации
31
Ручной�plantuml
Сгенери-рованный
Что ещё можно добавить?
Всё, что есть в конфиге и важно отразить на архитектуре ☺
Например:
33
33
33
Что если результат плачевный?
34
34
34
Сигнал о нарушении принципов:
35
35
35
Подробнее о принципах проектирования и исправлении их нарушений:
Ещё сложности
37
37
37
Генерировать постоянно
38
s
v
Внести изменения в единожды сгенерированное
Что если второе?
Проблемы архитектурных схем
0. Их отсутствие ✅
39
40
Сравниваем данные из архитектуры и конфигов
41
[
Сервис1 {
[ связь1, связь2 ]
},
Сервис2 {
[ связь1, связь2 ]
},
]
[
Сервис1 {
[ связь1, связь3 ]
},
Сервис2 {
[ связь1 ]
},
Сервис3
]
41
41
42
42
42
Пример — сопоставление списка сервисов
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);
});
43
43
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",
44
44
44
Проблемы �архитектурных схем
0. Их отсутствие ✅
45
Декларативность
46
Декларативность
47
Отсутствие контроля
48
Тесты на соблюдение архитектурных принципов
49
1. ACL (Anti-corruption Layer) Pattern
За интеграцию с внешними системами ответственны отдельные микросервисы-адаптеры, инкапсулирующие в себе знания о внешних системах (например, об их доменных сущностях)
50
50
50
1. ACL (Anti-corruption Layer) Pattern
51
1. ACL (Anti-corruption Layer) Pattern
Как протестить:
52
Container(goods_adapter, “Goods ACL", "NestJS", $tags="adapter")
52
52
Больше примеров принципов и тестов на них:
53
Проблемы архитектурных схем
0. Их отсутствие ✅
54
Предписания архитекторов могут нарушаться по незнанию или умышленно
55
Архитектурные изменения не пройдут мимо архитектора
55
55
Личный опыт
В «продакшне» несколько месяцев
56
Личный опыт, решённые проблемы
57
57
57
Как начать применять?
58
58
58
Как присоединиться к развитию OpenSource-репозитория?
59
Roadmap репозитория
https://github.com/Byndyusoft/aact/blob/main/roadmap.md
60
60
60
Roadmap репозитория. Покрытие архитектуры тестами�
✅ Покрытие тестами микросервисной архитектуры
✅ Покрытие тестами архитектуры модульного монолита
🟩 Добавление реализаций и примеров под разные стэки (сейчас TypeScript и C#)
⌛ Справочник принципов и паттернов проектирования (например, в формате ADR)
⌛ Примеры тестов на пункты справочника
61
61
61
Покрытие архитектуры тестами. Справочник паттернов�
62
62
62
Roadmap репозитория. Автогенерация�
✅ Автогенерация архитектурной схемы по конфигам инфраструктуры
🟩 Автогенерация конфигов инфраструктуры по архитектурной схеме
🟩 Добавление провайдеров для различных реализаций IaC
🟩 Автогенерация и архитектурной схемы, и конфигов инфраструктуры по архитектурному решению (ADR)
64
64
64
Roadmap репозитория. Инструменты рефакторинга микросервисной архитектуры�
🟩 Изменение сигнатуры метода API (endpoint’а)
🟩 Вынос метода API (endpoint'а) микросервиса в отдельный микросервис
🟩 Inline микросервиса — поглощение микросервиса своим потребителем
65
65
65
Welcome!
66
66
Спасибо!
Руслан Сафин, технический директор Бындюсофт