description: Delivers changes incrementally. Use when implementing any feature or change that touches more than one file. Use when you're about to write a large amount of code at once, or when a task feels too big to land in one step.
---
# Incremental Implementation
## Overview
Build in thin vertical slices — implement one piece, test it, verify it, then expand. Avoid implementing an entire feature in one pass. Each increment should leave the system in a working, testable state. This is the execution discipline that makes large features manageable.
## When to Use
- Implementing any multi-file change
- Building a new feature from a task breakdown
- Refactoring existing code
- Any time you're tempted to write more than ~100 lines before testing
**When NOT to use:** Single-file, single-function changes where the scope is already minimal.
## The Increment Cycle
```
┌──────────────────────────────────────┐
│ │
│ Implement ──→ Test ──→ Verify ──┐ │
│ ▲ │ │
│ └───── Commit ◄─────────────┘ │
│ │ │
│ ▼ │
│ Next slice │
│ │
└──────────────────────────────────────┘
```
For each slice:
1.**Implement** the smallest complete piece of functionality
2.**Test** — run the test suite (or write a test if none exists)
3.**Verify** — confirm the slice works as expected (tests pass, build succeeds, manual check)
4.**Commit** -- save your progress with a descriptive message (see `git-workflow-and-versioning` for atomic commit guidance)
5.**Move to the next slice** — carry forward, don't restart
## Slicing Strategies
### Vertical Slices (Preferred)
Build one complete path through the stack:
```
Slice 1: Create a task (DB + API + basic UI)
→ Tests pass, user can create a task via the UI
Slice 2: List tasks (query + API + UI)
→ Tests pass, user can see their tasks
Slice 3: Edit a task (update + API + UI)
→ Tests pass, user can modify tasks
Slice 4: Delete a task (delete + API + UI + confirmation)
→ Tests pass, full CRUD complete
```
Each slice delivers working end-to-end functionality.
### Contract-First Slicing
When backend and frontend need to develop in parallel:
```
Slice 0: Define the API contract (types, interfaces, OpenAPI spec)
Slice 1a: Implement backend against the contract + API tests
Slice 1b: Implement frontend against mock data matching the contract
Slice 2: Integrate and test end-to-end
```
### Risk-First Slicing
Tackle the riskiest or most uncertain piece first:
```
Slice 1: Prove the WebSocket connection works (highest risk)
Slice 2: Build real-time task updates on the proven connection
Slice 3: Add offline support and reconnection
```
If Slice 1 fails, you discover it before investing in Slices 2 and 3.
## Implementation Rules
### Rule 0: Simplicity First
Before writing any code, ask: "What is the simplest thing that could work?"
After writing code, review it against these checks:
- Are these abstractions earning their complexity?
- Would a staff engineer look at this and say "why didn't you just..."?
- Am I building for hypothetical future requirements, or the current task?
```
SIMPLICITY CHECK:
✗ Generic EventBus with middleware pipeline for one notification
✓ Simple function call
✗ Abstract factory pattern for two similar components
✓ Two straightforward components with shared utilities
✗ Config-driven form builder for three forms
✓ Three form components
```
Three similar lines of code is better than a premature abstraction. Implement the naive, obviously-correct version first. Optimize only after correctness is proven with tests.
This lets you merge small increments to the main branch without exposing incomplete work.
### Rule 4: Safe Defaults
New code should default to safe, conservative behavior:
```typescript
// Safe: disabled by default, opt-in
export function createTask(data: TaskInput, options?: { notify?: boolean }) {
const shouldNotify = options?.notify ?? false;
// ...
}
```
### Rule 5: Rollback-Friendly
Each increment should be independently revertable:
- Additive changes (new files, new functions) are easy to revert
- Modifications to existing code should be minimal and focused
- Database migrations should have corresponding rollback migrations
- Avoid deleting something in one commit and replacing it in the same commit — separate them
## Working with Agents
When directing an agent to implement incrementally:
```
"Let's implement Task 3 from the plan.
Start with just the database schema change and the API endpoint.
Don't touch the UI yet — we'll do that in the next increment.
After implementing, run `npm test` and `npm run build` to verify
nothing is broken."
```
Be explicit about what's in scope and what's NOT in scope for each increment.
## Increment Checklist
After each increment, verify:
- [ ] The change does one thing and does it completely
- [ ] All existing tests still pass (`npm test`)
- [ ] The build succeeds (`npm run build`)
- [ ] Type checking passes (`npx tsc --noEmit`)
- [ ] Linting passes (`npm run lint`)
- [ ] The new functionality works as expected
- [ ] The change is committed with a descriptive message
**Note:** Run each verification command after a change that could affect it. After a successful run, don't repeat the same command unless the code has changed since — re-running on unchanged code adds no information.
| "Let me run the build command again just to be sure" | After a successful run, repeating the same command adds nothing unless the code has changed since. Run it again after subsequent edits, not as reassurance. |
## Red Flags
- More than 100 lines of code written without running tests
- Multiple unrelated changes in a single increment
- "Let me just quickly add this too" scope expansion
- Skipping the test/verify step to move faster
- Build or tests broken between increments
- Large uncommitted changes accumulating
- Building abstractions before the third use case demands it
- Touching files outside the task scope "while I'm here"
- Creating new utility files for one-time operations
- Running the same build/test command twice in a row without any intervening code change
## Verification
After completing all increments for a task:
- [ ] Each increment was individually tested and committed