Effective Prompting for Code

Advanced Prompting Techniques

5 min read

Beyond basics, these advanced techniques help you get better results from AI coding assistants on complex tasks.

Few-Shot Prompting

Show examples of what you want:

Pattern Matching

Here's how we handle API responses in this project:

Example 1:
```typescript
// src/api/users.ts
export async function getUsers(): Promise<ApiResponse<User[]>> {
  try {
    const response = await api.get('/users');
    return { data: response.data, error: null };
  } catch (error) {
    return { data: null, error: handleApiError(error) };
  }
}

Example 2:

// src/api/products.ts
export async function getProducts(): Promise<ApiResponse<Product[]>> {
  try {
    const response = await api.get('/products');
    return { data: response.data, error: null };
  } catch (error) {
    return { data: null, error: handleApiError(error) };
  }
}

Now create similar functions for:

  • getOrders()
  • getOrderById(id: string)
  • createOrder(data: CreateOrderInput)

### Code Style Examples

Our component tests follow this pattern:

describe('Button', () => {
  it('renders with default props', () => {
    render(<Button>Click me</Button>);
    expect(screen.getByRole('button')).toHaveTextContent('Click me');
  });

  it('handles click events', async () => {
    const handleClick = jest.fn();
    render(<Button onClick={handleClick}>Click me</Button>);
    await userEvent.click(screen.getByRole('button'));
    expect(handleClick).toHaveBeenCalledTimes(1);
  });
});

Write tests for the Modal component following this exact pattern.


## Chain-of-Thought Prompting

Ask the AI to think step by step:

### For Algorithm Design

Design a rate limiter. Think step by step:

  1. First, explain what data structure would be most efficient
  2. Then, describe the algorithm logic
  3. Consider edge cases (distributed systems, time zone issues)
  4. Finally, write the implementation

Show your reasoning at each step.


### For Debugging

This function has a bug. Debug it step by step:

  1. First, read the code and explain what it's supposed to do
  2. Trace through the execution with example input
  3. Identify where the logic fails
  4. Explain the fix
  5. Implement the corrected version
function findDuplicates(arr: number[]): number[] {
  const seen = new Set();
  return arr.filter(item => {
    if (seen.has(item)) return true;
    seen.add(item);
  });
}

### For Architecture Decisions

I need to implement real-time notifications. Think through:

  1. What are the options? (WebSockets, SSE, polling)
  2. What are the trade-offs of each?
  3. Given we're using Next.js on Vercel, which makes most sense?
  4. What's the implementation plan?

Walk me through your reasoning before writing any code.


## Constraint Specification

Be explicit about constraints:

### Performance Constraints

Create a search function with these constraints:

  • Must handle 100,000+ items
  • Response time < 100ms
  • Memory usage < 50MB
  • Works on mobile browsers

Consider using:

  • Binary search if sorted
  • Index/cache for repeated searches
  • Web Workers for heavy computation

### Compatibility Constraints

Create a date picker component:

  • Must work with React 17 and 18
  • No external dependencies except date-fns
  • Support keyboard navigation (a11y)
  • Work in all browsers including Safari 14+
  • Support both controlled and uncontrolled usage

### Style Constraints

Generate code matching these style rules:

  • 2 space indentation
  • Single quotes for strings
  • No semicolons
  • Prefer const over let
  • Use arrow functions for callbacks
  • Named exports, no default exports

## Negative Prompting

Tell the AI what NOT to do:

Create a user authentication system.

DO NOT:

  • Use deprecated crypto APIs
  • Store passwords in plain text
  • Use synchronous bcrypt functions
  • Create custom JWT implementation (use jose library)
  • Add console.logs in production code
  • Use any as TypeScript type

DO:

  • Use bcrypt with cost factor 12
  • Implement proper CSRF protection
  • Add rate limiting on auth endpoints
  • Follow OWASP authentication guidelines

## Role-Based Prompting

Assign a specific role:

### Expert Role

You are a senior security engineer at a FAANG company.

Review this authentication code for security vulnerabilities. Think like an attacker trying to find exploits. Prioritize findings by severity (Critical/High/Medium/Low).

[code to review]

### Teacher Role

You are a patient coding mentor teaching a junior developer.

Explain how this React hook works, line by line. Use simple analogies when explaining complex concepts. After explaining, suggest improvements they could make.

[code to explain]

### Reviewer Role

You are a code reviewer at a company with strict quality standards.

Review this PR for:

  • Logic errors
  • Performance issues
  • Security concerns
  • Code style violations
  • Missing tests
  • Documentation gaps

Be constructive but thorough. Suggest specific fixes.


## Iterative Refinement Patterns

### The Funnel Pattern

Start broad, then narrow down:

Round 1: "Create a form handling utility" ↓ Round 2: "Add validation support with Zod schemas" ↓ Round 3: "Add support for async validation (API checks)" ↓ Round 4: "Add form state persistence to localStorage"


### The Layer Pattern

Build in layers:

Layer 1: Data Layer "Create TypeScript interfaces for the blog system"

Layer 2: API Layer "Create API routes for these interfaces"

Layer 3: Service Layer "Create service functions that call these APIs"

Layer 4: UI Layer "Create React components using these services"


### The Test-First Pattern

Step 1: "Write test cases for a URL validation utility" Step 2: "Now implement the utility to pass all tests" Step 3: "Add edge case tests for international URLs" Step 4: "Update implementation to pass new tests"


## Context Injection Techniques

### Using @-mentions Effectively

Looking at:

  • @src/types/user.ts (for type definitions)
  • @src/services/auth.ts (for existing patterns)
  • @src/utils/validation.ts (for validation helpers)

Create a user profile update service that:

  • Accepts partial user updates
  • Validates email uniqueness
  • Handles avatar upload
  • Follows the same patterns as the referenced files

### Embedding Documentation

According to the Prisma documentation for transactions:

await prisma.$transaction([ prisma.user.create({ data: userData }), prisma.account.create({ data: accountData }), ])

Implement an atomic user registration that creates both a User and their initial Organization in a single transaction.


## Prompt Templates Library

### API Endpoint Template

Create a [METHOD] endpoint at /api/[path]:

Input: [describe input schema] Output: [describe output schema] Auth: [auth requirements] Validation: [validation rules]

Error cases:

  • [case 1]: Return [status] with [message]
  • [case 2]: Return [status] with [message]

Follow the pattern in @src/app/api/[existing-endpoint]/route.ts


### Component Template

Create a [ComponentName] component:

Props:

  • [prop1]: [type] - [description]
  • [prop2]: [type] - [description]

Behavior:

  • [behavior 1]
  • [behavior 2]

States:

  • Loading: [how it looks]
  • Error: [how it handles errors]
  • Empty: [empty state display]

Style: Match @src/components/[SimilarComponent].tsx Tests: Include unit tests following our testing patterns


> **Advanced Insight:** The best prompts combine multiple techniques. Use few-shot for style, chain-of-thought for logic, constraints for quality, and negative prompting for safety.

In the next lesson, we'll build your personal prompt library for common scenarios.
:::

Quiz

Module 4: Effective Prompting for Code

Take Quiz