Что такое Quality Gates
Quality Gates (контрольные точки качества) -- это заранее определённые критерии, которые код должен пройти, прежде чем перейти на следующий этап разработки. Если хотя бы один критерий не выполнен -- продвижение блокируется.
В традиционной разработке Quality Gates существовали всегда: код-ревью, CI/CD проверки, ручное тестирование перед релизом. Но с появлением AI-ассистентов роль этих контрольных точек кардинально меняется.
Ключевой принцип: AI-генерированный код требует БОЛЬШЕ проверок, а не меньше. Недетерминированный выход требует детерминированной верификации.
Почему Quality Gates критичны именно для AI-кода
Между кодом, написанным человеком, и кодом, сгенерированным AI, есть принципиальная разница:
| Характеристика | Код человека | AI-генерированный код |
|---|---|---|
| Предсказуемость | Высокая (знаем стиль разработчика) | Низкая (зависит от промпта и контекста) |
| Консистентность | Стабильная в рамках навыков | Может варьироваться от идеального до ужасного |
| Скрытые ошибки | Типичные для уровня разработчика | Могут выглядеть правильно, но содержать тонкие баги |
| Скорость генерации | Медленная (есть время на обдумывание) | Мгновенная (нет паузы на рефлексию) |
| Объём за единицу времени | Умеренный | Огромный |
Высокая скорость генерации создаёт иллюзию продуктивности. Разработчик получает 200 строк кода за минуту вместо 20 за час -- и подсознательно снижает планку проверки. Именно здесь Quality Gates становятся спасением.
Quality Gate Framework для AI-assisted разработки
Gate 1: Pre-Generation Gate (Перед генерацией)
Самый недооценённый этап. Большинство разработчиков сразу прыгают к промпту, не подготовив спецификацию.
Критерии прохождения:
- Задача чётко сформулирована (что делаем, зачем)
- Определены acceptance criteria (как понять, что готово)
- Известны ограничения (технологии, паттерны проекта, запреты)
- Подготовлен контекст для AI (релевантные файлы, примеры кода)
- Edge cases продуманы до генерации
# Example: pre-generation checklist in YAML
pre_generation_gate:
task_definition:
what: "REST API endpoint for creating orders"
why: "Customers need to place orders via mobile app"
acceptance_criteria:
- "POST /api/v1/orders creates order and returns 201"
- "Validates required fields: product_id, quantity, shipping_address"
- "Returns 422 with field-level errors for invalid input"
- "Idempotent: duplicate requests with same idempotency_key return existing order"
constraints:
- "Must use existing OrderRepository pattern"
- "Must follow project naming conventions"
- "No raw SQL — use Doctrine ORM only"
edge_cases:
- "Product out of stock"
- "Invalid product_id"
- "Quantity exceeds maximum (1000)"
- "Concurrent creation with same idempotency_key"
Правило: Если вы не можете написать acceptance criteria -- вы не готовы генерировать код. Вернитесь к анализу требований.
Gate 2: Post-Generation Gate (Сразу после генерации)
Первичная проверка сгенерированного кода, которая занимает 2-5 минут, но предотвращает часы отладки.
Критерии прохождения:
- Код компилируется / не содержит синтаксических ошибок
- Код соответствует спецификации (все acceptance criteria покрыты)
- Нет очевидных проблем (TODO, placeholder-ы, mock-данные)
- Архитектура соответствует проекту (правильные слои, зависимости)
- Именование следует конвенциям проекта
# Quick post-generation checks
# PHP: syntax + static analysis
php -l src/Controller/OrderController.php
vendor/bin/phpstan analyse src/Controller/OrderController.php --level=9
# Go: compile + vet
go build ./cmd/api/...
go vet ./internal/order/...
# TypeScript: type check
npx tsc --noEmit src/api/orders.ts
# Universal: check for placeholders and TODOs
grep -rn "TODO\|FIXME\|PLACEHOLDER\|CHANGEME\|xxx\|your-.*-here" src/
Частые проблемы на этом этапе:
- Галлюцинации API -- AI использует несуществующие методы библиотек
- Несовместимость версий -- код для старой версии фреймворка
- Placeholder-ы --
// TODO: implement thisзамаскированные под рабочий код - Лишние зависимости -- AI добавляет пакеты, которые не нужны
Gate 3: Testing Gate (Тестирование)
AI может генерировать тесты -- но кто проверяет, что тесты правильные? Тестирование AI-кода требует особого внимания.
Критерии прохождения:
- Unit-тесты проходят (все зелёные)
- Integration-тесты проходят
- Edge cases покрыты тестами
- Тесты проверяют поведение, а не реализацию
- Нет "тавтологических" тестов (тест проверяет то же, что и код)
- Code coverage для нового кода >= 80%
<?php
declare(strict_types=1);
// ANTI-PATTERN: tautological test generated by AI
// This test just mirrors the implementation — it proves nothing
final class BadOrderTest extends TestCase
{
public function testCreateOrder(): void
{
$order = new Order(
productId: 1,
quantity: 5,
shippingAddress: '123 Main St'
);
// These assertions just verify the constructor works
// They don't test any business logic
$this->assertEquals(1, $order->getProductId());
$this->assertEquals(5, $order->getQuantity());
}
}
// GOOD PATTERN: behavior-focused test
final class GoodOrderTest extends TestCase
{
public function testRejectsQuantityAboveMaximum(): void
{
$this->expectException(InvalidQuantityException::class);
$this->expectExceptionMessage('Quantity cannot exceed 1000');
new Order(
productId: 1,
quantity: 1001,
shippingAddress: '123 Main St'
);
}
public function testIdempotentCreation(): void
{
$service = new OrderService($this->orderRepository);
$idempotencyKey = 'unique-key-123';
$first = $service->create($this->validData, $idempotencyKey);
$second = $service->create($this->validData, $idempotencyKey);
$this->assertSame($first->getId(), $second->getId());
$this->assertCount(1, $this->orderRepository->findAll());
}
/**
* @dataProvider invalidInputProvider
*/
public function testRejectsInvalidInput(array $data, string $expectedError): void
{
$this->expectException(ValidationException::class);
$this->expectExceptionMessage($expectedError);
$this->service->create($data);
}
public static function invalidInputProvider(): array
{
return [
'missing product_id' => [
['quantity' => 1, 'shipping_address' => 'addr'],
'product_id is required',
],
'zero quantity' => [
['product_id' => 1, 'quantity' => 0, 'shipping_address' => 'addr'],
'Quantity must be at least 1',
],
'empty address' => [
['product_id' => 1, 'quantity' => 1, 'shipping_address' => ''],
'shipping_address is required',
],
];
}
}
Gate 4: Security Gate (Безопасность)
AI часто генерирует функционально правильный, но небезопасный код. Этот Gate защищает от уязвимостей.
Критерии прохождения:
- Нет SQL-инъекций (все запросы параметризованы)
- Нет XSS (все данные экранированы на выходе)
- Нет хардкоженных секретов
- Валидация всех входных данных
- Проверка авторизации на каждом эндпоинте
- Нет path traversal в работе с файлами
- Пройден SAST-скан
# Automated security checks
# PHP: security-focused static analysis
vendor/bin/phpstan analyse --level=9 -c phpstan-security.neon src/
# Go: security scanner
gosec ./...
# Universal: secret scanning
gitleaks detect --source=. --no-git
# SAST with Semgrep (supports PHP, Go, JS, Python, etc.)
semgrep scan --config=auto --config=p/owasp-top-ten src/
# Dependency vulnerability check
composer audit # PHP
go vuln check ./... # Go (govulncheck)
npm audit # JavaScript
Gate 5: Performance Gate (Производительность)
AI оптимизирует на уровне строки, но часто упускает системные проблемы: N+1 запросы, отсутствие индексов, утечки памяти.
Критерии прохождения:
- Нет N+1 запросов к базе данных
- Запросы используют индексы (EXPLAIN проверен)
- Время ответа API < SLA (например, < 200ms для p95)
- Потребление памяти в допустимых пределах
- Нет блокирующих операций в hot path
-- Check for missing indexes on foreign keys
SELECT
tc.table_name,
tc.constraint_name,
kcu.column_name
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu
ON tc.constraint_name = kcu.constraint_name
LEFT JOIN pg_indexes pi
ON pi.tablename = tc.table_name
AND pi.indexdef LIKE '%' || kcu.column_name || '%'
WHERE tc.constraint_type = 'FOREIGN KEY'
AND pi.indexname IS NULL;
# Performance benchmarks
# API endpoint benchmarking with k6
k6 run --vus 50 --duration 30s loadtest.js
# Go benchmarks
go test -bench=. -benchmem ./internal/order/...
# PHP profiling with Xdebug/Blackfire
# Check for N+1 with Symfony Profiler doctrine panel
Gate 6: Review Gate (Код-ревью)
Финальная проверка человеком. Даже если все автоматические Gates пройдены, человеческий ревью незаменим.
Критерии прохождения:
- Код понятен другому разработчику без объяснений
- Архитектурные решения обоснованы
- Нет over-engineering (AI склонен к избыточным абстракциям)
- Naming конвенции соблюдены
- Документация обновлена (если нужно)
- Нет дублирования с существующим кодом
Важно: При ревью AI-кода обращайте особое внимание на "слишком красивый" код. AI часто создаёт элегантные абстракции, которые никогда не понадобятся (YAGNI violation). Простое решение почти всегда лучше.
Автоматизация Quality Gates
Pre-commit hooks
Первая линия обороны. Ловит проблемы ещё до того, как код попадёт в репозиторий.
#!/bin/bash
# .git/hooks/pre-commit
set -e
echo "Running pre-commit quality gates..."
# Gate: Formatting
echo "==> Checking code formatting..."
php-cs-fixer fix --dry-run --diff src/
prettier --check "src/**/*.{ts,vue}"
# Gate: Static Analysis
echo "==> Running static analysis..."
vendor/bin/phpstan analyse src/ --level=9 --no-progress
npx tsc --noEmit
# Gate: Security
echo "==> Scanning for secrets..."
gitleaks detect --staged --no-banner
# Gate: No debug artifacts
echo "==> Checking for debug statements..."
grep -rn "dd(\|dump(\|var_dump(\|console\.log(" src/ && {
echo "ERROR: Debug statements found!"
exit 1
} || true
echo "All pre-commit gates passed!"
CI/CD Pipeline
Полноценная проверка в изолированной среде:
# .github/workflows/quality-gates.yml
name: Quality Gates
on: [pull_request]
jobs:
gate-compile:
name: "Gate: Compilation"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: PHP Syntax Check
run: find src/ -name "*.php" -exec php -l {} \;
- name: TypeScript Check
run: npx tsc --noEmit
gate-tests:
name: "Gate: Tests"
needs: gate-compile
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Unit Tests
run: vendor/bin/phpunit --testsuite=unit
- name: Integration Tests
run: vendor/bin/phpunit --testsuite=integration
- name: Coverage Check
run: |
vendor/bin/phpunit --coverage-text --coverage-clover=coverage.xml
# Fail if coverage below 80% for new code
python scripts/check-coverage.py coverage.xml --min=80
gate-security:
name: "Gate: Security"
needs: gate-compile
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: SAST Scan
run: semgrep scan --config=auto --config=p/owasp-top-ten src/
- name: Dependency Audit
run: composer audit --no-dev
- name: Secret Scan
run: gitleaks detect --source=.
gate-quality:
name: "Gate: Code Quality"
needs: gate-compile
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Static Analysis
run: vendor/bin/phpstan analyse src/ --level=9
- name: Code Style
run: vendor/bin/php-cs-fixer fix --dry-run --diff src/
- name: Architecture Rules
run: vendor/bin/deptrac analyse
gate-performance:
name: "Gate: Performance"
needs: [gate-tests]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Load Test
run: k6 run --vus 10 --duration 10s tests/loadtest.js
- name: Query Analysis
run: php bin/console app:analyze-queries --max-time=100ms
Предотвращение Gate Fatigue
Gate Fatigue -- это состояние, когда разработчик начинает игнорировать или обходить Quality Gates, потому что их слишком много, они слишком медленные или генерируют ложные срабатывания.
Стратегии борьбы с Gate Fatigue
1. Приоритизация Gates:
Критичные (блокируют всегда):
- Компиляция
- Тесты
- Security scan
Важные (блокируют в CI):
- Static analysis
- Code coverage
- Performance benchmarks
Рекомендательные (не блокируют):
- Code style suggestions
- Complexity warnings
- Documentation coverage
2. Быстрый feedback loop:
| Gate | Максимальное время | Где запускать |
|---|---|---|
| Lint / Format | < 5 секунд | Pre-commit hook |
| Compile / Type check | < 15 секунд | Pre-commit hook |
| Unit tests | < 30 секунд | Pre-push hook |
| Static analysis | < 1 минута | CI pipeline |
| Integration tests | < 5 минут | CI pipeline |
| Security scan | < 3 минуты | CI pipeline |
| Performance tests | < 10 минут | CI pipeline (nightly) |
3. Инкрементальные проверки:
Проверяйте только изменённые файлы, а не весь проект:
# Only analyze changed files
CHANGED_FILES=$(git diff --name-only HEAD~1 -- '*.php')
if [ -n "$CHANGED_FILES" ]; then
vendor/bin/phpstan analyse $CHANGED_FILES --level=9
fi
Метрики эффективности Quality Gates
Чтобы понять, работают ли ваши Quality Gates, отслеживайте эти метрики:
Ключевые метрики
| Метрика | Описание | Целевое значение |
|---|---|---|
| Pass Rate | % прохождений с первой попытки | > 70% |
| Time-to-Pass | Среднее время от первого запуска до полного прохождения | < 15 минут |
| Defect Escape Rate | Баги, пропущенные Gates и найденные в production | < 5% |
| False Positive Rate | Ложные срабатывания | < 10% |
| Gate Execution Time | Общее время прохождения всех Gates | < 15 минут |
Пример дашборда
Quality Gates Dashboard — March 2026
=====================================
Overall Pass Rate: 78% (target: >70%) [OK]
Avg Time-to-Pass: 12 min (target: <15 min) [OK]
Defect Escape Rate: 3% (target: <5%) [OK]
False Positive Rate: 14% (target: <10%) [NEEDS ATTENTION]
By Gate:
Pre-Generation: 92% pass rate | avg 2 min
Post-Generation: 85% pass rate | avg 3 min
Testing: 71% pass rate | avg 8 min
Security: 88% pass rate | avg 4 min | 12% false positives
Performance: 95% pass rate | avg 6 min
Review: 65% pass rate | avg 45 min
Top Failure Reasons:
1. Missing edge case tests (23%)
2. PHPStan level 9 violations (18%)
3. N+1 query detection (12%)
4. Incomplete input validation (11%)
5. Naming convention violations (9%)
Практический пример: полный цикл с Quality Gates
Рассмотрим реальный сценарий -- разработка эндпоинта с помощью AI-ассистента:
Шаг 1: Pre-Generation Gate
## Task: Create Order API Endpoint
**What:** POST /api/v1/orders -- creates a new order
**Why:** Mobile app needs order placement functionality
**Who:** Authenticated customers (ROLE_USER)
### Acceptance Criteria:
1. Creates order with product_id, quantity, shipping_address
2. Returns 201 with order details on success
3. Returns 422 with validation errors on invalid input
4. Idempotent via X-Idempotency-Key header
5. Checks product stock availability
6. Dispatches OrderCreated event
### Constraints:
- Use existing CreateOrderCommand + handler pattern
- Doctrine ORM, no raw SQL
- Parameterized queries only
- All money values in cents (integer)
### Edge Cases:
- Product out of stock → 409 Conflict
- Duplicate idempotency key → return existing order
- Quantity > 1000 → 422 validation error
- Non-existent product → 404
Чеклист пройден: задача сформулирована, критерии определены, ограничения указаны, edge cases продуманы. Gate PASSED.
Шаг 2: Генерация и Post-Generation Gate
AI сгенерировал код. Проверяем:
# Does it compile?
php -l src/Controller/Api/V1/OrderController.php # OK
php -l src/Command/CreateOrderCommand.php # OK
php -l src/Handler/CreateOrderHandler.php # OK
# Static analysis
vendor/bin/phpstan analyse src/Controller/Api/V1/OrderController.php --level=9
# OK: no errors
# Check for placeholders
grep -rn "TODO\|FIXME\|PLACEHOLDER" src/Controller/Api/V1/ src/Command/ src/Handler/
# No matches found
# Check architecture (handler in correct namespace, no circular deps)
vendor/bin/deptrac analyse --config-file=deptrac.yaml
# OK: no violations
Компилируется, нет placeholder-ов, архитектура соответствует. Gate PASSED.
Шаг 3-6: Остальные Gates
Каждый последующий Gate строится по тому же принципу: определённые критерии, автоматизированные проверки, чёткий результат pass/fail.
Ключевые выводы
"Работа с AI-агентами требует БОЛЬШЕ строгости, БОЛЬШЕ структуры, БОЛЬШЕ качества кода -- а не меньше."
-
Quality Gates -- это не бюрократия, а страховка. Скорость AI-генерации делает Gates единственным надёжным механизмом контроля качества.
-
Автоматизируйте максимально. Каждый Gate, который можно проверить автоматически, должен быть автоматизирован. Человеческий ревью -- для того, что автоматизировать невозможно.
-
Быстрый feedback -- ключ к adoption. Если Gates работают медленно, разработчики будут их обходить.
-
Pre-Generation Gate -- самый важный. Чем лучше спецификация, тем выше качество генерации, тем меньше нагрузка на последующие Gates.
-
Измеряйте эффективность Gates. Без метрик вы не знаете, работают ли ваши контрольные точки.
-
Итерируйте. Quality Gates -- не статичный процесс. Анализируйте defect escape rate и добавляйте новые проверки для типов ошибок, которые проскальзывают.