Context is Key: Learnings from a GitHub Copilot Pilot Project

Hung V. Nguyen
Hung V. Nguyen
Featured Image Description
Software development is one of the branches in which daily tasks have been most affected by the rise of generative AI. Tools such as ChatGPT and Copilot are able to write and review code at lightning speed. While the quality of said output can vary, Infodation tested the structural integration of generative AI software into development practices by offering GitHub Copilot Business to 20 of its developers across two projects. Here are their 5 key findings on how to improve your companies GitHub Copilot experience.

GitHub copilot was used in two projects. For the first project, GitHub Copilot generated unit tests and modular code. The second project streamlined coding tasks, facilitating the review and improvement of code quality. 

“Deeming this pilot project a success, Infodation will now consider the company wide implementation of GitHub Copilot. ”

The developers found that providing detailed context improves the effectiveness of GitHub Copilot. They summarized their findings as “Context is key”, re-iterating that quality of context significantly boosts the accuracy and usefulness of LLMs suggestions. In other words: Yes, GitHub Copilot builds code based on the lines of script that already in the repository, but it also considers how the code is named, structured, refactored, whether there is cohesion within the code and many other factors. Tweaking this “context” created code tailormade for the individual projects. Here is how our developers did it:

Tip 1: Add Clear and Descriptive Comments 

  • Enhance code readability and maintenance. 
  • Foster a culture of clear communication and thorough documentation. 
  • Consistently update comments to reflect changes in code and remove outdated information. 
  • Comment with intent: Explain the reasons behind specific decisions instead of merely describing the code. 
  • Use standardized code formats: Adopt tools and/ or coding rules to maintain consistency. 

Example Python

Prompt:
“Explain the function including its inputs, outputs, and the used logic. Highlight key operations or algorithms”

Code without comments

Input:
def factorial(n):
    result = 1
    for i in range(1, n + 1):
        result *= i
    return result
Output:
The factorial function is designed to compute the factorial of a given non-negative integer n. A factorial, denoted as n! is the product of all positive integers less than or equal to n. Here's a detailed breakdown of the function:

Inputs

n: A non-negative integer. This integer represents the number at which the factorial calculation stops.

Outputs

Returns: The factorial of the integer n, calculated as n×(n−1)×(n−2)×...×1n \times (n-1) \times (n-2) \times ... \times 1.

Logic and Key Operations

Initialization: The function starts by initializing a variable result to 1. This initialization is crucial as the factorial of any number starts with the multiplication identity, which is 1.

Iteration: The function uses a for loop to iterate over a range of numbers from 1 to n inclusive. The range function range(1, n + 1) generates a sequence of integers starting at 1 and ending at n, providing the necessary values to compute the factorial.

Multiplication: In each iteration of the loop, the current loop variable ii is multiplied by the current value of the result. The operation result *= i is used, which is shorthand for result = result * i. This operation accumulates the product of all integers from 1 to n.

Return Value: After completing the loop (i.e., once all integers up to n have been multiplied), the function returns the value of the result, which now holds the computed factorial of n.

Key Algorithm

The algorithm employed here is a simple iterative method to compute the factorial of a number. The key operations involve initializing a variable to hold the running product and iteratively multiplying this variable by each number in a specified range.

The time complexity of this function is O(n), where nn is the input number. This is because the function needs to perform nn multiplications — one for each number from 1 to nn. The space complexity is O(1) as the function uses a fixed amount of space regardless of the size of nn.

This implementation is straightforward and efficient for computing factorials of moderately sized numbers. However, for very large numbers, this approach might lead to long computation times and potential integer overflow, depending on the limitations of the programming language's integer type.

Code with comments

Input:
def calculate_sum(numbers):
    # Initialize sum to zero
    total = 0
    # Iterate over each number and add to total
    for number in numbers:
        total += number
    return total  # Return the computed sum
Output:
The function calculate_sum is designed to compute the sum of a list of numbers. Here's a breakdown of its components and operations:

Inputs

numbers: A list of numbers (integers or floats). This is the input to the function, where each element in the list is a number to be summed.

Outputs

Returns: The total sum of all the numbers in the input list.

Logic and Key Operations

Initialization: The function starts by initializing a variable total to zero. This variable is used to store the running total of the numbers as they are added together.

Iteration: The function then enters a loop where it iterates over each element in the input list numbers. For each iteration, the current number is added to total.

Addition: In each iteration of the loop, the += operator is used to add the current number to total. This operator is a shorthand for total = total + number.

Return Value: After the loop has processed all the numbers in the list, the function returns the value of total, which by now holds the sum of all the input numbers.

Key Algorithm

The algorithm used here is a simple iterative method to accumulate a sum. It's a direct approach that operates in O(n) time complexity, where n is the number of elements in the list. This means that the time to compute the sum scales linearly with the number of elements.

Overall, this function is an example of straightforward and efficient use of iteration for summing a sequence of numbers.

The code with comments gives superior results for the example prompt 

Tip 2: Thoughtfully Name functions and variables 

  • Achieve code clarity with intuitive naming 
  • Establish naming conventions at the beginning of the project or at least before making any code modifications. 
  • Perform pair reviews to evaluate the clarity and suitability of naming conventions. 
  • Choose descriptive names that reflect the purpose of the variables or the outcomes of the functions. 
  • Follow established project naming conventions to ensure consistency. 

Example .NET

Prompt:
“Improve the current code”

Poorly named variables

Input:
int[] arr = {1, 2, 3};
int res = 0;
foreach (var item in arr) {
    res += item;
}
Output:
using System.Linq;
int[] arr = {1, 2, 3};
int res = arr.Sum();

Well chosen naming convention

Input:
int[] numbers = {1, 2, 3};
int total = 0;
foreach (int number in numbers) {
    total += number;
}
Output:
using System.Linq;
int[] numbers = {1, 2, 3};
int total = numbers.Sum();

Tip 3: Write Partial Code Snippets  

  • Simplify complex concepts and focus on key functionalities. 
  • Focus on the key functionalities that showcase core logic. 
  • Use partial snippets in internal documentation to illustrate specific coding techniques or issues. 
  • Isolate core logic of complex functions. 
  • Annotate snippets to guide through the logic. 

Example Javascript

Prompt:
“Optimize the FunctionName implementation to reduce its code complexity. Refactor to make it more modular, use clean coding practices, and eliminate redundant or deeply nested logic. Ensure the functionality and readability remain intact”

Full function

Input:
def calculate_sum(numbers):
    # Initialize sum to zero
    total = 0
    # Iterate over each number and add to total
    for number in numbers:
        total += number
    return total  # Return the computed sum
Output:
// Function to calculate sum of an array
function calculateSum(array) {
    return array.reduce((acc, cur) => acc + cur, 0);
}
// Function to calculate average of an array
function calculateAverage(array) {
    if (!Array.isArray(array) || array.length === 0) return null; // Validate input
    const sum = calculateSum(array); // Calculate sum
    return sum / array.length; // Calculate and return average
}

Focussed snippet

Input:
// Calculates the sum of an array of integers
public int CalculateSum(int[] numbers) {
    int sum = 0; // Initialize sum
    // Loop through numbers and accumulate the sum
    foreach (int num in numbers) {
        sum += num; // Add each number to sum
    }
    return sum; // Return total sum
}
Output:
// Function to calculate sum of an array
function calculateSum(array) {
    return array.reduce((acc, cur) => acc + cur, 0);
}
// Function to calculate average of an array
function calculateAverage(array) {
    if (array.length === 0) return null; // No data to process
    let sum = calculateSum(array); // Calculate sum using the helper function
    return sum / array.length; // Calculate and return average
}
// Example usage
let array = [10, 20, 30];
let average = calculateAverage(array);

Tip 4: Leverage Project-Specific Details 

  • Tailor coding practices to the unique challenges and requirements of the project. 
  • Understand and incorporate project requirements or documentation including relevant details to guide new and current developers. 
  • Integrate specific business logic and requirements. 
  • Highlight how project-specific tools or libraries are used. 

Example .NET

Use case studies or specific project scenarios where these practices improved outcomes

Contextual Prompt:
Suggest code when you are typing comments “Give a managing users module by API in the website”
Output:
using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
public class UserManager
{
    private readonly HttpClient _httpClient;
    private readonly string _baseUrl;
    public UserManager(string baseUrl)
    {
        _httpClient = new HttpClient();
        _baseUrl = baseUrl;
    }
    public async Task CreateUserAsync(User user)
    {
        try
        {
            var response = await _httpClient.PostAsJsonAsync($"{_baseUrl}/users", user);
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadFromJsonAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error creating user: {ex.Message}");
            return null;
        }
    }
    public async Task GetUserAsync(int userId)
    {
        try
        {
            return await _httpClient.GetFromJsonAsync($"{_baseUrl}/users/{userId}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error retrieving user: {ex.Message}");
            return null;
        }
    }
    public async Task UpdateUserAsync(int userId, User user)
    {
        try
        {
            var response = await _httpClient.PutAsJsonAsync($"{_baseUrl}/users/{userId}", user);
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadFromJsonAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error updating user: {ex.Message}");
            return null;
        }
    }
    public async Task DeleteUserAsync(int userId)
    {
        try
        {
            var response = await _httpClient.DeleteAsync($"{_baseUrl}/users/{userId}");
            response.EnsureSuccessStatusCode();
            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error deleting user: {ex.Message}");
            return false;
        }
    }
}
public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

Tip 5: Provide Sample Code/Template Code 

  • Offer concrete examples and templates to guide developers in applying best practices within their projects. 
  • Regularly maintain a repository of code templates, sample modules, and configuration files that are updated and reviewed for relevance. 
  • Share reusable code templates for common tasks. 
  • Illustrate best practices in action within the sample code. 

Example Python

Prompt:
“Based on the function, write a test case to test” 

Full function

Input:
def calculate_average(numbers):
    if not numbers:
        return None  # No numbers to process
    total = sum(numbers)  # Sum the numbers
    return total / len(numbers)  # Return average
Output:
def calculate_average(numbers):
    """
    Calculate and return the average of a list of numbers.
    Parameters:
    numbers (list of float/int): The list of numbers to average.
    Returns:
    float: The average of the numbers, or None if the list is empty.
    """
    if not numbers:  # Check if the list is empty
        return None
    return sum(numbers) / len(numbers)  # Calculate and return the average

Focussed snippet

Input:
total = sum(numbers)
average = total / len(numbers)
Output:
def calculate_average(numbers):
    """
    Calculate the average of a list of numbers.
    Args:
        numbers (list): A list of numbers (integers or floats).
    Returns:
        float: The average of the numbers in the list. Returns None if the list is empty.
    """
    if not numbers:  # Check if the list is empty
        return None  # Return None to indicate no numbers to process
    total = sum(numbers)  # Sum the numbers
    average = total / len(numbers)  # Calculate average
    return average

Conclusion

While there has not been a formal case study regarding the evaluation of the efficiency of GitHub Copilot, anecdotal evidence suggests that its usage improved code quality and accelerates project timelines and was especially fruitful for category testing.  Developers were able to focus on creative solutions rather than repetitive coding tasks, resulting in an averaged updated happiness score. It however also became apparent that without a skilled developer interpreting the results, GitHub Copilot lost a lot of its shine. Deeming this pilot project a success, Infodation will now consider the company wide implementation of GitHub Copilot. 


Hung V. Nguyen
Hung V. Nguyen is a Software Engineer with extensive experience at Infodation (since June 2015), specializing in data science, machine learning, computer vision, and NLP. He has expertise in electronics, IoT, and QC automation, integrating smart systems for efficiency and precision. Skilled in AutoCAD and MS Office, he optimizes technical design, documentation, and workflows. With a multidisciplinary approach, he bridges software, hardware, and AI to solve complex challenges. In addition to his technical expertise, he has experience mentoring students and interns, providing training in AI, automation, and software development. Passionate about innovation, he leverages cutting-edge technology to drive efficiency and transformation. 

Get inspired


Commitment You Can Count On