I've been experimenting with AI-assisted development tools like Cursor for code reviews and refactoring, and I'm constantly surprised by how much they can teach you about better coding patterns. Rather than just generating code, these tools can become excellent teachers and pair programming partners when used thoughtfully.
AI isn't just about generating code faster - it's about learning better patterns and catching issues you might miss during regular development.
Beyond Code Generation: AI as a Learning Tool
Most developers I talk to think of AI coding tools primarily as code generators. While that's useful, I've found the real value comes from using them as intelligent reviewers and teachers. They can spot patterns you might miss, suggest improvements you hadn't considered, and explain the reasoning behind their suggestions.
Limited Approach
- • Using AI only to generate new code
- • Accepting suggestions without understanding them
- • Treating AI as a magic solution
- • Not customizing prompts for your context
- • Ignoring the learning opportunities
Thoughtful AI Usage
- • Using AI to review and improve existing code
- • Asking for explanations of suggested changes
- • Learning new patterns from AI suggestions
- • Customizing prompts for your specific needs
- • Combining AI insights with human judgment
Practical Code Review with Cursor
Here's how I use Cursor to review and improve code. The key is asking specific questions rather than just requesting generic improvements.
Example 1: Laravel Controller Refactoring
Let's start with a typical Laravel controller that handles user registration:
class UserController extends Controller
{
public function register(Request $request)
{
// Validate input
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:8|confirmed',
]);
if ($validator->fails()) {
return response()->json([
'errors' => $validator->errors()
], 422);
}
// Create user
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
'email_verified_at' => null,
]);
// Send verification email
Mail::to($user->email)->send(new VerifyEmail($user));
// Create token
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'user' => $user,
'token' => $token,
'message' => 'User registered successfully'
], 201);
}
}
💡 Cursor Prompt I Use:
"Review this Laravel controller method for potential improvements. Focus on separation of concerns, error handling, and maintainability. Explain the reasoning behind your suggestions."
Cursor typically suggests improvements like this:
class UserController extends Controller
{
public function register(RegisterUserRequest $request)
{
try {
DB::beginTransaction();
$user = $this->userService->createUser($request->validated());
event(new UserRegistered($user));
DB::commit();
return new UserResource($user, [
'token' => $user->createToken('auth_token')->plainTextToken,
'message' => 'User registered successfully'
]);
} catch (Exception $e) {
DB::rollback();
Log::error('User registration failed', [
'email' => $request->email,
'error' => $e->getMessage()
]);
return response()->json([
'message' => 'Registration failed. Please try again.'
], 500);
}
}
}
Key Improvements Suggested
- • Form Request: Move validation to a dedicated request class
- • Service Layer: Extract user creation logic to a service
- • Events: Use events for side effects like email sending
- • Database Transactions: Ensure data consistency
- • Error Handling: Proper exception handling and logging
- • API Resources: Standardize response format
Example 2: JavaScript Function Optimization
Here's a JavaScript function that processes user data:
function processUsers(users) {
let result = [];
for (let i = 0; i < users.length; i++) {
if (users[i].active === true) {
let user = users[i];
let processedUser = {
id: user.id,
name: user.firstName + ' ' + user.lastName,
email: user.email.toLowerCase(),
role: user.role || 'user',
lastLogin: user.lastLogin ? new Date(user.lastLogin).toISOString() : null
};
if (user.preferences) {
processedUser.preferences = JSON.parse(user.preferences);
}
result.push(processedUser);
}
}
return result;
}
🤖 My Cursor Prompt:
"Refactor this JavaScript function for better readability and performance. Show me modern JavaScript patterns I could use and explain any potential edge cases."
Cursor suggests a more modern approach:
const processUsers = (users) => {
if (!Array.isArray(users)) {
throw new Error('Expected users to be an array');
}
return users
.filter(user => user?.active === true)
.map(user => {
try {
return {
id: user.id,
name: `${user.firstName || ''} ${user.lastName || ''}`.trim(),
email: user.email?.toLowerCase() || '',
role: user.role || 'user',
lastLogin: user.lastLogin
? new Date(user.lastLogin).toISOString()
: null,
preferences: user.preferences
? JSON.parse(user.preferences)
: {}
};
} catch (error) {
console.warn('Failed to process user:', user.id, error.message);
return null;
}
})
.filter(Boolean); // Remove any null results
};
Learning Points from AI Review
- • Input validation: Check if the input is actually an array
- • Functional approach: Use filter/map instead of imperative loops
- • Null safety: Handle undefined/null values gracefully
- • Error handling: Catch JSON parsing errors per user
- • Edge cases: Handle missing names and email addresses
Database Query Optimization
One area where AI really shines is identifying potential performance issues in database queries. Here's an example with Laravel Eloquent:
N+1 Query Problem Detection
class BlogController extends Controller
{
public function index()
{
$posts = Post::where('published', true)
->orderBy('created_at', 'desc')
->paginate(10);
return view('blog.index', compact('posts'));
}
}
// In the Blade template:
@foreach($posts as $post)
{{ $post->title }}
By {{ $post->author->name }}
{{ $post->comments->count() }} comments
@foreach($post->tags as $tag)
{{ $tag->name }}
@endforeach
@endforeach
🚨 Cursor Identifies:
This code will cause N+1 query problems. For 10 posts, you'll execute 1 query for posts + 10 queries for authors + 10 for comment counts + 10 for tags = 31 queries total!
AI suggests this optimization:
class BlogController extends Controller
{
public function index()
{
$posts = Post::with([
'author:id,name',
'tags:id,name',
])
->withCount('comments')
->where('published', true)
->orderBy('created_at', 'desc')
->paginate(10);
return view('blog.index', compact('posts'));
}
}
// Updated Blade template:
@foreach($posts as $post)
{{ $post->title }}
By {{ $post->author->name }}
{{ $post->comments_count }} comments
@foreach($post->tags as $tag)
{{ $tag->name }}
@endforeach
@endforeach
Performance Improvement
Now the same page load uses only 4 queries regardless of the number of posts: 1 for posts + 1 for authors + 1 for comment counts + 1 for tags. That's an 87% reduction in database queries!
Security-Focused Reviews
AI tools are excellent at spotting common security vulnerabilities. Here's an example of how Cursor can help identify potential security issues:
File Upload Vulnerability
public function uploadAvatar(Request $request)
{
$file = $request->file('avatar');
if ($file) {
$filename = $file->getClientOriginalName();
$path = $file->move(public_path('uploads'), $filename);
auth()->user()->update([
'avatar' => 'uploads/' . $filename
]);
return redirect()->back()->with('success', 'Avatar updated!');
}
return redirect()->back()->with('error', 'No file selected');
}
⚠️ Security Issues Identified:
- • No file type validation
- • Using original filename (path traversal risk)
- • No file size limits
- • Files stored in public directory
- • No MIME type checking
AI suggests a more secure approach:
public function uploadAvatar(Request $request)
{
$request->validate([
'avatar' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048'
]);
$file = $request->file('avatar');
// Generate secure filename
$filename = Str::uuid() . '.' . $file->getClientOriginalExtension();
// Store in private storage
$path = $file->storeAs('avatars', $filename, 'private');
// Delete old avatar if exists
if (auth()->user()->avatar) {
Storage::disk('private')->delete(auth()->user()->avatar);
}
auth()->user()->update([
'avatar' => $path
]);
return redirect()->back()->with('success', 'Avatar updated successfully!');
}
// Add route to serve private files
public function serveAvatar($filename)
{
$path = storage_path('app/private/avatars/' . $filename);
if (!file_exists($path)) {
abort(404);
}
return response()->file($path);
}
Learning from AI Suggestions
The key to getting value from AI code reviews is asking follow-up questions. Don't just accept suggestions - understand them.
Effective Follow-up Prompts
Questions That Deepen Understanding
- • "Why is this approach better than what I had before?"
- • "What are the potential drawbacks of this solution?"
- • "Are there any edge cases I should consider?"
- • "How would this perform with large datasets?"
- • "What testing strategy would you recommend for this code?"
Building Your Own Patterns
As you work with AI suggestions, you'll start recognizing patterns that work well for your specific use cases. I keep a personal collection of prompts that work well for different types of reviews:
Code Quality Prompts
Focus on readability and future changes
Database queries, loops, memory usage
Input validation, authorization, data exposure
Learning-Focused Prompts
Learn current best practices
Understand when to use different approaches
Learn testing strategies
Refactoring Legacy Code
AI tools are particularly helpful when working with legacy code that might not follow current best practices. They can suggest incremental improvements that make code easier to maintain.
Gradual Modernization
Here's a typical legacy PHP function:
function calculate_order_total($order_items, $tax_rate, $discount_code = null) {
$subtotal = 0;
foreach($order_items as $item) {
$subtotal += $item['price'] * $item['quantity'];
}
$discount = 0;
if($discount_code != null) {
if($discount_code == 'SAVE10') {
$discount = $subtotal * 0.1;
} elseif($discount_code == 'SAVE20') {
$discount = $subtotal * 0.2;
}
}
$discounted_total = $subtotal - $discount;
$tax = $discounted_total * $tax_rate;
$total = $discounted_total + $tax;
return array(
'subtotal' => $subtotal,
'discount' => $discount,
'tax' => $tax,
'total' => $total
);
}
💡 Cursor Prompt for Legacy Code:
"Refactor this legacy PHP function to be more maintainable and testable. Show me how to break it down into smaller, focused functions while keeping the same external interface."
AI suggests a more modular approach:
class OrderCalculator
{
private array $discountRules = [
'SAVE10' => 0.1,
'SAVE20' => 0.2,
];
public function calculateTotal(array $orderItems, float $taxRate, ?string $discountCode = null): array
{
$subtotal = $this->calculateSubtotal($orderItems);
$discount = $this->calculateDiscount($subtotal, $discountCode);
$discountedTotal = $subtotal - $discount;
$tax = $this->calculateTax($discountedTotal, $taxRate);
$total = $discountedTotal + $tax;
return [
'subtotal' => round($subtotal, 2),
'discount' => round($discount, 2),
'tax' => round($tax, 2),
'total' => round($total, 2),
];
}
private function calculateSubtotal(array $orderItems): float
{
return array_reduce($orderItems, function ($carry, $item) {
return $carry + ($item['price'] * $item['quantity']);
}, 0);
}
private function calculateDiscount(float $subtotal, ?string $discountCode): float
{
if (!$discountCode || !isset($this->discountRules[$discountCode])) {
return 0;
}
return $subtotal * $this->discountRules[$discountCode];
}
private function calculateTax(float $amount, float $taxRate): float
{
return $amount * $taxRate;
}
}
Testing AI-Suggested Code
Always test AI suggestions thoroughly. While AI is great at identifying patterns and potential improvements, it doesn't always understand your specific business context or edge cases.
Verification Strategies
Before Implementing AI Suggestions
- • Write tests for the current behavior first
- • Understand what the AI suggestion is trying to improve
- • Consider your specific use cases and constraints
- • Test the suggestion with your actual data
- • Review the changes with teammates when possible
Building Your AI Review Workflow
Here's the workflow I've developed for using AI tools effectively in code reviews:
My Weekly AI Review Process
- 1. Monday: Review last week's commits for refactoring opportunities
- 2. Wednesday: Run AI review on the most complex functions or classes
- 3. Friday: Focus on performance and security reviews
- 4. Ongoing: Use AI for immediate feedback during development
Team Integration
If you're working on a team, consider these approaches for sharing AI insights:
Individual Practice
Team Sharing
Limitations and Considerations
AI code review tools are powerful, but they're not perfect. Here are some limitations to keep in mind:
Context Limitations
AI doesn't understand your specific business requirements, performance constraints, or team conventions. Always apply human judgment to AI suggestions.
Pattern Matching
AI suggestions are based on common patterns from training data. Sometimes your "unconventional" approach is actually the right choice for your specific situation.
Over-Engineering Risk
AI might suggest complex solutions when simple ones would suffice. Always consider whether the suggested improvement is worth the added complexity.
The Learning Mindset
The biggest benefit of using AI for code reviews isn't the immediate improvements - it's the patterns and techniques you learn over time. Each suggestion is an opportunity to understand why certain approaches work better than others.
I've found that my own code quality has improved significantly just from seeing consistent AI feedback on common issues. It's like having a patient mentor who never gets tired of explaining why certain patterns are better.
🎯 Key Takeaways
Use AI as a learning tool, not just a code generator. Ask questions, understand the reasoning, and build your own collection of effective patterns.
Remember: the goal is to become a better developer, not just to have AI write your code for you. The best AI-assisted developers are those who understand when to accept, modify, or reject AI suggestions.
Want to level up your AI-assisted development skills or share experiences with using Cursor for code reviews? I'd love to hear what patterns and prompts work best for your team. Learning from each other makes us all better developers.

Chris Page
Fractional CTO and Software Engineer with 25+ years of experience. I help startups scale from 0 to 7 figures using AI-assisted development and proven frameworks.