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, andschemafields to all endpoints. - Concurrency: Add optimistic locking to the
checkoutendpoint. - 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
importstatements 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_payloadfunction withpriceas a required field may be generated withpriceas an optional argument if the prompt doesn’t specify. - Confusing
asyncandawait: The AI frequently generatesasyncfunctions but forgets toawaitthe result of a database call, leading to unawaited coroutines that silently returnNonein production. - Inconsistent naming: The AI uses
user_idin one file anduserIdin 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.
Join the Newsletter
Get the latest updates and deep insights shipped directly to your inbox.