Skip to main content

使用 GitHub Copilot 实现旧代码现代化

Copilot Chat 通过建议代码重构和创建用于捕获潜在问题的测试来帮助实现旧代码的现代化。

Note

本文中显示的响应是示例。 Copilot Chat 响应是不确定的,所以你可能会得到与这里所显示的不同的响应。

旧代码是指旧版、过时或不再受原始开发人员支持的代码。 此类代码很难维护和扩展,因为它可能不遵循新式最佳做法,例如使用一致的命名约定或编写清晰明确的文档。

实现旧代码现代化可帮助你:

  • 提升性能和可伸缩性。
  • 使代码更易于维护和扩展。
  • 降低在进行更改时引入 bug 的风险。
  • 使代码更易于测试。

Copilot 可以通过以下方式帮助你实现旧代码现代化:

  • 提供重构代码以遵循新式最佳做法的建议****。
  • 生成文档以帮助了解代码的工作原理****。
  • 生成测试以帮助验证更改是否未引入 bug****。

示例方案

在此示例中,我们将查看用 COBOL 编写的帐户管理系统并将其现代化为 Node.js。 可以在 modernize-legacy-cobol-app 存储库中找到 COBOL 代码。

帐户管理系统由三个关键文件组成:

  • main.cob:从用户读取输入并调用相应子程序的主要程序。
  • operations.cob:对帐户数据执行操作(例如存款、取款和查看余额)的子程序。
  • data.cob:管理帐户余额存储的子程序。

步骤 1:获取存储库的本地副本

编译并运行程序之前,需要在本地拥有代码。 如果尚未克隆存储库,请导航到要存储项目的目录并运行以下命令:

Shell
git clone https://github.com/continuous-copilot/modernize-legacy-cobol-app.git

步骤 2:编译并运行程序

可以在首选开发环境中(例如开源 GnuCOBOL 编译器)中安装 COBOL 编译器,也可以在 GitHub Codespaces 中使用 Copilot Chat。

如果使用 MacOS,则可以使用 Homebrew 安装 GnuCOBOL:

Shell
brew install gnu-cobol

如果使用 Codespaces 或 Ubuntu Linux 系统,则可以使用 apt 安装 GnuCOBOL:

Shell
sudo apt-get update && \
sudo apt-get install gnucobol

若要编译代码、链接文件并创建可执行文件,请从存储库的根目录运行以下命令:

Shell
cobc -x main.cob operations.cob data.cob -o accountsystem

若要运行程序,请使用以下命令:

Shell
./accountsystem

步骤 3:解释文件和代码

实现代码现代化的第一步是了解代码的工作原理。 可以要求 Copilot Chat 解释每个文件中的代码。

在 IDE 中打开存储库,然后在 Copilot Chat 面板中输入以下提示。

示例提示 1

/explain #file:main.cob #file:operations.cob #file:data.cob Can you please create a high level overview of the app. It will be great if you can explain each file in detail and how they are linked.

示例响应 1

以下是上述提示响应的摘录:

Sure! Here's a high-level overview of the COBOL application, along with detailed explanations of each file and how they are linked together.

High-Level Overview

This COBOL application simulates an account management system. It allows users to view the current balance, credit the account, debit the account, and exit the application. The application is divided into three main COBOL source files: main.cob, operations.cob, and data.cob. ...

步骤 4:绘制文件之间的数据流

下一步是了解如何将文件链接在一起。 可以使用 @workspace 为应用程序创建数据流关系图。

Note

VS Code 和 Visual Studio 中的 @workspace 聊天参与者为 Copilot 提供工作区中所有代码的上下文。 当希望 Copilot 考虑项目的结构以及代码的不同部分如何进行交互时,可以使用 @workspace。 如果使用 JetBrains IDE,请使用 @project 而不是 @workspace

示例提示 2

@workspace can you create a sequence diagram of the app showing the data flow of the app. Please create this in mermaid format so that I can render this in a markdown file.

Copilot 输出用于显示应用程序工作原理的完整序列图的 Mermaid 标记。 可以将此标记复制并粘贴到 Mermaid 应用程序中以生成关系图。

步骤 5:生成测试计划

创建测试计划,以确保应用程序在你进行更改后按预期工作。 可使用 @workspace 生成涵盖项目中所有文件的测试计划。

示例提示 3

@workspace The current Cobol app has no tests. Can you please create a test plan of current business logic that I can use to validate with business stakeholders about the current implementation.

Later I would like to use this test plan to create unit and integration tests in a node.js app. I am in the middle of transforming the current Cobol app to a node.js app.

The test plan should include the following:

1. Test Case ID
2. Test Case Description
3. Pre-conditions
4. Test Steps
5. Expected Result
6. Actual Result
7. Status (Pass/Fail)
8. Comments

Please create the test plan in a markdown table format. The test plan should cover all the business logic in the current Cobol app.

Convert this to markdown syntax to insert as a new file

Copilot 以 Markdown 格式输出测试计划,该计划可用于验证应用程序。 若要在此过程的后面部分使用此计划,请创建一个名为 TESTPLAN.md 的文件,并将建议的计划复制到其中。 这样,在后续步骤中生成测试用例时便可引用测试计划。

步骤 6:将文件从 COBOL 转换为 Node.js

下一步是将 COBOL 文件转换为 Node.js。 请务必牢记以下提示做法:

  • 提供上下文
  • 发出清晰明确的指令
  • 具体说明想要实现的结果

首先在项目中创建一个临时目录,在其中保存要创建的 JavaScript 文件。

Shell
mkdir temp-JS-project-directory

然后,以迭代方式将 COBOL 文件转换为 Node.js。

示例提示 4

Can you convert code in #file:main.cob to node.js?

示例响应 4

Sure! Here is the equivalent Node.js code for the main.cob file. This code will simulate the same account management system functionality.

### COBOL Code:

main.cob

```COBOL
IDENTIFICATION DIVISION.
       PROGRAM-ID. MainProgram.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  CONTINUE-FLAG      PIC X VALUE 'Y'.
       01  USER-CHOICE        PIC 9.
       01  FINAL-BALANCE      PIC 9(6)V99 VALUE 1000.00.

       PROCEDURE DIVISION.
           PERFORM UNTIL CONTINUE-FLAG = 'N'
               DISPLAY "1. View Balance"
               DISPLAY "2. Credit Account"
               DISPLAY "3. Debit Account"
               DISPLAY "4. Exit"
               ACCEPT USER-CHOICE

               EVALUATE USER-CHOICE
                   WHEN 1
                       CALL 'Operations' USING 'TOTAL'
                   WHEN 2
                       CALL 'Operations' USING 'CREDIT'
                   WHEN 3
                       CALL 'Operations' USING 'DEBIT'
                   WHEN 4
                       MOVE 'N' TO CONTINUE-FLAG
                       DISPLAY "Exiting the program. Goodbye!"
                   WHEN OTHER
                       DISPLAY "Invalid choice. Please try again."
               END-EVALUATE
           END-PERFORM
           STOP RUN.

### Node.js Code: `main.js`
```javascript
const readline = require('readline');

let continueFlag = 'Y';
let finalBalance = 1000.00;

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

function displayMenu() {
    console.log("1. View Balance");
    console.log("2. Credit Account");
    console.log("3. Debit Account");
    console.log("4. Exit");
}

function handleUserChoice(choice) {
    switch (choice) {
        case '1':
            viewBalance();
            break;
        case '2':
            creditAccount();
            break;
        case '3':
            debitAccount();
            break;
        case '4':
            continueFlag = 'N';
            console.log("Exiting the program. Goodbye!");
            rl.close();
            break;
        default:
            console.log("Invalid choice. Please try again.");
            promptUser();
            break;
    }
}

function viewBalance() {
    console.log(`Current balance: ${finalBalance.toFixed(2)}`);
    promptUser();
}

function creditAccount() {
    rl.question("Enter credit amount: ", (amount) => {
        amount = parseFloat(amount);
        if (!isNaN(amount) && amount > 0) {
            finalBalance += amount;
            console.log(`Amount credited. New balance: ${finalBalance.toFixed(2)}`);
        } else {
            console.log("Invalid amount. Please try again.");
        }
        promptUser();
    });
}

function debitAccount() {
    rl.question("Enter debit amount: ", (amount) => {
        amount = parseFloat(amount);
        if (!isNaN(amount) && amount > 0) {
            if (finalBalance >= amount) {
                finalBalance -= amount;
                console.log(`Amount debited. New balance: ${finalBalance.toFixed(2)}`);
            } else {
                console.log("Insufficient funds for this debit.");
            }
        } else {
            console.log("Invalid amount. Please try again.");
        }
        promptUser();
    });
}

function promptUser() {
    if (continueFlag === 'Y') {
        displayMenu();
        rl.question("Select an option: ", handleUserChoice);
    }
}

promptUser();

This Node.js code replicates the functionality of the COBOL main.cob file, providing a simple command-line interface for viewing the balance, crediting the account, debiting the account, and exiting the application.

在使用建议的代码之前,应对其进行仔细评审。 对生成的代码感到满意后,请按照以下步骤在本地保存代码并完成转换:

  1. 在前面创建的临时目录中,创建一个名为 main.js 的新文件。
  2. 从 Copilot Chat 面板复制生成的代码并将其粘贴到 main.js
  3. 保存文件。
  4. 使用类似的提示将 operations.cobdata.cob 转换为 Node.js。
  5. 在同一临时目录中创建相应的 JavaScript 文件 operations.jsdata.js
  6. 将生成的代码复制并粘贴到每个文件中,然后保存。

将所有文件转换为 Node.js 后,需要将它们链接在一起,并设置一个工作 Node.js 项目。

  1. 导航到终端中的临时目录。

  2. 运行以下命令以创建 package.json 文件:

    Shell
    npm init -y
    
  3. 如果应用程序需要外部包,请通过运行以下命令安装:

    Shell
    npm install
    
  4. 运行以下命令以启动该应用:

    Shell
    npm start
    

此时,Node.js 应用程序可能无法完全复制原始 COBOL 程序的功能。 例如,余额可能无法正确更新,或者计算可能与 COBOL 逻辑不匹配。

若要优化应用程序,需要:

  • 运行该程序并将其与 COBOL 版本进行比较来识别错误行为****。

  • 以迭代方式使用 Copilot 以调整逻辑,直到 Node.js 程序按预期运行****。

  • 使用定向提示调试和改进代码的特定部分,例如****:

    @workspace - analyze main.js and ensure account balance updates correctly when crediting an account.

重构旧代码并不总是一步到位 - Copilot 在你优化新的 Node.js 实现时有助于调试和改进功能。

步骤 8:生成单元和集成测试

下一步是生成单元和集成测试,以确保应用程序按预期工作。 可使用 @workspace 生成涵盖项目中所有文件的测试计划。

示例提示 5

@workspace I would like to create unit and integration tests cases from the test plan mentioned in #file:TESTPLAN.md file The node.js code is in node-accounting-app folder and I am looking to generate tests for #file:operations.js file. Use a popular testing framework and also provide all the dependencies required to run the tests.

示例响应 5

Copilot 生成了一些使用 Jest(JavaScript 测试框架)编写的测试,并提供了有关如何实现和运行这些测试的完整分步指南。

以下是上述提示响应的摘录:

“This test plan covers the main functionalities of the COBOL application, including viewing the balance, crediting the account, debiting the account, and exiting the application. The test cases are implemented using Jest, a popular testing framework for Node.js. Validate this test plan with the business stakeholders to ensure it meets the business requirements. Once validated, you can use this plan to create corresponding unit tests and integration tests for the Node.js application.”

步骤 9:运行测试和优化代码

生成测试计划和编写测试后,需要运行它们并修复所有失败的测试。 测试是一个迭代过程,你可能需要修改代码来解决问题,然后重新运行测试,直到所有测试均通过。

如果测试失败,请使用 Copilot 来帮助调试和优化实现。

示例提示 6

@workspace - analyze test failures in operations.test.js and suggest fixes to match the expected behavior.

即使所有测试都通过,程序也可能存在问题。 自动测试并不总能捕获遗漏的功能错误或逻辑错误,因此需要手动测试来确保应用程序按预期运行。

步骤 10:将 JavaScript 项目移动到新位置

应用程序按预期工作后,将新的 JavaScript 项目移出 COBOL 目录,单独保存。

  1. 导航到 COBOL 项目的父目录。

  2. 将 JavaScript 项目移动到新位置:

    Shell
    mv modernize-legacy-cobol-app new-js-project
    
  3. 导航到新项目目录并确认一切正常运行:

    Shell
    cd new-js-project
    npm start
    

现在,经过重构的 Node.js 应用程序位于其自己的独立项目文件夹中,与原始 COBOL 文件分开。

结束语

在此示例中,我们研究了用 COBOL 编写的帐户管理系统,并将其现代化为 Node.js。 我们使用了 Copilot Chat 来解释代码、绘制数据流图表、生成测试计划并将代码转换为 Node.js。 通过执行这些步骤,可以实现旧代码的现代化,使其更易于维护和扩展。 下面是一些用于实现旧代码现代化的其他提示:

  • 提示最佳做法至关重要:提示的质量决定了 Copilot 的建议质量****。 提供清晰明确的上下文,将复杂任务分解为较小的步骤,提供示例,并向 Copilot 给出要实现的具体目标。 这使得工作流更流畅,结果更精确
  • 检查代码后再使用:请确保了解 Copilot 提供的代码,然后再在应用程序中使用此代码****。 这将帮助你找出任何潜在的问题,确保代码满足你的要求。
  • 验证更改:对代码进行更改后,请务必验证应用程序是否仍按预期工作****。 可以使用 Copilot 生成的测试计划为应用程序创建单元和集成测试。

其他阅读材料