# Incremental Implementation

> Поставляет изменения инкрементально. Используй при реализации любой фичи или изменения, затрагивающего больше одного файла. Используй, когда собираешься написать сразу много кода или когда задача кажется слишком большой, чтобы закрыть её одним шагом.

- Skill: `aleksandr-litvinenko/incremental-implementation` (Agent Skill)
- Install (CLI): `npx skillmds@latest add aleksandr-litvinenko/incremental-implementation`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aleksandr-litvinenko/incremental-implementation/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Aleksandr-Litvinenko (https://skillmd.com/u/aleksandr-litvinenko)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/aleksandr-litvinenko/incremental-implementation

---


# Инкрементальная реализация

## Обзор

Строй тонкими вертикальными срезами: реализовал кусок — протестировал — проверил — расширил. Не реализуй фичу целиком за один заход. Каждый инкремент должен оставлять систему в работающем и проверяемом состоянии. Это та исполнительская дисциплина, которая делает крупные фичи управляемыми.

## Когда применять

- Реализуешь любое изменение, затрагивающее несколько файлов
- Строишь новую фичу по декомпозиции задач
- Рефакторишь существующий код
- Каждый раз, когда тянет написать больше ~100 строк до первого прогона тестов

**Когда НЕ применять:** изменения в одном файле и одной функции, где объём и так минимален.

## Цикл инкремента

```
┌──────────────────────────────────────────┐
│                                          │
│   Реализовал ──→ Тест ──→ Проверил ──┐   │
│       ▲                              │   │
│       └───── Коммит ◄────────────────┘   │
│              │                           │
│              ▼                           │
│         Следующий срез                   │
│                                          │
└──────────────────────────────────────────┘
```

Для каждого среза:

1. **Реализуй** наименьший цельный кусок функциональности
2. **Протестируй** — прогони набор тестов (или напиши тест, если его нет)
3. **Проверь** — убедись, что срез работает как задумано (тесты зелёные, сборка успешна, ручная проверка)
4. **Закоммить** — сохрани прогресс с осмысленным сообщением (про атомарные коммиты см. `git-workflow-and-versioning`)
5. **Переходи к следующему срезу** — двигайся вперёд, не начинай заново

## Стратегии нарезки

### Вертикальные срезы (предпочтительно)

Строй один полный путь через весь стек:

```
Срез 1: Создать задачу (БД + API + базовый UI)
    → Тесты проходят, пользователь может создать задачу через интерфейс

Срез 2: Список задач (запрос + API + UI)
    → Тесты проходят, пользователь видит свои задачи

Срез 3: Редактировать задачу (обновление + API + UI)
    → Тесты проходят, пользователь может менять задачи

Срез 4: Удалить задачу (удаление + API + UI + подтверждение)
    → Тесты проходят, CRUD закрыт полностью
```

Каждый срез даёт работающую сквозную функциональность.

### Нарезка от контракта

Когда бэкенд и фронтенд нужно разрабатывать параллельно:

```
Срез 0: Определить контракт API (типы, интерфейсы, спека OpenAPI)
Срез 1a: Реализовать бэкенд по контракту + тесты API
Срез 1b: Реализовать фронтенд на моках, соответствующих контракту
Срез 2: Интегрировать и протестировать сквозной сценарий
```

### Нарезка от риска

Берись сначала за самый рискованный или самый неопределённый кусок:

```
Срез 1: Доказать, что WebSocket-соединение работает (наибольший риск)
Срез 2: Построить обновления задач в реальном времени на проверенном соединении
Срез 3: Добавить офлайн-режим и переподключение
```

Если срез 1 провалится, ты узнаешь об этом до того, как вложился в срезы 2 и 3.

## Правила реализации

### Правило 0: сначала простота

Прежде чем писать код, спроси: «Что самое простое, что могло бы сработать?»

После того как написал код, прогони его через эти проверки:
- Можно ли сделать это меньшим числом строк?
- Оправдывают ли эти абстракции свою сложность?
- Посмотрит ли на это staff-инженер и скажет ли «а почему ты просто не…»?
- Я строю под гипотетические будущие требования или под текущую задачу?

```
ПРОВЕРКА НА ПРОСТОТУ:
✗ Универсальная шина событий с конвейером middleware ради одного уведомления
✓ Обычный вызов функции

✗ Паттерн «абстрактная фабрика» ради двух похожих компонентов
✓ Два прямолинейных компонента с общими утилитами

✗ Конструктор форм на конфигах ради трёх форм
✓ Три компонента форм
```

Три похожие строки кода лучше преждевременной абстракции. Сначала реализуй наивную, очевидно правильную версию. Оптимизируй только после того, как корректность доказана тестами.

### Правило 0.5: дисциплина границ

Трогай только то, что требует задача.

НЕ надо:
- «Прибираться» в коде по соседству с твоим изменением
- Рефакторить импорты в файлах, которые ты не меняешь
- Удалять комментарии, которые ты понял не до конца
- Добавлять фичи, которых нет в спеке, потому что они «вроде полезные»
- Осовременивать синтаксис в файлах, которые ты только читаешь

Если заметил что-то стоящее улучшения за пределами своей задачи — зафиксируй, но не чини:

```
ЗАМЕТИЛ, НО НЕ ТРОГАЮ:
- В src/utils/format.ts есть неиспользуемый импорт (не относится к этой задаче)
- Middleware аутентификации не помешали бы понятные сообщения об ошибках (отдельная задача)
→ Завести под это задачи?
```

### Правило 1: по одной вещи за раз

Каждый инкремент меняет одну логическую вещь. Не смешивай разные вещи:

**Плохо:** один коммит, который добавляет новый компонент, рефакторит существующий и правит конфиг сборки.

**Хорошо:** три отдельных коммита — по одному на каждое изменение.

### Правило 2: держи проект собирающимся

После каждого инкремента проект должен собираться, а существующие тесты — проходить. Не оставляй кодовую базу сломанной между срезами.

### Правило 3: фича-флаги для незаконченных фич

Если фича ещё не готова для пользователей, но инкременты нужно вливать:

```typescript
// Фича-флаг для незавершённой работы
const ENABLE_TASK_SHARING = process.env.FEATURE_TASK_SHARING === 'true';

if (ENABLE_TASK_SHARING) {
  // Новый UI шеринга
}
```

Так можно вливать мелкие инкременты в основную ветку, не показывая пользователям недоделанное.

### Правило 4: безопасные значения по умолчанию

Новый код должен по умолчанию вести себя безопасно и консервативно:

```typescript
// Безопасно: по умолчанию выключено, включается явно
export function createTask(data: TaskInput, options?: { notify?: boolean }) {
  const shouldNotify = options?.notify ?? false;
  // ...
}
```

### Правило 5: удобство отката

Каждый инкремент должен откатываться независимо:

- Аддитивные изменения (новые файлы, новые функции) откатываются легко
- Правки существующего кода должны быть минимальными и точечными
- У миграций БД должны быть соответствующие откатные миграции
- Не удаляй что-то и не заменяй это в одном и том же коммите — разнеси на два

## Работа с агентами

Когда направляешь агента на инкрементальную реализацию:

```
«Давай реализуем задачу 3 из плана.

Начни только с изменения схемы БД и эндпоинта API.
UI пока не трогай — сделаем его следующим инкрементом.

После реализации прогони команды тестов и сборки этого репозитория,
чтобы убедиться, что ничего не сломалось.»
```

Явно проговаривай, что входит и что НЕ входит в объём каждого инкремента.

## Чеклист инкремента

После каждого инкремента проверяй командами самого репозитория (см. раздел «Сначала разберись со стеком» в скилле test-driven-development):

- [ ] Изменение делает одну вещь и делает её полностью
- [ ] Все существующие тесты по-прежнему проходят (команда тестов репозитория: `npm test`, `./gradlew test`, `pytest`, …)
- [ ] Сборка успешна (команда сборки репозитория)
- [ ] Проверка типов проходит, если в стеке она есть (`npx tsc --noEmit`, `mypy`, …)
- [ ] Линтер проходит (команда линтера репозитория)
- [ ] Новая функциональность работает как задумано
- [ ] Изменение закоммичено с осмысленным сообщением

**Замечание:** запускай каждую проверочную команду после изменения, которое могло на неё повлиять. После успешного прогона не повторяй ту же команду, если код с тех пор не менялся — повторный прогон на неизменившемся коде не даёт новой информации.

## Типовые самооправдания

| Самооправдание | Как на самом деле |
|---|---|
| «Протестирую всё в конце» | Баги накапливаются. Баг в срезе 1 делает срезы 2–5 неверными. Тестируй каждый срез. |
| «Быстрее сделать всё сразу» | Это *кажется* быстрее ровно до момента, когда что-то ломается и ты не можешь найти, какая из 500 изменённых строк виновата. |
| «Эти изменения слишком мелкие, чтобы коммитить отдельно» | Мелкие коммиты ничего не стоят. Крупные коммиты прячут баги и делают откат болезненным. |
| «Фича-флаг добавлю потом» | Если фича не закончена, она не должна быть видна пользователю. Добавь флаг сейчас. |
| «Этот рефакторинг мелкий, включу его сюда же» | Рефакторинг вперемешку с фичами усложняет и ревью, и отладку обоих. Разнеси их. |
| «Прогоню сборку ещё раз, просто чтобы убедиться» | После успешного прогона повтор той же команды ничего не даёт, если код с тех пор не менялся. Запускай её снова после последующих правок, а не для самоуспокоения. |

## Тревожные признаки

- Написано больше 100 строк кода без единого прогона тестов
- Несколько несвязанных изменений в одном инкременте
- Расползание границ в стиле «дай я быстренько ещё вот это добавлю»
- Пропуск шага теста/проверки ради скорости
- Сборка или тесты сломаны между инкрементами
- Копятся большие незакоммиченные изменения
- Строятся абстракции до того, как их потребовал третий случай применения
- Трогаешь файлы вне задачи «раз уж я всё равно здесь»
- Создаёшь новые файлы утилит ради разовой операции
- Запускаешь одну и ту же команду сборки/тестов дважды подряд без единой правки кода между ними

## Проверка

После завершения всех инкрементов задачи:

- [ ] Каждый инкремент был отдельно протестирован и закоммичен
- [ ] Полный набор тестов проходит
- [ ] Сборка чистая
- [ ] Фича работает сквозным сценарием, как описано
- [ ] Незакоммиченных изменений не осталось

## См. также

Проверка на каждом инкременте — локальный контроль. Прежде чем объявлять задачу выполненной, примени общий для проекта Definition of Done как финальные ворота: это постоянная планка, которую проходит любой инкремент вне зависимости от задачи. См. `../../references/definition-of-done.md`.

