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

9.8 KiB
Raw Blame History

Архитектурный анализ 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, 1013, стабилизационные прогоны. Нумерация уже не отражает реальный порядок, часть скриптов дублирует функциональность (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-apilk-api-gateway) локализована в yaml-generator (авто-детект по index.cfm в URL) — это хорошо изолировано и риск здесь низкий; но тот же эндпоинт продублирован дефолтом в docs-generator, то есть точка знания об API размазана по двум генераторам.
  • Секреты в profile.env — операционный риск утечки при копировании конфигов между стендами.

Итог: структура сильна по вертикальному разделению (инструменты/продукт/исходники) и слаба по горизонтальным контрактам между компонентами — модель данных YAML, версия и знание об API-эндпоинте не имеют единого источника и продублированы в нескольких местах. Первым сломается именно то, что продублировано.