От Vibe Coding к инженерному подходу
Vibe coding и production engineering -- это не два противоположных лагеря, а два конца спектра. Задача инженера -- понимать, где на этом спектре он находится в данный момент, и осознанно выбирать подходящий уровень дисциплины.
СПЕКТР ПОДХОДОВ:
Vibe Coding ←──────────────────────────────────→ Production Engineering
"Оно работает" "Оно работает "Оно работает надежно,
и протестировано" безопасно и масштабируемо"
Скорость: 10x Скорость: 5x Скорость: 3x
Риск: Высокий Риск: Средний Риск: Низкий
Для: Прототипов Для: MVP Для: Production
Production engineering с AI -- это подход, при котором AI-ассистенты используются как мощные инструменты, но каждый их вывод проходит через инженерные quality gates.
Чего AI не делает автоматически
AI генерирует код, но не обеспечивает автоматически то, что нужно для production:
1. Тестирование
<?php
declare(strict_types=1);
// AI generates the function:
final class PriceCalculator
{
public function calculateDiscount(Money $price, int $quantity): Money
{
return match (true) {
$quantity >= 100 => $price->multiply(0.8), // 20% discount
$quantity >= 50 => $price->multiply(0.9), // 10% discount
$quantity >= 10 => $price->multiply(0.95), // 5% discount
default => $price,
};
}
}
// AI does NOT automatically generate:
// - Tests for boundary values (9, 10, 11, 49, 50, 51, 99, 100, 101)
// - Tests for zero quantity
// - Tests for negative quantity
// - Tests for very large quantity (integer overflow?)
// - Tests for zero price
// - Tests with different currencies
// - Performance tests with millions of calculations
2. Безопасность
AI не проверяет:
| Область | Что пропускает AI |
|---|---|
| Аутентификация | Endpoint без проверки токена |
| Авторизация | Доступ к чужим ресурсам (IDOR) |
| Валидация | Принятие опасного ввода |
| Шифрование | Хранение секретов в открытом виде |
| Rate Limiting | Отсутствие ограничений на запросы |
| CORS | Слишком открытые настройки |
| SQL Injection | Конкатенация строк в запросах |
| XSS | Отсутствие экранирования |
3. Observability
# AI generates endpoints but not:
# Structured logging
logging:
format: json
fields:
- request_id
- user_id
- action
- duration_ms
- status_code
# Health checks
health_check:
endpoints:
- /health/live # Is the process running?
- /health/ready # Can it serve traffic?
- /health/startup # Has it finished initializing?
# Metrics
metrics:
- http_requests_total
- http_request_duration_seconds
- business_events_total
- error_rate
# Alerting
alerts:
- name: HighErrorRate
condition: error_rate > 1%
for: 5m
severity: critical
4. Документация
AI пишет код, но не объясняет:
- Почему выбрано именно такое решение (а не альтернативное)
- Какие trade-offs были рассмотрены
- Как это связано с бизнес-требованиями
- Когда это решение может стать неадекватным (при каком масштабе)
- Кто должен быть уведомлен при изменении
5. Error Handling
// AI-generated: basic error handling
func ProcessPayment(ctx context.Context, req PaymentRequest) error {
result, err := gateway.Charge(ctx, req.Amount)
if err != nil {
return err // What kind of error? Retryable? User error? System error?
}
return nil
}
// Production: comprehensive error handling
func ProcessPayment(ctx context.Context, req PaymentRequest) error {
result, err := gateway.Charge(ctx, req.Amount)
if err != nil {
var gatewayErr *GatewayError
if errors.As(err, &gatewayErr) {
switch gatewayErr.Code {
case "card_declined":
// User error: don't retry, inform user
return fmt.Errorf("payment declined: %w", ErrCardDeclined)
case "insufficient_funds":
return fmt.Errorf("insufficient funds: %w", ErrInsufficientFunds)
case "rate_limited":
// Transient: retry with backoff
slog.WarnContext(ctx, "payment gateway rate limited",
"request_id", req.ID,
)
return fmt.Errorf("temporary error, retry later: %w", ErrRetryable)
case "gateway_timeout":
// Ambiguous: payment may or may not have been charged
// CRITICAL: must check status before retrying
slog.ErrorContext(ctx, "payment gateway timeout - status unknown",
"request_id", req.ID,
"amount", req.Amount,
)
return fmt.Errorf("payment status unknown: %w", ErrAmbiguous)
default:
slog.ErrorContext(ctx, "unexpected gateway error",
"code", gatewayErr.Code,
"message", gatewayErr.Message,
)
return fmt.Errorf("payment system error: %w", ErrInternal)
}
}
// Non-gateway error (network, serialization, etc.)
return fmt.Errorf("process payment for request %s: %w", req.ID, err)
}
slog.InfoContext(ctx, "payment processed",
"request_id", req.ID,
"transaction_id", result.TransactionID,
"amount", req.Amount,
)
return nil
}
Workflow: AI-Assisted Engineering
Инженерный workflow с AI состоит из шести этапов. AI участвует в каждом, но ни один не выполняется AI полностью автономно.
┌────────────────────────────────────────────────────────────────┐
│ AI-ASSISTED ENGINEERING WORKFLOW │
│ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ PLAN │→ │ SPEC │→ │ GEN │→ │VERIFY│→ │REFINE│→ │ SHIP │ │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ │Human │ │Human │ │ AI │ │Human │ │ Both │ │Human │ │
│ │+ AI │ │+ AI │ │ │ │+ CI │ │ │ │ │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
│ Plan: Определить ЧТО делаем, ЗАЧЕМ, для КОГО │
│ Spec: Написать четкую спецификацию и тесты │
│ Gen: AI генерирует код по спецификации │
│ Verify: Проверить качество, безопасность, производительность │
│ Refine: Доработать на основе результатов проверки │
│ Ship: Deploy с мониторингом и rollback-планом │
└────────────────────────────────────────────────────────────────┘
Этап 1: Plan (Планирование)
Прежде чем писать промпт для AI, ответьте на вопросы:
## Planning Template
### Задача
Что именно нужно сделать? (Конкретно, без "сделай красиво")
### Контекст
- Какие системы затронуты?
- Какие зависимости есть?
- Какие ограничения (SLA, compliance, бюджет)?
### Критерии приемки
- [ ] Функциональные требования (что работает)
- [ ] Нефункциональные (производительность, безопасность)
- [ ] Обратная совместимость
### Риски
- Что может пойти не так?
- Какой план отката?
### Оценка
- Сложность: low / medium / high
- Подход: single-shot / iterative / spec-driven / agent loop
AI помогает на этапе планирования:
- Предложить альтернативные подходы
- Найти потенциальные проблемы
- Оценить сложность
- Предложить структуру
Но решения принимает инженер.
Этап 2: Spec (Спецификация)
Четкая спецификация -- ключ к качественной генерации. Чем точнее spec, тем ближе результат AI к production-ready.
<?php
declare(strict_types=1);
/**
* SPECIFICATION: User Registration Service
*
* Requirements:
* 1. Accept email, password, name
* 2. Validate email format and uniqueness
* 3. Enforce password policy (min 8 chars, 1 uppercase, 1 digit)
* 4. Hash password with bcrypt (cost 12)
* 5. Create user in database within transaction
* 6. Send verification email asynchronously
* 7. Return UserDTO (never expose password hash)
*
* Error handling:
* - DuplicateEmailException if email exists
* - ValidationException with field-level errors
* - ServiceUnavailableException if email service is down (user still created)
*
* Performance:
* - < 500ms response time (p99)
* - Email sending must not block response
*
* Security:
* - Rate limit: 5 registrations per IP per hour
* - Log registration attempts (without password)
* - Sanitize all inputs
*/
interface UserRegistrationServiceInterface
{
/**
* @throws DuplicateEmailException
* @throws ValidationException
*/
public function register(RegisterUserDTO $dto): UserDTO;
}
final readonly class RegisterUserDTO
{
public function __construct(
public string $email,
#[\SensitiveParameter] public string $password,
public string $name,
public string $ipAddress,
) {}
}
Написав спецификацию, вы можете попросить AI реализовать ее. Спецификация служит и документацией, и контрактом.
Этап 3: Generate (Генерация)
Теперь AI генерирует код. Важно дать правильный контекст:
## Промпт для AI (пример):
Реализуй UserRegistrationService по следующей спецификации:
[вставить спецификацию]
Контекст проекта:
- Symfony 7.4, PHP 8.4
- PostgreSQL 18
- RabbitMQ для async messaging
- Паттерн: тонкие контроллеры, логика в сервисах
- Все поля readonly, constructor injection
- Тесты: PHPUnit 11, PHPStan level 9
Существующие интерфейсы:
[вставить релевантные интерфейсы]
Coding conventions:
[вставить из CLAUDE.md / стиль-гайда]
Этап 4: Verify (Проверка)
Самый критичный этап. AI-генерированный код проходит через автоматические и ручные проверки:
# Automated verification pipeline
verification:
static_analysis:
- phpstan level 9
- psalm with taint analysis
- phpmd (complexity, coupling)
tests:
- unit tests (PHPUnit)
- integration tests
- contract tests (API contracts)
- mutation tests (Infection PHP)
security:
- composer audit (dependency vulnerabilities)
- psalm taint analysis (injection detection)
- custom security rules
performance:
- load tests (k6 / Locust)
- query analysis (EXPLAIN ANALYZE)
- memory profiling
manual_review:
- business logic correctness
- error handling completeness
- edge cases coverage
- architecture compliance
# Practical verification commands
# Static analysis
vendor/bin/phpstan analyse src/ --level=9
vendor/bin/psalm --taint-analysis
# Tests
vendor/bin/phpunit --testsuite=unit
vendor/bin/phpunit --testsuite=integration
# Mutation testing (are your tests actually catching bugs?)
vendor/bin/infection --min-msi=80
# Security
composer audit
vendor/bin/psalm --taint-analysis
# Complexity
vendor/bin/phpmd src/ text codesize,design
Этап 5: Refine (Доработка)
На основе результатов проверки AI и инженер совместно дорабатывают код:
Результаты проверки → Список проблем → AI исправляет → Повторная проверка
Пример:
PHPStan: "Parameter $amount has no type hint" → AI добавляет type hint
Tests: "testNegativeAmount fails" → AI добавляет валидацию
Security: "SQL injection in search query" → AI параметризирует запрос
Review: "Missing retry logic for email" → AI добавляет retry с backoff
Цикл Verify-Refine повторяется до тех пор, пока все проверки не пройдены.
Этап 6: Ship (Доставка)
Деплой с инженерными гарантиями:
# Deployment checklist
deployment:
pre_deploy:
- [ ] All tests pass in CI
- [ ] Security scan clean
- [ ] Performance benchmarks pass
- [ ] Database migrations tested on staging
- [ ] Rollback plan documented
- [ ] Monitoring dashboards ready
- [ ] Alerting rules configured
- [ ] Feature flags set (gradual rollout)
deploy:
- strategy: canary # 5% → 25% → 50% → 100%
- health_check: /health/ready
- rollback_trigger: error_rate > 1% for 5m
post_deploy:
- [ ] Smoke tests pass
- [ ] Metrics normal
- [ ] No new errors in logs
- [ ] Performance within SLA
Интеграция AI в профессиональный workflow
1. Начните с четких требований
# BAD: vague prompt
"Сделай API для пользователей"
# GOOD: specific requirements
"Реализуй эндпоинт GET /api/v1/users/{id} который:
- Требует JWT-аутентификацию
- Возвращает UserDTO (id, name, email, created_at)
- Проверяет что текущий пользователь имеет право видеть запрошенного
- Возвращает 404 если пользователь не найден
- Возвращает 403 если нет доступа
- Логирует запрос (без PII)
- Кэширует ответ на 5 минут (invalidate при обновлении)
Паттерн: Symfony Controller + Service + Repository"
2. Предоставьте контекст
# Project structure context
tree src/ -L 2
# Existing patterns context
cat src/Controller/AbstractApiController.php
cat src/DTO/UserDTO.php
cat src/Repository/UserRepository.php
# Coding standards
cat CLAUDE.md
cat phpstan.neon
cat .php-cs-fixer.php
3. Проверяйте критически
Чек-лист при review AI-генерированного кода:
## Critical Review Checklist
### Понимание
- [ ] Я понимаю КАЖДУЮ строку этого кода
- [ ] Я понимаю, ПОЧЕМУ выбрано именно это решение
- [ ] Я могу объяснить этот код коллеге
### Корректность
- [ ] Код соответствует спецификации
- [ ] Все edge cases обработаны
- [ ] Error handling полный и содержательный
### Безопасность
- [ ] Нет hardcoded секретов
- [ ] Входные данные валидируются
- [ ] Авторизация проверяется
- [ ] Нет injection-уязвимостей
### Архитектура
- [ ] Код соответствует архитектуре проекта
- [ ] Нет нарушения SOLID-принципов
- [ ] Зависимости инжектятся (не создаются внутри)
- [ ] Нет дублирования с существующим кодом
### Совместимость
- [ ] Не ломает существующие API
- [ ] Миграции обратно совместимы
- [ ] Конфигурация не требует ручного вмешательства
4. Пишите тесты (и проверяйте AI-тесты)
AI-генерированные тесты тоже нуждаются в review:
<?php
declare(strict_types=1);
// AI-generated test: looks correct but has problems
final class UserServiceTest extends TestCase
{
public function testCreateUser(): void
{
$service = new UserService($this->repository);
$user = $service->create('[email protected]', 'password123');
// PROBLEM 1: Only tests happy path
// PROBLEM 2: 'password123' is not a strong password -- does the test
// actually test password policy enforcement?
// PROBLEM 3: No assertion on what's stored in repository
// PROBLEM 4: No test for duplicate email
// PROBLEM 5: No test for invalid email format
$this->assertInstanceOf(User::class, $user);
$this->assertEquals('[email protected]', $user->getEmail());
}
}
// What you should have:
final class UserServiceTest extends TestCase
{
#[DataProvider('invalidEmailProvider')]
public function testRejectsInvalidEmail(string $email): void
{
$this->expectException(ValidationException::class);
$this->service->create($email, 'ValidPass123');
}
public static function invalidEmailProvider(): array
{
return [
'empty' => [''],
'no at sign' => ['invalid'],
'no domain' => ['test@'],
'no local part' => ['@example.com'],
'spaces' => ['test @example.com'],
'double dot' => ['[email protected]'],
'too long' => [str_repeat('a', 255) . '@example.com'],
];
}
#[DataProvider('weakPasswordProvider')]
public function testRejectsWeakPassword(string $password): void
{
$this->expectException(ValidationException::class);
$this->service->create('[email protected]', $password);
}
public static function weakPasswordProvider(): array
{
return [
'too short' => ['Ab1'],
'no uppercase' => ['password123'],
'no digit' => ['PasswordOnly'],
'no lowercase' => ['PASSWORD123'],
'common password' => ['Password1'],
];
}
public function testRejectsDuplicateEmail(): void
{
$this->service->create('[email protected]', 'ValidPass123');
$this->expectException(DuplicateEmailException::class);
$this->service->create('[email protected]', 'AnotherPass456');
}
public function testPasswordIsHashed(): void
{
$user = $this->service->create('[email protected]', 'ValidPass123');
// Password hash should NOT be the plain text password
$this->assertNotEquals('ValidPass123', $user->getPasswordHash());
// Should be a valid bcrypt hash
$this->assertTrue(password_verify('ValidPass123', $user->getPasswordHash()));
}
public function testSendsVerificationEmailAsynchronously(): void
{
$this->service->create('[email protected]', 'ValidPass123');
// Verify the message was dispatched, not sent synchronously
$this->transport->assertCount(1);
$this->transport->assertQueued(SendVerificationEmailMessage::class);
}
}
5. Security Scan
# Dependency vulnerabilities
composer audit
# Static analysis for security
vendor/bin/psalm --taint-analysis src/
# Check for hardcoded secrets
grep -rn "password\s*=" src/ --include="*.php" | grep -v "->password"
grep -rn "api_key\s*=" src/ --include="*.php"
grep -rn "secret\s*=" src/ --include="*.php"
# Check for unsafe functions
grep -rn "eval(" src/ --include="*.php"
grep -rn "exec(" src/ --include="*.php"
grep -rn "system(" src/ --include="*.php"
grep -rn "shell_exec(" src/ --include="*.php"
6. Performance Validation
<?php
declare(strict_types=1);
// Performance test: ensure AI-generated code scales
final class UserSearchPerformanceTest extends TestCase
{
public function testSearchPerformanceWithLargeDataset(): void
{
// Seed 100,000 users
$this->seedUsers(100_000);
$start = hrtime(true);
$results = $this->searchService->search(
query: 'john',
page: 1,
perPage: 20,
);
$durationMs = (hrtime(true) - $start) / 1_000_000;
// Must complete in under 100ms
$this->assertLessThan(100, $durationMs, sprintf(
'Search took %.2fms, expected < 100ms',
$durationMs
));
// Must use index, not full table scan
$this->assertCount(20, $results->getItems());
}
}
Роль инженера: от кодера к оркестратору
С AI роль инженера фундаментально меняется:
РАНЬШЕ: ТЕПЕРЬ:
Инженер = кодер Инженер = оркестратор
├─ Пишет код вручную ├─ Формулирует требования
├─ Отлаживает свой код ├─ Настраивает AI-контекст
├─ Знает каждую строку ├─ Верифицирует AI-вывод
├─ Медленно, но предсказуемо ├─ Быстро, с проверками
└─ 100% своего кода └─ 30% своего + 70% AI
Что становится БОЛЕЕ важным
| Навык | Почему важнее |
|---|---|
| Архитектура | AI не проектирует системы, он реализует компоненты |
| Code Review | Объем кода вырос, качество review критично |
| Тестирование | Единственный надежный способ проверить AI-код |
| Безопасность | AI не думает о безопасности по умолчанию |
| Системное мышление | Как компоненты взаимодействуют -- AI не видит |
| Бизнес-знания | AI не знает ваш домен |
Что становится МЕНЕЕ важным
| Навык | Почему менее критично |
|---|---|
| Скорость набора кода | AI набирает быстрее |
| Знание синтаксиса наизусть | AI помнит синтаксис |
| Boilerplate код | AI генерирует шаблоны мгновенно |
| Типовые реализации | CRUD, сериализация, валидация -- AI справляется |
Метрики: баланс скорости и качества
Time-to-Ship vs Quality-at-Ship
Quality-at-Ship
▲
│
100% │ ◆ Production
│ ╱ Engineering
│ ╱
80% │ ◆───╱─── Sweet Spot
│ ╱
│ ╱
60% │ ◆───╱
│ ╱
│ ╱
40% │ ╱
│╱
20% ◆ Vibe Coding
│
└───┬───┬───┬───┬───┬───► Time-to-Ship
1d 3d 1w 2w 1m
Что измерять
# Metrics for AI-Assisted Engineering
metrics:
speed:
- time_to_first_pr: "How fast from task to PR"
- cycle_time: "PR creation to merge"
- deployment_frequency: "How often we ship"
quality:
- defect_rate: "Bugs per 1000 lines"
- test_coverage: "% of code covered by tests"
- security_score: "Vulnerabilities found post-deploy"
- mttr: "Mean time to recovery"
ai_specific:
- ai_acceptance_rate: "% of AI code accepted without changes"
- ai_rework_rate: "% of AI code that needed significant rework"
- review_time_per_line: "Time spent reviewing AI-generated code"
- ai_bug_rate: "Bugs traced back to AI-generated code"
Целевые показатели
| Метрика | Vibe Coding | AI + Engineering | Целевое значение |
|---|---|---|---|
| Time to PR | 2 часа | 4 часа | 4 часа |
| Defect rate | 15/1000 loc | 2/1000 loc | < 3/1000 loc |
| Test coverage | 0% | 80%+ | 80%+ |
| Security issues | 5+/sprint | 0-1/sprint | 0/sprint |
| MTTR | 4+ часа | < 30 мин | < 30 мин |
| AI rework rate | 60%+ | 15-20% | < 20% |
Практический пример: полный цикл
Задача: добавить API для экспорта отчетов
Plan:
Задача: REST API для экспорта отчетов в PDF/CSV
Контекст: Существующая система отчетов, ~50,000 записей
Ограничения: < 30 сек генерация, max 100 MB файл
Риски: OOM при большом отчете, timeout при генерации
Spec:
<?php
declare(strict_types=1);
interface ReportExportServiceInterface
{
/**
* Generates a report export file asynchronously.
* Returns a job ID that can be polled for status.
*
* @throws ValidationException if parameters are invalid
* @throws QuotaExceededException if user has too many pending exports
*/
public function requestExport(ExportRequest $request, User $user): ExportJob;
public function getJobStatus(string $jobId, User $user): ExportJobStatus;
/**
* @throws ExportNotFoundException
* @throws AccessDeniedException
*/
public function downloadExport(string $jobId, User $user): StreamedResponse;
}
Generate: AI генерирует реализацию по спецификации.
Verify: Прогон через CI, тесты, security scan, load test.
Refine: Исправление найденных проблем (batched processing для больших отчетов, streaming для download).
Ship: Canary deploy, мониторинг, документация.
Ключевые выводы
-
Production engineering с AI -- это не отказ от AI, а использование AI с инженерными guardrails.
-
Workflow Plan-Spec-Generate-Verify-Refine-Ship обеспечивает баланс скорости и качества.
-
Роль инженера смещается от написания кода к формулированию требований, верификации и оркестрации.
-
Автоматизация проверок критична -- CI/CD, линтеры, security scan, тесты должны ловить ошибки AI автоматически.
-
Тесты -- ваш контракт с AI. Спецификация определяет ЧТО, тесты проверяют, что ЭТО сделано правильно.
-
Измеряйте не только скорость, но и качество, безопасность, надежность -- баланс определяет long-term успех.
Главный принцип: AI ускоряет генерацию кода в 3-10 раз. Но экономия времени имеет смысл только если код надежный, безопасный и поддерживаемый. Production engineering с AI -- это способ получить и скорость, и качество.