Unleashing Efficiency and Creativity with GitHub Copilot

Unleashing Efficiency and Creativity with GitHub Copilot
Reading Time: 9 minutes

This article was co-authored with Harris Naseh and Nia Brown

Developers are always looking for ways to streamline their processes and overcome roadblocks. One challenge is the time-consuming effort of digging up syntax or struggling with the logic of what seem to be simple functions or methods. With the explosion of AI-powered software over the last year this seems like the perfect time to tackle this decades old problem. Fortunately, GitHub Copilot is a potent remedy that is available today. By giving developers an essential tool for overcoming these obstacles and speeding up their project initiation process, this AI-powered coding assistant is ready to transform the development landscape. 

GitHub Copilot is powered by OpenAI Codex which has been trained on billions of lines of code from publicly available repositories on GitHub. ChatGPT also uses OpenAI Codex, but the convenience of Copilot is that it is installed right in your code editors and provides suggestions in a more cohesive manner. Copilot analyzes the context in the file you are editing, as well as related files, and offers suggestions from within your text editor.

Setting Up Copilot with VSCode

By selecting the square “Extensions” icon in the left sidebar of Visual Studio Code or by pressing the keyboard shortcut Ctrl+Shift+X (Windows/Linux) or Cmd+Shift+X (Mac), you can access the Extensions view. Search “GitHub Copilot” and the extension should come right up. After installing, reload or restart VS Code if requested. You might be prompted to log in with your GitHub account after starting VS Code in order to get Copilot running. GitHub Copilot will smoothly integrate into your VS Code environment once it has been installed and authenticated. 

Unlike ChatGPT, there is no free version of GitHub Copilot – instead you are given the option of a 30-day trial after which you will be asked to pay $10 a month or $100 a year for individuals. VS Code is not the only code editor that supports GitHub Copilot: NeoVim, JetBrains Client, IntelliJ IDEA, and many more support the integration. 

Testing Copilot with the White Elephant Project

White Elephant is an app developed by Mission Data based on the game of the same name. Players put their gifts in a pile, and those gifts can be unwrapped or stolen during each player’s turn. We were tasked with making a number of changes to the app, and as we developed these new features, we used GitHub Copilot to get a good understanding of where it can be helpful. One of these features was related to user accessibility. While viewing the White Elephant webpage as a participant, you are unable to leave a game that isn’t active, as the only option is to “provide a gift” (assuming you haven’t already): 

Our goal was to make sure a participant can leave a game without canceling it for the rest of the participants. The idea is to discard the GameParticipant record that represents that player for that specific game.

We were able to find a way to allow a current_participant (the user that is viewing the page or clicks a button) to leave by creating a leave method in our games_controller. We found that Copilot was quite effective at interpreting our intent with the method via a comment, as it provided an accurate suggestion of how to handle leaving a game. As you can see in the image below, we first provided a comment about what the method should do, and Copilot was able to produce a suggestion complete with a name and basic logic. This suggested method even made use of the Discard Gem used elsewhere in the project, showing how Copilot was able to read the context of the surrounding app and adapt to it.

However, the suggestion was not perfect, as Copilot did not understand the relationships in the database. Specifically, Copilot did not understand that each participant has multiple game_participants, which represents each game that the participant is part of at a given time. To be fair, this required some investigation from us to figure out, which goes to show that the suggestions are just that, suggestions. Copilot does a great job doing the grunt work but should not be expected to do all the work perfectly. The developer is still responsible for understanding the context of the application and creating accurate code.

While Copilot was very helpful in directing us with the leave method, it was still our responsibility to make the other Rails changes to make this leave action functional. For one, a route needed to be added so that this new endpoint could be hit by the app. In config/routes.rb, we added the leave route as a games resource, as this endpoint is defined in the games_controller.

Finally, in the primary view file (_upcoming_games_list.html.erb), a few front-end adjustments were made. Embedded Ruby (ERB) conditional statements were extremely helpful in streamlining how different elements were displayed on the page. If the current participant didn’t have a gift (condition 1) and wasn’t the moderator (condition 2), the only options that would show in the actions tab would be “provide a gift” and “leave game”.

The next issue we wanted to address was the game being stalled by a player who is AFK. It’s been quite common that a user either disconnects or isn’t available. Currently, only that user can make their moves, so this causes the entire game to stall. This issue did not require the creation of a new method or function. Instead, we needed to add code to an existing method and frontend elements. 

Currently, the pick method in the game_controller.rb file is in charge of the logic of picking a gift. However, this method only allows the player whose turn it is to take an action. We added logic to accept input from the moderator even if it is not their turn yet. 

This was a simple fix, but GitHub Copilot did not offer many suggestions as it was not sure what we wanted to do. However, Copilot did make the process faster by seeing what method we were half-way through typing and offered a suggestion on how we would complete it. For example when we were typing @game.is_, intending to write @game.is_moderator(current_participant), Copilot correctly suggested that we enter current_participant as an argument. 

Now that we have the backend set up, we still need to present the buttons to the moderator in the frontend. This is what the UI looks like for the user whose turn it is to perform an action. This is not available to the moderator when it is not their turn. 

This is the code for the “Unwrap” button. The same structure applies to the steal button as well.

apply_to_participant_id takes a participant ID and displays the button to only that user. However, this does not take multiple arguments, so we made a different button to display for the moderator. We typed a comment over apply_to_participant_id to see if we would get a suggestion so the moderator would also see the action buttons. We did not get any useful suggestions from Copilot, as it just repeated “apply_to_participant_id: game.next_player&.participant&.id”.  

We then fetched the game’s moderator using the ActiveRecord find method. Once GitHub Copilot saw that we had a variable titled moderator, Copilot was able to correctly interpret our comment for setting apply_to_participant_id, and gave us the suggestion we went with.

The page now looks like this for the moderator.

We then needed a couple of if statements in the html.erb file to make sure the moderator doesn’t see both buttons when it’s their turn. Copilot was smart enough to know we needed a closing <% end %> tag, and correctly suggested where to close our if statements.

Another area we discovered Copilot to be particularly helpful is when refactoring code. Here, the output of the code does not change, but the methods or names we use might. We were tasked with changing a webpage to go from using HTML tables to display data to using Bootstrap, which can make a web app reactive to different display sizes.

Copilot was able to detect that we intended to refactor from an HTML table to a Bootstrap approach, and realized which parts of the <thead> and <tbody> we wanted to group together. At first, Copilot would only suggest small snippets, like shown in the image above. Once we moved to other files however, where there were many more rows in the table, it offered a suggestion where all items were already refactored, and we did not have to update them one by one.

GitHub Copilot has the ability to intelligently comprehend the context of a deleted section of code. We wanted to have every wrapped gift have a unique image if there were 12 or less gifts. Our method looked like this:

We deleted the entire method looking to start over, as it was pretty simple. After we typed our comment for the new random_wrapped_present_image, we noticed that Copilot suggested the same name for the method as the one we had just deleted. 

Copilot saw the comment prompt and understood that we wanted the same method and assumed we wanted the same name as well. Then Copilot provided a suggestion based on the comment above and got /images/present#{rand(1..12)}.svg from the deleted method. This is helpful because the method was being called in multiple files, and keeping the name the same helped avoid reacting to other files. The suggested code wasn’t quite right, but we were given a good foundation to build on.

How Helpful was Copilot?

Copilot has its strengths and weaknesses. In terms of its strengths, Copilot does a pretty good job at both interpreting and providing code suggestions based on a comment that is made within a file. For example, for the “AFK player” card, Copilot was used in app/controllers/games_controller.rb to allow a moderator to play for a participant. 

Initially, the only lines of code we typed were lines 119 and 120. After pressing return, Copilot began to generate an entire method of suggestions based on our comment prompt (lines 121-132). This suggestion was a slightly more generalized version of the final code we needed to switch control from the participant to the moderator. However, it puts us (somewhat) on the right track. After Copilot’s suggestion, line 123 was slightly altered so that the game participants were found by participant: current_participant

In terms of Copilot being able to help with larger tasks, it seems that a somewhat strong foundation is needed prior to using it as a tool. The AI tool can be helpful with generating the first steps to an issue, depending on how specific the prompt is and what file you are trying to integrate it with. For Ruby files, Copilot seems to have a pretty decent understanding of your goal based on your prompt, but also sometimes falls short in creating a function that can be deemed useful for code execution. For ERB files, Copilot seems to struggle more with generating code based on a specific prompt, especially if a similar line of code isn’t already in the file. It is important to note that some of these issues could be attributed to what languages Copilot is most (or least) proficient in. 

The impact of Copilot on the software development workflow may be seen in its capacity to automate time-consuming and repetitive coding operations, freeing developers to concentrate on more complex design and problem-solving elements. It enables seasoned engineers to increase their output and enables teams to produce software more quickly. A great tool for experienced developers aiming to further streamline their coding process, Copilot also promotes knowledge exchange by offering insights and best practices.

But it’s important to understand that GitHub Copilot is not intended for those who are just starting to learn programming. While it can be a great help to seasoned engineers, it may be difficult for newcomers to completely understand the subtleties of the code the tool produces. Copilot cannot replace the need to grasp essential ideas and lay a solid foundation when learning to code. Instead, it acts as an additional tool for those who are already familiar with coding.

GitHub Copilot has some drawbacks, like any technology, including the potential for bias replication and difficulties managing sophisticated reasoning. It is imperative for developers to exercise caution, carefully considering the code recommendations, and make sure the created code adheres to the specified functionality and security requirements.

New call-to-action