Skip to content

Building Prompts for Repeated Use

K. C. Ramakrishna edited this page Jun 27, 2025 · 1 revision

1. Overview

Purpose: This document outlines the development process and the final standardized prompt used by our teams to analyze and improve error handling in our codebase.

The Goal: To establish a consistent, high-quality, and efficient method for identifying and rectifying error handling issues. By using a standardized AI prompt, we ensure that all code reviews for error handling are thorough, adhere to our best practices, and produce actionable recommendations, regardless of the developer's experience level.

Audience: All developers, from Junior to Senior.


2. The Problem Statement: Why a Standard Prompt?

Inconsistent error handling is a primary source of bugs, system instability, and poor user experience. Manual code reviews for error handling can be time-consuming and subjective. We observed several challenges:

  • Inconsistency: Different developers focused on different aspects of error handling, leading to an uneven quality bar across projects.
  • Missed Edge Cases: Common but subtle failure points (e.g., promise rejections, unexpected null values, network timeouts) were frequently overlooked.
  • Knowledge Gaps: Junior developers were often unsure of what constituted "good" error handling, while senior developers spent significant time on repetitive feedback.
  • Inefficiency: Manual analysis of every try/catch block and callback is tedious and prone to human error.

To solve this, we decided to leverage AI-powered code analysis. However, a simple request like "find errors" yielded generic and often unhelpful results. This led us to an iterative process of prompt engineering to create a tool that is precise, focused, and reliable.


3. The Evolution of the Prompt

Our journey from a vague request to a highly specific, role-based directive demonstrates the principles of effective prompt engineering.

Phase 1: Initial Vague Prompts (Prompts 1-3)

1. Analyze this for error handling and suggest ways to improve error handling.

2. You are an senior software architect. You should ensure that all world class best practices have been implemented in the code. Please review the code the suggest what can be improved here.

3. You are a senior software expert developer in nodejs and javascript. Analyze and review this file for error handling.

Learning: A good prompt needs a persona and specialization to provide relevant, high-quality feedback.

Phase 2: Adding Specificity (Prompts 4-8)

4. You are a senior software expert developer in nodejs and javascript. Analyze and review this file for error handling. Ensure that all corner cases and all error codes and error types are handled properly.

5. You are a senior software expert specializing in Node.js and JavaScript. Analyze and review this file with a focus on error handling. Ensure that all edge cases, error codes, and exception types are properly managed. Identify any unhandled errors, suggest improvements for robustness, and recommend best practices for structured error handling, logging, and recovery mechanisms.

6. Act as a seasoned software architect with deep expertise in Node.js and JavaScript. Your role is to critically analyze and review the provided file, focusing specifically on error handling. Ensure that all edge cases are accounted for, error codes are correctly assigned, and different types of exceptions are properly managed.

Identify any unhandled errors, inconsistencies, or potential failure points. Provide actionable recommendations for improving robustness, structured error handling, and logging. Where applicable, suggest best practices aligned with industry standards to enhance maintainability and fault tolerance.

7. Act as a seasoned software architect with deep expertise in Node.js and JavaScript. Your role is to critically analyze and review the provided file, focusing specifically on error handling. Ensure that all edge cases are accounted for, error codes are correctly assigned, and different types of exceptions are properly managed.

Identify any unhandled errors, inconsistencies, or potential failure points. Provide actionable recommendations for improving robustness, structured error handling, and logging. Where applicable, suggest best practices aligned with industry standards to enhance maintainability and fault tolerance.

8. Assume the role of a seasoned software architect specializing in Node.js and JavaScript. Your task is to conduct a comprehensive analysis and review of the provided file, with a specific focus on error handling.

Ensure that all edge cases are addressed, error codes are correctly implemented, and exception handling is thorough and consistent. Identify unhandled errors, potential failure points, and any gaps in fault tolerance.

Provide detailed recommendations to improve robustness, maintainability, and adherence to industry best practices. Where applicable, suggest structured error-handling patterns, logging strategies, and recovery mechanisms to enhance overall system resilience.

Learning: The more specific the vocabulary and the more detailed the requirements, the more thorough and professional the output.

Phase 3: Sharpening the Focus with Negative Constraints (Prompts 9-11)

9. Assume the role of a seasoned software architect specializing in Node.js and JavaScript. Your task is to conduct a comprehensive analysis and review of the provided file, focusing exclusively on error handling.

Ensure that all edge cases are accounted for, error codes are correctly implemented, and exception handling is thorough and consistent. Identify unhandled errors, improper error propagation, and any gaps in fault tolerance.

Provide detailed recommendations solely related to error handling, such as improving error classification, structured error-handling patterns, and logging strategies. Do not suggest improvements related to validation, security, performance optimization, or documentation—limit your analysis strictly to error handling.

10. Assume the role of a seasoned software architect specializing in Node.js, JavaScript, Typescript and React. Your task is to critically analyze the provided file with an exclusive focus on error handling.

Ensure that all edge cases are properly addressed, error codes are correctly implemented, and exception handling is consistent and robust. Identify unhandled errors, improper error propagation, and any weaknesses in fault tolerance.

Limit your analysis strictly to error handling—do not suggest improvements related to validation, security, performance optimization, or documentation. Provide actionable recommendations solely for enhancing error classification, structured handling patterns, and logging strategies to improve reliability and maintainability.

11. Assume the role of a seasoned software architect specializing in Node.js and JavaScript. Your task is to thoroughly analyze the provided file, focusing exclusively on error handling.

Ensure all edge cases are covered, error codes are appropriately assigned, and exceptions are handled consistently and effectively. Identify unhandled errors, improper error propagation, and any gaps in fault tolerance.

Strictly limit your analysis to error handling—do not provide recommendations related to validation, security, performance optimization, or documentation. Offer precise, actionable suggestions to improve error classification, structured handling patterns, and logging strategies, ensuring greater reliability and maintainability.

Provide a detailed report outlining the identified issues and suggested improvements. At the end of the analysis, consolidate all recommended changes into a structured summary, ensuring clarity and ease of implementation.

Learning: Negative constraints are as important as positive instructions. A focused prompt that also specifies the desired output format is key to making the analysis actionable.


4. The Final Standard Prompt

After extensive iteration, we arrived at the following standard prompt. It combines a clear persona, specific technical expertise, a checklist of requirements, contextual assumptions, and strict negative constraints.

Assume the role of a seasoned software architect with deep expertise in TypeScript and React. Your objective is to critically analyze the provided code file with a focused lens on error handling and logging integration.

Specifically, assess the following:
* Whether all edge cases and failure modes are properly anticipated.
* If error codes and messages are meaningful, consistent, and correctly applied.
* Whether exceptions are being handled with clear propagation paths and do not result in silent failures.
* If structured and consistent error-handling patterns (e.g., try/catch, fallback flows, centralized error boundaries) are followed.
* Whether all error scenarios and exceptions are logged using the already implemented logger functionality, ensuring uniformity and observability across the application.

The logger is assumed to be available and integrated. Recommendations should emphasize making full use of this logger, including appropriate log levels, contextual metadata, and structured output formats.

Limit your analysis strictly to error handling and logging practices—do not suggest changes related to input validation, security, performance, testing, or documentation. Your response should contain actionable, architecture-aligned recommendations that improve fault tolerance, classification, traceability, and long-term maintainability.


5. How to Use the Standard Prompt

  1. Copy the Prompt: Copy the entire text of the standard prompt.
  2. Paste into Your AI Tool: Paste the prompt into your preferred AI chat interface or analysis tool.
  3. Provide the Code: After the prompt, add a clear separator (e.g., --- CODE ---) and then paste the contents of the code file you want to analyze.
  4. Review the Output: Carefully review the analysis generated by the AI for accuracy and helpfulness.
  5. Integrate and Automate: For daily use, consider using an AI assistant that integrates with your IDE (like Cody or GitHub Copilot). These tools allow you to save prompts and apply them directly to your code, eliminating the need for manual copy-pasting.

6. Practical Example: Analyzing a React Component

Let's walk through a real-world example to see the prompt in action.

Step 1 & 2: Input to the AI Tool

Here is the full input, combining our standard prompt with a sample React component that fetches user data.

Assume the role of a seasoned software architect with deep expertise in TypeScript and React. Your objective is to critically analyze the provided code file with a focused lens on error handling and logging integration.

Specifically, assess the following:
* Whether all edge cases and failure modes are properly anticipated.
* If error codes and messages are meaningful, consistent, and correctly applied.
* Whether exceptions are being handled with clear propagation paths and do not result in silent failures.
* If structured and consistent error-handling patterns (e.g., try/catch, fallback flows, centralized error boundaries) are followed.
* Whether all error scenarios and exceptions are logged using the already implemented logger functionality, ensuring uniformity and observability across the application.

The logger is assumed to be available and integrated. Recommendations should emphasize making full use of this logger, including appropriate log levels, contextual metadata, and structured output formats.

Limit your analysis strictly to error handling and logging practices—do not suggest changes related to input validation, security, performance, testing, or documentation. Your response should contain actionable, architecture-aligned recommendations that improve fault tolerance, classification, traceability, and long-term maintainability.

--- CODE ---

import React, { useState, useEffect } from 'react';
// Assume 'logger' is imported and available, e.g., from './logger';

interface User {
  id: number;
  name: string; 
  email: string;  
}

const UserProfile \= ({ userId }: { userId: number }) \=\> {
  const \[user, setUser\] \= useState\<User | null\>(null); 
  const \[error, setError\] \= useState\<string | null\>(null);

  useEffect(() \=\> {
    const fetchUser \= async () \=\> {
      try {
        const response \= await fetch(\`https://api.example.com/users/${userId}\`);
        const data: User \= await response.json();
        setUser(data);
      } catch (err) {
        setError('Failed to fetch data');
      }
    };

    fetchUser();
  }, \[userId\]);

  if (error) {
    return \<div\>Error: {error}\</div\>;
  }

  if (\!user) {
    return \<div\>Loading...\</div\>; // Note: This is a UI concern, the AI should ignore it.
  }

  return (
    \<div\>
      \<h1\>{user.name}\</h1\>
      \<p\>{user.email}\</p\>
    \</div\>
  );
};

export default UserProfile;

Step 3: Example AI Analysis Output

Here is a high-quality response generated from the prompt and code above.

As a seasoned software architect specializing in TypeScript and React, I have analyzed the provided UserProfile component with an exclusive focus on error handling and logging.

Analysis Summary

The component has basic error handling but misses several critical edge cases and lacks robust logging, which can lead to silent failures and difficult debugging.

Identified Issues and Actionable Recommendations

1. Unhandled Non-200 HTTP Status Codes

  • Issue: The fetch API does not throw an error for HTTP status codes like 404 (Not Found) or 500 (Internal Server Error). The code proceeds to response.json(), which may fail or process an error object as if it were a user, leading to unpredictable behavior.
  • Recommendation: Explicitly check if the response was successful using response.ok. If not, create and throw a custom error to be caught by the try/catch block.

2. Lack of Logging

  • Issue: When an error occurs, the state is updated (setError), but the actual error object (err) is discarded. This is a silent failure from an observability perspective, as there is no record of what went wrong.

  • Recommendation: Integrate the existing logger. In the catch block, log the error with a meaningful message and contextual metadata. Use the .error() level for unexpected failures.

      } catch (err) {
    
      logger.error('Failed to fetch user profile', { userId, error: err });
      
      setError('An unexpected error occurred. Please try again later.');
      
      }
    

3. Race Condition on Component Unmount

  • Issue: If the component unmounts while the fetch request is in-flight, the setUser or setError function will be called on an unmounted component, causing a memory leak warning in React.
  • Recommendation: Implement a cleanup function in useEffect using an AbortController. This is the standard, modern pattern for cancelling fetch requests.

4. Vague Error Message Propagated to UI

  • Issue: The error message "Failed to fetch data" is displayed to the user but lacks specificity for debugging and isn't user-friendly.
  • Recommendation: Display a generic, user-friendly error message. The specific technical details should be logged for developers, not exposed in the UI.

Refactored Code with Recommendations Applied

Here is a revised version of the component incorporating all the error handling and logging improvements:

import React, { useState, useEffect } from 'react';  
// import logger from './logger';

interface User { id: number; name: string; email: string; }

const UserProfile \= ({ userId }: { userId: number }) \=\> {  
  const \[user, setUser\] \= useState\<User | null\>(null);  
  const \[error, setError\] \= useState\<string | null\>(null);

  useEffect(() \=\> {  
    const abortController \= new AbortController();  
    const signal \= abortController.signal;

    const fetchUser \= async () \=\> {  
      try {  
        const response \= await fetch(\`https://api.example.com/users/${userId}\`, { signal });

        if (\!response.ok) {  
          // Throw an error to be handled by the catch block  
          throw new Error(\`API request failed with status ${response.status}\`);  
        }

        const data: User \= await response.json();  
        setUser(data);

      } catch (err) {  
        if (err.name \=== 'AbortError') {  
          // This is an expected error when the component unmounts, so we can ignore it.  
          console.log('Fetch aborted');  
        } else {  
          // This is an unexpected error. Log it and set a user-friendly error state.  
          logger.error('Failed to fetch user profile', { userId, error: err });  
          setError('An unexpected error occurred. Please try again later.');  
        }  
      }  
    };

    fetchUser();

    // Cleanup function to abort the fetch on unmount  
    return () \=\> {  
      abortController.abort();  
    };
  }, \[userId\]);

  if (error) {  
    return \<div\>Error: {error}\</div\>;  
  }

  if (\!user) {  
    return \<div\>Loading...\</div\>;  
  }

  return (  
    \<div\>  
      \<h1\>{user.name}\</h1\>  
      \<p\>{user.email}\</p\>  
    \</div\>  
  );  
};

export default UserProfile;

Step 4: Analysis of the Result

This example demonstrates the power of our standardized prompt:

  • Focused: The AI ignored the Loading... state and other UI/UX concerns, focusing only on error handling and logging as instructed.
  • Thorough: It identified not just the obvious try/catch but also subtle yet critical issues like non-200 responses and race conditions.
  • Actionable: The recommendations are clear, specific, and directly lead to a more robust implementation. The provided refactored code serves as a perfect template.
  • Context-Aware: It correctly assumed a logger was available and provided a best-practice example of how to use it with contextual metadata (userId, error).
  • High-Quality: The suggestion to use AbortController is a modern, senior-level best practice that a junior developer might not be aware of, fulfilling the goal of up-leveling our code quality.

Clone this wiki locally