大家好,我是Edison。
近期我们一直在使用GitHub Copilot协助开发编码工作,总结了一些实际场景的用法,可能在目前网络中很多的博客中都没有提及到,本文一一分享给你。
GitHub Copilot 是一款 AI 结对程序员,可帮助您更快、更少地编写代码。它从注释和代码中提取上下文,以立即建议单独的行和整个函数。GitHub Copilot 由 GitHub、OpenAI 和 Microsoft 开发的生成式 AI 模型(CodeX)提供支持。它可作为 Visual Studio Code、Visual Studio、Neovim 和 JetBrains 等集成开发环境 (IDE) 套件的扩展。
GitHub Copilot具备什么样的能力?
自动创建函数、类、变量等代码结构
自动填充代码块、方法、函数
消除重复代码
基于自然语言编写的注释,自动生成可执行代码
对代码的语义进行理解和解读
对于像我一样的.NET程序员来说,我们主要使用Visual Studio 或 Visual Studio Code,你需要确保你的Visual Studio 2022版本在17.10即以上,然后即可安装GitHub Copilot扩展,十分方便!
这里,Edison使用的是公司的企业GitHub订阅账号登录使用的,你可以通过自行购买订阅,个人版是10美刀一个月,100美刀一年。
在实际使用中,代码补全(Code Completion) 和 内联对话(Inline Chat) 我用的比较多,但很多时候需要借助提示词工程(Prompt Engineering)的场景,我们会使用 对话窗口(Chat Window)更多一些,下面的场景也更多会使用对话窗口来实现。
好了,废话就不多说了,下面我们进入一些我所学习和实践到的一些实际场景,看看一些你可能在其他中文博客中没有见过的用法,建议收藏!
在实际使用中,借助Copilot来做Code Review是一件特别容易得事儿。而且强烈建议在每个Team内部建立一个Code Review的标准提示词,以便在每个成员的项目中可以使用同一个标准。我们的实践是建了一个针对SDLC(软件开发生命周期)的提示词git仓库,大家共享同一个仓库中的提示词,并可以及时做修改和完善做版本管理。
一个Code Review的Prompt示例,你只需要将需要进行Review的代码方法选中或将其所在文件保持打开的状态,然后将下面的prompt发给Copilot即可:
I would like you to code review this code. Can you offer me any suggestions on how I could improve it? Focus on: - Correcting security concerns in the code. - Correction of code smells. - Offer advice on improving performance if possible. - Offer advice on improving code maintainability if possible. - Correct logical errors in code.
NOTE:由于我们日常工作中使用英文较多,所以提示词也用的英文。不过,我会对这些提示词做一些解释,方便你理解。后续不再赘述,谢谢!
对于Code Review,最重要的就是告诉Copilot它需要关注哪些方面的内容,比如上面的prompt中我们告诉它需要关注代码安全风险、代码坏味道、可维护性、逻辑错误等等。你可以根据你团队的需要,更改这些关注点,以适配你团队项目的需求。
此外,在很多团队中,都建立了一些自己的代码标准规范的文档,我们也可以修改上面的prompt,让Copilot参考这个文档(比如markdown文件)给出Review建议,以符合团队之前就定义好的代码规范。
I would like you to code review this code in #editor to ensure it follows our team's coding standards in #file:Your-Team-Coding-Standard.md, adheres to security best practices, it well-documented, and is written to be maintainable and performant.
在上面的prompt中,我们使用了#file指令告诉Copilot需要参考的markdown文件(即已有的代码规范文档),这样Copilot会参考已有的规范文档侧重点给出更准确的建议。但是,准确度的保证是依赖于你的代码规范文档的内容是否严格按照markdown格式编写,以及内容的完整程度是否较好。
在实际使用中,借助Copilot来做Code Translation(代码翻译)也很容易,比如在一些大型的金融企业,往往存在一些使用上古编程神器(如cobol)编写的系统,当你想把他们用高级编程语言来改写的话,使用Copilot来做翻译就会省下很多effort。
假设有一个csv-reader.cobol文件如下:
IDENTIFICATION DIVISION. PROGRAM-ID. CSV-READER. DATA DIVISION. FILE SECTION. FD CSV-FILE. 01 CSV-RECORD. 05 CSV-FIELD PIC X(100). WORKING-STORAGE SECTION. 01 WS-EOF PIC X VALUE 'N' 01 WS-DELIMITER PIC X VALUE ',' PROCEDURE DIVISION. MAIN-LOGIC. OPEN INPUT CSV-FILE. PERFORM UNTIL WS-EOF = 'Y' READ CSV-FILE AT END MOVE 'Y' TO WS-EOF NOT AT END DISPLAY CSV-FIELD END-PERFORM CLOSE CSV-FILE. STOP RUN.
我们只需要简单地告诉Copilot:
Can you convert this code into Python for me?
它就会快速地用Python实现对应cobol代码:
import csv def main(): # Open the CSV file with open('csv_file.csv', mode='r', newline='') as csvfile: csv_reader = csv.reader(csvfile) # Read and display each row in the CSV file for row in csv_reader: print(','.join(row)) if __name__ == "__main__": main()
举一反三:假设你有一个Angular写的前端组件,想用React来改写,也只需要告诉Copilot即可,例如:
Can you show me how to rewrite the Angular components #file:settings.component.html using React?
需要注意的就是使用#file指令告诉Copilot你需要改写的组件代码作为上下文。
编写单元测试可能是我们使用Copilot干的最多的事儿了!如果你的应用是基于面向接口的设计原则实现的,并且所有依赖的对象都是可以Mock的,那么我们分享一个在Copilot中的prompt模版给你,你可以根据这个模板来改写其中的一些规则来适配你的项目需要:
Please help to write unit tests for the method {methodName} in #attachFile, and its reference interfaces are #attachFiles. Please follow the rules below: 1. Follow "MethodName_TestScenario_ExpectedResult" naming standard. 2. Please use Arrange-Act-Assert mode in your code. 3. Please take the catch part code into consideration if there's try-catch in the method. 4. Please use MockPackage in your code, you can study it from #XXXXServiceTests. 5. Please use xUnit and Moq as default test frameworks in your code. 6. Please use Errors.Code.Name to compare in assert code if there's a custom exception, for example Assert.Equal(Errors.Common.UnexpectedException.Name, result.ErrorMessage.Name); 7. Don't need to explain any code, just write the code directly. If there's some issues, user will give you feedback.
这个prompt指定了需要Copilot为哪个file中的哪个方法些单元测试,还告诉了这个方法依赖的接口定义是哪些,这就给Copilot提供了一个上下文。同时,通过指定7个规则,让Copilot知道它的输出会有什么样的约束条件,比如使用xUnit和Moq框架、使用Arrange-Act-Assert的模式、使用“方法名_测试场景_测试结果”的命名规范 等等。你完全可以根据你自己的需要,改写其中一些你不需要的规则 或者 增加一些你需要的规则!
在做系统的自动化测试 或 集成测试时,我们往往都需要先生成一些测试数据,这个生成的过程其实也比较原始。有了Copilot之后,我们也可以让它来帮我们做这个事儿。
比如,让Copilot迅速生成一个csv的测试数据集:
I'd like some test data for my music collection management library, can you generate a CSV containing 10 Hip Hop Artists. Include the following Columns: Name, Album, Year of Release.
那么,Copilot会生成一个csv格式的数据如下所示:
Name,Album,Year of Release Kendrick Lamar,good kid, m.A.A.d city,2012 J. Cole,2014 Forest Hills Drive,2014 Drake,Take Care,2011 Kanye West,The College Dropout,2004 Nas,Illmatic,1994 Jay-Z,The Blueprint,2001 Eminem,The Marshall Mathers LP,2000 OutKast,Stankonia,2000 A Tribe Called Quest,The Low End Theory,1991 Wu-Tang Clan,Enter the Wu-Tang (36 Chambers),1993
又如,让Copilot迅速生成一些SQL脚本用于INSERT测试数据:
I'd like some test data for my music collection management library, can you generate a sql file containing 10 MSSQL Insert statements of Hip Hop Artists. Include the following Columns: Name, Album, Year of Release.
那么,Copilot则会生成一些INSERT语句让你可以快速插入数据表:
INSERT INTO MusicCollection (Name, Album, YearOfRelease) VALUES ('Kendrick Lamar', 'good kid, m.A.A.d city', 2012); INSERT INTO MusicCollection (Name, Album, YearOfRelease) VALUES ('J. Cole', '2014 Forest Hills Drive', 2014); INSERT INTO MusicCollection (Name, Album, YearOfRelease) VALUES ('Drake', 'Take Care', 2011); INSERT INTO MusicCollection (Name, Album, YearOfRelease) VALUES ('Kanye West', 'The College Dropout', 2004); INSERT INTO MusicCollection (Name, Album, YearOfRelease) VALUES ('Nas', 'Illmatic', 1994); INSERT INTO MusicCollection (Name, Album, YearOfRelease) VALUES ('Jay-Z', 'The Blueprint', 2001); INSERT INTO MusicCollection (Name, Album, YearOfRelease) VALUES ('Eminem', 'The Marshall Mathers LP', 2000); INSERT INTO MusicCollection (Name, Album, YearOfRelease) VALUES ('OutKast', 'Stankonia', 2000); INSERT INTO MusicCollection (Name, Album, YearOfRelease) VALUES ('A Tribe Called Quest', 'The Low End Theory', 1991); INSERT INTO MusicCollection (Name, Album, YearOfRelease) VALUES ('Wu-Tang Clan', 'Enter the Wu-Tang (36 Chambers)', 1993);
在做一些小的系统运维的任务时,通常会需要使用到类似PowerShell这样的命令行工具,但不是每个人都对Powershell比较熟悉。
有了Copilot之后,我们就可以借助Copilot在Visual Studio Code中的集成,来快速使用Copilot帮我们生成对应的命令,例如我想要一个快速找到当前目录中所有以.md结尾的markdown文件的命令,我可以直接在VS Code中的Terminal中直接以Inline Chat的方式快速提问:
对于一些新手的Product Owner或者没有IT技术背景的朋友在承担Product Owner或者Business Analyst角色的工作时,编写用户故事和拆分任务是一件具有较大挑战的事情。
有了Copilot之后,我们或许也可以借助Copilot来帮我们生成初稿。例如,假设你是一个Product Owner,你有一个了解到的feature(功能)是给某个电商系统做一个购物车的功能,你可以这样告诉Copilot让它给你一个初稿,逐步完善:
I'm working on a feature for a shopping cart in an e-commerce application. The feature should allow users to add items to their shopping cart, view the items in their cart, and remove items from their cart. The shopping cart should keep track of the total cost of all items in the cart. Can you provide me with a user story and associated tasks for this feature?
这时,Copilot可能会给你一个如下所示的初稿,有模有样的:
User Story Title: Shopping Cart Management As a user of the e-commerce application, I want to manage my shopping cart by adding, viewing, and removing items, so that I can keep track of the items I intend to purchase and their total cost. Associated Tasks Add Items to Cart Task: Create a function to add items to the shopping cart. Sub-tasks: Define the data structure for the shopping cart. Implement the logic to add an item to the cart. Update the total cost of the cart when an item is added. Validate that the item being added exists and has sufficient stock. View Items in Cart Task: Create a function to view items in the shopping cart. Sub-tasks: Implement the logic to retrieve and display all items in the cart. Display the total cost of the items in the cart. Ensure the cart view updates dynamically as items are added or removed. Remove Items from Cart Task: Create a function to remove items from the shopping cart. Sub-tasks: Implement the logic to remove an item from the cart. Update the total cost of the cart when an item is removed. Validate that the item being removed is in the cart. Calculate Total Cost Task: Ensure the shopping cart keeps track of the total cost of all items. Sub-tasks: Implement the logic to calculate the total cost when items are added or removed. Display the total cost in the cart view. Ensure the total cost is accurate and updates correctly. Testing Task: Write unit tests for all shopping cart functionalities. Sub-tasks: Test adding items to the cart. Test viewing items in the cart. Test removing items from the cart. Test the accuracy of the total cost calculation. Error Handling Task: Implement error handling for shopping cart operations. Sub-tasks: Handle cases where an item to be added does not exist or is out of stock. Handle cases where an item to be removed is not in the cart. Display appropriate error messages to the user. Acceptance Criteria Users can add items to their shopping cart. Users can view all items in their shopping cart along with the total cost. Users can remove items from their shopping cart. The total cost of the shopping cart is accurately calculated and displayed. All functionalities are covered by unit tests. Appropriate error messages are displayed for invalid operations.
如果你想的是BDD(行为驱动开发)风格的描述,也可以给到Copilot反馈:
BDD Syntax for Shopping Cart Feature Feature: Shopping Cart Management As a user of the e-commerce application, I want to manage my shopping cart by adding, viewing, and removing items, so that I can keep track of the items I intend to purchase and their total cost. Scenario: Add Items to Cart Given I am on the product page, When I click the "Add to Cart" button for a product, Then the product should be added to my shopping cart, And the total cost of the cart should be updated. Scenario: View Items in Cart Given I have items in my shopping cart, When I navigate to the shopping cart page, Then I should see a list of all items in my cart, And I should see the total cost of the items in my cart. Scenario: Remove Items from Cart Given I have items in my shopping cart, When I click the "Remove" button for an item, Then the item should be removed from my shopping cart, And the total cost of the cart should be updated. Scenario: Calculate Total Cost Given I have items in my shopping cart, When I add or remove items from the cart, Then the total cost of the cart should be accurately calculated and displayed. Scenario: Handle Adding Non-Existent or Out-of-Stock Items Given I am on the product page, When I try to add a non-existent or out-of-stock item to the cart, Then I should see an error message indicating the item cannot be added. Scenario: Handle Removing Non-Existent Items from Cart Given I am on the shopping cart page, When I try to remove an item that is not in the cart, Then I should see an error message indicating the item cannot be removed. Scenario: Display Error Messages for Invalid Operations Given I perform an invalid operation on the shopping cart, When the operation fails, Then I should see an appropriate error message explaining the failure.
当有了User Story 和 Task 后,我们开发者可能会先做一定的设计,有了一个初步的规划,同时结合已有代码的相关规范和风格,我们就可以开始编码了。
而有了Copilot之后,简单一点的重复性开发编码工作,或许就可以丢给Copilot来实现。这个场景中,我们把自己定义为Senior Developer,而把Copilot看成自己的小弟(Junior Developer),你在现实场景是如何指导小弟给你分担开发任务的,是不是也需要一步一步告诉他详细的需求 和 参考代码,那么,对待Copilot,你也需要像这个样子!
这里,分享一个所谓的Code Blueprints的模式,通过User Story, Code Standards 以及 最后的Prompt 三位一体,来让Copilot帮我们快速实现一个功能原型。
首先,将User Story文件(假定为user-story.md)也放到解决方案中,建议放到Git仓库中的Document文档目录中。这里主要是把Goals(目标)说清楚,这一步很重要!
# Story Description As a user of my web application, I want to be able to register with my email address and a password. My username will be my email address. The username and password should be persisited to my database so that I can login once I have successfully confirmed my email address is active. ## Goals 1. A new API for the users registration should be created in a Controller called UsersController. Logic should be kept out of the UsersController. 2. The Controller should use IOperationExecutor to send a request object and receive a response. 3. The API should have a method called Register that takes in the following object: ``` { "userName": {SomeUsername}, "password": {password} } ``` 4. Password should be encrypted using BCrypt before being saved to the database dbo. 5. All data access should occur within a repository layer, and Entity Framework should be used. 6. The dbo.Users table should be checked to make sure the userName is unique before added. 7. Username and password are required fields. 8. dbo.Users table has the following structure: ``` UserId: int PK UserName: varchar(50) Password: varchar(50) DateAdded: Today's date. ```
其次,编写一个blueprint文件(假定为blueprints-api.md),把API任务需要参考的代码标准 和 已有代码参考示例 定义清楚,如下所示:
# Outline This blueprint describes the patterns that should be followed when generating a new API and the corresponding business Operation. ## Standards 1. New Controllers should be named appropriately to describe the business process. 2. Controller should be named using pluralized nouns. 3. API methods in Controllers should be named using nouns. 4. Controllers and methods should have block level comments. 5. The Controllers should use IOperationExecutor to send a request object and receive a response. 6. Request objects should implement IRequest<T>, where T is the response object type. 7. Database data access should be done using Entity Framework in a Repository. 8. FluentValidation should be used to generate validation rules for all request objects. 9. Provide examples of DI registration changes needed in Startup.cs for new dependencies. ## Coding Standards Use the following files as example for how you should generate this code: - [./References/MoviesController.cs](MovieController.cs) - [./References/CreateMovieHandler.cs](CreateMovieHandler.cs) - [./References/CreateMovieRequest.cs](CreateMovieRequest.cs) - [./References/CreateMovieResponse.cs](CreateMovieResponse.cs) - [./References/CreateMovieRequestValidator.cs](CreateMovieRequestValidator.cs) - [./References/MovieRepository.cs](MovieRepository.cs) - [./References/IMovieRepository.cs](IMovieRepository.cs)
在实际场景中,建议将各自开发模板中的典型代码整理一下,形成一个给Copilot参考学习的最小文件夹目录。
最后,编写prompt,并将这个prompt最终发给Copilot:
Please generate the code that satisfies the goals in #file:user-story.md using the #file:blueprints-api.md as a guide.
可以看到由于前期的工作(user-story 和 blueprint-api)比较充分,在prompt阶段就只需要指明参考这两个文件(以user-story.md为准满足其定义的目标,以blueprint-api.md为准满足其定义的规范和风格要求)去生成code就行了。
本文简单介绍了GitHub Copilot在Edison所在公司的一些实际应用场景,在对开发者的辅助方面起到了一些实质性的帮助,特别是Code Review 和 Unit Test方面,已经是完全采纳Copilot生成的代码作为单元测试了。
相信,随着使用的深入,我们会总结更多地实际场景案例模板,以帮助我们所在团队的开发者得到更大的解放,从而可以更多参与到AI Agent的转型探索之中。
本文示例工具:Visual Studio & Visual Studio Code + GitHub Copilot