Plan-First Development
Break complex projects into detailed multi-phase plans before writing any code. Prevents scope creep, refactoring waste, and missed requirements.
When to use
- Starting any project with >1000 lines of code
- Building systems with multiple interacting components
- Performance-critical applications (HFT, real-time, embedded)
- Projects where requirements are complex but knowable upfront
- When multiple developers need coordination
When NOT to use
- Exploratory prototypes where requirements are unknown
- Trivial scripts (<100 lines)
- Already well-understood patterns (CRUD apps)
- Research projects where discovery is the goal
Instructions
Step 1: Define Project Scope
Create a project overview document with:
# [Project Name] - Implementation Plan
## Overview
[2-3 sentence description]
## Core Constraints
- ❌ [What we CANNOT use/do]
- ✅ [What we MUST use/do]
## Success Criteria
- [ ] [Measurable outcome 1]
- [ ] [Measurable outcome 2]
- [ ] [Performance target, if applicable]
Step 2: Break Into Phases
Divide project into 5-10 sequential phases. Each phase should:
- Build on previous phases (dependencies clear)
- Have concrete deliverable (working code + tests)
- Take 1-4 hours to complete
- Be independently testable
Template:
### Phase N: [Component Name]
**Objective**: [What are we building?]
**Files to create:**
- `path/to/file1.ext` - [Purpose]
- `path/to/file2.ext` - [Purpose]
**Key implementation details:**
- [Technical decision 1 with rationale]
- [Technical decision 2 with rationale]
**Dependencies:**
- Requires Phase [X] to be complete
- Provides [Y] for Phase [Z]
**Testing strategy:**
- Unit tests: [What to test]
- Integration tests: [If applicable]
- Performance validation: [Targets]
**Success criteria:**
- [ ] [Specific measurable outcome]
- [ ] [Tests passing]
- [ ] [Performance target met]
Step 3: Specify Data Structures
For each major type/struct/class:
**[StructName]** (`src/module.rs`):
```[language]
struct/class definition with comments
Key implementation details:
- Size: [X] bytes (if fixed)
- Alignment: [Y] bytes
- Memory: [Stack/Heap]
- Special properties: [Copy, Send, Sync, etc.]
Compile-time assertions:
// Size verification
// Alignment verification
### Step 4: Define Critical Paths
Identify hot paths (performance-critical code):
```markdown
## Critical Performance Paths
**Path 1: [Operation Name]**
- Entry point: `function_name()`
- Steps:
1. [Operation 1] - Target: <X ns/µs/ms
2. [Operation 2] - Target: <Y ns/µs/ms
- Total target: <Z ns/µs/ms
- Memory access pattern: [Sequential/Random/...]
- Constraints: [No heap allocation, No locks, etc.]
Step 5: Create Verification Checklist
End plan with measurable validation:
## Verification Checklist
### Correctness
- [ ] All unit tests passing (target: X tests)
- [ ] Property tests verify invariants
- [ ] Concurrency tests pass (if applicable)
### Performance
- [ ] Operation A: <X ns/µs (measured)
- [ ] Operation B: <Y ns/µs (measured)
- [ ] Throughput: >Z ops/sec (sustained)
### Code Quality
- [ ] No heap allocations on hot path (verified with profiler)
- [ ] Zero unsafe warnings
- [ ] Documentation complete
### Platform Support
- [ ] Builds on [Platform 1]
- [ ] Tests pass on [Platform 2]
Step 6: Get Approval & Execute
- Review plan - Share with team/stakeholders
- Refine - Adjust based on feedback
- Lock & Execute - No major scope changes during implementation
- Validate per phase - Check success criteria after each phase
Examples
Example 1: Planning a Lock-Free Queue
Good plan structure:
## Phase 1: Core Types
- `src/types.rs` - Element wrapper (32 bytes, repr(C))
- Compile-time size assertions
- Zero-copy serialization
- Tests: size, alignment, serialization round-trip
## Phase 2: SPSC Ring Buffer
- `src/ring.rs` - Single-producer, single-consumer queue
- Cache-line padded atomics (64 bytes)
- Power-of-two size for fast modulo
- Release/Acquire memory ordering
- Tests: push/pop, wrap-around, FIFO order, concurrent access (Loom)
- Target: <50ns per push+pop
## Phase 3: Benchmarking
- `benches/ring_bench.rs` - Criterion benchmarks
- Measure P50, P99, P99.9 latency
- Validate <50ns target met
Why this works:
- Phase 1 validates data layout before building on it
- Phase 2 completes core algorithm with tests
- Phase 3 verifies performance before adding features
Example 2: Planning a REST API
## Phase 1: Database Schema
- migrations/001_users.sql
- migrations/002_posts.sql
- Seed data for testing
- Tests: schema validation, constraints
## Phase 2: Repository Layer
- src/repositories/user.rs
- src/repositories/post.rs
- CRUD operations
- Tests: all operations, error cases
## Phase 3: Service Layer
- src/services/auth.rs (JWT)
- src/services/posts.rs (business logic)
- Tests: authorization, validation
## Phase 4: HTTP Handlers
- src/handlers/auth.rs
- src/handlers/posts.rs
- Tests: integration tests, E2E
## Phase 5: Performance & Security
- Benchmarks: target <10ms P99
- Security audit: SQL injection, XSS, CSRF
- Load test: 1000 req/sec sustained
Best Practices
✅ Do
- Write plan in markdown - Easy to read, version control, share
- Include "why" not just "what" - Document rationale for decisions
- Set measurable targets - "Fast" → "<50ns P99 latency"
- Phase dependencies clear - Use arrows/diagrams
- Test strategy per phase - Don't leave testing to end
- Review before coding - 30 min planning saves hours debugging
❌ Don't
- Don't plan implementation details - Plan structure, not every function
- Don't skip performance targets - You'll optimize wrong things later
- Don't make phases too large - Max 4 hours each
- Don't change plan mid-execution - Finish phase, then reassess
- Don't skip validation checklist - How will you know you're done?
Common Pitfalls
Pitfall 1: "I'll figure it out as I go"
Problem: Leads to refactoring entire codebase when you discover architectural mismatch
Solution: Spend 10-15% of project time on planning upfront
Pitfall 2: Too much detail
Problem: Planning every function becomes maintenance burden
Solution: Plan modules/components, not individual functions
Pitfall 3: Ignoring dependencies
Problem: Build Phase 5 before Phase 2, realize Phase 2 API doesn't work
Solution: Draw dependency graph, execute in topological order
Pitfall 4: No performance targets
Problem: Build entire system, discover it's 10x too slow, no idea where bottleneck is
Solution: Set targets per phase, measure immediately
Integration with Development Tools
With GitHub Projects
- Create one issue per phase
- Label:
phase-1,phase-2, etc. - Each issue has checklist from success criteria
With Git
# Branch per phase
git checkout -b phase-1-core-types
# ... implement & test ...
git checkout main
git merge phase-1-core-types
git checkout -b phase-2-ring-buffer
# ... etc
With CI/CD
- Run tests after each phase merge
- Benchmark comparisons in PR comments
- Block merge if phase success criteria not met
Measuring Success
Indicators plan worked:
- ✅ Few/no major refactorings during implementation
- ✅ All tests written concurrently with code
- ✅ Performance targets met in final product
- ✅ Schedule variance <20% (planned vs actual time)
- ✅ Team members understand architecture
Indicators plan failed:
- ❌ Constant "back to the drawing board" moments
- ❌ Tests written as afterthought
- ❌ Performance surprises at end
- ❌ Schedule blown (2x+ planned time)
- ❌ Confusion about component responsibilities
Related skills
- incremental-validation - Test after each phase
- parallel-subagent-orchestration - Execute validation in parallel
- documentation-while-fresh - Document decisions in plan
Skill Version: 1.0 Last Updated: 2025-01-06
