[isTMS]課程 - GitHub Copilot實戰
 

從初階到進階:程式碼重構的藝術

當你的程式碼能正常運作後,下一個挑戰來了:如何讓它更優雅、更易維護?

問題的浮現

看看我們目前的程式碼:

double applePrice = 35;
double appleDiscount = 0.1;
Console.WriteLine("蘋果折扣後價格是:" + applePrice * (1 - appleDiscount));

double bananaPrice = 25;
double bananaDiscount = 0.15;
Console.WriteLine("香蕉折扣後價格是:" + bananaPrice * (1 - bananaDiscount));

這段程式碼有幾個明顯的問題:

  1. 違反 DRY 原則(Don't Repeat Yourself):計算折扣的邏輯重複多次
  2. 缺乏抽象化:沒有使用物件導向的設計
  3. 難以擴展:每增加一種水果就複製貼上一次,未來若修改計算方式,每一段都要重新調整。
  4. 不易測試:商業邏輯(BLL) 與 輸出輸入(IO)混在一起

這時候,就需要進行程式碼重構(Refactoring)。

使用 Copilot 進行重構

傳統的重構方式需要:

  1. 思考如何設計類別結構
  2. 手動建立類別(class)和屬性(property)
  3. 實作類別中的方法(method)
  4. 修改原有的呼叫程式碼,並且確保正確無誤。

但有了 Copilot,這件事情變得簡單許多。

Step 1: 用註解描述你的設計意圖

在程式碼最尾端新增加一行,然後在其中寫下這段「咒語」(註解):

//建立一個計算折扣後價格的類別,具有水果名稱、單價、折扣這三個屬性,以及一個計算折扣後價格的方法

這段註解就像是給 Copilot 的需求規格書,也是一種提示詞。好的提示詞應該清晰明確,且包含:

  • 要做什麼(建立一個類別)
  • 會有什麼(三個屬性、一個方法)
  • 能實現什麼(計算BMI)

Step 2: 讓 AI 生成類別

按下 Enter 後,Copilot 會自動生成類似這樣的類別:

public class Fruit
{
    public string FruitName { get; set; }
    public double Price { get; set; }
    public double Discount { get; set; }
    
    public double CalculateDiscountedPrice()
    {
        return Price * (1 - Discount);
    }
}

這個類別展現了良好的物件導向設計:

  • 封裝(Encapsulation):將資料和行為包裝在一起
  • 單一職責原則(Single Responsibility Principle):只負責計算折扣價格
  • 易於測試:計算邏輯獨立於輸出

Step 3: 重構主程式

現在,我們可以使用 Inline Coding(內嵌程式碼建議)的方案,來重構主程式。只需開始輸入:

var apple = new

Copilot 會自動建議:

var apple = new Fruit
{ 
    FruitName = "蘋果", 
    Price = 35, 
    Discount = 0.1 
};
Console.WriteLine($"{apple.FruitName}折扣後價格是:{apple.CalculateDiscountedPrice()}");

注意 Copilot 可能還會自動使用字串插值(String Interpolation)語法 $"{...}",這比字串串接更現代、更易讀。

你也可以選取片段程式碼,使用 (CTRL+I),在跳出的視窗中,直接輸入: 『改成使用底下的 Fruit 類別進行計算』

看看結果如何?

影片

完整的重構結果

最終,我們的程式碼變成:

public class Fruit
{
    public string FruitName { get; set; }
    public double Price { get; set; }
    public double Discount { get; set; }
    
    public double CalculateDiscountedPrice()
    {
        return Price * (1 - Discount);
    }
}

// 主程式
var apple = new Fruit { FruitName = "蘋果", Price = 35, Discount = 0.1 };
Console.WriteLine($"{apple.FruitName}折扣後價格是:{apple.CalculateDiscountedPrice()}");

var banana = new Fruit { FruitName = "香蕉", Price = 25, Discount = 0.15 };
Console.WriteLine($"{banana.FruitName}折扣後價格是:{banana.CalculateDiscountedPrice()}");

var orange = new Fruit { FruitName = "橘子", Price = 30, Discount = 0.2 };
Console.WriteLine($"{orange.FruitName}折扣後價格是:{orange.CalculateDiscountedPrice()}");

這段程式碼的優勢:

  • 更易維護:修改折扣計算邏輯只需改一個地方
  • 更易擴展:新增水果只需建立新的物件實例
  • 更易測試:可以針對 CalculateDiscountedPrice() 方法撰寫單元測試
  • 更易閱讀:程式碼意圖一目了然

Copilot 的工作原理:不只是程式碼補全

你可能會好奇:Copilot 到底是如何做到這些的?

上下文理解(Context Awareness)

Copilot 會分析:

  • 檔案中的現有程式碼 : 了解你的編碼風格和邏輯模式
  • 註解內容 : 理解你的意圖
  • 檔案名稱與專案結構 : 推測程式碼的用途
  • 已開啟的其他檔案 : 獲取更廣泛的上下文

例如,當你寫完蘋果的計算邏輯,Copilot 注意到:

  1. 變數命名模式:xxxPricexxxDiscount
  2. 計算邏輯模式:price * (1 - discount)
  3. 輸出模式:Console.WriteLine 顯示結果

基於這些模式,它推論你可能需要計算其他水果的價格。

機率性預測(Probabilistic Prediction)

Copilot 使用大型語言模型(Large Language Model, LLM),基於數十億行開源程式碼訓練而成。當你輸入程式碼時,它會:

  1. 計算下一段程式碼最可能的樣子
  2. 生成多個候選建議
  3. 根據上下文排序建議
  4. 呈現最佳建議給你

這就是為什麼按下 Ctrl + Enter 時,你會看到多個替代方案——每個都是 Copilot 認為「可能」的解決方案, 但機率不同。

最佳實踐:如何讓 Copilot 更貼心

1. 寫清楚的註解

不好的註解:

//計算

好的註解:

//建立一個計算折扣後價格的類別,具有水果名稱、單價、折扣這三個屬性,以及一個計算折扣後價格的方法

清楚的註解包含:

  • 動作(建立)
  • 對象(類別)
  • 細節(三個屬性、一個方法)
  • 目的(計算折扣後價格)

2. 提供範例程式碼

Copilot 從模式中學習。先寫一個完整的範例,它就能推論出後續的模式:

// 第一個範例(你寫的)
double applePrice = 35;
double appleDiscount = 0.1;
Console.WriteLine("蘋果折扣後價格是:" + applePrice * (1 - appleDiscount));

// 後續範例(Copilot 生成的)
double bananaPrice = 25; // Copilot 自動建議
...

3. 使用一致的命名慣例

保持變數、函數命名的一致性,能幫助 Copilot 更好地理解你的意圖:

// 一致的命名
double applePrice, appleDiscount;
double bananaPrice, bananaDiscount;

// 而非
double applePrice, discount_for_apple;
double price_banana, bananaDisc;

4. 善用快捷鍵探索選項

不要總是接受第一個建議。
使用 Ctrl + Enter 查看其他選項,可能會發現更好的解決方案:

  • 第一個建議可能使用 for 迴圈
  • 第二個建議可能使用 LINQ
  • 第三個建議可能使用函數式程式設計

選擇最適合你需求的方案。

5. 段落式開發(Incremental Development)

不要一次讓 Copilot 生成太複雜的程式碼。分階段進行:

  1. 先寫基本邏輯
  2. 再用註解描述重構方向
  3. 逐步接受 Copilot 的建議
  4. 每個階段都測試驗證

這樣能保持對程式碼的掌控,也能讓 Copilot 提供更精準的建議。


相關資源: