← [Раздел](README.md) · [Главная](../README.md)

# Тестирование архитектуры

## Цель

Узнать, как закреплять **архитектурные решения тестами** (fitness functions), проверять **нефункциональные требования (NFR)** автоматически и не допускать «расползания» границ модулей со временем.

## Предварительно

- [Тестирование компонентов](testirovanie-komponentov.md)
- Знакомство с C4 и ADR (разделы 01–03 курса)

## Время

~60 минут

---

## Архитектура тоже «гниёт»

Без проверок:

- сервис A начинает ходить в БД сервиса B;
- циклические зависимости между пакетами;
- запрещённый sync-вызов в hot path появляется «на один релиз».

**Architecture tests** ловят это в CI раньше code review.

---

## Fitness functions (Georgiev / Ford)

**Fitness function** — автоматизированная проверка архитектурного свойства.

| Свойство | Тест |
|----------|------|
| Слои не перепутаны | `domain` не импортирует `http` |
| Нет циклов | ArchUnit, dependency-cruiser |
| Только async между X и Y | Статический анализ вызовов |
| Все API за gateway | Ingress policy test |

Это не unit-тест бизнес-логики — это **тест инварианта системы**.

---

## Примеры правил

### Зависимости модулей (Java/Kotlin — ArchUnit)

```java
// псевдо
noClasses().that().resideInPackage("..domain..")
    .should().dependOnClassesThat().resideInPackage("..api..");
```

### JavaScript/TypeScript — dependency-cruiser

```json
{
  "forbidden": [
    { "from": { "path": "^src/features/orders" },
      "to": { "path": "^src/features/billing" } }
  ]
}
```

### OpenAPI как контракт

CI проверяет: реализация соответствует `openapi.yaml` (schemathesis, Dredd).

---

## NFR как проверяемые критерии

| NFR | Как тестировать |
|-----|-----------------|
| Latency p95 < 300 ms | Smoke load в CI (лёгкий) |
| Нет секретов в repo | gitleaks, trufflehog |
| Образ без root | OPA / conftest на Dockerfile |
| TLS только 1.2+ | terraform compliance |
| Доступность health | kube-score, polaris |

Чеклист NFR из [lab-02](../12-praktikum/lab-02-nfr-checklist.md) превращайте в **автоматические** gate по мере зрелости.

---

## ADR и тесты

Каждый [ADR](https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions) (Architecture Decision Record) может содержать пункт **«Проверка»**:

```markdown
## Решение
Используем outbox pattern для событий заказа.

## Проверка
- Тест: при создании заказа есть запись в таблице outbox
- Arch test: producer не вызывает Kafka напрямую из handler
```

Если решение нельзя проверить — оно часто забывается.

---

## Structurizr / C4 и drift

Диаграмма C4 — не картинка для Confluence. Храните **model as code** (Structurizr DSL, Mermaid в repo) и сверяйте:

- задокументированные контейнеры = реальные deployment'ы;
- новый сервис в k8s без записи в модели → warning в PR.

Полная автоматизация сложна; минимум — **ручной чеклист** в architectural review.

---

## Policy as Code

```rego
# OPA: пример — запрет latest тега
deny[msg] {
  input.kind == "Deployment"
  endswith(input.spec.template.spec.containers[_].image, ":latest")
  msg := "image tag must not be latest"
}
```

Conftest проверяет Kubernetes YAML и Terraform plan в CI.

---

## Когда НЕ автоматизировать

| Ситуация | Альтернатива |
|----------|--------------|
| Ранний MVP | ADR + quarterly review |
| Сложное правило «на глаз» | Architecture review meeting |
| Стоимость теста > пользы | Документировать исключение |

Добавляйте fitness functions, когда боль от нарушений уже была.

---

## Процесс в команде

1. Архитектор/техлид формулирует **инвариант** (одно предложение).
2. Инженер пишет тест в репозитории.
3. Падение теста = либо фикс кода, либо новый ADR с изменением правила.

---

## Самопроверка

1. Что такое fitness function?
2. Приведите пример NFR, проверяемого в CI.
3. Как ADR связан с архитектурными тестами?
4. Зачем policy-as-code для Kubernetes манифестов?

---

## Дальше

→ [Нагрузочное и chaos-lite](nagruzochnoe-i-chaos-lite.md)  
← [Тестирование компонентов](testirovanie-komponentov.md)
