HardТеория12 min

Паттерны спецификаций

Проверенные шаблоны для написания эффективных спецификаций для AI

Почему паттерны важны

Не все спецификации одинаково полезны для AI. Одна и та же фича может быть описана десятком способов -- и AI выдаст радикально разный результат в зависимости от формата спецификации.

Паттерны спецификаций -- это проверенные шаблоны, которые систематически производят предсказуемый и качественный выход от AI. Выбор правильного паттерна зависит от типа фичи, сложности и того, какой аспект системы наиболее критичен.

Паттерн спецификации        Тип фичи
─────────────────────       ──────────
API-First                →  REST/GraphQL эндпоинты
Test-First               →  Бизнес-логика, алгоритмы
State Machine            →  Сущности с жизненным циклом
Contract                 →  Критичные интерфейсы
Example-Driven           →  Сложные трансформации данных
Constraint               →  Безопасность, производительность

Ключевой инсайт: AI-модели генерируют код на основе статистических паттернов. Чем ближе ваша спецификация к формату, который AI "видел" в обучающих данных, тем качественнее результат. OpenAPI-спецификация -- это формат, на котором тренировались все большие модели. BDD-сценарии -- тоже. Авторский свободный текст -- нет.


Паттерн 1: API-First Spec

Суть

Определите API-контракт до реализации. OpenAPI-схема становится и спецификацией, и документацией, и основой для генерации кода.

Когда использовать

  • REST API endpoints
  • Микросервисные интеграции
  • Публичные API
  • Когда frontend и backend разрабатываются параллельно

Как это работает

# specs/api/user-registration.yaml
openapi: 3.1.0
info:
  title: User Registration API
  version: 1.0.0
  description: |
    Handles user registration with email confirmation.
    Rate limited to 5 attempts per IP per hour.

paths:
  /api/v1/auth/register:
    post:
      operationId: registerUser
      summary: Register a new user account
      tags: [Authentication]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegisterRequest'
            examples:
              valid:
                summary: Valid registration
                value:
                  email: "[email protected]"
                  password: "SecurePass123"
                  password_confirmation: "SecurePass123"
              invalid_email:
                summary: Invalid email format
                value:
                  email: "not-an-email"
                  password: "SecurePass123"
                  password_confirmation: "SecurePass123"
      responses:
        '201':
          description: User created, confirmation email sent
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserResponse'
              example:
                id: "01910f9a-7b4e-7d5a-8c3b-2e4f6a8b0c1d"
                email: "[email protected]"
                status: "pending_confirmation"
                created_at: "2026-03-07T10:30:00Z"
        '400':
          $ref: '#/components/responses/ValidationError'
        '409':
          description: Email already registered
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                code: 409
                message: "Email already registered"
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Seconds until rate limit resets

components:
  schemas:
    RegisterRequest:
      type: object
      required: [email, password, password_confirmation]
      properties:
        email:
          type: string
          format: email
          maxLength: 255
        password:
          type: string
          minLength: 8
          maxLength: 128
          description: "Must contain uppercase, lowercase, and digit"
        password_confirmation:
          type: string

    UserResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
        email:
          type: string
          format: email
        status:
          type: string
          enum: [pending_confirmation, active, blocked]
        created_at:
          type: string
          format: date-time

    Error:
      type: object
      properties:
        code:
          type: integer
        message:
          type: string

  responses:
    ValidationError:
      description: Validation failed
      content:
        application/json:
          schema:
            type: object
            properties:
              code:
                type: integer
                example: 400
              message:
                type: string
                example: "Validation failed"
              errors:
                type: object
                additionalProperties:
                  type: array
                  items:
                    type: string

Промпт для AI

Given this OpenAPI specification (attached), generate:
1. Symfony controller implementing all endpoints
2. Request DTO classes with validation attributes
3. Response DTO classes
4. Integration tests verifying all response codes and schemas

Follow conventions:
- PHP 8.4, strict_types
- Final classes, constructor property promotion
- Symfony Validator attributes on DTOs
- PHPUnit integration tests using WebTestCase

Преимущества API-First

Преимущество Описание
Однозначность JSON Schema не допускает двойных трактовок
Генерация кода Множество инструментов генерируют код из OpenAPI
Документация Swagger UI автоматически из той же спецификации
Тестирование Можно валидировать ответы против схемы
Параллелизм Frontend работает по контракту до готовности backend

Паттерн 2: Test-First Spec

Суть

Определите поведение как набор тестов до реализации. AI пишет код, чтобы тесты прошли. По сути -- TDD, где тесты и есть спецификация.

Когда использовать

  • Чистая бизнес-логика без внешних зависимостей
  • Алгоритмы и расчёты
  • Утилитарные функции
  • Валидаторы и трансформаторы данных

Как это работает

<?php

declare(strict_types=1);

namespace Tests\Unit\Service;

use App\Service\PasswordStrengthValidator;
use App\Exception\WeakPasswordException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

/**
 * SPEC: Password must be 8+ characters, contain at least
 * one uppercase letter, one lowercase letter, and one digit.
 * Special characters are allowed but not required.
 */
final class PasswordStrengthValidatorTest extends TestCase
{
    private PasswordStrengthValidator $validator;

    protected function setUp(): void
    {
        $this->validator = new PasswordStrengthValidator();
    }

    // --- Valid passwords ---

    #[Test]
    public function accepts_password_meeting_all_criteria(): void
    {
        // 8+ chars, uppercase, lowercase, digit
        $this->assertTrue($this->validator->isValid('SecurePass1'));
    }

    #[Test]
    public function accepts_password_with_special_characters(): void
    {
        $this->assertTrue($this->validator->isValid('S3cure!@#'));
    }

    #[Test]
    public function accepts_password_exactly_8_characters(): void
    {
        $this->assertTrue($this->validator->isValid('Abcdef1x'));
    }

    #[Test]
    public function accepts_very_long_password(): void
    {
        $password = str_repeat('Aa1', 42) . 'x'; // 127 chars
        $this->assertTrue($this->validator->isValid($password));
    }

    // --- Invalid passwords ---

    #[Test]
    public function rejects_password_shorter_than_8_characters(): void
    {
        $this->assertFalse($this->validator->isValid('Abcde1'));
    }

    #[Test]
    public function rejects_password_without_uppercase(): void
    {
        $this->assertFalse($this->validator->isValid('abcdefg1'));
    }

    #[Test]
    public function rejects_password_without_lowercase(): void
    {
        $this->assertFalse($this->validator->isValid('ABCDEFG1'));
    }

    #[Test]
    public function rejects_password_without_digit(): void
    {
        $this->assertFalse($this->validator->isValid('Abcdefgh'));
    }

    #[Test]
    public function rejects_empty_password(): void
    {
        $this->assertFalse($this->validator->isValid(''));
    }

    // --- Error messages ---

    #[Test]
    public function returns_all_violation_messages(): void
    {
        $violations = $this->validator->validate('abc');

        $this->assertContains('Password must be at least 8 characters', $violations);
        $this->assertContains('Password must contain at least one uppercase letter', $violations);
        $this->assertContains('Password must contain at least one digit', $violations);
    }

    #[Test]
    public function returns_empty_array_for_valid_password(): void
    {
        $violations = $this->validator->validate('SecurePass1');

        $this->assertEmpty($violations);
    }

    // --- Edge cases ---

    #[Test]
    public function handles_unicode_characters(): void
    {
        // Unicode letters should not count as uppercase/lowercase latin
        $this->assertFalse($this->validator->isValid('пароль1А'));
    }

    #[Test]
    public function rejects_password_exceeding_128_characters(): void
    {
        $password = str_repeat('Aa1', 43); // 129 chars
        $this->assertFalse($this->validator->isValid($password));
    }
}

Промпт для AI

Here are the tests for PasswordStrengthValidator (attached).
Implement the class so that ALL tests pass.

Requirements:
- src/Service/PasswordStrengthValidator.php
- Final class, no dependencies
- Methods: isValid(string): bool, validate(string): array
- validate() returns array of violation message strings
- PHP 8.4, strict_types

Do NOT modify the tests.

Преимущества Test-First

Преимущество Описание
Верификация встроена Тесты -- одновременно спека и проверка
Однозначность Тест либо проходит, либо нет
Edge cases Граничные случаи зафиксированы как тесты
Regression Тесты остаются как защита от регрессии
Понятность AI "Make tests pass" -- самый чёткий промпт

Паттерн 3: State Machine Spec

Суть

Определите систему как набор состояний и переходов между ними. Чёткие правила: какие переходы допустимы, что их вызывает, какие побочные эффекты возникают.

Когда использовать

  • Сущности с жизненным циклом (заказ, документ, задача)
  • Workflow-системы
  • Конечные автоматы в бизнес-логике
  • Системы с явными статусами

Как это работает

# State Machine: Order Lifecycle

## States

| State | Description | Terminal |
|-------|-------------|----------|
| `created` | Order placed, awaiting payment | No |
| `paid` | Payment received | No |
| `processing` | Being prepared for shipment | No |
| `shipped` | Handed to courier | No |
| `delivered` | Customer received | Yes |
| `cancelled` | Order cancelled | Yes |
| `refunded` | Payment returned | Yes |

## Transitions

| From | To | Trigger | Guard | Side Effect |
|------|----|---------|-------|-------------|
| `created` | `paid` | PaymentReceived | amount == order.total | SendConfirmationEmail |
| `created` | `cancelled` | CancelOrder | — | ReleaseInventory |
| `paid` | `processing` | StartProcessing | inventory.available | ReserveInventory |
| `paid` | `refunded` | RefundOrder | — | ProcessRefund, ReleaseInventory |
| `processing` | `shipped` | ShipOrder | tracking_number present | SendShippingNotification |
| `processing` | `cancelled` | CancelOrder | — | ProcessRefund, ReleaseInventory |
| `shipped` | `delivered` | ConfirmDelivery | — | — |
| `shipped` | `refunded` | RefundOrder | within 14 days | ProcessRefund |

## Forbidden Transitions
- `delivered` → any (terminal state)
- `cancelled` → any (terminal state)
- `refunded` → any (terminal state)
- `created` → `shipped` (must go through paid + processing)
- `paid` → `delivered` (must go through processing + shipped)

## Invariants
- Order total never changes after creation
- State transition timestamp is always recorded
- Only one active state at a time
- State history is immutable (append-only)
stateDiagram-v2
    [*] --> created
    created --> paid : PaymentReceived
    created --> cancelled : CancelOrder
    paid --> processing : StartProcessing
    paid --> refunded : RefundOrder
    processing --> shipped : ShipOrder
    processing --> cancelled : CancelOrder
    shipped --> delivered : ConfirmDelivery
    shipped --> refunded : RefundOrder
    delivered --> [*]
    cancelled --> [*]
    refunded --> [*]

Промпт для AI

Implement this state machine (attached) for the Order entity.

Requirements:
1. Order entity with status field (enum)
2. OrderStateMachine service with transition() method
3. Guards as separate validator classes
4. Side effects dispatched via MessageBus (async)
5. State history tracked in order_state_history table
6. Forbidden transitions throw InvalidTransitionException

Stack: Symfony 7.4, PHP 8.4 enums, Messenger for async.
Use Symfony Workflow component as the underlying engine.

Преимущества State Machine Spec

Преимущество Описание
Полнота Все возможные состояния и переходы явно определены
Запреты Явно указано, что НЕ может произойти
Тестируемость Каждый переход -- отдельный тест-кейс
Визуализация Диаграмма сразу видна (Mermaid/PlantUML)
AI-дружелюбность Таблица переходов -- идеальный формат для AI

Паттерн 4: Contract Spec

Суть

Определите контракты для каждого компонента: предусловия (preconditions), постусловия (postconditions), инварианты. Подход Design by Contract Бертрана Мейера.

Когда использовать

  • Критичные бизнес-компоненты
  • Финансовые расчеты
  • Интерфейсы между модулями
  • Когда корректность важнее производительности

Как это работает

# Contract: MoneyTransferService

## Method: transfer(from, to, amount)

### Preconditions (REQUIRE)
- `from` account exists and is active
- `to` account exists and is active
- `from` != `to` (no self-transfer)
- `amount` > 0
- `amount` <= `from.balance`
- `from.currency` == `to.currency` (same currency)
- No pending transfer for same from/to/amount (idempotency)

### Postconditions (ENSURE)
- `from.balance` decreased by exactly `amount`
- `to.balance` increased by exactly `amount`
- `from.balance` + `to.balance` == old(from.balance) + old(to.balance)
  (conservation of money)
- Transfer record created with status "completed"
- AuditLog entry created

### Invariants
- Account balance is never negative
- Sum of all account balances is constant (closed system)
- Every transfer has exactly two ledger entries (debit + credit)
- Ledger entries are immutable after creation

### Error conditions
- InsufficientFundsException: amount > from.balance
- AccountNotFoundException: from or to doesn't exist
- SamAccountException: from == to
- InvalidAmountException: amount <= 0
- CurrencyMismatchException: different currencies
- DuplicateTransferException: idempotency violation

Промпт для AI

Implement MoneyTransferService according to these contracts (attached).

Requirements:
1. All preconditions checked at method entry, throw specific exceptions
2. All postconditions verified via assertions after execution
3. Invariants checked in a separate InvariantChecker that runs
   in dev/test environments
4. Database transaction wraps the entire transfer
5. Pessimistic locking on both accounts (ORDER BY id to prevent deadlock)

Stack: Symfony 7.4, PHP 8.4, Doctrine ORM, PostgreSQL.
<?php

declare(strict_types=1);

namespace App\Service;

use App\Entity\Account;
use App\Exception\InsufficientFundsException;
use App\Exception\InvalidAmountException;
use App\Exception\SameAccountException;

final class MoneyTransferService
{
    // Contract: transfer money between accounts
    //
    // REQUIRE: fromAccount.isActive && toAccount.isActive
    // REQUIRE: fromAccount.id != toAccount.id
    // REQUIRE: amount > 0
    // REQUIRE: amount <= fromAccount.balance
    // REQUIRE: fromAccount.currency == toAccount.currency
    //
    // ENSURE: fromAccount.balance == old(fromAccount.balance) - amount
    // ENSURE: toAccount.balance == old(toAccount.balance) + amount
    // ENSURE: transferRecord.status == 'completed'
    //
    // INVARIANT: fromAccount.balance >= 0
    // INVARIANT: sum(all_balances) == const
    public function transfer(Account $from, Account $to, int $amount): Transfer
    {
        // Check preconditions
        $this->checkPreconditions($from, $to, $amount);

        $oldFromBalance = $from->getBalance();
        $oldToBalance = $to->getBalance();

        // Execute transfer
        $from->debit($amount);
        $to->credit($amount);

        $transfer = new Transfer($from, $to, $amount);

        // Verify postconditions
        assert($from->getBalance() === $oldFromBalance - $amount);
        assert($to->getBalance() === $oldToBalance + $amount);
        assert($from->getBalance() + $to->getBalance() === $oldFromBalance + $oldToBalance);

        return $transfer;
    }
}

Преимущества Contract Spec

Преимущество Описание
Математическая строгость Контракты можно формально верифицировать
Самодокументирование Контракты в коде -- живая документация
Раннее обнаружение ошибок Precondition violations ловят баги на входе
AI-понятность Чёткая структура REQUIRE/ENSURE/INVARIANT

Паттерн 5: Example-Driven Spec

Суть

Опишите поведение через конкретные примеры входных и выходных данных. AI обобщает паттерн из примеров. Близко к BDD (Behavior-Driven Development) с форматом Given/When/Then.

Когда использовать

  • Сложные трансформации данных
  • Бизнес-правила с множеством вариаций
  • Когда формальное описание правил слишком сложное
  • Когда stakeholders мыслят примерами, а не абстракциями

Как это работает

# Feature: Price Calculator

## Scenario 1: Simple purchase without discounts
**Given** products in cart:
  | Product | Price | Quantity |
  |---------|-------|----------|
  | Widget  | 1000  | 2        |

**When** calculating total
**Then** result should be:
  | Subtotal | Discount | Tax (20%) | Total |
  |----------|----------|-----------|-------|
  | 2000     | 0        | 400       | 2400  |

## Scenario 2: Quantity discount (10+ items = 10% off)
**Given** products in cart:
  | Product | Price | Quantity |
  |---------|-------|----------|
  | Widget  | 1000  | 15       |

**When** calculating total
**Then** result should be:
  | Subtotal | Discount | Tax (20%) | Total  |
  |----------|----------|-----------|--------|
  | 15000    | 1500     | 2700      | 16200  |

## Scenario 3: Multiple products with mixed discounts
**Given** products in cart:
  | Product  | Price | Quantity |
  |----------|-------|----------|
  | Widget   | 1000  | 15       |
  | Gadget   | 5000  | 3        |

**And** promo code "SAVE20" applied (20% off gadgets)

**When** calculating total
**Then** result should be:
  | Line     | Subtotal | Line Discount | After Discount |
  |----------|----------|---------------|----------------|
  | Widget   | 15000    | 1500 (qty)    | 13500          |
  | Gadget   | 15000    | 3000 (promo)  | 12000          |

  | Combined | Discount | Tax (20%) | Total  |
  |----------|----------|-----------|--------|
  | 30000    | 4500     | 5100      | 30600  |

## Scenario 4: Edge case — empty cart
**Given** empty cart
**When** calculating total
**Then** result should be:
  | Subtotal | Discount | Tax | Total |
  |----------|----------|-----|-------|
  | 0        | 0        | 0   | 0     |

## Scenario 5: Edge case — discount larger than subtotal
**Given** products in cart:
  | Product | Price | Quantity |
  |---------|-------|----------|
  | Widget  | 100   | 1        |

**And** promo code "FLAT200" applied (200 flat discount)

**When** calculating total
**Then** result should be:
  | Subtotal | Discount | Tax | Total |
  |----------|----------|-----|-------|
  | 100      | 100      | 0   | 0     |

Note: Discount capped at subtotal, total never negative

Промпт для AI

Implement a PriceCalculator service that produces
the results shown in these scenarios (attached).

Requirements:
1. Accept cart items (product, price, quantity)
2. Accept optional promo codes
3. Apply quantity discounts (10+ items = 10% off that line)
4. Apply promo code discounts
5. Calculate tax at 20% on discounted subtotal
6. Return detailed breakdown (per-line and total)
7. All money in integer cents (no floating point)

Write the service AND tests that verify all 5 scenarios.

Преимущества Example-Driven

Преимущество Описание
Понятность Примеры понятны даже не-техническим людям
Конкретность Нет абстракций -- только входы и выходы
Тестируемость Каждый сценарий = один тест
Полнота Edge cases естественно включаются как сценарии
AI-эффективность AI хорошо обобщает паттерны из примеров

Паттерн 6: Constraint Spec

Суть

Определите, что система НЕ должна делать. Негативные требования так же важны, как позитивные -- и часто более критичны, потому что их нарушение ведёт к уязвимостям, утечкам данных и деградации производительности.

Когда использовать

  • Требования безопасности
  • Бюджеты производительности
  • Compliance и регуляторные требования
  • Запрещённые паттерны в коде

Как это работает

# Constraints: User API

## Security Constraints

### C-SEC-1: No raw SQL
- MUST NOT use raw SQL queries anywhere in the codebase
- All database access through Doctrine ORM/DBAL query builder
- Verification: grep for "->query(", "->exec(", "->executeQuery("
  with raw string parameters

### C-SEC-2: No user-controlled data in logs
- MUST NOT log passwords, tokens, or PII
- Allowed in logs: user ID (UUID), email domain (not full email),
  action type, timestamp
- Verification: PHPStan custom rule checking log calls

### C-SEC-3: No sensitive data in responses
- MUST NOT include password_hash in any API response
- MUST NOT include internal IDs (database serial) — only UUIDs
- MUST NOT include stack traces in production errors
- Verification: integration tests check response schemas

### C-SEC-4: Authentication required by default
- All endpoints MUST require authentication UNLESS explicitly
  marked as public in security.yaml
- Public endpoints: /api/v1/auth/register, /api/v1/auth/login,
  /api/v1/auth/confirm/{token}, /api/health
- Verification: security configuration audit, penetration test

## Performance Constraints

### C-PERF-1: Response time budget
- All API endpoints MUST respond within 200ms (p95)
- Database queries MUST complete within 50ms each
- No endpoint may make more than 5 database queries
- Verification: load testing with k6/wrk

### C-PERF-2: No N+1 queries
- MUST NOT perform queries inside loops
- All related data loaded via JOINs or batch queries
- Verification: Doctrine query counter in test environment

### C-PERF-3: Payload size limit
- API responses MUST NOT exceed 1MB
- List endpoints MUST use pagination (max 50 items per page)
- Verification: integration tests check Content-Length

## Code Quality Constraints

### C-CODE-1: No suppressed errors
- MUST NOT use @phpstan-ignore, @phpstan-ignore-next-line
- MUST NOT use error suppression operator (@)
- All type errors must be fixed, not suppressed
- Verification: grep for suppression patterns

### C-CODE-2: No magic numbers
- All numeric constants MUST be named (const or enum)
- Exception: 0, 1, -1 in obvious contexts
- Verification: code review checklist

### C-CODE-3: No service locator pattern
- MUST NOT use ContainerInterface::get() to fetch services
- All dependencies via constructor injection
- Verification: PHPStan rule, grep for "->get("

## Data Constraints

### C-DATA-1: No hard deletes
- MUST NOT DELETE user data (soft delete with deleted_at)
- Exception: temporary tokens (confirmation, password reset)
- Verification: migration review, grep for "DELETE FROM" without
  token/session tables

### C-DATA-2: No OFFSET pagination
- MUST NOT use OFFSET for pagination
- Use keyset (cursor-based) pagination
- Verification: grep for "->setFirstResult(", "OFFSET"

Промпт для AI

Implement the User API following these constraints (attached).

When generating code:
1. Check each constraint BEFORE writing code
2. After implementation, verify each constraint is satisfied
3. Add inline comments referencing constraint IDs
   where relevant (e.g., // C-SEC-1: using query builder)

If a constraint conflicts with a functional requirement,
flag it and ask for clarification.

Проверка constraints в CI

# .github/workflows/constraints.yml
name: Constraint Verification

on: [push, pull_request]

jobs:
  security-constraints:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # C-SEC-1: No raw SQL
      - name: Check for raw SQL
        run: |
          ! grep -rn "->query\s*(" src/ --include="*.php" | \
            grep -v "QueryBuilder"

      # C-CODE-1: No suppressed errors
      - name: Check for error suppression
        run: |
          ! grep -rn "@phpstan-ignore" src/ --include="*.php"
          ! grep -rn "^\s*@\$" src/ --include="*.php"

      # C-CODE-3: No service locator
      - name: Check for service locator
        run: |
          ! grep -rn "ContainerInterface" src/ --include="*.php" | \
            grep -v "CompilerPass"

      # C-DATA-2: No OFFSET pagination
      - name: Check for OFFSET pagination
        run: |
          ! grep -rn "setFirstResult\|OFFSET" src/ --include="*.php"

Преимущества Constraint Spec

Преимущество Описание
Безопасность Явные запреты предотвращают уязвимости
Автоматизация Constraints проверяемы в CI
Культура Команда знает, что запрещено
AI-контроль AI знает границы дозволенного

Выбор паттерна: матрица решений

Не все паттерны подходят для всех задач. Используйте эту матрицу для выбора.

Тип фичи Рекомендуемый паттерн Дополнительный паттерн
REST API эндпоинт API-First Constraint
Бизнес-логика (расчёты) Test-First Example-Driven
Сущность с жизненным циклом State Machine Contract
Финансовые операции Contract Constraint
Трансформация данных Example-Driven Test-First
Безопасность / compliance Constraint Contract
CRUD-операции API-First —
Интеграция с внешним API Contract API-First
Workflow / процессы State Machine Example-Driven
Валидация данных Test-First Constraint

Комбинирование паттернов

Для сложных фич используйте несколько паттернов одновременно:

# Feature: Order System

## API Contract (API-First)
→ OpenAPI spec for all order endpoints

## Order Lifecycle (State Machine)
→ States and transitions diagram

## Pricing Rules (Example-Driven)
→ Scenarios with expected calculations

## Security (Constraint)
→ What the system MUST NOT do

## Payment Processing (Contract)
→ Pre/post conditions for financial operations

Практический совет: Начните с одного паттерна -- того, который лучше всего подходит для главного аспекта фичи. Добавляйте другие паттерны по мере необходимости. Не нужно использовать все шесть для каждой задачи.


Итоги

Паттерны спецификаций -- это ваш набор инструментов для общения с AI. Каждый паттерн оптимизирован для определённого типа задач:

  1. API-First -- когда контракт взаимодействия важнее реализации
  2. Test-First -- когда поведение важнее структуры
  3. State Machine -- когда состояния и переходы определяют систему
  4. Contract -- когда корректность критична
  5. Example-Driven -- когда правила лучше понятны через примеры
  6. Constraint -- когда запреты важнее разрешений

Мастерство в SDD -- это умение быстро выбрать правильный паттерн и написать спецификацию, которая даст AI максимум информации при минимуме двусмысленности.