Affected files: 00. Inbox/Study Toshiba TC956x/00. Inbox.md 00. Inbox/USB.canvas 00. Inbox/clean code.md
16 KiB
16 KiB
tags, aliases, date, time, description
| tags | aliases | date | time | description |
|---|---|---|---|---|
| 2025-08-04 | 16:49:36 |
核心設計原則
遵循3Rs架構:
- 可讀性(Readability):讓程式碼易於理解和維護
- 可重用性(Reusability):減少重複程式碼,提高開發效率
- 可重構性(Refactorability):支援模組化設計和持續改進
第一階段:基礎理論與核心原則
- Clean Code定義與重要性
- 什麼是Clean Code:易讀、易懂、易維護的程式碼
- 技術債務的概念與影響
- 童子軍規則:讓程式碼比接手時更乾淨
Good code:
def calculate_doubled_value_plus_one(input_value):
"""計算輸入值的兩倍加一"""
OFFSET = 1
if input_value <= 0:
raise ValueError("Input value must be positive")
doubled_value = input_value * 2
result = doubled_value + OFFSET
return result
Bad code:
def f(x):
if x > 0:
y = x * 2
# TODO: fix this later
z = y + 1 # magic number
return z
else:
return -1
- 有意義的命名規範
- 使用具描述性且明確的變數名稱
- 函式命名:動詞片語表達動作意圖
- 類別命名:名詞表達實體概念
- 避免縮寫和神秘數字
Good code:
// 良好的命名
let elapsedTimeInDays;
let activeUsers = [];
let calculateTotalPrice = (price, quantity) => price * quantity;
def fetch_user_profile():
return user_profile_data
def validate_user_credentials():
# 驗證使用者憑證
codes.....
Bad code:
// 糟糕的命名
let d; // 經過的天數
let u = []; // 使用者列表
let calc = (a, b) => a * b;
def data():
return user_info
def process():
# 處理某些東西
pass
- 函式設計原則
- 單一職責原則:一個函式只做一件事
- 函式長度控制:目標在20行以下
- 參數管理:最多3個參數的建議
- 避免副作用與Flag參數
一個函式只做一件事
Good code:
# 遵循單一職責的函式
def validate_user_data(user_data):
"""僅負責驗證使用者資料"""
if not user_data.get('email'):
raise ValueError("Email required")
return True
def save_user_to_database(user_data):
"""僅負責儲存資料"""
database.save(user_data)
def send_welcome_notification(email):
"""僅負責發送歡迎郵件"""
email_service.send_welcome_email(email)
def log_user_registration(username):
"""僅負責記錄日誌"""
logger.info(f"User {username} registered successfully")
Bad code:
# 違反單一職責的函式
def process_user_data(user_data):
# 驗證資料
if not user_data.get('email'):
raise ValueError("Email required")
# 儲存到資料庫
database.save(user_data)
# 發送通知郵件
email_service.send_welcome_email(user_data['email'])
# 記錄日誌
logger.info(f"User {user_data['name']} processed")
避免副作用與Flag參數
Good code:
# 無副作用、單一職責的函式
def transform_data(data):
"""純函式:只負責資料轉換"""
return processed_data
def save_processed_data(data):
"""專門負責儲存資料"""
save_to_disk(data)
def send_processing_notification():
"""專門負責發送通知"""
send_notification_email()
def update_processing_count():
"""專門負責更新計數"""
global last_processed_count
last_processed_count += 1
Bad code:
# 帶有副作用和flag參數的糟糕函式
def process_data(data, save_to_file=False, send_email=False):
# 處理資料
processed_data = transform_data(data)
# 副作用:修改全域變數
global last_processed_count
last_processed_count += 1
# Flag參數導致函式做多件事
if save_to_file:
save_to_disk(processed_data)
if send_email:
send_notification_email()
return processed_data
- 程式碼組織結構
- 降層原則:由上到下的閱讀順序
- 錯誤處理:使用例外處理取代錯誤碼
- 這點值得商榷,業界也爭論不休,不用硬性規定,應該依實際情況決定。
降層原則:由上到下的閱讀順序
Good code:
# 遵循降層原則的順序
def main_process():
"""主要處理流程"""
setup_environment()
result = core_logic()
cleanup()
return result
def setup_environment():
"""設定處理環境"""
# 設定環境
pass
def core_logic():
"""核心邏輯處理"""
return helper_function()
def helper_function():
"""輔助函式"""
return "helper"
def cleanup():
"""清理資源"""
# 清理
pass
Bad code:
# 混亂的函式順序
def helper_function():
return "helper"
def main_process():
setup_environment()
result = core_logic()
cleanup()
return result
def setup_environment():
# 設定環境
pass
def core_logic():
return helper_function()
def cleanup():
# 清理
pass
錯誤處理:使用例外處理取代錯誤碼
這點值得商榷,業界也爭論不休,不用硬性規定,應該依實際情況決定。 錯誤碼針對已知、能預測的錯誤,而例外則傾向於「不應該、不可能」的錯誤。
Good code:
# 使用例外處理
def process_file(filename):
"""處理檔案,使用例外處理錯誤"""
try:
with open(filename, 'r') as file:
content = file.read()
return process_content(content)
except FileNotFoundError:
raise FileProcessingError(f"檔案 {filename} 不存在")
except PermissionError:
raise FileProcessingError(f"沒有權限讀取檔案 {filename}")
except Exception as e:
raise FileProcessingError(f"處理檔案時發生錯誤: {str(e)}")
Bad code:
// 使用錯誤碼的方式
int process_file(const char* filename) {
FILE* file = fopen(filename, "r");
if (file == NULL) {
return -1; // 錯誤碼
}
char buffer[100];
if (fread(buffer, 1, sizeof(buffer), file) == 0) {
fclose(file);
return -2; // 另一個錯誤碼
}
fclose(file);
return 0; // 成功
}
-
註解最佳實踐
- 何時需要註解,何時不需要
- 讓程式碼自我說明
- 有效註解的撰寫技巧
-
程式碼格式化
- 一致性的重要性
- 縮排與空白字元的運用
- 程式碼區塊的邏輯分組
第二階段:進階設計原則
- 五大SOLID原則詳解
- S:單一職責原則(SRP)
- O:開放封閉原則(OCP)
- L:里氏替換原則(LSP)
- I:介面隔離原則(ISP)
- D:依賴反轉原則(DIP)
單一職責原則(SRP)
Good code:
class User:
def __init__(self, username, email):
self.username = username
self.email = email
class UserRepository:
def save(self, user):
database.save(user)
class EmailService:
def send_email(self, email, message):
email_service.send(email, message)
class UserReportGenerator:
def generate_report(self, user):
return f"User: {user.username}, Email: {user.email}"
Bad code:
class User:
def __init__(self, username, email):
self.username = username
self.email = email
def save_to_database(self):
# 儲存使用者到資料庫
database.save(self)
def send_email(self, message):
# 發送郵件
email_service.send(self.email, message)
def generate_report(self):
# 產生使用者報告
return f"User: {self.username}, Email: {self.email}"
開放封閉原則(OCP)
Good code:
from abc import ABC, abstractmethod
class DiscountStrategy(ABC):
@abstractmethod
def calculate_discount(self, amount):
pass
class RegularCustomerDiscount(DiscountStrategy):
def calculate_discount(self, amount):
return amount * 0.05
class PremiumCustomerDiscount(DiscountStrategy):
def calculate_discount(self, amount):
return amount * 0.10
class VIPCustomerDiscount(DiscountStrategy):
def calculate_discount(self, amount):
return amount * 0.15
class DiscountCalculator:
def __init__(self, strategy: DiscountStrategy):
self.strategy = strategy
def calculate_discount(self, amount):
return self.strategy.calculate_discount(amount)
Bad code:
class DiscountCalculator:
def calculate_discount(self, customer_type, amount):
if customer_type == "regular":
return amount * 0.05
elif customer_type == "premium":
return amount * 0.10
elif customer_type == "vip":
return amount * 0.15
else:
return 0
-
實務應用案例
- 每個原則的程式碼範例
- 違反原則的常見問題
-
常用設計模式
- 工廠模式:封裝物件創建
- 策略模式:演算法替換
- 觀察者模式:事件處理
- 裝飾者模式:功能擴展
- 還有其他的設計模式,這裡不一一列出。設計模式可以給大家一個共同的語言,溝通可以更清楚、方便。
工廠模式:封裝物件創建
Good code:
from abc import ABC, abstractmethod
class Transport(ABC):
@abstractmethod
def deliver(self):
pass
class Car(Transport):
def deliver(self):
return "Delivering by car"
class Bike(Transport):
def deliver(self):
return "Delivering by bike"
class TransportFactory:
_transports = {
"car": Car,
"bike": Bike
}
@classmethod
def create_transport(cls, transport_type):
transport_class = cls._transports.get(transport_type)
if not transport_class:
raise ValueError(f"Unknown transport type: {transport_type}")
return transport_class()
Bad code:
# 直接創建物件,違反開放封閉原則
def create_transport(transport_type):
if transport_type == "car":
return Car()
elif transport_type == "bike":
return Bike()
elif transport_type == "plane":
return Plane()
else:
raise ValueError("Unknown transport type")
策略模式:演算法替換
Good code:
class PaymentStrategy(ABC):
@abstractmethod
def process_payment(self, amount):
pass
class CreditCardPayment(PaymentStrategy):
def process_payment(self, amount):
return f"Processing ${amount} via credit card"
class PayPalPayment(PaymentStrategy):
def process_payment(self, amount):
return f"Processing ${amount} via PayPal"
class PaymentProcessor:
def __init__(self, strategy: PaymentStrategy):
self.strategy = strategy
def set_strategy(self, strategy: PaymentStrategy):
self.strategy = strategy
def process_payment(self, amount):
return self.strategy.process_payment(amount)
Bad code:
class PaymentProcessor:
def process_payment(self, amount, payment_type):
if payment_type == "credit_card":
# 信用卡處理邏輯
return self._process_credit_card(amount)
elif payment_type == "paypal":
# PayPal處理邏輯
return self._process_paypal(amount)
elif payment_type == "bank_transfer":
# 銀行轉帳處理邏輯
return self._process_bank_transfer(amount)
- 重構基本概念
- 重構定義:改善內部結構不影響外部行為
- 重構時機:三次法則與預備性重構
- 安全重構:依賴測試確保正確性
重構定義:改善內部結構不影響外部行為
Good code:
# 重構後:清晰且易於維護的程式碼
def calculate_price(items):
return sum(calculate_item_price(item) for item in items)
def calculate_item_price(item):
base_price = item['price'] * item['quantity']
discount = get_discount_rate(item)
return base_price * (1 - discount)
def get_discount_rate(item):
discount_rules = {
'book': lambda qty: 0.1 if qty > 10 else 0,
'electronics': lambda qty: 0.15 if qty > 5 else 0
}
rule = discount_rules.get(item['type'], lambda qty: 0)
return rule(item['quantity'])
Bad code:
# 重構前:複雜且難以理解的程式碼
def calculate_price(items):
total = 0
for item in items:
if item['type'] == 'book':
if item['quantity'] > 10:
total += item['price'] * item['quantity'] * 0.9
else:
total += item['price'] * item['quantity']
elif item['type'] == 'electronics':
if item['quantity'] > 5:
total += item['price'] * item['quantity'] * 0.85
else:
total += item['price'] * item['quantity']
else:
total += item['price'] * item['quantity']
return total
- 常用重構手法
- 提取方法(Extract Method)
- 封裝成員變數(Encapsulate Field)
- 方法更名(Rename Method)
- 消除重複程式碼
第三階段:實戰應用
- TDD基本概念與流程
- 紅燈-綠燈-重構循環
- 單元測試的撰寫技巧
- 測試覆蓋率與品質指標
紅燈-綠燈-重構循環
Good code:
# 正確的TDD方法:先寫測試
import pytest
# 1. 紅燈:先寫失敗的測試
def test_factorial_of_zero():
assert calculate_factorial(0) == 1
def test_factorial_of_positive_number():
assert calculate_factorial(5) == 120
def test_factorial_of_negative_number():
with pytest.raises(ValueError):
calculate_factorial(-1)
# 2. 綠燈:寫最少的程式碼讓測試通過
def calculate_factorial(n):
if n < 0:
raise ValueError("Factorial is not defined for negative numbers")
if n == 0:
return 1
result = 1
for i in range(1, n + 1):
result *= i
return result
# 3. 重構:改善程式碼品質
def calculate_factorial(n):
"""計算階乘值"""
if n < 0:
raise ValueError("Factorial is not defined for negative numbers")
if n <= 1:
return 1
return n * calculate_factorial(n - 1)
Bad code:
# 錯誤的TDD方法:先寫實作再寫測試
def calculate_factorial(n):
if n < 0:
return None
if n == 0 or n == 1:
return 1
result = 1
for i in range(2, n + 1):
result *= i
return result
# 之後才寫測試
def test_factorial():
assert calculate_factorial(5) == 120
assert calculate_factorial(0) == 1
-
專案案例分析
- BMI計算機Clean Code版本實作
- 購物車系統的Clean Code改造
- 登錄註冊系統的重構實戰
-
程式碼審查流程
- 審查清單建立
- 給予建設性回饋的技巧
- 處理團隊中程式碼品質分歧
審查清單建立
Good
✅ 良好的程式碼審查評論:
- "這個函式做了太多事情,建議分解成較小的函式以提高可讀性"
- "考慮使用更描述性的變數名稱,例如將 'data' 改為 'user_profiles'"
- "這裡可能有空指標例外的風險,建議加上 null 檢查"
- "很好的重構!這樣的設計更容易測試和維護"
- "建議加上單元測試來覆蓋這個邊界情況"
Bad
❌ 糟糕的程式碼審查評論:
- "你的程式碼很爛"
- "為什麼要這樣寫?"
- "這個不對"
- "重寫整個函式"
第四階段:進階實踐
-
效能最佳化考量
- 何時最佳化?
- Clean Code與效能的權衡
- 常見效能反模式避免
-
建立個人程式碼品質標準