AI Dev Tools
·5 min read·career

What Senior Engineers Actually Look for in Code Reviews

Stop worrying about formatting and syntax. Learn what senior engineers look for in code reviews, from architectural consistency and state management to hidden failure modes.

If your pull request gets 20 comments, and 15 of them are about variable naming, trailing commas, or minor style choices, you aren't getting a code review. You're getting an automated linter run by a human who is too tired to look at your architecture.

When you transition from a mid-level engineer to a senior engineer, your relationship with the pull request (PR) changes. You stop looking at the diff as a series of modified lines and start looking at it as a delta in a living, breathing system.

If you want to pass senior code reviews without the back-and-forth cycles that drag your tickets across sprint boundaries, you need to understand what is actually happening when a senior engineer opens your PR.

The Real Checklist of What Senior Engineers Look for in Code Reviews

Seniors do not care about style guide violations. If a style issue can be automated, it should be blocked by a git hook or a CI pipeline. If it isn't, it's a tooling failure, not a developer failure.

Instead, senior engineers evaluate code across four distinct axes:

  1. State Mutation & Concurrency Safety: How does this code behave under load, when network packets are dropped, or when a user double-clicks a submit button?
  2. Failure Domains & Error Isolation: If this new feature crashes, does it take down the entire application or degrade gracefully?
  3. API Contracts & Schema Drift: Does this change break assumptions made by downstream services, database schemas, or frontend clients?
  4. Cognitive Load & Maintainability: Can a junior engineer debug this at 2:00 AM during an on-call rotation without having to reconstruct a complex state machine in their head?

With the rise of modern AI tools writing our boilerplate—as we've seen in our deep dive into Cursor Composer 2.5—the human reviewer's job has shifted almost entirely to these higher-level architectural vectors.


1. State Mutation and Concurrency Safety

The most common class of bugs that bypass automated tests but get caught in senior reviews are race conditions and untracked state transitions.

Consider this seemingly straightforward TypeScript service designed to fetch user profiles and cache them in memory. A mid-level engineer might write this:

typescript
// THE BUGGY APPROACH
export class UserService {
  private cache = new Map<string, any>();
  private pendingRequests = new Map<string, Promise<any>>();
 
  async getUserProfile(userId: string): Promise<any> {
    if (this.cache.has(userId)) {
      return this.cache.get(userId);
    }
 
    // Bug: If two components call this simultaneously, they both trigger fetches
    const response = await fetch(`/api/users/${userId}`);
    const data = await response.json();
    
    this.cache.set(userId, data);
    return data;
  }
}

This code works perfectly in a local development environment with zero latency and a single component mounting. But in production, under real-world conditions, it triggers multiple network requests for the same user ID, causing cache stampedes and UI flickers.

Here is what a senior engineer expects to see: proper request deduplication, explicit error handling, and abort signals to prevent memory leaks from abandoned requests.

typescript
// THE PRODUCTION-READY APPROACH
export class UserService {
  private cache = new Map<string, any>();
  private pendingRequests = new Map<string, Promise<any>>();
 
  async getUserProfile(userId: string, signal?: AbortSignal): Promise<any> {
    if (this.cache.has(userId)) {
      return this.cache.get(userId);
    }
 
    // Deduplicate concurrent in-flight requests
    let promise = this.pendingRequests.get(userId);
    if (!promise) {
      promise = this.fetchProfile(userId, signal)
        .finally(() => {
          this.pendingRequests.delete(userId);
        });
      this.pendingRequests.set(userId, promise);
    }
 
    return promise;
  }
 
  private async fetchProfile(userId: string, signal?: AbortSignal): Promise<any> {
    try {
      const response = await fetch(`/api/users/${userId}`, { signal });
      if (!response.ok) {
        throw new Error(`Failed to fetch user ${userId}: ${response.statusText}`);
      }
      const data = await response.json();
      this.cache.set(userId, data);
      return data;
    } catch (error) {
      if (error instanceof Error && error.name === 'AbortError') {
        // Handle abort silently or log cleanly
        throw error;
      }
      // Log to observability platform
      console.error(`UserService: Error fetching user ${userId}`, error);
      throw error;
    }
  }
}

When a senior reviews your code, they are actively looking for these asynchronous edge cases. They are asking: What happens if this promise rejects? What happens if the component unmounts before this resolves?


2. Failure Domains and Error Isolation

A junior writes code for the happy path. A mid-level engineer adds a try/catch block around the whole function. A senior engineer designs code to fail gracefully, ensuring that a failure in a non-critical feature doesn't crash the critical application path.

Imagine you are adding a tracking widget to a checkout page. If the widget fails to load its third-party script, should the user be blocked from checking out? Obviously not. Yet, without proper isolation, that is exactly what happens.

When writing or reviewing AI-assisted code, this is a frequent pain point. If you are leveraging LLMs to generate your code, make sure you configure your environments to enforce error boundaries, as discussed in our guide on optimizing GPT-4o system prompts for TypeScript.

Here is a real-world scenario of a telemetry service integration:

typescript
// POOR ISOLATION
export async function processOrder(order: Order): Promise<void> {
  await db.saveOrder(order);
  
  // If the telemetry service is down, the entire order process fails
  // and the user sees a 500 error, even though their payment succeeded.
  await telemetryService.logOrderProcessed(order.id);
  
  await sendConfirmationEmail(order.email);
}

A senior engineer will flag this immediately. Telemetry is a secondary concern. The order processing pipeline must be isolated from telemetry failures:

typescript
// RESILIENT ISOLATION
export async function processOrder(order: Order): Promise<void> {
  await db.saveOrder(order);
  
  // Fire-and-forget telemetry with error isolation
  telemetryService.logOrderProcessed(order.id).catch((err) => {
    // Log the error locally but do not bubble it up to block the user
    logger.warn('Telemetry logging failed for order', { orderId: order.id, error: err });
  });
  
  try {
    await sendConfirmationEmail(order.email);
  } catch (emailError) {
    // Email failure is critical to know about, but the order is still saved.
    // Queue a background job to retry the email later.
    await queueEmailRetry(order.id, order.email);
  }
}

3. Cognitive Load: The "6-Months-Later" Rule

Code is read 10x more than it is written. When a senior reviews your code, they are checking if they can understand its execution flow within 30 seconds of looking at it.

Avoid deeply nested logical branches. Use guard clauses to exit early. This reduces the mental stack space required to parse your function.

Consider this nested nightmare:

typescript
// HIGH COGNITIVE LOAD
function checkAccess(user: User, resource: Resource): boolean {
  if (user !== null) {
    if (user.isActive) {
      if (resource.isPublic) {
        return true;
      } else {
        if (user.role === 'admin') {
          return true;
        } else {
          return user.permissions.includes(resource.requiredPermission);
        }
      }
    } else {
      return false;
    }
  }
  return false;
}

Now, look at the refactored version using guard clauses. The logic is linear, flat, and immediately obvious:

typescript
// LOW COGNITIVE LOAD
function checkAccess(user: User, resource: Resource): boolean {
  if (!user || !user.isActive) {
    return false;
  }
 
  if (resource.isPublic) {
    return true;
  }
 
  if (user.role === 'admin') {
    return true;
  }
 
  return user.permissions.includes(resource.requiredPermission);
}

The PR Template That Pre-empts Senior Comments

If you want to speed up your reviews, stop forcing your reviewers to reverse-engineer your code to figure out what it does.

When you open a PR, provide the context they need to evaluate your architectural decisions. Use this exact template for your PR descriptions to address what senior engineers look for in code reviews before they even ask.

markdown
## Context & Goals
<!-- What problem does this solve? Why is this implementation chosen over alternatives? -->
 
## Architecture & System Impact
- **State Changes:** Describe any changes to state management or database schemas.
- **Concurrency & Async Safety:** How does this handle rapid consecutive requests or race conditions?
- **Failure Modes & Degradation:** What happens if the external dependencies (APIs, databases) fail? How does the UI/system degrade gracefully?
 
## Verification Plan
### Automated Tests
- [ ] Unit tests added/updated (link to test file)
- [ ] Integration tests verify the failure domains
 
### Manual Verification
<!-- Provide step-by-step instructions or terminal commands to verify the change -->
1. Run `npm run service:test`
2. Simulate network latency of 3000ms using Chrome DevTools.
3. Verify that the loading spinner displays and double-clicking the submit button does not trigger duplicate API calls.

This Week's Action Plan

To immediately level up the quality of your pull requests and build trust with the senior engineers on your team, execute this three-step plan this week:

  1. Audit Your Next PR for Guard Clauses: Before you push your next branch, refactor any nested if/else statements into early returns. Reduce your function nesting to a maximum of two levels.
  2. Trace Your Failure Modes: Look at every external API call, database query, or asynchronous operation you wrote. Ask yourself: “If this line throws an unhandled exception, does it crash the parent context?” If yes, wrap it in a localized catch block, fallback state, or retry mechanism.
  3. Use the Pre-emptive PR Template: Fill out the PR template above for your next two pull requests. Note how it shifts the feedback you receive from syntactic nits to productive, high-level architectural design discussions.
ShareTweet

Related Posts