<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>ADR on Михаил Шогин</title><link>https://mshogin.ru/tags/adr/</link><description>Recent content in ADR on Михаил Шогин</description><generator>Hugo -- gohugo.io</generator><language>ru</language><copyright>Михаил Шогин</copyright><lastBuildDate>Tue, 09 Dec 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://mshogin.ru/tags/adr/index.xml" rel="self" type="application/rss+xml"/><item><title>Spec-Driven Development: контроль AI-кодогенерации</title><link>https://mshogin.ru/blog/spec-driven-development/</link><pubDate>Tue, 09 Dec 2025 00:00:00 +0000</pubDate><guid>https://mshogin.ru/blog/spec-driven-development/</guid><description>&lt;img src="https://mshogin.ru/blog/spec-driven-development/cover.svg" alt="Featured image of post Spec-Driven Development: контроль AI-кодогенерации" /&gt;&lt;h2 id="в-этой-статье"&gt;В этой статье
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="#%d0%bf%d1%80%d0%be%d0%b1%d0%bb%d0%b5%d0%bc%d0%b0" &gt;Проблема&lt;/a&gt;: большие MR и размытые требования&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="#%d0%b8%d0%b4%d0%b5%d1%8f" &gt;Идея&lt;/a&gt;: спецификации как контракт&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="#%d0%bc%d0%b5%d1%82%d0%be%d0%b4" &gt;Метод&lt;/a&gt;: структура и размеры спецификаций&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="#%d1%87%d1%82%d0%be-%d0%b4%d0%b5%d0%bb%d0%b0%d0%b5%d1%82-ai" &gt;Что делает AI&lt;/a&gt;: редактор и исполнитель&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="#%d1%8d%d0%ba%d1%81%d0%bf%d0%b5%d1%80%d0%b8%d0%bc%d0%b5%d0%bd%d1%82" &gt;Эксперимент&lt;/a&gt;: 85% воспроизводимости за 20 минут&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="#%d0%be%d0%b3%d1%80%d0%b0%d0%bd%d0%b8%d1%87%d0%b5%d0%bd%d0%b8%d1%8f" &gt;Ограничения&lt;/a&gt; и &lt;a class="link" href="#%d0%b8%d1%82%d0%be%d0%b3%d0%b8" &gt;Итоги&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="проблема"&gt;Проблема
&lt;/h2&gt;&lt;h3 id="большие-mr"&gt;Большие MR
&lt;/h3&gt;&lt;p&gt;4000 строк в одном MR. Три часа на ревью, 12 замечаний, исправления - ещё 800 строк. На четвёртом заходе я закрыл вкладку и понял: проблема не в коде, а в том, что никто не знал, что именно нужно было написать.&lt;/p&gt;
&lt;p&gt;Если ты работаешь с большими кодовыми базами, ситуация знакомая. Большие MR - симптом. Когда непонятно, что именно нужно сделать, разработчик пишет больше кода, чем требуется. Добавляет на всякий случай. Покрывает сценарии, которые никто не просил. MR растёт не потому что задача большая, а потому что границы размыты.&lt;/p&gt;
&lt;p&gt;Другая причина - иллюзия, что проще сделать всё в одной задаче, чем декомпозировать. Кажется, что разбиение создаёт лишнюю работу. На практике монолитный MR на 4000 строк никто не может нормально проверить, и баги просачиваются в продакшн.&lt;/p&gt;
&lt;h3 id="ai-кодогенерация"&gt;AI-кодогенерация
&lt;/h3&gt;&lt;p&gt;С AI эта проблема становится критичнее. Агент пишет код быстро, но если требования размыты - генерирует то же самое: много кода на всякий случай.&lt;/p&gt;
&lt;p&gt;Я пользуюсь AI ежедневно. Claude Code - основной инструмент, в который можно подключить разные модели: Anthropic, DeepSeek, GPT-семейство, локальные через Ollama. И в какой-то момент заметил закономерность: чем точнее формулирую задачу, тем лучше результат. Промпты становились всё более структурированными - простые инструкции, потом шаблоны, потом что-то похожее на техническое задание.&lt;/p&gt;
&lt;p&gt;Где проблема? Сначала я думал, что ленюсь давать AI детальные инструкции. Потом решил, что AI Agent собирает недостаточный контекст - нужен RAG или что-то подобное. В итоге понял, что проблема в обоих местах: создавать полные инструкции кажется оверкилом, а как помочь агенту собрать нужный контекст - непонятно.&lt;/p&gt;
&lt;p&gt;Но главное - нечего проверять. Нет артефакта, на который можно указать и сказать: здесь написано одно, а сделано другое.&lt;/p&gt;
&lt;h2 id="идея"&gt;Идея
&lt;/h2&gt;&lt;p&gt;Идея не новая - в индустрии давно говорят о spec-first подходе. Я долго хотел попробовать и наконец решил проверить.&lt;/p&gt;
&lt;p&gt;Если формализовать требования в виде спецификации до начала кодирования, то:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;AI Agent будет генерировать более предсказуемый код&lt;/li&gt;
&lt;li&gt;Результат можно будет валидировать против спецификации&lt;/li&gt;
&lt;li&gt;Архитектура останется контролируемой&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Когда AI Agent генерирует сотни строк кода за минуту, единственный способ контролировать результат - иметь формальное описание того, что должно получиться, и инструмент, который проверит соответствие реализации спецификации. О втором - в отдельной статье.&lt;/p&gt;
&lt;h2 id="метод"&gt;Метод
&lt;/h2&gt;&lt;p&gt;Я решил проверить гипотезу на реальном проекте - инструменте для построения архитектурных графов из Go кода. Правило простое: ни одной строчки кода без спецификации.&lt;/p&gt;
&lt;p&gt;Первая спецификация - &lt;a class="link" href="https://github.com/mshogin/archlint/blob/main/specs/done/0001-init-project.md" target="_blank" rel="noopener"
&gt;создать пустой проект&lt;/a&gt; на Go со стандартным layout. Вторая - &lt;a class="link" href="https://github.com/mshogin/archlint/blob/main/specs/done/0003-data-model.md" target="_blank" rel="noopener"
&gt;модель графа&lt;/a&gt;. Третья - &lt;a class="link" href="https://github.com/mshogin/archlint/blob/main/specs/done/0004-go-analyzer.md" target="_blank" rel="noopener"
&gt;анализатор Go кода&lt;/a&gt;. За несколько дней накопилось 10 завершённых спецификаций.&lt;/p&gt;
&lt;h3 id="структура-хранения"&gt;Структура хранения
&lt;/h3&gt;&lt;p&gt;Kanban-подобная организация через файловую систему:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;specs/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── todo/ # очередь задач
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── 0010-feature-x.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── 0020-feature-y.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── inprogress/ # в работе (максимум одна - WIP limit)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── 0005-current.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── done/ # выполнено
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 0001-init-project.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 0003-data-model.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └── 0004-go-analyzer.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Приоритизация через числовой префикс: меньше число - выше приоритет. Переход между состояниями - перемещение файла между директориями.&lt;/p&gt;
&lt;div class="mermaid"&gt;
graph LR
TODO["todo/"] --&gt; INPROGRESS["inprogress/"]
INPROGRESS --&gt; DONE["done/"]
&lt;/div&gt;
&lt;h3 id="размеры-спецификаций"&gt;Размеры спецификаций
&lt;/h3&gt;&lt;p&gt;Классификация по времени на написание спецификации (T-shirt sizing):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;S (Small)&lt;/strong&gt; - до 10 минут&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;M (Medium)&lt;/strong&gt; - 10-20 минут&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;L (Large)&lt;/strong&gt; - больше 20 минут&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Размер определяет глубину проработки. S-задача: Problem Statement и 5 Acceptance Criteria. L-задача: полные UML/C4 диаграммы, детальные Requirements, 15+ критериев приёмки. Корреляция между размером спецификации и предсказуемостью результата - прямая.&lt;/p&gt;
&lt;p&gt;Если начинаешь с нуля - попробуй с S-спецификации. Это минимальные затраты на эксперимент.&lt;/p&gt;
&lt;h3 id="пример-s-спецификации-инициализация-проекта"&gt;Пример S-спецификации: инициализация проекта
&lt;/h3&gt;&lt;div class="expandable-code" id="expandable-1777685812527455000"&gt;
&lt;pre class="expandable-code-pre" style="max-height: 18em; overflow: hidden;"&gt;&lt;code class="language-markdown"&gt;
# Spec 0001: Initialize Standard Golang Project Layout
**Metadata:**
- Priority: 0001
- Status: Done
- Effort: S
## Overview
### Problem Statement
Необходимо создать базовую структуру Go проекта для инструмента
archlint согласно стандартным практикам разработки.
### Solution Summary
Инициализировать Go module и создать минимальную структуру проекта.
## Requirements
### R1: Go Module Initialization
- Инициализировать Go module с именем github.com/mshogin/archlint
### R2: Minimal Directory Structure
- Создать cmd/archlint/ для точки входа
- Создать internal/ для приватного кода
- Создать pkg/ для публичных библиотек
## Acceptance Criteria
- [x] AC1: go.mod создан с module path github.com/mshogin/archlint
- [x] AC2: cmd/archlint/main.go существует и компилируется
- [x] AC3: Директории internal/ и pkg/ существуют
&lt;/code&gt;&lt;/pre&gt;
&lt;button class="expandable-code-btn" onclick="toggleExpandable('expandable-1777685812527455000')"&gt;Показать полностью&lt;/button&gt;
&lt;/div&gt;
&lt;style&gt;
.expandable-code {
position: relative;
margin-bottom: 1em;
}
.expandable-code-pre {
margin-bottom: 0 !important;
transition: max-height 0.3s ease;
}
.expandable-code.expanded .expandable-code-pre {
max-height: none !important;
}
.expandable-code-btn {
display: block;
width: 100%;
padding: 0.5em;
background: var(--card-background);
border: 1px solid var(--border-color);
border-top: none;
cursor: pointer;
font-size: 0.9em;
color: var(--accent-color);
}
.expandable-code-btn:hover {
background: var(--border-color);
}
.expandable-code.expanded .expandable-code-btn {
display: none;
}
&lt;/style&gt;
&lt;script&gt;
function toggleExpandable(id) {
var el = document.getElementById(id);
el.classList.add('expanded');
}
&lt;/script&gt;
&lt;p&gt;Минимум деталей, максимум конкретики. AI получает чёткие границы задачи.&lt;/p&gt;
&lt;h3 id="пример-m-спецификации-команда-collect"&gt;Пример M-спецификации: команда collect
&lt;/h3&gt;&lt;p&gt;Средние задачи требуют диаграмм. Я экспериментировал с Sequence-диаграммами - отправлял их агенту вместе с требованиями. Заметил, что по ним AI Agent выдаёт в целом то, что ожидается.&lt;/p&gt;
&lt;div class="expandable-code" id="expandable-1777685812527475000"&gt;
&lt;pre class="expandable-code-pre" style="max-height: 18em; overflow: hidden;"&gt;&lt;code class="language-markdown"&gt;
# Spec 0006: Implement Collect Command
**Metadata:**
- Priority: 0006
- Status: Done
- Effort: M
## Overview
### Problem Statement
Необходимо реализовать команду collect для сбора архитектуры
из исходного кода и сохранения графа в YAML файл.
### Solution Summary
Создать подкоманду collect, которая использует GoAnalyzer
для анализа кода и сохраняет результат в YAML формате.
## Architecture
### Sequence Flow (PlantUML)
@startuml
title Sequence: Collect Command
actor User
participant "collectCmd" as CC
participant "GoAnalyzer" as GA
participant "saveGraph" as SG
User -&gt; CC: archlint collect . -o arch.yaml
CC -&gt; GA: Analyze(dir)
GA --&gt; CC: *Graph
CC -&gt; SG: saveGraph(graph)
SG --&gt; CC: nil
CC --&gt; User: "Graph saved to arch.yaml"
@enduml
## Requirements
### R1: Command Definition
var collectCmd = &amp;cobra.Command{
Use: "collect [директория]",
Short: "Сбор архитектуры из исходного кода",
Args: cobra.ExactArgs(1),
RunE: runCollect,
}
### R2: Flags
-o, --output: выходной YAML файл (default: architecture.yaml)
-l, --language: язык программирования (default: go)
## Acceptance Criteria
- [x] AC1: Команда принимает директорию как аргумент
- [x] AC2: Флаги -o и -l работают
- [x] AC3: Результат сохраняется в YAML
- [x] AC4: Выводится статистика по компонентам
&lt;/code&gt;&lt;/pre&gt;
&lt;button class="expandable-code-btn" onclick="toggleExpandable('expandable-1777685812527475000')"&gt;Показать полностью&lt;/button&gt;
&lt;/div&gt;
&lt;style&gt;
.expandable-code {
position: relative;
margin-bottom: 1em;
}
.expandable-code-pre {
margin-bottom: 0 !important;
transition: max-height 0.3s ease;
}
.expandable-code.expanded .expandable-code-pre {
max-height: none !important;
}
.expandable-code-btn {
display: block;
width: 100%;
padding: 0.5em;
background: var(--card-background);
border: 1px solid var(--border-color);
border-top: none;
cursor: pointer;
font-size: 0.9em;
color: var(--accent-color);
}
.expandable-code-btn:hover {
background: var(--border-color);
}
.expandable-code.expanded .expandable-code-btn {
display: none;
}
&lt;/style&gt;
&lt;script&gt;
function toggleExpandable(id) {
var el = document.getElementById(id);
el.classList.add('expanded');
}
&lt;/script&gt;
&lt;p&gt;Sequence-диаграмма определяет порядок вызовов. AI следует ей буквально.&lt;/p&gt;
&lt;h3 id="пример-l-спецификации-анализатор-go-кода"&gt;Пример L-спецификации: анализатор Go кода
&lt;/h3&gt;&lt;p&gt;Большие задачи требуют нескольких диаграмм - Data Model и Sequence:&lt;/p&gt;
&lt;div class="expandable-code" id="expandable-1777685812527489000"&gt;
&lt;pre class="expandable-code-pre" style="max-height: 18em; overflow: hidden;"&gt;&lt;code class="language-markdown"&gt;
# Spec 0004: Implement Go Code Analyzer
**Metadata:**
- Priority: 0004
- Status: Done
- Effort: L
## Overview
### Problem Statement
Необходимо реализовать анализатор Go кода, который парсит исходный код
с помощью AST и строит граф зависимостей между компонентами.
### Solution Summary
Создать GoAnalyzer в пакете internal/analyzer, который использует
go/ast и go/parser для анализа Go файлов и построения графа.
## Architecture
### Data Model
@startuml
class GoAnalyzer {
-packages: map[string]*PackageInfo
-types: map[string]*TypeInfo
-functions: map[string]*FunctionInfo
-nodes: []model.Node
-edges: []model.Edge
--
+NewGoAnalyzer() *GoAnalyzer
+Analyze(dir string) (*model.Graph, error)
-parseFile(filename string) error
-buildGraph()
}
class PackageInfo {
+Name: string
+Path: string
+Imports: []string
}
class TypeInfo {
+Name: string
+Package: string
+Kind: string
+Fields: []FieldInfo
}
GoAnalyzer "1" *-- "*" PackageInfo
GoAnalyzer "1" *-- "*" TypeInfo
@enduml
### Sequence Diagram
@startuml
title Sequence: Code Analysis
actor User
participant "GoAnalyzer" as GA
participant "go/parser" as GP
participant "buildGraph" as BG
User -&gt; GA: Analyze(dir)
loop For each .go file
GA -&gt; GP: ParseFile(filename)
GP --&gt; GA: *ast.File
GA -&gt; GA: Extract packages, types, functions
end
GA -&gt; BG: buildGraph()
BG --&gt; GA: *Graph
GA --&gt; User: *Graph, nil
@enduml
## Requirements
### R1: AST Parsing
- Парсить все .go файлы в директории
- Извлекать packages, types, functions, methods
### R2: Graph Building
- Создавать Node для каждого компонента
- Создавать Edge для каждой связи (import, calls, uses)
### R3: External Dependencies
- Идентифицировать внешние зависимости
- Помечать их как entity: external
## Acceptance Criteria
- [x] AC1: Анализатор корректно парсит Go код
- [x] AC2: Все типы компонентов извлекаются
- [x] AC3: Все типы связей определяются
- [x] AC4: Внешние зависимости идентифицируются
- [x] AC5: Граф сериализуется в YAML
&lt;/code&gt;&lt;/pre&gt;
&lt;button class="expandable-code-btn" onclick="toggleExpandable('expandable-1777685812527489000')"&gt;Показать полностью&lt;/button&gt;
&lt;/div&gt;
&lt;style&gt;
.expandable-code {
position: relative;
margin-bottom: 1em;
}
.expandable-code-pre {
margin-bottom: 0 !important;
transition: max-height 0.3s ease;
}
.expandable-code.expanded .expandable-code-pre {
max-height: none !important;
}
.expandable-code-btn {
display: block;
width: 100%;
padding: 0.5em;
background: var(--card-background);
border: 1px solid var(--border-color);
border-top: none;
cursor: pointer;
font-size: 0.9em;
color: var(--accent-color);
}
.expandable-code-btn:hover {
background: var(--border-color);
}
.expandable-code.expanded .expandable-code-btn {
display: none;
}
&lt;/style&gt;
&lt;script&gt;
function toggleExpandable(id) {
var el = document.getElementById(id);
el.classList.add('expanded');
}
&lt;/script&gt;
&lt;p&gt;Для L-задач несколько диаграмм - необходимость. Data Model, Sequence, Component - вместе они задают архитектуру приложения и управляют зависимостями между компонентами.&lt;/p&gt;
&lt;h2 id="что-делает-ai"&gt;Что делает AI
&lt;/h2&gt;&lt;p&gt;AI ускоряет работу, но архитектуру я не делегирую: решения фиксируются в спецификации, проходят ревью и проверяются валидаторами. Однако решения редко рождаются из воздуха: я приношу первичные варианты и ограничения, агент предлагает альтернативы и подсвечивает слепые зоны. Это влияет на ход мысли, и я это осознаю. Финальное &amp;ldquo;да/нет&amp;rdquo; и ответственность лежит на мне.&lt;/p&gt;
&lt;p&gt;У агента две зоны ответственности.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Specification Editor&lt;/strong&gt;
Я диктую голосом сырой поток мыслей (диктую быстрее, чем печатаю). Агент приводит его к &lt;a class="link" href="https://github.com/mshogin/archlint/blob/main/templates/spec-template.md" target="_blank" rel="noopener"
&gt;моему шаблону спецификации&lt;/a&gt;: раскладывает по секциям, уточняет недосказанное, формулирует требования и критерии приемки так, чтобы их можно было проверить. После этого я ревьюю и фиксирую спецификацию как исходный контракт.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implementation Executor&lt;/strong&gt;
Когда спецификация согласована, я отдаю её агенту на реализацию. Агент пишет код по спецификации, а я проверяю результат: ревью, валидация, итерации до тех пор, пока архитектура не станет чистой и предсказуемой.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="mermaid"&gt;
graph LR
A["Идеи/варианты (я)"] --&gt; B["AI дополняет и формализует"]
B --&gt; C["Спецификация"]
C --&gt; D["Ревью и решения (я)"]
D --&gt; E["Реализация (AI)"]
&lt;/div&gt;
&lt;h2 id="эксперимент"&gt;Эксперимент
&lt;/h2&gt;&lt;p&gt;За несколько дней - 10 завершённых спецификаций и работающий проект. Код соответствует архитектуре из диаграмм.&lt;/p&gt;
&lt;p&gt;Чтобы проверить, насколько спецификации самодостаточны, я провёл эксперимент: дал Claude Code пустую директорию и 10 спецификаций из archlint - без доступа к исходному коду. Задача: воссоздать проект с нуля.&lt;/p&gt;
&lt;p&gt;Результат за 20 минут:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;85.5%&lt;/strong&gt; успешность воспроизведения&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;100%&lt;/strong&gt; структурная идентичность (директории, файлы, типы)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;23 мутации&lt;/strong&gt; в деталях реализации&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Структура проекта воспроизведена полностью. Все acceptance criteria из спецификаций выполнены. Проект компилируется и проходит тесты.&lt;/p&gt;
&lt;p&gt;Мутации возникли там, где спецификации описывали что делать, но не как. Критический пример: алгоритм построения sequence-диаграммы был реализован иначе - функционально эквивалентно, но с другой логикой обхода стека вызовов. Ещё одна категория мутаций - стилистические: язык комментариев, порядок функций в файлах, именование переменных.&lt;/p&gt;
&lt;p&gt;Вывод для улучшения спецификаций: для критических алгоритмов нужен псевдокод или конкретные примеры входов/выходов. Спецификация что + как даёт более точное воспроизведение, чем только что.&lt;/p&gt;
&lt;p&gt;Полный отчёт с каталогом мутаций: &lt;a class="link" href="https://github.com/mshogin/archlint-reproduction" target="_blank" rel="noopener"
&gt;github.com/mshogin/archlint-reproduction&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="идемпотентность-спецификаций"&gt;Идемпотентность спецификаций
&lt;/h2&gt;&lt;p&gt;Чтобы спецификации оставались воспроизводимыми, все изменения должны проходить через них. Никаких доработок в режиме copilot, никаких чатов с &amp;ldquo;поправь вот это&amp;rdquo;. Каждое изменение - обновление спецификации, затем реализация.&lt;/p&gt;
&lt;p&gt;Это основной вызов. Хочется быстро поправить баг в диалоге, а не возвращаться к спеке. Но каждая такая правка - потеря воспроизводимости.&lt;/p&gt;
&lt;p&gt;Trade-off очевиден:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Нужен результат здесь и сейчас - режим copilot быстрее&lt;/li&gt;
&lt;li&gt;Нужна воспроизводимость - только через спецификации&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Выбор зависит от контекста. Прототип или эксперимент - copilot. Продуктовый код с долгим жизненным циклом - спецификации.&lt;/p&gt;
&lt;h2 id="ограничения"&gt;Ограничения
&lt;/h2&gt;&lt;p&gt;Подход не решает проблемы автоматически. Он не заменяет понимание предметной области, не придумывает требования и не гарантирует хороший дизайн. Он делает ошибки видимыми раньше и заставляет держать архитектуру в рамке.&lt;/p&gt;
&lt;p&gt;Цена: время на написание спецификаций, их ревью и итерации после валидации. Если относиться к спекам формально, всё скатывается обратно в хаос. Честно спроси себя: готов ли ты тратить 10-30 минут на спецификацию, чтобы агент реализовал её за 5-20 минут?&lt;/p&gt;
&lt;p&gt;Детали реализации варьируются. Эксперимент с воспроизводимостью показал 23 мутации - алгоритмы интерпретируются по-разному, стилистика кода отличается. Для критических участков нужен псевдокод, а не только описание.&lt;/p&gt;
&lt;p&gt;Я думаю, что подход работает хорошо там, где есть поставленный, сформированный и рабочий процесс. В процессах с фокусом на дисциплину, на понятные зоны ответственности, ревью, критерии готовности. Можно смотреть на этот процесс как на конвейер, доставляющий ПО 24/7.&lt;/p&gt;
&lt;h2 id="итоги"&gt;Итоги
&lt;/h2&gt;&lt;p&gt;Гипотеза подтвердилась:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;AI генерирует более предсказуемый код - да, при наличии диаграмм&lt;/li&gt;
&lt;li&gt;Результат можно валидировать - да, 85.5% воспроизводимость&lt;/li&gt;
&lt;li&gt;Архитектура остаётся контролируемой - да, 100% структурная идентичность&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Суть простая: без спецификации нечего проверять, со спецификацией - есть артефакт для валидации. Не нужен идеальный AI или идеальный промпт.&lt;/p&gt;
&lt;p&gt;Эксперимент продолжается.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Шаблоны и примеры:&lt;/strong&gt; &lt;a class="link" href="https://github.com/mshogin/archlint" target="_blank" rel="noopener"
&gt;github.com/mshogin/archlint&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Если пробуешь spec-driven подход или уже используешь - расскажи в комментариях, что работает, а что нет. Пишу о практике AI-кодогенерации и архитектуре в Telegram: &lt;a class="link" href="https://t.me/MikeShogin" target="_blank" rel="noopener"
&gt;@MikeShogin&lt;/a&gt;&lt;/p&gt;</description></item></channel></rss>