Home

Published

- 7 min read

How to Get the Best Out of GitHub Copilot: A Guide to Enhancing Code Quality

img of How to Get the Best Out of GitHub Copilot: A Guide to Enhancing Code Quality

One of the biggest challenges when working with GitHub Copilot is getting consistently useful results. While Copilot can be a powerful tool, its output can vary greatly: sometimes it generates near-perfect code that handles edge cases you didn’t even think of, but other times it produces confusing or even incorrect suggestions. This inconsistency often means you have to spend time evaluating and refining the code.

I see Copilot more as Rubber duck debugging on steroids.” Instead of just passively listening, Copilot actively suggests ideas, which can help you think through problems more effectively.

Improving Code Quality with Copilot

One of the most valuable ways to use Copilot is for improving code quality. You can ask Copilot to review your code and provide suggestions for enhancements. By following these suggestions and implementing improvements, you not only refine your current code but also set a higher standard for future development.

Good code quality makes it easier for all developers to understand, maintain, and extend your project. This also benefits GitHub Copilot: as your input code improves, the quality of Copilot’s suggestions improves as well, creating a positive feedback loop.

To ensure high code quality, I follow a systematic approach that includes the following steps:

  1. Request a code Review
  2. Improve Code Variables
  3. Write Unit Tests
  4. Improve the Efficiency of the code?
  5. Write Documentation

Example Code

This is from my react-sandbox Learn-Typing:

import * as React from 'react'
import { Link } from 'react-router-dom'
import { Button } from '../../../src/components/Button/Button'
import { Card } from '../../../src/components/Card/Card'

interface LessonCardProps {
	lesson: Lesson
}

const LessonCard: React.FC<LessonCardProps> = ({ lesson }) => (
	<Card>
		<h2>{lesson.title}</h2>
		<p>{lesson.description}</p>
		<Link to={`/lesson/${lesson.id}`}>
			<Button>Start Lesson</Button>
		</Link>
	</Card>
)

Step One: Request a Code Review

Now the first thing you can ask copilot is to do a code review of the file open in the editor the prompt would be:

Do a codereview of @currentfile

Copilot’s code review typically comes in four parts:

  1. Positive Aspects: This section highlights the strengths of your code. It’s useful for understanding what you did well and can help you incorporate these best practices from the start when writing new code.
  2. Suggestions for Improvement: This part contains actionable recommendations. It’s important to review each suggestion carefully and decide whether it’s worth implementing based on the context of your project.
  3. Revised Code: Copilot may provide a rewritten version of your code based on its suggestions. This can be helpful for seeing alternative implementations, but it’s crucial to evaluate if the changes align with your project’s requirements.
  4. Additional Considerations: This final section might include broader recommendations, such as adding unit tests or writing documentation to enhance the overall quality and maintainability of your code.

Rerun Command after reworking the code

After you applied the changes you want ask Copilot to do a code review using the prompt:

Do a codereview of @currentfile

Copilot will generate a structured list of suggestions based on your current file. However, if you run this command multiple times, you’ll notice a diminishing return in the quality of feedback. While the first set of suggestions is usually helpful, subsequent reviews tend to become repetitive or increasingly irrelevant.

Step Two: Ask for better Variable Names

There are only two hard things in Computer Science: cache invalidation and naming things. — Phil Karlton

Well, it seems one of these problems just got significantly easier to solve. The main issue when it comes to naming things is that the next developer often has no clue what the variables represent. You can’t predict how the next developer will interpret your naming conventions or if they’ll understand the context behind your choices. This ambiguity can lead to confusion and misinterpretation, making the code harder to maintain.

Now we have Copilot to highlight bad variable names and suggest better names:

How would you improve the variable names @currentfile

What is really nice about the answer from copilot is that it gives a specific reasoning why it would like to change the different names. And tries to explain why a variable name is unclear.

Here again, it generates the code automatically, but I usually just glance over it to get a feel of what the code would look like.

Step Three: Generate Unit Tests

You should set up a tool to run unit tests for your code, which will vary depending on the programming language you’re using.

In this React project, I’ve set up Vitest as the test runner. Once your test runner is configured, you can start writing test files. For example, if you have a component named LessonCard.tsx, you can create a corresponding test file called LessonCard.test.tsx.

Next, open LessonCard.tsx and prompt Copilot to generate tests by simply typing:

\test

Copilot will recognize the context and automatically generate a complete unit test for your component.

Note: Occasionally, Copilot might mix up the test framework (e.g., Jest vs. Vitest). However, the more tests you write, the better Copilot gets at recognizing which framework you’re using.

Step Four: Optimize Your Code

You probably cannot out-optimize the compiler these days. – C++ developer

In most cases, developers fall into the trap of premature optimization. However, now that we’ve completed the essential steps to ensure a solid code base, including thorough unit testing, we can safely explore optimization without risking code quality.

Instead of spending excessive time brainstorming ways to manually rewrite the code for better performance, this is a task where Copilot truly shines. It can analyze the existing code and suggest more efficient implementations automatically. Simply ask:

is there any way that you would optimize this file?

Review the optimized code that Copilot generates, run your tests to verify nothing is broken, and you’re good to go.

Step Five: Write Documentation

Writing documentation is probably one of the least exciting and most tedious tasks for any developer. Fortunately, this is another area where Copilot can shine. It can quickly transform your code into human-readable text with a simple prompt:

\doc

With this command, you can save yourself hours of painstaking effort. However, keep in mind that you may still need to manually explain certain aspects of the code, especially those driven by specific business requirements that aren’t obvious just from reading the code. Even so, Copilot’s help makes it much quicker and easier for the next developer to understand the code.

Example: Output After Applying Suggestions

After following the steps and applying several of Copilot’s suggestions, let’s look at an example of the final output. By systematically improving code quality, enhancing variable names, writing unit tests, optimizing the code, and generating documentation, we end up with a more polished and maintainable codebase.

LessonCard.tsx

import * as React from 'react'
import { Link } from 'react-router-dom'
import { Button } from '../../../components/Button/Button'
import { Card } from '../../../components/Card/Card'

/**
 * Props for the LessonCard component.
 *
 * @interface LessonCardProps
 * @property {Lesson} lessonData - The data for the lesson, including id, title, and description.
 */

interface LessonCardProps {
	lessonData: Lesson
}

/**
 * A functional component that renders a card for a lesson.
 *
 * @component
 * @param {LessonCardProps} props - The props for the component.
 * @returns {JSX.Element} The rendered LessonCard component.
 *
 * @example
 * <LessonCard lessonData={{ id: 1, title: "Lesson 1", description: "This is lesson 1" }} />
 */
const LessonCardComponent: React.FC<LessonCardProps> = ({
	lessonData: { id, title, description }
}) => (
	<Card>
		<h2>{title}</h2>
		<p>{description}</p>
		<Link to={`/lesson/${id}`}>
			<Button aria-label={`Start lesson ${title}`}>Start Lesson</Button>
		</Link>
	</Card>
)

export const LessonCard = React.memo(LessonCardComponent)

Conclusion

Here’s what we achieved:

  1. Improved Code Structure: The code is now easier to read and maintain, with meaningful variable names and a consistent format.
  2. Comprehensive Unit Tests: We have a robust set of tests that ensure the code behaves as expected and reduces the risk of bugs.
  3. Optimized Code: Copilot’s optimizations have streamlined the code, making it more efficient without sacrificing readability.
  4. Clear Documentation: With the help of Copilot, we generated clear and concise documentation, making it easier for the next developer to understand the code’s purpose and functionality.

In the end, by leveraging Copilot effectively, we saved time and effort while achieving a high-quality output.

Related Posts

There are no related posts yet. 😢