程式碼函式庫維護是軟體開發流程中不可或缺的一環,涵蓋修正錯誤、適應新需求、提升程式碼品質以及預防潛在問題等導向。穩健的維護流程包含識別問題、檢查測試覆寫率、規劃變更、實作、驗證、整合以及佈署等步驟。在實際操作中,可以藉助 GitHub Copilot 等工具輔助程式碼維護和效能最佳化。例如,在購物車處理流程中,可以利用 Copilot 生成測試案例,驗證付款失敗時不發貨的邏輯,並進一步重構程式碼以提升可維護性。此外,效能最佳化也是程式碼維護的重要環節。透過裝飾器可以方便地測量函式執行時間,找出效能瓶頸。例如,將原本以巢狀迴圈處理重複記錄的程式碼,改用集合來儲存已處理的記錄,可以將時間複雜度從 O(n^2) 降低到 O(n),大幅提升程式碼執行效率。
維護現有程式碼函式庫
簡介
在軟體開發領域中,「Brownfield」一詞指的是維護現有的程式碼。作為開發者,大部分工作都涉及現有程式碼的維護,而不是從零開始建立新專案。與之相對的是「Greenfield」,即全新的專案,沒有任何現有的程式碼。因此,瞭解如何維護現有的程式碼函式庫至關重要。
本章節將探討以下主題:
- 不同型別的維護工作
- 如何在維護過程中降低引入變更所帶來的風險
- 利用 GitHub Copilot 協助維護工作
提示策略
本章節與書中其他章節略有不同,重點在於描述在維護現有程式碼函式庫時可能遇到的各種問題。讀者可以根據個人喜好選擇最舒適的提示方式,無論是使用註解還是聊天介面。鼓勵嘗試三種主要的提示模式:PIC、TAG 或探索模式。
不同型別的維護工作
維護工作有多種型別,瞭解它們之間的差異非常重要。常見的維護型別包括:
- 修正性維護:修復錯誤的過程
- 適應性維護:根據新的需求變更程式碼
- 完善性維護:在不改變功能的前提下改程式式碼,例如重構或提升效能
- 預防性維護:變更程式碼以預防未來可能出現的錯誤或問題
維護流程
每次變更程式碼時,都會引入風險。例如,修復一個錯誤可能會引入新的錯誤。為了降低這種風險,需要遵循一定的流程。建議的流程包括以下步驟:
- 識別:識別需要解決的問題或變更
- 檢查:檢查測試覆寫率以及程式碼被測試覆寫的程度
- 規劃:規劃變更,包括決定如何進行變更、需要編寫哪些測試以及需要執行哪些測試
- 實作:實作變更
- 驗證:驗證變更是否按預期運作,包括執行測試、檢查日誌等
- 整合:確保在分支中所做的變更被合併到主分支中
- 釋出/佈署變更:確保終端使用者能夠受益於變更
並非每次變更都需要遵循所有這些步驟,具體取決於變更的大小和複雜度。
處理錯誤
有些錯誤比其他的更嚴重。在最好的情況下,錯誤很少出現,即使出現也不會造成太大影響。在最壞的情況下,錯誤可能會導致金錢損失。以下是一個例子,假設正在營運一個電子商務網站,而某個錯誤可能導致金錢損失。
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,表示付款失敗,但如果沒有正確處理這個傳回值,訂單仍然可能被發貨。
我們的處理方法是:
- 識別問題:閱讀程式碼並檢查測試,以瞭解是否存在問題。
- 使用 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_payment 和 ship_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()
內容解密:
profile函式是一個裝飾器,接受一個函式func作為輸入,並傳回一個包裝函式wrapper。wrapper函式計算func的執行時間,並列印出來。- 使用
@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]}')
內容解密:
- 原始程式碼使用兩個巢狀迴圈來比較每對記錄,時間複雜度為 O(n^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)
內容解密:
- 新的程式碼使用一個集合(set)來儲存已處理的記錄。
- 對於每個記錄,檢查它是否已存在於集合中。如果存在,則列印重複記錄;否則,將其加入集合。
- 這種方法的時間複雜度為 O(n),因為集合操作(如檢查成員和新增元素)通常是常數時間 O(1)。
Big O 符號計算
原始程式碼的時間複雜度為 O(n^2),而新程式碼的時間複雜度為 O(n)。這意味著當記錄數量增加時,新程式碼的執行時間將線性增加,而原始程式碼的執行時間將以二次方速率增加。
測量效能
使用前面定義的 profile 裝飾器來測量原始程式碼和新程式碼的執行時間。對於 10,000 筆記錄:
- 原始程式碼的執行時間約為 5.19 秒。
- 新程式碼的執行時間約為 0.00112 秒。
內容解密:
- 新程式碼比原始程式碼快得多,這證明瞭使用合適的資料結構(如集合)來改善效能的有效性。
- 結合 GitHub Copilot 的建議和自己的知識,可以有效地改善程式碼的效能。