Backend Development Principles
Principles for production-quality Python backend development with AI assistance.
Core Philosophy
Willison's Golden Rule: Never commit AI-generated code you cannot fully explain. If you can't articulate what every line does and why, don't ship it.
Spec-Driven Development: Before writing code, generate a spec.md with requirements, architecture decisions, and constraints. The spec guides implementation; implementation validates the spec.
Architecture First, Code Second: AI generates code for patterns you specify—it cannot reason about production trade-offs. You provide the architectural judgment; AI provides velocity.
System Design Principles
Distributed Systems
- •Specify consistency requirements (strong, eventual, causal) before implementing data flows
- •Design for failure: circuit breakers, retries with exponential backoff and jitter, graceful degradation
- •Prefer idempotent operations—repeated calls produce the same result
- •Document CAP theorem trade-offs explicitly
Service Architecture
- •Start monolith, extract services only when team/scaling boundaries demand it
- •Service boundaries follow domain boundaries, not technical layers
- •Each service owns its data—no shared databases between services
- •Design APIs for backward compatibility from day one
Data Patterns
- •Separate read and write models when query patterns diverge (CQRS)
- •Event sourcing for audit requirements or complex state reconstruction
- •Define cache invalidation strategy before implementing caching
- •Database choice follows access patterns, not familiarity
Python/FastAPI Standards
Project Structure
src/ ├── api/v1/ # Thin route handlers ├── core/ # Config, security, dependencies ├── domain/ # Business logic, domain models ├── infrastructure/ # Database, external services ├── schemas/ # Pydantic API contracts └── tests/
Code Patterns
- •Route handlers are thin: validate → call domain → return response
- •Dependency injection for sessions, auth, shared resources
- •Pydantic models for ALL API boundaries
- •Async for I/O-bound, sync for CPU-bound
- •Background tasks for non-immediate operations
Type Safety
- •Enable
strictmode in pyproject.toml - •Type hints on ALL function signatures
- •
TypedDictfor complex dictionary structures - •Prefer dataclasses/Pydantic over raw dicts
Error Handling
- •Custom exceptions mapping to HTTP status codes
- •Centralized exception handler middleware
- •Never expose internal errors to consumers
- •Structured responses:
{"error": {"code": "...", "message": "...", "details": {...}}}
Testing Strategy
Target: 80%+ coverage on domain logic, 60%+ overall.
# Single file (fast iteration) pytest tests/unit/test_user_service.py -v # With coverage pytest tests/unit/test_user_service.py --cov=src/domain/user -v
For detailed testing patterns, see references/testing.md.
API Design
For comprehensive REST conventions, response standards, and versioning, see references/api-design.md.
Security Principles
Secure by Design: Security is integrated from the start, not bolted on. Document threat models during planning. Every design decision considers attack surface.
Least Privilege: Users and workflows get exactly the minimum permissions required—nothing more. Privilege escalation requires explicit auditing.
Defense in Depth: Multiple layers of security controls. No single point of failure in security architecture.
For detailed security patterns, input validation, file handling, and error handling, see references/security.md.
Do NOT
- •Do NOT use
*imports - •Do NOT put business logic in route handlers
- •Do NOT use
Anytype without justification - •Do NOT commit commented-out code
- •Do NOT use raw SQL strings
- •Do NOT hardcode configuration
- •Do NOT skip migrations
- •Do NOT catch generic
Exceptionwithout re-raising or logging
AI Workflow Integration
Before Prompting
- •Write spec.md with requirements and constraints
- •Define data model and API contract
- •Identify applicable architectural patterns
- •List explicit constraints (versions, existing patterns)
Prompt Structure
Context: [system purpose, tech stack, constraints] Task: [specific deliverable] Patterns: [reference existing code or patterns] Constraints: [what NOT to do, versions] Output: [expected format]
After Generation
- •Verify against spec.md
- •Check type hints are complete
- •Ensure error handling follows patterns
- •Run single-file tests first
- •Explain every line before committing
Anti-Patterns to Reject
| Pattern | Problem | Correction |
|---|---|---|
| God service | Single class doing everything | Decompose by responsibility |
| Anemic domain | Logic scattered in handlers | Encapsulate in domain objects |
| Shotgun surgery | One change requires many files | Consolidate related logic |
| N+1 queries | Loop that queries per item | Use joins or eager loading |
| Primitive obsession | Raw strings for domain concepts | Create value objects |
Reference Implementations
When generating code, follow patterns from:
- •FastAPI Full-Stack Template:
github.com/fastapi/full-stack-fastapi-template - •FastAPI Best Practices:
github.com/zhanymkanov/fastapi-best-practices - •Amazon Builders' Library for distributed systems patterns