Skip to content

ArctiqTeam/copilot-deep-learning-labs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Lab 1: Development Use Cases

Prerequisites

To participate in this lab you will need to have one of the following IDEs setup and ready for use:

Additionally, your chosen IDE should have the necessary Copilot extension installed and authenticated to work with your GitHub account.

Runtime Environment

The primary example in this repository for this lab is written in C#. As such, you will need to install and be able to run the ASP.NET 9.0 Framework.

Development Tools

Acquiring the code can be accomplished via GitHub as a compressed archive or using git.

Lab Source Code

In order to work from the same source code as in this lab, you will need to either have this repository checked out from GitHub or have downloaded the Archive file for the appropriate stage of the lab.

Estimated time

  • 45 minutes

Objectives

In this lab we are going to talk about how to use Copilot to get the most out of it. We are going to learn how to use Github Copilot for common development use cases. We are going to look at how to do these things and how to sidestep some of the challenges you might experience while using Copilot.

  • Common problems and solutions
  • Explaining code and errors
  • Writing documentation
  • Adding a feature to the codebase

While learning about doing these things we will talk about improving the output of Copilot both by applying the prompt crafting methods previously discussed and the best-practices when encountering issues like:

  • Missing or changed elements of code
  • Hallucinations
  • Incomplete or naive implementations
  • Stalling and repetitive answers

Step 1 - Common Problems and Solutions

First, a little more theory. Based on the prompts you have crafted and fed into Copilot, or the amount of code you are working with, you may or may not get the results you wanted. There are a number of ways in which Copilot's answers can fall short of expectations. Commonly you may see it:

  • stall on autocomplete
  • repeat itself
  • deviate from existing code in answer
  • omit or hallucinate content
  • provide an obsolete or dated answer
  • give a naive or inefficient solution
  • retract an answer that matches public code

Copilot Stalls on Autocomplete

  • It can happen that Copilot does not autocomplete when it seems clear to the user that they are pausing for a suggestion. The simple fix here is to give it a little push by starting either a comment or a method and it should trigger copilot.

Copilot Repeats Itself

  • It can also happen that Copilot will regenerate the same content over and over again as if it has forgotten that it just gave that code. This is a form of hallucination error and does illustrate why copilot is not in the driver's seat. It requires an experienced user to scrutinize the suggested code and decide if it should be incorporated into the codebase or if more context is required.

Deviates from Existing Code in Answer

  • As the developer you must carefully review the code provided by Copilot as the full example, if given, may not be an appropriate replacement for the code in place. Copilot may have chosen to change the implementation slightly from what is currently in place. This may be ok or you may wish to not allow your logic to drift away from its familiar form especially if the affected code is not part of the changes you are making. You can ask copilot to avoid changing the original code as much as possible or only show the changed code. It is, in any event, advisable to carefully review suggestions to make sure they agree with your codebase before replacing. Also, ensuring the releavant files are in scope of Copilot Chat when the prompt is given can help keep Copilot on track.

Omits or Hallucinates Content

  • Copilot might refactor variable names in its answer. It is not clear why it does this nor why it might omit statements that exist in your method body but, again, this outlines why user review of all suggestions are necessary. An inability to understand the answers given by Copilot are a recipe for a quagmire of code that does not work.

  • Copilot might also omit a large body of code that appears in the answer to simplify the answer and draw your attention to the changed code. In all cases you need to understand what you are accepting into your codebase from Copilot.

Provides an Obsolete or Dated Answer

  • By virtue of the fact that the model Copilot was trained on has a cutoff date, this means that some answers may be inaccessible to Copilot. In these cases, familiarity with the newer components and frameworks will be essential for the developer to provide that oversight.

Gives a Naive or Inefficient Answer

  • Copilot may answer a tricky question with a simple, effective, but inefficient answer. It often finds an answer that meets the objectives but if efficiency isn't a stated goal in the prompt, it may not prioritize that and the developer will need to re-request that the answer be optimized in the way they desire. The lesson is that you cannot assume Copilot will always choose the optimal solution-- its goal is to meet the prompt and if efficiency isn't specified it might settle on the simplest answer.

Retracts an Answer that Matches Public Code

  • One setting in your GitHub account or Organization is the toggle that Copilot will filter results that match public code. This means that if it generates an answer that happens to match a public code solution for the same thing it will retract the answer. This can be very frustrating and actually fairly common. The simple solution to this is to add to the prompt the phrase "Do not match public code." This informs Copilot that it should attempt to originate a new answer specifically avoiding a public code match. It really works.

Keep these practices in mind when submitting prompts to Copilot. You will see many of these issues.

Step 2 - Explaining Code and Errors

  • Perhaps one of your first forays into using Copilot will be to use it to gain a basic understanding of a codebase or segment of code that is unclearly documented or otherwise unfamiliar to you. It just so happens that we have a project from which to start such an exploration. The first "command" we can use to focus the intent of our prompt is the /explain command. This informs Copilot that the desire is for a specific kind of response focused on a detailed explanation of the selection, file, or message.

  • You can trigger an inline request for code explanation by pressing the hotkey that opens Copilot inline and issuing the command /explain along with additional prompt cues.

    Prompt to explain code inline in VSCode

    Figure 1: Prompting to explain inline in VSCode

  • You can, of course, prompt from an inline location or using the Copilot Chat sidebar. This can be helpful if the program logic is not very clear or unnecessarily convoluted.

    Prompt to explain a method inline in JetBrains Rider

    Figure 2: Prompting to explain a method inline in Rider

  • The /explain keyword can be used to help understand cryptic error messages returned by the runtime or the build process. In VSCode the Copilot Chat can be directed to access @terminal with the keyword /explain to review the error output.

    Prompt to the VSCode terminal for explanation of a build warning

    Figure 3: Requesting an explanation in VSCode to a build warning in the terminal.

  • In IDEs that do not support the @terminal agent, you can cut-and-paste error messages into the chat window to include as part of the prompt.

    Prompt to JetBrains Rider for explanation of a build warning

    Figure 4: Requesting an explanation in JetBrains Rider to a build warning.

Step 3 - Writing Documentation

  • In terms of documentation, Copilot can relieve a lot of tedium. Copilot can generate documentation for you and it can adopt your particular style of documentation given enough examples to work from. So write a few comments yourself and Copilot will resume in a consistent way. The special command for this activity is /doc.

  • If starting without any existing examples, it can be helpful to refer to a standard style.

    Initialize Documentation from Standard reference

    Figure 5: Starting documentation (VSCode)

  • Once you have an example, Copilot can pick up the hint. Your inline suggestions should align with other examples:

    Inline Commenting Suggestions

    Figure 6: Inline Commenting Suggestions

  • Another trick to use when generating documentation is to ask Copilot to create Mermaid.js diagrams. In this way you can have quick diagramming of Entity-Relationships, Classes, Interactions, etc. (See Example Diagrams) You will need to have an extension in your IDE that supports Mermaid diagrams to view them.

    Requesting an entity-relationship diagram

    Figure 7: A request for a mermaid-based entity-relationship diagram.

  • The following is an example of a Mermaid diagram that Copilot generated for the chessweb application:

    erDiagram
    GameState {
        Board Board
        PieceColor CurrentTurn
        bool IsGameOver
        Position LastMoveFrom
        Position LastMoveTo
        string FEN
    }
    
    Board {
        Piece Squares[8x8]
    }
    
    Piece {
        PieceColor Color
        Position Position
        PieceType Type
        string ImagePath
        char Symbol
    }
    
    Pawn {
        char Symbol
    }
    
    Queen {
        char Symbol
    }
    
    Position {
        int Row
        int Column
    }
    
    GameState ||--|| Board: contains
    Board ||--o{ Piece: contains
    Piece ||--|| Position: has
    Pawn ||--|| Piece: inherits
    Queen ||--|| Piece: inherits
    
    Loading

Step 4 - Adding a Feature to the Codebase

Setting the Stage

To begin this part of the lab, you need to get the codebase branch set to this lab portion:

git switch lab1-1-development-use-cases-add-fen-box

The ChessWeb Codebase

  • Our example application is called ChessWeb. It is a simple Web Application designed to have just enough complexity in its function to be an interesting target for Copilot work. It can be found in the repository under chessweb-cs (C#), chessweb-node (NodeJS), and chessweb-java (Java).

  • This sample application is far from a complete Chess-playing interface. In fact, all it does is to provide a view of a chessboard that allows turn-based moves to be entered with very basic piece rules applied. It serves as a basis for extension using Copilot. If you don't have knowledge of or interest in Chess, don't worry, no expertise is required to participate in this part.

  • Let's take a look at what we have:

  • We can start the application by entering the chessweb-cs directory and running it.

    cd chessweb-cs
    dotnet run
  • If successful we can now open a browser to the URI http://localhost:5111 and see something like this:

    Application Startup View

    Figure 8: Application Startup View

  • In this view we can see a familiar chessboard with pieces set up for the beginning of a game. There is a button that can be used to reset the position. The board is labeled on the ranks and files: ranks are labeled 1-8 and files are labeled a-h. Finally, there is a turn indicator to the right of the board that will display which side and which colour is due to play.

About the Chess FEN Notation

  • A reasonable feature to add is a display of the current board position in a standard text-based representation known as Forsyth-Edwrads Notation or FEN. This is a text encoding that can be used to rebuild a Chess position and represent the current game state in both a human and machine-readable fashion. You can read more about FEN here.

As a simple visual explanation of the encoding, see the below diagram which identifies several example chess ranks (rows) with the corresponding FEN portion. (Source: Chess.com)

fen_cheatsheet

The rules are simple:

  • black pieces are represented by lowercase letters r,n,b,q,k,p
  • white pieces are represented by uppercase letters R,N,B,Q,K,P
  • a chess board has coordinates from a1-h8 with a1 being on the bottom right
  • each rank is represented in FEN from top to bottom 8->1 and left to right (a-h)
  • sequential empty squares are grouped and given a number for the size of the gap
  • There are some additional facts about the board position given at the end of the FEN as:
    • side to move next (w or b)
    • castling rights remaining (kingside and queenside for each player)
    • en-passant target square (if applicable)
    • current half-move clock
    • current move number

We won't bother with the addtional facts yet as they do not affect our ability to add the simple FEN feature.

Planning the changes

There are a number of ways to begin this work. Here I present two paths:

  1. An Holistic Approach: Ask copilot to solve it all at once
  2. A Systematic Approach: Apply some knowledge of the application and target our changes

Option 1: An Holistic Approach (Step 4a)

One way could be to ask Copilot to do all the heavy lifting for us. Sometimes this can work but the more complicated your codebase, the dicier this becomes. Such an holistic approach might look like this:

Step 4a-1: Prompting for the whole answer
  • I will give Copilot a suitable prompt to begin this change:

    add-FEN-box-prompt

    Figure 9: VSCode FEN Prompt with workspace specifier

    Note: The above image includes use of the @workspace context specifier which (at the time of this writing) is only supported in VSCode.

    To get Copilot to expand its context to include your workspace you should eliminate distracting open files from the context (by closing all open files in the editor) This will ensure Copilot will widen its context for the following prompt.

    To clarify, if you have an file open in the editor when you issue the above prompt, Copilot will constrain its answer to that file. You can confirm this at the end of the output:

    using-one-ref

    Figure 10: Limited context indication.

    The answer from copilot will include changes to the in-context files only. Depending on the change you want to make and your familiarity with the codebase, you may wish to increase the context or constrain it in this way.

    In our case, we will close all open files in editor windows and issue this prompt.

    Let's extend this interface to display the current board position as 
    Forsyth-Edwards Notation (FEN). This should take the form of a text 
    input box below the chessboard with the current FEN string of the board 
    position that gets updated as pieces are moved on the board.
    

    And, again, if using VSCode, you can choose the @workspace specifier to increase the scope explicitly. In which case it doesn't matter if there are open files, it will expand its context.

  • We can expect a reponse similar to this from our prompt:

    cs-app-add-fen-response

    Figure 11: A response from Copilot to our prompt

  • Of course the response from Copilot will come with code as well. Any code that comes out of this will need to be reviewed and integrated into your codebase.

Step 4a-2: Applying the HTML update
  • The first suggestion should have been to add an element to the chessboard view to house the FEN string display. You can compare to this example and apply as needed.

    cs-app-add-fen-container-code

    Figure 12: Code to add to index.cshtml for FEN container

    Note that the name of the CSS class for the FEN container may not have been in context (it's defined in webroot/css/chess.css) and not named correctly in the Copilot response. Just ensure it's named like the above and you're good to go.

    If your answer does not specify where to put the element, put it on line 58 just after the div labeled "game-controls".

Step 4a-2: Updating the GameState
  • The second suggestion should be to update the Game State with the FEN string.

    cs-app-vscode-fen-prompt-answer-step2

    Figure 13: Update Game State step

    Note that the above does not include the full code output from Copilot. You will have to integrate the suggestion into your code as needed.

Step 4a-3: Updating the GameController
  • The third suggestion should be to update the GameController.

    cs-app-vscode-fen-prompt-answer-step3

    Figure 14: Update Game Controller code step

Step 4a-4: Updating the Index Javascript
  • The fourth suggestion should be to update the index.cshtml for the game view when pieces are moved

    cs-app-vscode-fen-prompt-answer-step4

    Figure 15: Update index.cshtml for piece move

Step 4a-5: Correcting an oversight
  • At this point, if you've been making the changes as suggested by Copilot, you may have noticed that there's a problem. The Game State change included a call to a method called GenerateFEN but the Board class does not have this method. Alternatively, Copilot generated the answer correctly and you have a step 5 that does include it. In my case, it didn't happen. This is part of the reconciliation of Copilot answers. My response is to prompt Copilot to complete its answer:
Your answer was missing the GenerateFEN method referenced in GameState. Can you fix this?

Note: These steps include an implementation of the GenerateFEN in the Board.cs class. While this is fine and does work, a better location for this method is in the GameState class itself. Copilot may have simply suggested this approach and if you applied such a change, go with it.

  • Now Copilot has a multistep answer for us:

    cs-app-vscode-fen-supp-ask-step1

    Figure 16: The first step of the supplemental prompt

    This change should include the missing GenerateFEN method to insert to the Board class.

  • The second change we need to apply is to expose the CurrentTurn member property in the Board class.

    cs-app-vscode-fen-supp-ask-step2

    Figure 17: Step to expose the CurrentTurn member in the Board class

  • The third and final change is to

    cs-app-vscode-fen-supp-ask-step3

    Figure 18: Instructions to set CurrentTurn in Board class.

  • After applying these changes we can run the app and confirm the new feature has been added:

    dotnet run

    cs-app-lab1-1-fen-update-done

    Figure 18: The UI now shows the FEN and is refreshed when board state changes.

This concludes the set of changes using the holistic approach. You're done!

Option 2: The Systematic Approach (Step 4b)

Alternatively, we might choose to attack this problem more directly as we have some familiarity with the codebase already and have ideas of our own where changes should be made. We're not asking Copilot to think for us so much as speed up the development effort.

What we know about the chessweb-cs app:

  • It has a Piece class with specific implementations for each chess piece
  • It has a Board class to track the movement of pieces on the board
  • It has a GameState class to track the state of each game
  • A Controller class to interface between UI and backend
  • An HTML and javascript view to display the game.
Step 4b-1: Modifying GameState

We inspect our GameState class because it seems to be the highest level object before the handoff to the UI. Logically, it should be responsible for the representation of the FEN because it has access to the Board data as well as the additional information about player turns that aren't stored in the Board itself.

We find there isn't any method presently that does this so we find a likely place to start and prompt Copilot.

Inline Prompt for generateFEN

Note: In the Various IDEs you can trigger inline suggestions and prompting with:

OS IDE Inline Suggest Inline Prompt
Win VSCode Alt+\ Ctrl+Enter
Win Rider Alt+\ Ctrl+Shift+I
Win Visual Studio Alt+\ Ctrl+Enter
OSX VSCode Option+\ Cmd+I
OSX Rider Option+\ Ctrl+Shift+I

Figure 19: Prompting within the Inline Copilot Prompt Window

We can choose to forego this even and create a comment that will spark Copilot into action:

Inline Comment prompt for GenerateFEN

Figure 20: Prompting within a comment

We should scrutinize the answer and make sure the method generated is going to work with our existing code. One thing the watch for here is how the FEN character is determined. If we didn't specify that the Piece.symbol should be used, we might have Copilot trying to invent a method to get the FEN Char and no such method exists anywhere here.

It might be necessary to correct the code we got. If so, we can simply highlight the problem code and use our hotkey to bring up Inline prompter:

cs-app-vscode-inline-symbol-correction

Figure 21: Correcting the symbol assignment

Once we have the GenerateFEN method we need to use it within the class. There are a couple of places where we need to update the class:

  • In the constructor
  • When pieces are moved
  • When the board is reset

So we should add a call to update the FEN property in each of these cases.

cs-app-vscode-inline-reset

Figure 22: adding the call to GenerateFEN()

When we're happy we can move along. We now have a GameState that updates itself when events affecting the board position are triggered.

Step 4b-2: Modifying GameController

The next change we need to make is to the GameController class. This conveys changes in the backend to the frontend. It also has a "Move" action will be called when the UI processes a piece move event. The important part of this component is that it returns the FEN string to the UI once the change has been made. We need to make sure it does this.

At the end of the IActionResult Move method we return a message and this needs to contain the FEN string.

cs-app-vscode-inline-controller

Figure 23: Prompting to update the successful move return action

Step 4b-3: Updating the UI components

Finally, we need to update the UI itself. The Views/Game/index.cshtml holds the chessboard view and it a little more to get our hands around because it's a mix of HTML and javascript. We also don't want to hunt around for exactly where to put this new code in so we can select all the code and trigger the inline prompter with our hotkey.

cs-app-vscode-inline-index

Figure 24: Prompting to update the index.cshtml

This should result in some in place replacements that cover both the FEN box and the javascript action that affects it. Apply those changes, save, and run.

At this point you should have a running version of the chessweb application that updates its FEN string after every move.

Congratulations you've completed it! πŸŽ‰

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published