Effective Prompting for Code
Prompting Fundamentals for Code
The quality of AI-generated code directly depends on the quality of your prompts. This lesson teaches the foundational techniques that separate average results from excellent ones.
The Anatomy of a Good Prompt
┌─────────────────────────────────────────────────────────────┐
│ Effective Code Prompt │
├─────────────────────────────────────────────────────────────┤
│ 1. CONTEXT │
│ - What exists already? │
│ - What technologies are in use? │
│ │
│ 2. TASK │
│ - What do you want created/changed? │
│ - What's the expected behavior? │
│ │
│ 3. CONSTRAINTS │
│ - What must it work with? │
│ - What patterns to follow? │
│ │
│ 4. OUTPUT FORMAT (optional) │
│ - File structure? │
│ - Documentation style? │
└─────────────────────────────────────────────────────────────┘
The CRISPE Framework
A structured approach for code prompts:
| Component | Description | Example |
|---|---|---|
| Context | Project background | "This is a Next.js 14 app using Prisma" |
| Role | Who the AI should be | "Act as a senior backend developer" |
| Instructions | What to do | "Create a user authentication system" |
| Specifics | Technical details | "Use JWT, bcrypt, httpOnly cookies" |
| Patterns | Examples to follow | "Match the style in auth.service.ts" |
| Exclusions | What to avoid | "Don't use deprecated APIs" |
Good vs Bad Prompts
Example 1: Creating a Function
Bad:
Create a function to validate email
Good:
Create an email validation function:
- TypeScript, exported from src/utils/validation.ts
- Accept string, return boolean
- Handle edge cases: empty string, missing @, multiple @
- Include JSDoc comment
- Match the validation pattern used in src/utils/phone.ts
Example 2: Building a Component
Bad:
Make a login form
Good:
Create a LoginForm component for our Next.js app:
Requirements:
- Email and password fields with validation
- "Remember me" checkbox
- Submit button with loading state
- Error message display
- Use React Hook Form with Zod validation
- Follow the styling in src/components/forms/SignupForm.tsx
- Add accessibility attributes (aria-labels, etc.)
- Include TypeScript interfaces for props
Example 3: Refactoring
Bad:
Refactor this code to be better
Good:
Refactor src/services/payment.ts:
Goals:
- Extract Stripe logic into src/services/adapters/stripe.ts
- Create PaymentProvider interface for payment gateways
- Keep the same public API (no breaking changes)
- Add proper error handling with custom exceptions
- Maintain existing test coverage
The refactored code should allow adding PayPal in the future
without modifying the main payment service.
Context Is King
Providing Project Context
Method 1: Direct Description
This is a React 18 e-commerce app using:
- TypeScript strict mode
- Tailwind CSS for styling
- React Query for server state
- Zustand for client state
- Next.js 14 App Router
Method 2: Reference Files
Looking at the patterns in:
- @src/components/ProductCard.tsx
- @src/hooks/useProducts.ts
Create a similar component for displaying user profiles.
Method 3: Constraints
Must work with:
- Our existing auth middleware
- The User type from src/types/user.ts
- The API client in src/lib/api.ts
Specificity Levels
Match your specificity to task complexity:
Level 1: Quick Fixes
Fix the TypeScript error on line 42 of src/utils/format.ts
Level 2: Small Features
Add a "copy to clipboard" button to the CodeBlock component
that shows a checkmark for 2 seconds after copying.
Level 3: Medium Features
Implement pagination for the user list:
- Use cursor-based pagination
- Show 20 users per page
- Add "Load more" button
- Preserve scroll position
- Handle loading and error states
Level 4: Large Features
Create a notification system:
Database:
- Notification model with type, message, readAt, userId
- Relations to User model
API:
- GET /api/notifications (with pagination)
- PATCH /api/notifications/:id/read
- POST /api/notifications/read-all
Frontend:
- NotificationBell component with unread count
- NotificationDropdown with infinite scroll
- Mark as read on click
Real-time:
- WebSocket connection for new notifications
- Sound notification option
The Iteration Principle
Don't expect perfection on the first try:
Round 1: Generate initial code
↓
Round 2: "Add error handling for network failures"
↓
Round 3: "Make the loading state more user-friendly"
↓
Round 4: "Add unit tests for the main function"
↓
Done: Production-ready code
Common Mistakes
1. Being Too Vague
❌ "Make it work" ✅ "Handle the case where the user is not authenticated"
2. Assuming Context
❌ "Add it to the form" ✅ "Add the phone field to the UserProfileForm component in src/components/forms/"
3. Missing Constraints
❌ "Create an API endpoint" ✅ "Create an API endpoint following our existing pattern in src/app/api/users/route.ts"
4. Overloading Single Prompts
❌ "Build the entire authentication system with social login, email verification, password reset, and two-factor auth" ✅ Start with core auth, then iterate to add features
Templates for Common Tasks
Bug Fix Template
Bug: [What's happening]
Expected: [What should happen]
Location: [File and line if known]
Steps to reproduce: [How to trigger]
Related code: @[relevant file]
Feature Template
Feature: [Name]
User Story:
As a [user type], I want to [action] so that [benefit].
Technical Requirements:
- [Requirement 1]
- [Requirement 2]
Acceptance Criteria:
- [ ] [Criterion 1]
- [ ] [Criterion 2]
Patterns to follow: @[example file]
Prompting Truth: A well-crafted prompt takes 30 seconds but saves 10 minutes of iteration. Invest in your prompts.
In the next lesson, we'll explore advanced techniques like few-shot prompting and chain-of-thought. :::