Files
tf_provider/HISTORY/OPUS/2026-07-06_architectural_analysis.md
T
“Naeel” 53d03004de fix: architectural improvements per Opus analysis
1. Version sync: provider/main.go = profile.env = 5.0.60
2. docs-generator: removed detectVersion() — no more dependency on provider/
3. docs-generator: removed detectRoot(), pickPath() — all paths via flags/env
4. docs-generator: require --version, --resources, --docs flags
5. Auto-rebuild: yaml-generator rebuilds if sources newer than binary
6. Three version vars → one VERSION in profile.env
7. Created TOOLS/lib/ — shared YAML contract types (not yet integrated)
2026-07-06 09:25:21 +04:00

71 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Архитектурный анализ tf_provider — 2026-07-06
**Кто делал:** Claude Opus (по запросу пользователя)
**Метод:** Анализ реальной файловой структуры репозитория (не только промпт)
**Выводы:** Без предложений по рефакторингу, без кода
---
## 1. Разделение ответственности TOOLS / generated / provider
Разделение проведено чисто и последовательно. Три вершины треугольника не смешиваются: TOOLS — только инструменты сборки, generated — только продукт (полностью в .gitignore), provider — только исходники универсального ядра. Границы соблюдаются на уровне файловой системы, а не договорённостей, что делает их устойчивыми.
Ключевое наблюдение: provider **не является самодостаточным Go-модулем**. `internal/resources_core/*.go` на этапе компиляции импортируют пакеты `terraform-provider-nubes/resources_yaml` и `internal/resources_gen`, а `provider.go` вызывает `resources_gen.AllResources()`. Обе директории gitignored и физически отсутствуют в репозитории — они появляются только при сборке. Следствие: provider в чистом виде не собирается и не проходит `go build`/`go test` без предварительного прогона генераторов. Ядро формально отделено от сгенерированного кода, но связано с ним жёсткой компиляционной зависимостью через импорты пакетов, а не через интерфейс.
---
## 2. Пайплайн
Пайплайн линейный и предсказуемый (API → YAML → Go/docs → build → S3). Узкие места:
- **Двойное копирование через temp-директории.** И `02_...` (resource-generator пишет в temp, потом копирует в `generated/{stand}/go/`), и `03_...` (весь provider копируется в `mktemp -d`, сверху накладываются YAML и Go) используют промежуточные каталоги. Для `03` это оправдано изоляцией по стендам, для `02` — лишний слой.
- **Предсобранные бинарники в bin.** Скрипты вызывают готовые `yaml-generator`/`resource-generator`/`docs-generator`, но большинство скриптов их не пересобирают. Это тихий источник рассинхрона: правка `main.go` генератора не влияет на результат, пока бинарник не пересобран вручную.
- **Разросшийся набор скриптов.** Помимо основных 01–04 есть `template_v2`, `10``13`, стабилизационные прогоны. Нумерация уже не отражает реальный порядок, часть скриптов дублирует функциональность (`02_...v2` vs `02_...template_v2`).
---
## 3. Конфигурация стендов
`profile.env` содержит ~14 переменных, смешивая три разных класса:
- (а) параметры окружения (endpoint, namespace, registry host)
- (б) версии (`RELEASE_VERSION`=`PROVIDER_VERSION`=`DOCS_VERSION` — три идентичных значения)
- (в) пути к секретам (GPG-ключи, S3-конфиг, token-файл)
Смешение секретов и конфигурации в одном env-файле — главный риск этого узла: легко утечь при копировании, трудно ротировать. Дублирование версии в трёх переменных — источник рассинхрона (плюс версия ещё и захардкожена в main.go = `5.0.75`, при том что `test/profile.env` = `5.0.60`; фактически версия живёт в двух местах и они уже разошлись).
---
## 4. Сборка provider через temp-копирование vs go:embed
Текущая модель — физическое копирование provider в temp + наложение generated сверху. `go:embed` используется только для `operation_timeouts.json`.
Наблюдения:
- Для **сгенерированного Go-кода** `go:embed` в принципе неприменим — это компилируемые пакеты, а не данные; их нельзя «встроить», только скомпилировать. Так что альтернативы копированию здесь по сути нет, вопрос лишь в том, копировать в temp или прямо в `provider/internal/resources_gen/`.
- Для **YAML-спеков**, которые читаются в рантайме (`resources_core` подгружает метаданные из пакета `resources_yaml`), уже применяется гибрид: в `generated/{stand}/resources_yaml/` лежит `embed.go`. То есть YAML встраивается в бинарник через embed на стороне генерируемого пакета — это консистентно.
- Плата за temp-подход: невозможность запустить IDE/линтер/тесты на «настоящем» дереве, потому что рабочее дерево неполно. Отладка идёт по эфемерной копии.
---
## 5. Генераторы — дублирование
Три генератора — три независимых Go-модуля, каждый со своим `go.mod` и единственной зависимостью `gopkg.in/yaml.v3`. Структуры `ServiceSpec`, `OperationSpec`, `ParamSpec`, `OutputParam` **продублированы** в трёх отдельных `internal/types/`. Общей библиотеки нет.
Это самый явный архитектурный долг: YAML — это фактический контракт между генераторами, но контракт не выражен единым типом. Добавление поля в спеку требует синхронной правки трёх файлов; расхождение проявится только в рантайме или в кривом выводе, без ошибки компиляции. Функционально генераторы не пересекаются (у каждого своя роль), пересекаются именно модели данных.
Дополнительно: `docs-generator` (самый крупный, ~316 строк) имеет второй режим `--ops` с отдельным входом `resources_ops_yaml/` — то есть в нём живут фактически два генератора с разными источниками, что размывает его единую ответственность.
---
## 6. Архитектурные риски — что сломается первым
- **Дрейф YAML-контракта между генераторами** — самое вероятное первое место поломки. Дублированные структуры разойдутся при любой эволюции схемы.
- **Рассинхрон версии** — уже произошёл (`main.go` 5.0.75 vs `profile.env` 5.0.60). Версия определена в нескольких местах без единого источника.
- **Устаревшие бинарники в bin** — правка исходников генератора не даёт эффекта без ручной пересборки; ошибка молчаливая.
- **Хрупкость provider как модуля** — нельзя собрать/протестировать без прогона всего пайплайна; CI и локальная разработка вынуждены проходить полный цикл, чтобы получить компилируемое дерево.
- **Смена API (`deck-api``lk-api-gateway`)** локализована в `yaml-generator` (авто-детект по `index.cfm` в URL) — это хорошо изолировано и риск здесь низкий; но тот же эндпоинт продублирован дефолтом в `docs-generator`, то есть точка знания об API размазана по двум генераторам.
- **Секреты в `profile.env`** — операционный риск утечки при копировании конфигов между стендами.
---
**Итог:** структура сильна по вертикальному разделению (инструменты/продукт/исходники) и слаба по горизонтальным контрактам между компонентами — модель данных YAML, версия и знание об API-эндпоинте не имеют единого источника и продублированы в нескольких местах. Первым сломается именно то, что продублировано.