The GitHub Blog 01月23日
Modernizing legacy code with GitHub Copilot: Tips and examples
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文探讨了如何利用GitHub Copilot等AI工具来现代化遗留代码,特别是针对COBOL等老旧语言。文章指出,遗留代码常常面临技术债务、集成挑战、数据迁移困难、成本高昂、性能瓶颈以及安全漏洞等问题。GitHub Copilot通过提供代码解释、测试生成、问题修复等功能,显著提升了代码现代化效率。文章还分享了使用Copilot的最佳实践,包括利用斜杠命令、聊天参与者、聊天变量以及GitHub技能等,并建议从小处着手,逐步推进代码现代化。

🛠️遗留代码现代化面临多重挑战:技术债务堆积、集成困难、数据迁移复杂、成本高昂、性能受限以及安全风险,这些问题使得代码更新成为一项艰巨的任务。

💡GitHub Copilot通过多种功能助力代码现代化:包括代码解释、测试生成与修复、问题查找与修复等,显著提升了开发效率,减少了在Google和Stack Overflow上搜索的时间。

🚀使用Copilot的最佳实践:利用斜杠命令快速执行操作,通过聊天参与者精确定位问题,使用聊天变量提供上下文信息,并结合GitHub技能获取更深入的信息。

🎯从小处着手,逐步推进:建议开发者从单个函数或模块入手,逐步推进整个系统的现代化,避免一次性大规模重构带来的风险。

Let’s talk about legacy code—you know, the code that’s old enough to drive and definitely old enough to haunt your dreams. Maybe it’s a sprawling COBOL system or an early version of C++ written back when “Y2K” was a serious concern. Now, decades later, you’re being asked to “look into it” and modernize it (while wondering if you need to send a note to that person who retired a few years ago and may know how this thing works).

This is where AI coding tools like GitHub Copilot can offer some much-needed assistance—and I’m speaking from personal experience. In my day-to-day work, I often help organizations in the public sector, finance, and retail to deploy GitHub Copilot, and one question I hear again and again is, “How can we use Copilot to modernize legacy systems?”

In this article, I’ll walk you through just that using one of the most infamous old-school languages: COBOL. This isn’t because I’m a masochist—lots of critical systems still use COBOL. But while it still does what it’s supposed to do, there are a lot of integration and compatibility challenges (it is pretty old), and the number of developers who can read and write COBOL isn’t exactly what it used to be. All of this makes COBOL programs that much harder to modernize. In our example, we’ll take an account management system written in COBOL and modernize it into Node.js.

Here’s something fun, too: Everything we share below can be done with any GitHub Copilot tier—including our free tier.

With that in mind, I’ll show you how Copilot can help you navigate and modernize legacy code, including the common pain points like wrangling technical debt, migrating to modern frameworks, and dealing with that one cryptic variable named X. (Seriously, why is it always X?)

So, grab your debugger and buckle up.

The challenges of legacy code

Let’s face it: working with legacy code can feel like stepping into a time machine, except instead of a cool DeLorean, you’re handed a dusty, 10,000-line COBOL program with zero documentation, and a warning that, if this breaks, the entire payroll system goes down.”

No pressure.

The truth is, modernizing legacy code isn’t just about updating syntax or swapping out old libraries. You’re more than likely staring at technical debt, compatibility issues, and the knowledge that the people who originally wrote this code are happily retired or have long since left your organization.

Here’s a closer look at the common pain points and challenges any developer dealing with legacy systems will likely face:

All of this means that modernizing legacy systems isn’t just a nice-to-have—but that doesn’t make it any easier. And since you’re reading this article, there’s a good chance you’ve been asked to help modernize some legacy code.

It may feel like a big ask, but for all those reasons above (and then some) it’s super important.

How GitHub Copilot helps you refactor and modernize legacy code

Modernizing legacy code can feel like an uphill battle, especially when you’re diving into unfamiliar languages like COBOL. But GitHub Copilot makes this process faster, smoother, and—dare I say—less painful.

Before Copilot, I spent a lot of time on Google and Stack Overflow searching for information about whatever legacy language or system I was about to dive into. Don’t get me wrong, it was helpful, but it took a lot of time, and took me away from the code itself. With Copilot, I can stay in my IDE and my flow state while asking my AI programmer these questions instead. Nine times out of 10 it gives me the right answer, or points me in the right direction. That speed—and not having to break out of my flow—is really what’s so impactful for me.

Here are a few best practices I follow when using Copilot to modernize legacy code:

Modernizing a legacy COBOL application with GitHub Copilot: A practical example

Ok, let’s jump into our code. Like I said earlier, we’ll be looking at an account management system written in COBOL and modernizing it into Node.js.

Notably, every step I’m going to walk you through below works in all tiers of GitHub Copilot—including the Free version. And just in case you’re wondering, I use OpenAI’s GPT-4o model (in the Free tier of Copilot you can choose between that and Anthropic’s Claude 3.5 Sonnet).

You can head to my demo repository yourself and fork it if you want to follow along (I include step-by-step instructions there, too).

This repository includes three key files—data.cob, main.cob, and operations.cob—that work together to perform various operations like crediting, debiting, viewing the account balance balance, and even exiting the program.

An important note: since Copilot is powered by generative AI models, which are nondeterministic in terms of outputs, you will likely get slightly different responses even if you follow my step-by-step instructions.

Step 1: Compile and run the program

You have two options here: you can either install a COBOL compiler (I recommend the open source GnuCOBOL compiler) or open up the terminal in a GitHub Codespaces environment (this is what I do since it’s a bit simpler). Copilot will work in either.

To install GnuCOBOL, use this brew command when using MacOS:

brew install gnucobol 

If you decide to use Codespaces or an Ubuntu Linux system, you need to run the following command to install the COBOL compiler in your instance:

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

From there, you need to compile the code, link the files, and create an executable with the following command:

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

Step 2: Explain the files and code

While I don’t deal with COBOL in my day-to-day work normally, my next step is simple: find out what on Earth these files are doing. That’s where Copilot enters the picture. It’s great at helping explain (and document) code, including legacy code like we’re working with now.

Here’s the first prompt I use in Copilot Chat:

/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.

Note how I use a combination of a slash command, pointing to specific files using the #file chat variable, and a prompt. This helps Copilot focus on exactly what I want explained by pointing it at the right files.

Copilot returns around a rather lengthy explanation that I’ll excerpt here:

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 OverviewThis 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.

This alone gives me a good starting point—and Copilot’s full response offers far more detail on the logic of each file, the links between them, and the different sections of code.

Step 3: Chart out the data flow between the files

But I still need a better idea of how these three files are working together in our executable. This is where Copilot, once again, proves to be incredibly helpful with the @workspace command.

A little explanation first: entering @workspace in Copilot Chat lets you ask questions about your codebase including finding code, making plans for complex edits, explaining higher-level concepts, and more (VS Code has some good documentation on using @workspace).

For this exercise, I use @workspace to prompt Copilot for a data flow diagram while asking it to output it in a Mermaid diagram so I can clearly visualize it.

@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 then outputs a full sequence diagram in Mermaid that shows me exactly how this application works, rendered as a Markdown file. This looks like the following:

This helps me visually understand how this application is functioning and how the data is flowing through the program.

Step 4: Generate a test plan

In our demo repository, you can see that we currently have no tests. That’s not great, so the next step is to generate tests.

We’ll use the @workspace command again with the following prompt:

@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 ID2. Test Case Description3. Pre-conditions4. Test Steps5. Expected Result6. Actual Result7. Status (Pass/Fail)8. CommentsPlease create the test plan in a markdown table format. The test plan should cover all the business logic in the current Cobol app.

Copilot will then generate a test plan I can use. But in my instance, I had to take one more step: ask Copilot to generate the markdown file format for my test plan to insert it as a new file.

Convert this to markdown syntax to insert as a new file

Step 5: Convert the files from COBOL to Node.js

Now, it’s time to convert our three COBOL files into a Node.js application. Here, it’s important to use good prompting practices: provide context, give clear directions, and be specific about the outcome you want to achieve.

We start by creating a Node.js project directory:

mkdir node-accounting-appcd node-accounting-app

From there, we iteratively convert the files main.cob, operations.cob, and data.cob into Node.js files. I’ll use the code in main.cob as the example here. Here’s my prompt for reference:

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

Copilot then generates the following answer:

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```COBOLIDENTIFICATION 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````javascriptconst 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.

Simple enough, right? Of course, we need to review this code—it’s always a requirement to trust but verify when using AI coding tools. After review, I execute similar prompts for the other two files.

Once we finish translating each COBOL file into Node.js, we need to link all the new files to initialize, install, and run the Node application. I use the following prompt to do that:

link all node.js files to work together in one accounting application and with npm commands to initialize and install and to run the app.

Copilot returns the needed program logic while linking everything together, so I just need to execute the main.js file after initializing npm.

Step 6: Generate unit and integration tests

For our last step, we generate unit and integration tests to ensure all of our new Node.js code works. Here, I again use @workspace in Copilot Chat. My prompt looks like this:

@workspace I would like to create unit and integration tests cases form 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.

Copilot generates a number of tests in Jest, a JavaScript testing framework, with a full, step-by-step guide on how to implement and run them.

In Copilot’s own words: “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.”

Remember, you can always ask Copilot to generate tests for edge cases, or even prompt it to find these cases by asking if there are any additional tests you—or even it—may have forgotten.

Take this with you

Modernizing legacy code doesn’t have to be a headache. With GitHub Copilot, you have a powerful tool to accelerate the process, stay in your flow, and focus on what matters most: writing great code. Here’s what to keep in mind as you embark on your modernization journey:

Refactoring legacy code might feel like a daunting challenge, but it’s also an opportunity to learn, improve, and build something better. With GitHub Copilot by your side, you’re equipped to handle even the most stubborn systems. So, dive in, experiment with prompts, and start turning that dusty code into something modern and efficient. You’ve got this—and Copilot’s got your back.

Start using GitHub Copilot for free
Our free version of GitHub Copilot is included by default in personal GitHub accounts and VS Code to help you start new projects, manage existing repositories, and more.

Start using GitHub Copilot >

The post Modernizing legacy code with GitHub Copilot: Tips and examples appeared first on The GitHub Blog.

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

GitHub Copilot 遗留代码 代码现代化 AI工具 COBOL
相关文章