- Learn
- Development Workflows
- Code Generation Workflows
Master effective workflows for generating high-quality code with AI—from single functions to complex features.
Code Generation Workflows
Code generation is where AI shines, but the quality of output depends heavily on your workflow. This lesson covers proven patterns for generating code that works correctly the first time.
The Staged Generation Approach
Don't generate everything at once. Use stages:
Stage 1: Types/Interfaces
Stage 2: Core Logic
Stage 3: Integration
Stage 4: Error Handling
Stage 5: Tests
Each stage builds on the previous, with review between stages.
Stage 1: Types First
Always start with types and interfaces. They serve as contracts for the rest of the code.
Define TypeScript interfaces for a shopping cart feature.
Requirements:
- Cart contains items with product, quantity, and price
- Support for discount codes
- Track subtotal, tax, and total
- Handle multiple shipping addresses
Output:
1. All necessary interfaces
2. Type unions for states (empty, has-items, checked-out)
3. Utility types if needed
Result:
interface CartItem {
productId: string;
name: string;
quantity: number;
unitPrice: number;
totalPrice: number;
}
interface DiscountCode {
code: string;
type: 'percentage' | 'fixed';
value: number;
}
interface CartTotals {
subtotal: number;
discount: number;
tax: number;
shipping: number;
total: number;
}
type CartState =
| { status: 'empty' }
| { status: 'has-items'; items: CartItem[]; totals: CartTotals }
| { status: 'checked-out'; orderId: string };
Stage 2: Core Logic
With types defined, generate the core business logic:
Using these types:
[paste types from Stage 1]
Generate the cart calculation functions:
1. calculateItemTotal(item: CartItem): number
2. calculateSubtotal(items: CartItem[]): number
3. applyDiscount(subtotal: number, discount: DiscountCode): number
4. calculateTax(amount: number, taxRate: number): number
5. calculateCartTotals(items: CartItem[], discount?: DiscountCode): CartTotals
Requirements:
- Pure functions, no side effects
- Handle edge cases (empty cart, invalid discount)
- Round to 2 decimal places
Stage 3: Integration Layer
Connect the pure logic to your application:
Using these types and functions:
[paste types and functions]
Create a React hook useCart that:
- Manages cart state
- Provides addItem, removeItem, updateQuantity
- Applies discount codes
- Persists to localStorage
- Syncs with server on changes
Use this pattern from our codebase:
[paste example hook]
Stage 4: Error Handling
Add comprehensive error handling:
Add error handling to this cart implementation:
[paste code]
Handle:
- Network failures when syncing
- Invalid quantities (negative, non-integer)
- Out-of-stock items
- Expired discount codes
- Concurrent modification conflicts
Use our error handling pattern:
- Custom error classes
- User-friendly error messages
- Error recovery where possible
Stage 5: Tests
Generate tests for each layer:
Generate tests for the cart calculation functions:
[paste functions]
Include:
- Happy path tests
- Edge cases (empty arrays, zero values)
- Error conditions
- Boundary values (max quantities, min prices)
Use Jest with our test patterns:
[paste example test]
The Skeleton Approach
For complex features, generate a skeleton first:
Step 1: Request Skeleton
Create a skeleton for a REST API file upload service.
Include:
- Express router structure
- Endpoint stubs (no implementation)
- Middleware placeholders
- Error handling structure
- Type definitions
Don't implement the actual logic yet—just the structure.
Step 2: Fill In One Section
Here's the skeleton:
[paste skeleton]
Now implement only the upload endpoint with:
- Multer for file handling
- File validation (size, type)
- Storage to local filesystem
- Return file metadata on success
Step 3: Continue Section by Section
Now implement the download endpoint using the same patterns.
[continue for each section]
Pattern-Based Generation
Leverage existing patterns in your codebase:
Example prompt:
Here's an existing component that follows our patterns:
// ExistingComponent.tsx
export const UserCard: FC<UserCardProps> = ({ user, onEdit }) => {
// ... implementation
};
Generate a similar component for products:
- Same styling approach
- Same prop patterns
- Same state management approach
Product-specific requirements:
- Show image, name, price
- Add to cart button
- Quantity selector
Incremental Enhancement
Build up complexity gradually:
Version 1: Basic
Create a basic search input that:
- Accepts user input
- Calls onSearch prop with value
- Basic styling
Version 2: Add Features
Enhance this search input:
[paste v1 code]
Add:
- Debouncing (300ms)
- Loading indicator
- Clear button
Version 3: Polish
Finalize this search input:
[paste v2 code]
Add:
- Keyboard shortcuts (Escape to clear)
- Accessibility (ARIA labels)
- Focus styles
- Placeholder text customization
Context-Rich Generation
Provide rich context for better results:
Example prompt:
Generate a data fetching hook for user profiles.
Project Context:
- React 18 with TypeScript
- React Query for data fetching
- Zod for validation
- API returns:
{ user: User, permissions: string[] }
Existing Pattern to follow:
// How we structure hooks
export const useUsers = (filters: UserFilters) => {
return useQuery({
queryKey: ['users', filters],
queryFn: () => api.getUsers(filters),
select: (data) => data.users,
});
};
Requirements:
- Fetch profile by userId
- Include error handling
- Support refetching
- Return loading/error states
Handling Large Features
Chunk the Work
I need to build a complete comment system.
Instead of generating everything, let's chunk it:
Chunk 1: Database schema and Prisma models
Chunk 2: API endpoints (CRUD)
Chunk 3: React components (list, form, item)
Chunk 4: Real-time updates (WebSocket)
Let's start with Chunk 1. Generate the Prisma schema for comments:
- Supports nested replies (2 levels max)
- Author relationship
- Soft delete
- Timestamps
Track Dependencies
We've completed:
- [x] Prisma schema (generates Comment, Reply)
- [x] API endpoints (GET, POST, DELETE)
Now generate Chunk 3: React components.
These components should use:
- The types generated from Prisma
- The API endpoints we created
- Our existing component patterns
Generate:
1. CommentList - displays all comments
2. CommentForm - new comment form
3. CommentItem - single comment display
4. ReplyForm - reply to comment form
Quality Checks
After generating code, always verify:
Type Safety Check
Review this generated code for type safety:
[paste code]
Check for:
- Any use of 'any' type
- Missing type annotations
- Possible null/undefined issues
- Type assertions that could fail
Pattern Consistency Check
Does this code follow our project patterns?
Our patterns:
- Error handling: [pattern]
- Naming: [conventions]
- File structure: [structure]
Generated code:
[paste code]
What deviates from our patterns?
Security Check
Review this generated code for security:
[paste code]
Check for:
- Input validation gaps
- Injection vulnerabilities
- Authentication/authorization issues
- Data exposure risks
Common Generation Pitfalls
1. Generating Without Context
Always provide project context and existing patterns.
2. Accepting Code Blindly
Review and test before integrating.
3. Overriding Good Code
Don't regenerate working code—enhance it.
4. Generating Too Much
Generate in stages, not all at once.
Practice Exercise
Generate a feature using the staged approach:
Feature: Email notification preferences
- Stage 1: Define types for notification settings
- Stage 2: Create validation functions
- Stage 3: Build the settings form component
- Stage 4: Add error handling and loading states
- Stage 5: Generate tests
Document your prompts and review after each stage.
Summary
- Use staged generation: types → logic → integration → errors → tests
- Generate skeletons first for complex features
- Provide rich context and existing patterns
- Chunk large features into manageable pieces
- Always verify generated code before using
Next Steps
Next, let's explore Test-Driven Development with AI—using tests to guide code generation.