Глава 9: Декомпозиция задач
9 апреля 2026 г.
Принцип
Сложную задачу проще решить, разбив на независимые подзадачи. Каждая подзадача — отдельный промпт с чётким входом и выходом.
Горизонтальная декомпозиция
Разбиение последовательной задачи на этапы.
Pipeline паттерн
Задача: ETL pipeline
Этап 1: Extract
├─ Вход: путь к файлу
├─ Выход: raw DataFrame
└─ Промпт: "Прочитай CSV в DataFrame"
Этап 2: Transform
├─ Вход: raw DataFrame
├─ Выход: clean DataFrame
└─ Промпт: "Очисти данные: удали дубликаты, заполни пропуски"
Этап 3: Load
├─ Вход: clean DataFrame
├─ Выход: статус загрузки
└─ Промпт: "Загрузи DataFrame в PostgreSQL"
Примеры
Пример 1: ML Pipeline
"Задача: модель классификации
Подзадачи:
1. EDA → понимание данных, выбор признаков
2. Preprocessing → очистка, кодирование, нормализация
3. Baseline → простая модель, метрики
4. Optimization → гиперпараметры, feature engineering
5. Evaluation → финальные метрики, анализ ошибок
Сейчас: подзадача 2
Вход: результаты EDA (колонки X, Y, Z важны; W — мусор)
Выход: Pipeline sklearn для preprocessing"
Пример 2: Рефакторинг
"Задача: разбить монолит
Подзадачи:
1. Анализ → найти границы модулей, зависимости
2. Интерфейсы → определить контракты между модулями
3. Выделение → создать отдельные пакеты
4. Интеграция → связать через dependency injection
Сейчас: подзадача 1
Вход: код монолита $ссылка$
Выход: граф зависимостей, предложение границ"
Пример 3: Code Review
"Задача: полный review PR
Подзадачи:
1. Security → уязвимости, injection, auth
2. Performance → сложность, память, запросы
3. Correctness → логика, edge cases, типы
4. Maintainability → читаемость, тесты, документация
Сейчас: подзадача 1
Вход: diff PR
Выход: список security issues с severity"
Вертикальная декомпозиция
Разбиение по слоям абстракции или компонентам.
Layer паттерн
Задача: CRUD для сущности
Слой 1: Model (данные)
├─ Ответственность: структура, валидация
└─ Промпт: "Создай SQLAlchemy модель User"
Слой 2: Repository (доступ к данным)
├─ Ответственность: CRUD операции с БД
└─ Промпт: "Создай UserRepository с методами get, create, update, delete"
Слой 3: Service (бизнес-логика)
├─ Ответственность: бизнес-правила, оркестрация
└─ Промпт: "Создай UserService с регистрацией, аутентификацией"
Слой 4: API (интерфейс)
├─ Ответственность: HTTP endpoints
└─ Промпт: "Создай FastAPI роутер для /users"
Примеры
Пример 1: Web Application
"Задача: фича 'избранное'
Слои:
1. Model: FavoriteItem(user\_id, item\_id, created\_at)
2. Repository: add, remove, get\_all, exists
3. Service: toggle, get\_user\_favorites, is\_favorite
4. API: POST/DELETE /favorites/\{item\_id\}, GET /favorites
Сейчас: слой 2
Зависимости: модель FavoriteItem уже создана
Выход: класс FavoriteRepository"
Пример 2: Data Processing
"Задача: pipeline обработки логов
Слои:
1. Reader: чтение из разных источников (file, kafka, s3)
2. Parser: парсинг разных форматов (json, csv, custom)
3. Transformer: нормализация, обогащение
4. Writer: запись в разные destinations
Сейчас: слой 2
Интерфейс: Protocol с методом parse(raw: bytes) -\> LogEntry
Выход: реализации JsonParser, CsvParser"
Пример 3: Testing
"Задача: покрытие модуля auth
Слои:
1. Unit: отдельные функции (validate\_password, hash\_password)
2. Integration: взаимодействие (AuthService + UserRepository)
3. E2E: полный flow (register → login → access protected)
Сейчас: слой 1
Функции для тестирования:
- validate\_password(password: str) -\> bool
- hash\_password(password: str) -\> str
- verify\_password(password: str, hash: str) -\> bool
Выход: pytest тесты"
Рекурсивная декомпозиция
Подзадачи декомпозируются дальше, пока не станут атомарными.
Задача: Парсер математических выражений
Уровень 1:
├─ Токенизация
├─ Парсинг
└─ Вычисление
Уровень 2 (Токенизация):
├─ Разбиение на символы
├─ Классификация (число, оператор, скобка)
└─ Создание токенов
Уровень 2 (Парсинг):
├─ Построение AST
├─ Обработка приоритетов операторов
└─ Обработка скобок
Уровень 2 (Вычисление):
├─ Обход AST
├─ Выполнение операций
└─ Обработка ошибок
Пример промпта
"Задача: парсер выражений
Текущий уровень: Токенизация → Классификация
Контекст:
- Токенизатор уже разбивает строку на символы
- Нужна классификация каждого символа
Типы токенов:
- NUMBER: цифры и точка
- OPERATOR: + - \* / ^
- PAREN: ( )
- WHITESPACE: пробелы (игнорировать)
Вход: '123', '+', '(', ' '
Выход: TokenType.NUMBER, TokenType.OPERATOR, TokenType.PAREN, TokenType.WHITESPACE
Напиши функцию classify\_char(char: str) -\> TokenType"
Паттерны композиции
Map-Reduce
Map: применить операцию к каждому элементу
Reduce: агрегировать результаты
Пример: Анализ кодовой базы
Map промпт (для каждого файла):
"Файл: \{filename\}
Извлеки:
- Публичные функции
- Классы
- Импорты
Формат: JSON"
Reduce промпт:
"Результаты анализа:
\{all\_map\_results\}
Задачи:
1. Построй граф зависимостей
2. Найди циклические импорты
3. Определи ключевые модули"
Fork-Join
Fork: разделить на независимые подзадачи
Join: объединить результаты
Пример: Комплексный code review
Fork (параллельно):
- Задача A: security review
- Задача B: performance review
- Задача C: style review
Join:
"Результаты ревью:
Security: \{A\_result\}
Performance: \{B\_result\}
Style: \{C\_result\}
Задача:
1. Убери дубликаты
2. Приоритизируй (critical → warning → info)
3. Сформируй единый отчёт"
Pipeline с условиями
Пример: Обработка с валидацией
Этап 1: Валидация
"Проверь входные данные.
Если валидны: верни 'VALID'
Если нет: верни 'INVALID: $причина$'"
Условие:
if result.startswith('VALID'):
→ Этап 2
else:
→ Обработка ошибки
Этап 2: Обработка
"Данные валидны. Обработай: $данные$"
Определение границ подзадач
Критерии хорошей декомпозиции
| Критерий | Описание |
|---|---|
| Независимость | Подзадачи минимально зависят друг от друга |
| Атомарность | Каждая подзадача решается за один промпт |
| Тестируемость | Результат подзадачи можно проверить |
| Переиспользуемость | Подзадачи могут использоваться в других контекстах |
Пример анализа
Плохая декомпозиция:
1. "Напиши половину функции"
2. "Напиши вторую половину"
Проблема: нет логической границы
Хорошая декомпозиция:
1. "Напиши функцию валидации входных данных"
2. "Напиши функцию обработки (вход уже валиден)"
3. "Напиши функцию форматирования результата"
Преимущество: каждая функция независима и тестируема
Отслеживание состояния
Передача контекста между подзадачами
"Предыдущие этапы:
1. ✓ Модель User создана (поля: id, email, hashed\_password, created\_at)
2. ✓ Repository реализован (методы: get\_by\_id, get\_by\_email, create)
3. → Текущий: Service
Задача: UserService
Зависимости:
- UserRepository (injected)
- PasswordHasher (injected)
Методы:
- register(email, password) → User
- authenticate(email, password) → User | None
- change\_password(user\_id, old\_password, new\_password) → bool"
Формат состояния
\# Структура для отслеживания
state = \{
'completed': $\{'step': 1, 'name': 'Model', 'output': 'class User...'\},
\{'step': 2, 'name': 'Repository', 'output': 'class UserRepository...'\}$,
'current': \{
'step': 3,
'name': 'Service',
'dependencies': $'User', 'UserRepository'$
\},
'remaining': $\{'step': 4, 'name': 'API'\}$
\}