返回文章列表

程式碼函式庫維護策略與效能最佳化

本文探討軟體開發中程式碼函式庫維護的重要性,涵蓋不同型別的維護工作、降低風險的流程以及如何利用 GitHub Copilot 輔助維護和效能最佳化。文章以購物車處理流程為例,示範如何識別程式碼問題、編寫測試案例並利用 Copilot

軟體開發 程式設計

程式碼函式庫維護是軟體開發流程中不可或缺的一環,涵蓋修正錯誤、適應新需求、提升程式碼品質以及預防潛在問題等導向。穩健的維護流程包含識別問題、檢查測試覆寫率、規劃變更、實作、驗證、整合以及佈署等步驟。在實際操作中,可以藉助 GitHub Copilot 等工具輔助程式碼維護和效能最佳化。例如,在購物車處理流程中,可以利用 Copilot 生成測試案例,驗證付款失敗時不發貨的邏輯,並進一步重構程式碼以提升可維護性。此外,效能最佳化也是程式碼維護的重要環節。透過裝飾器可以方便地測量函式執行時間,找出效能瓶頸。例如,將原本以巢狀迴圈處理重複記錄的程式碼,改用集合來儲存已處理的記錄,可以將時間複雜度從 O(n^2) 降低到 O(n),大幅提升程式碼執行效率。

維護現有程式碼函式庫

簡介

在軟體開發領域中,「Brownfield」一詞指的是維護現有的程式碼。作為開發者,大部分工作都涉及現有程式碼的維護,而不是從零開始建立新專案。與之相對的是「Greenfield」,即全新的專案,沒有任何現有的程式碼。因此,瞭解如何維護現有的程式碼函式庫至關重要。

本章節將探討以下主題:

  • 不同型別的維護工作
  • 如何在維護過程中降低引入變更所帶來的風險
  • 利用 GitHub Copilot 協助維護工作

提示策略

本章節與書中其他章節略有不同,重點在於描述在維護現有程式碼函式庫時可能遇到的各種問題。讀者可以根據個人喜好選擇最舒適的提示方式,無論是使用註解還是聊天介面。鼓勵嘗試三種主要的提示模式:PIC、TAG 或探索模式。

不同型別的維護工作

維護工作有多種型別,瞭解它們之間的差異非常重要。常見的維護型別包括:

  • 修正性維護:修復錯誤的過程
  • 適應性維護:根據新的需求變更程式碼
  • 完善性維護:在不改變功能的前提下改程式式碼,例如重構或提升效能
  • 預防性維護:變更程式碼以預防未來可能出現的錯誤或問題

維護流程

每次變更程式碼時,都會引入風險。例如,修復一個錯誤可能會引入新的錯誤。為了降低這種風險,需要遵循一定的流程。建議的流程包括以下步驟:

  1. 識別:識別需要解決的問題或變更
  2. 檢查:檢查測試覆寫率以及程式碼被測試覆寫的程度
  3. 規劃:規劃變更,包括決定如何進行變更、需要編寫哪些測試以及需要執行哪些測試
  4. 實作:實作變更
  5. 驗證:驗證變更是否按預期運作,包括執行測試、檢查日誌等
  6. 整合:確保在分支中所做的變更被合併到主分支中
  7. 釋出/佈署變更:確保終端使用者能夠受益於變更

並非每次變更都需要遵循所有這些步驟,具體取決於變更的大小和複雜度。

處理錯誤

有些錯誤比其他的更嚴重。在最好的情況下,錯誤很少出現,即使出現也不會造成太大影響。在最壞的情況下,錯誤可能會導致金錢損失。以下是一個例子,假設正在營運一個電子商務網站,而某個錯誤可能導致金錢損失。

def process_cart():
    # 從資料函式庫取得購物車
    cart = get_cart()
    card = cart.get_card()
    process_payment(card, cart)
    ship_order(cart)

內容解密:

此段程式碼展示了一個簡單的購物車處理流程。然而,它存在一個嚴重的問題:如果 process_payment 失敗,ship_order 仍然會被呼叫,這可能導致訂單被發貨但未收到付款。

def process_payment(card, cart):
    if card.is_valid():
        if card.has_funds(cart.total):
            charge_card(card, cart.total)
            return 0
        else:
            return 1

內容解密:

在這個例子中,process_payment 傳回一個數值程式碼來表示付款結果。如果傳回 1,表示付款失敗,但如果沒有正確處理這個傳回值,訂單仍然可能被發貨。

我們的處理方法是:

  1. 識別問題:閱讀程式碼並檢查測試,以瞭解是否存在問題。
  2. 使用 GitHub Copilot 編寫測試,以驗證 ship_order 不應該在 process_payment 傳回 1 時被呼叫。
import unittest
from unittest.mock import Mock, patch
from your_module import process_cart # 請替換為實際的模組名稱

class TestProcessCart(unittest.TestCase):
    @patch('your_module.process_payment')
    @patch('your_module.ship_order')
    def test_process_cart_payment_fails(self, mock_ship_order, mock_process_payment):
        mock_process_payment.return_value = 1
        process_cart()
        mock_ship_order.assert_not_called()

if __name__ == '__main__':
    unittest.main()

內容解密:

這段測試程式碼使用 unittest.mock 模擬 process_paymentship_order 的行為。當 process_payment 傳回 1 時,驗證 ship_order 是否被正確地未呼叫。這樣可以確保程式碼在付款失敗時不會發貨,從而避免金錢損失。

維護現有程式碼函式庫:使用 GitHub Copilot 進行程式碼改進和新功能新增

在軟體開發過程中,維護現有的程式碼函式庫是一項非常重要的任務。隨著需求的變化和新功能的新增,程式碼需要不斷地被改進和擴充套件。本文將介紹如何使用 GitHub Copilot 來幫助我們維護現有的程式碼函式庫,包括識別問題、實施變更和新增新功能。

識別問題並進行測試

首先,我們需要識別程式碼中的問題或需要改進的地方。以一個購物車處理功能為例,我們發現當付款處理失敗時,訂單仍然會被發貨。為瞭解決這個問題,我們需要編寫測試來驗證當付款處理傳回錯誤碼時,發貨功能不會被呼叫。

class TestProcessCart(unittest.TestCase):
    @patch('your_module.get_cart') 
    @patch('your_module.process_payment')
    @patch('your_module.ship_order')
    def test_order_not_shipped_if_payment_fails(self, mock_ship_order, mock_process_payment, mock_get_cart):
        # Arrange
        mock_cart = Mock()
        mock_cart.get_card.return_value = 'test_card'
        mock_get_cart.return_value = mock_cart
        mock_process_payment.return_value = 1
        
        # Act
        process_cart()
        
        # Assert
        mock_ship_order.assert_not_called()

這個測試將幫助我們驗證當付款處理失敗時,發貨功能是否被正確地阻止。

實施變更

一旦我們有了測試,我們就可以使用 GitHub Copilot 來幫助我們實施變更。我們可以提供一個提示,例如「如果 process_payment 傳回 1,則不應呼叫 ship_order」,Copilot 將幫助我們生成所需的程式碼變更。

def process_cart():
    # 從資料函式庫取得購物車
    cart = get_cart()
    card = cart.get_card()
    payment_status = process_payment(card, cart)
    # 僅在付款成功時發貨
    if payment_status != 1:
        ship_order(cart)

進一步地,我們可以使用 Copilot 來重構程式碼,使其更容易維護。

def get_payment_status(cart):
    card = cart.get_card()
    return process_payment(card, cart)

def process_cart():
    # 從資料函式庫取得購物車
    cart = get_cart()
    payment_status = get_payment_status(cart)
    # 僅在付款成功時發貨
    if payment_status != 1:
        ship_order(cart)

新增新功能

假設我們需要為現有的程式碼新增對美國運通卡的支援。我們首先需要識別需要更改的功能,例如 validate_card 函式。使用 GitHub Copilot,我們可以提供一個提示,例如「新增對美國運通卡的支援」,Copilot 將幫助我們生成所需的變更。

def validate_card(card):
    # Visa 卡以 4 開頭,長度為 13 或 16 位。
    # MasterCard 卡以 51 至 55 開頭,長度為 16 位。
    # American Express 卡以 34 或 37 開頭,長度為 15 位。
    visa_pattern = r'^4[0-9]{12}(?:[0-9]{3})?$'
    mastercard_pattern = r'^5[1-5][0-9]{14}$'
    amex_pattern = r'^3[47][0-9]{13}$'
    
    if re.match(visa_pattern, card):
        return 'Visa'
    elif re.match(mastercard_pattern, card):
        return 'MasterCard'
    elif re.match(amex_pattern, card):
        return 'American Express'
    else:
        return None

新增新功能後,我們還需要編寫測試來驗證新功能的正確性。

class TestValidateCard(unittest.TestCase):
    def test_validate_card_returns_amex_for_valid_amex_card(self):
        # Arrange
        valid_amex_card = '378282246310005'
        # Act
        result = validate_card(valid_amex_card)
        # Assert
        self.assertEqual(result, 'American Express')

效能改進與程式碼維護

在軟體開發的過程中,效能改進是一項常見且重要的任務。為了達到最佳的效能,通常需要特定的工具來測量程式碼的執行時間,並找出需要改進的部分。使用裝飾器(decorator)來計算函式的執行時間是一種有效的方法。

使用裝飾器測量執行時間

以下是一個簡單的裝飾器範例,用於測量函式的執行時間:

import time

def profile(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f'{func.__name__} 執行時間:{end - start} 秒')
        return result
    return wrapper

@profile
def sleep_two_seconds():
    time.sleep(2)

sleep_two_seconds()

內容解密:

  1. profile 函式是一個裝飾器,接受一個函式 func 作為輸入,並傳回一個包裝函式 wrapper
  2. wrapper 函式計算 func 的執行時間,並列印出來。
  3. 使用 @profile 裝飾 sleep_two_seconds 函式,以測量其執行時間。

改善程式碼效能

考慮以下原始程式碼,用於處理記錄並找出重複項:

def process_records(records):
    for i in range(len(records)):
        for j in range(len(records)):
            if i != j and records[i] == records[j]:
                print(f'發現重複記錄:{records[i]}')

內容解密:

  1. 原始程式碼使用兩個巢狀迴圈來比較每對記錄,時間複雜度為 O(n^2)。
  2. 這種方法效率低下,特別是在處理大量資料時。

使用 GitHub Copilot 改善程式碼

向 GitHub Copilot 詢問如何改善上述程式碼的效能,可以得到以下建議:

def process_records(records):
    record_set = set()
    for record in records:
        if record in record_set:
            print(f'發現重複記錄:{record}')
        else:
            record_set.add(record)

內容解密:

  1. 新的程式碼使用一個集合(set)來儲存已處理的記錄。
  2. 對於每個記錄,檢查它是否已存在於集合中。如果存在,則列印重複記錄;否則,將其加入集合。
  3. 這種方法的時間複雜度為 O(n),因為集合操作(如檢查成員和新增元素)通常是常數時間 O(1)。

Big O 符號計算

原始程式碼的時間複雜度為 O(n^2),而新程式碼的時間複雜度為 O(n)。這意味著當記錄數量增加時,新程式碼的執行時間將線性增加,而原始程式碼的執行時間將以二次方速率增加。

測量效能

使用前面定義的 profile 裝飾器來測量原始程式碼和新程式碼的執行時間。對於 10,000 筆記錄:

  • 原始程式碼的執行時間約為 5.19 秒。
  • 新程式碼的執行時間約為 0.00112 秒。

內容解密:

  1. 新程式碼比原始程式碼快得多,這證明瞭使用合適的資料結構(如集合)來改善效能的有效性。
  2. 結合 GitHub Copilot 的建議和自己的知識,可以有效地改善程式碼的效能。