Artificial intelligence-powered coding assistants are reshaping how developers tackle everyday programming challenges. These tools streamline everything from codebase documentation to unit test generation, yet many developers—whether new to the field or seasoned professionals—encounter frustration when the AI doesn't produce the expected results. The root cause often lies not with the tool itself, but with how developers communicate their needs to it.
Consider a scenario where GitHub Copilot was asked to create an ice cream cone using p5.js, a JavaScript library designed for creative coding. Initial attempts yielded irrelevant suggestions or nothing at all. Once the developers understood how GitHub Copilot processes information, they adjusted their communication approach and achieved the desired output. This experience highlights a fundamental truth: learning to work effectively with generative AI requires understanding the technology's mechanics.
Rizel, who has leveraged GitHub Copilot to build a browser extension, rock, paper, scissors game, and to send a Tweet, and Michelle, who launched an AI company in 2016, both serve as developer advocates at GitHub. Together, they've distilled their insights into actionable guidance for the development community. Their framework addresses what prompts are, explores prompt engineering concepts, outlines three core best practices alongside three supplementary tips, and provides a hands-on example for building a browser extension.
Understanding Prompts and Prompt Engineering
The definition of a prompt shifts depending on the audience. Machine learning researchers building and refining these models understand prompts differently than developers using them in integrated development environments. For developers working with generative AI coding tools in an IDE, a prompt consists of code blocks, individual lines, or natural language comments written to generate specific suggestions from GitHub Copilot. Prompt engineering, from a developer's perspective, means providing instructions or comments to produce particular coding suggestions.
Context—the details developers supply to specify desired output—plays a crucial role. Behind the scenes, algorithms compile IDE code and relevant context, including comments and code in open files, which is continuously sent to the model. ML researchers, by contrast, focus on creating algorithms that generate prompts for large language models, with context referring to the details algorithms send to an LLM as supplementary information about the code.
Three Best Practices for Prompt Crafting
1. Set the stage with a high-level goal
This approach proves especially valuable when starting with a blank file or empty codebase where GitHub Copilot lacks context about your objectives. Priming the AI pair programmer with a comprehensive description of what you want to build before diving into specifics mirrors how you'd approach a conversation with a colleague. Think about how you'd break down the problem for pair programming.
When building a markdown editor in Next.js, a developer might write:
/* Create a basic markdown editor in Next.js with the following features: - Use react hooks - Create state for markdown with default text "type markdown here" - A text area where users can write markdown - Show a live preview of the markdown text as I type - Support for basic markdown syntax like headers, bold, italics - Use React markdown npm package - The markdown text and resulting HTML should be saved in the component's state and updated in real time */
This level of detail enables GitHub Copilot to generate a functional markdown editor in under 30 seconds, though results may still be non-deterministic. For instance, while the prompt specified default text saying "type markdown here," GitHub Copilot generated "markdown preview" instead.
2. Make your ask simple and specific
After communicating the main objective, articulate the logic and steps required to achieve it. GitHub Copilot comprehends goals more effectively when you break them into manageable pieces—similar to writing a recipe with discrete steps rather than a paragraph describing the finished dish. Request code generation after each step rather than asking for everything at once.
3. Give GitHub Copilot an example or two
Examples benefit both human and artificial learners. When extracting names from a nested array of objects without providing an example, GitHub Copilot might produce:
const data = [
[
{ name: 'John', age: 25 },
{ name: 'Jane', age: 30 }
],
[
{ name: 'Bob', age: 40 }
]
];
const mappedData = data.map(x => x.name);
console.log(mappedData);
// Results: [undefined, undefined]
However, when an example is included with the desired outcome specified:
// Map through an array of arrays of objects
// Example: Extract names from the data array
// Desired outcome: ['John', 'Jane', 'Bob']
const data = [
[{ name: 'John', age: 25 }, { name: 'Jane', age: 30 }],
[{ name: 'Bob', age: 40 }]
];
const mappedData = data.flatMap(sublist => sublist.map(person => person.name));
console.log(mappedData);
The result matches expectations:
// Results: ['John', 'Jane', 'Bob']
Three Additional Tips for Prompt Crafting
1. Experiment with your prompts
Prompt crafting resembles conversation—more art than science. If initial attempts don't yield desired results, refine your prompt using the best practices outlined above. A vague prompt like "Write some code for grades.py" lacks context and boundaries. Iteration helps: "Implement a function in grades.py to calculate the average grade" is more specific but still unclear about input and output requirements. Further refinement—"Implement the function calculate_average_grade in grades.py that takes a list of grades as input and returns the average grade as a floating-point number"—sets clear boundaries and produces the intended results. Determining which details matter most often requires experimentation.
2. Keep a couple of relevant tabs open
GitHub Copilot employs a technique called neighboring tabs that enables the AI pair programmer to understand your code by processing all open IDE files, not just the current one. While no exact tab count guarantees optimal results, experience suggests one or two relevant tabs prove helpful. GitHub Copilot doesn't necessarily treat all open files as necessary context, but the capability exists to leverage them.
3. Use good coding practices
Descriptive variable and function names, consistent coding styles, and established patterns significantly influence GitHub Copilot's output. A well-named function using snake case conventions:
def authenticate_user(username, password):
prompts GitHub Copilot to generate relevant suggestions:
def authenticate_user(username, password): # Code for authenticating the user if is_valid_user(username, password): generate_session_token(username) return True else: return False
Conversely, inconsistent style and poor naming:
def rndpwd(l):
results in a generic response:
def rndpwd(l): # Code goes here
Critical Validation Remains Essential
Large language models powering generative AI coding tools identify and extrapolate patterns from training data, applying those patterns to generate code. Given their scale, they may produce code sequences that don't yet exist in documented form. Just as you would review a colleague's work, always assess, analyze, and validate AI-generated code before integrating it into your projects.