AI pair programming is a collaborative workflow where a human developer and a machine intelligence system work side-by-side in real time, with the AI acting as a co-author, reviewer, and problem-solver. This pattern matters when a team needs to accelerate feature delivery, reduce cognitive load, or maintain code quality across a growing codebase—especially during onboarding, refactoring, or complex bug fixing. It is most effective when the AI is context-aware, can reason across multiple files, and responds to natural language prompts with code, edits, or suggestions.

Writing a New Function from a Specification

When a developer is tasked with implementing a function based on a natural language description, the AI pair becomes a proactive assistant that interprets intent, suggests structure, and validates correctness. The process begins with a prompt that includes the function signature, input types, and expected behavior.

Write a function that takes a list of user IDs and returns a dictionary mapping each user ID to their most recent activity, where activity is defined as a timestamped event with a type and description.

The function should:
- Use a database query to fetch all events for the given users.
- Prioritize events by timestamp, with newer events taking precedence.
- Return a dictionary with the user ID as the key and a single event object as the value.
- Handle missing users by including them with a null or default event.

The AI responds with a complete implementation, often using a familiar language and framework. It may also include a test case and a brief explanation.

def get_recent_user_activities(user_ids: list[str]) -> dict[str, dict]:
    """
    Fetch the most recent activity for each user in the provided list.
    
    Args:
        user_ids: List of user identifiers to fetch activities for.

    Returns:
        Dictionary mapping each user ID to their most recent activity.
        If a user has no activities, returns a default event.
    """
    # Build a query to fetch all events for the given users, ordered by timestamp descending
    query = """
        SELECT u.id, e.type, e.description, e.timestamp
        FROM users u
        LEFT JOIN events e ON u.id = e.user_id
        WHERE u.id = ANY($1)
        ORDER BY e.timestamp DESC
    """
    
    # Execute query and gather results
    results = db.query(query, user_ids)
    
    # Build result dictionary
    recent_activities = {}
    for row in results:
        user_id = row['id']
        # Only store the first (most recent) event per user
        if user_id not in recent_activities:
            recent_activities[user_id] = {
                'type': row['type'],
                'description': row['description'],
                'timestamp': row['timestamp']
            }
    
    # Add users with no activities
    for user_id in user_ids:
        if user_id not in recent_activities:
            recent_activities[user_id] = {
                'type': 'default',
                'description': 'No activities found',
                'timestamp': None
            }
    
    return recent_activities

The developer reviews the AI’s output, often refining the prompt with follow-up questions such as: “Use SQLAlchemy instead of raw SQL,” or “Add type hints for the returned event object.”

Refactoring an Existing Module

When refactoring a codebase—especially a legacy module—the AI pair helps identify patterns, suggest improvements, and apply changes across multiple files. The developer starts by selecting a module and asking the AI to analyze its structure and propose refactorings.

Analyze the `inventory` module for code smells, performance issues, and opportunities for improvement. Suggest 3 major refactorings, with a focus on reducing duplication and improving testability.

The AI returns a structured report with recommendations, each including a description, rationale, and code changes.

Suggestion 1: Extract InventoryService class from inventory/utils.py

> The current module contains utility functions like add_item, remove_item, and get_item_status that are tightly coupled with database access and business logic. These functions operate on raw data and lack cohesion. > > Proposed change: Create a InventoryService class that encapsulates all inventory operations, with dependency injection for the database connection. > > Impact: Reduces code duplication in other modules, enables easier testing via mocking, and provides a clear API for inventory operations.

The AI then generates a patch for the refactoring:

diff --git a/inventory/utils.py b/inventory/utils.py
index abc123..def456 100644
--- a/inventory/utils.py
+++ b/inventory/utils.py
@@ -1,4 +1,4 @@
-from database import get_connection
+from database import DatabaseConnection
 from models import Item, StockRecord
-from typing import List, Dict, Optional
+from typing import List, Dict, Optional, Callable
 from datetime import datetime
-import logging
+import logging
+from contextlib import contextmanager
+
+class InventoryService:
+    def __init__(self, db_connection: DatabaseConnection):
+        self.db = db_connection
+        self.logger = logging.getLogger(__name__)
+
+    def add_item(self, item: Item) -> bool:
+        query = "INSERT INTO items (name, sku, quantity) VALUES ($1, $2, $3)"
+        result = self.db.execute(query, item.name, item.sku, item.quantity)
+        self.logger.info(f"Added item {item.sku}")
+        return result
+
+    def remove_item(self, sku: str) -> bool:
+        query = "DELETE FROM items WHERE sku = $1"
+        result = self.db.execute(query, sku)
+        self.logger.info(f"Removed item {sku}")
+        return result
+
+    def get_item_status(self, sku: str) -> Dict[str, Optional[str]]:
+        query = """
+            SELECT i.name, i.quantity, s.status
+            FROM items i
+            LEFT JOIN stock_records s ON i.sku = s.sku
+            WHERE i.sku = $1
+        """
+        result = self.db.query_one(query, sku)
+        return {
+            'name': result['name'],
+            'quantity': result['quantity'],
+            'status': result['status']
+        }
+
+    def bulk_update_stock(self, updates: List[Dict]) -> int:
+        # Implementation
+        pass
+
+    def with_transaction(self, func: Callable) -> Callable:
+        @contextmanager
+        def wrapper(*args, **kwargs):
+            with self.db.transaction():
+                return func(*args, **kwargs)
+        return wrapper

The developer applies the patch and validates it. The AI then suggests additional changes: “Add tests for InventoryService using pytest and unittest.mock,” and generates a test file.

Debugging a Production Crash

When an error appears in production logs, the AI pair assists in isolating and resolving the issue. The developer copies the error trace, including stack trace, environment details, and request payloads.

Error: 500 Internal Server Error
Timestamp: 2024-01-08T12:34:56Z
Service: order-processing
Environment: production
Stack trace:
  File "/app/order_processing/handlers.py", line 142, in create_order
    order = create_order_from_payload(payload)
  File "/app/order_processing/models.py", line 78, in create_order_from_payload
    line_items = [create_line_item(item) for item in payload['line_items']]
  File "/app/order_processing/models.py", line 76, in create_line_item
    return LineItem(
    TypeError: __init__() missing 1 required positional argument: 'price'

The AI responds with a diagnosis: “The LineItem class is missing a price field in its constructor. The payload sent to /orders includes a price field in the line items, but the model expects price as a required argument.”

It generates a patch and a test case.

diff --git a/order_processing/models.py b/order_processing/models.py
index 789abc..456def 100644
--- a/order_processing/models.py
+++ b/order_processing/models.py
@@ -73,7 +73,7 @@ class LineItem:
     def __init__(self, name: str, sku: str, quantity: int, category: str):
         self.name = name
         self.sku = sku
         self.quantity = quantity
-        self.category = category
+        self.category = category
+        self.price = None  # Add missing field
+
+    @classmethod
+    def from_dict(cls, data: dict) -> 'LineItem':
+        return cls(
+            name=data['name'],
+            sku=data['sku'],
+            quantity=data['quantity'],
+            category=data['category'],
+            price=data.get('price')  # Populate price from input
+        )

The AI also suggests adding a validation step before creating the order.

def validate_line_items(line_items: list[dict]) -> bool:
    """Ensure each line item has required fields."""
    required_fields = {'name', 'sku', 'quantity', 'price'}
    for i, item in enumerate(line_items):
        missing = required_fields - set(item.keys())
        if missing:
            logging.warning(f"Line item {i} missing fields: {missing}")
            return False
    return True

The developer adds this function and enhances the create_order_from_payload function to call it.

Responding to Code Review

When a pull request is submitted, the AI pair helps the reviewer by generating detailed feedback. The developer provides the diff and a list of review goals.

Review the following PR: Add cart checkout feature
Goals:
- Check for consistency in error handling
- Ensure all endpoints are documented in OpenAPI format
- Verify that the checkout process handles concurrent updates
- Suggest improvements for test coverage

The AI returns structured feedback, including inline comments and a summary.

Summary

  • Error Handling: Use consistent error codes and messages across endpoints.
  • OpenAPI Documentation: Add description, example, and schema fields to all endpoints.
  • Concurrency: Add optimistic locking to the checkout endpoint.
  • Test Coverage: Add a test for partial checkout with multiple concurrent requests.

Inline Comments

[CR] src/api/checkout.py:45
> def checkout(cart_id: int) -> dict:
    """Process a cart checkout."""
    cart = get_cart(cart_id)
    if not cart:
        return {"error": "Cart not found", "code": 404}

    # Update cart status and apply discounts
    cart.status = "processing"
    cart.total = calculate_total(cart)
    cart.updated_at = datetime.now()

    # Save changes
    db.execute("UPDATE carts SET status = $1, total = $2, updated_at = $3 WHERE id = $4",
               cart.status, cart.total, cart.updated_at, cart_id)

    return {"status": "success", "order_id": 12345}

Comment: The checkout function returns a hardcoded order_id, but the order_id should be generated from the database. Also, the function does not handle concurrent updates. Add a version field to carts and use optimistic locking.

The AI generates a patch to fix these issues.

diff --git a/src/api/checkout.py b/src/api/checkout.py
index 123abc..456def 100644
--- a/src/api/checkout.py
+++ b/src/api/checkout.py
@@ -1,5 +1,5 @@
 from database import db
 from models import Cart, Order
-from datetime import datetime
+from datetime import datetime
+from contextlib import contextmanager
 from typing import Dict, Optional
+
+class ConcurrencyError(Exception):
+    """Raised when a concurrent update fails due to version mismatch."""
+
+def checkout(cart_id: int) -> Dict[str, Optional[int]]:
+    """Process a cart checkout with optimistic locking."""
+    with db.transaction():
+        cart = db.query_one(
+            "SELECT * FROM carts WHERE id = $1 FOR UPDATE",
+            cart_id
+        )
+        if not cart:
+            return {"error": "Cart not found", "code": 404}
+
+        # Check if cart has been modified by another process
+        if cart['version'] != cart['expected_version']:
+            raise ConcurrencyError("Cart was modified by another process")
+
+        # Apply changes
+        cart.status = "processing"
+        cart.total = calculate_total(cart)
+        cart.updated_at = datetime.now()
+        cart.version += 1
+
+        # Insert new order
+        order_id = db.execute(
+            "INSERT INTO orders (cart_id, total, status) VALUES ($1, $2, $3) RETURNING id",
+            cart_id, cart.total, "created"
+        )
+
+        # Update cart with new version
+        db.execute(
+            "UPDATE carts SET status = $1, total = $2, updated_at = $3, version = $4 WHERE id = $5",
+            cart.status, cart.total, cart.updated_at, cart.version, cart_id
+        )
+
+        return {
+            "status": "success",
+            "order_id": order_id,
+            "version": cart.version
+        }

The AI also generates a test case using pytest and unittest.mock.

Common Pitfalls and Silent Failures

  • AI misses context across files: The AI assumes a function exists in a module that is not imported, or refers to a variable that is defined in a different file but not visible. The developer must explicitly include import statements or clarify the file structure.
  • Over-reliance on default prompts: The AI often applies the same style to all code, even when it doesn’t fit. A create_order_from_payload function with price as a required field may be generated with price as an optional argument if the prompt doesn’t specify.
  • Confusing async and await: The AI frequently generates async functions but forgets to await the result of a database call, leading to unawaited coroutines that silently return None in production.
  • Inconsistent naming: The AI uses user_id in one file and userId in another, leading to mismatches in JSON payloads and database queries.
  • Missing error handling: The AI returns a function that works for the happy path but fails silently on edge cases, such as empty input lists or missing keys in JSON payloads.

These patterns are not about a tool or a platform. They are about how humans and machines collaborate in real time, leveraging the strengths of each—intuition, domain knowledge, and pattern recognition from the human, and speed, precision, and scalability from the AI. The success of the pair lies not in the AI’s output, but in the conversation it enables.

This page was rewritten on 11 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.