--- tags: aliases: date: 2025-08-04 time: 16:49:36 description: --- # 核心設計原則 遵循3Rs架構: 1. 可讀性(Readability):讓程式碼易於理解和維護 2. 可重用性(Reusability):減少重複程式碼,提高開發效率 3. 可重構性(Refactorability):支援模組化設計和持續改進 # 第一階段:基礎理論與核心原則 - **Clean Code定義與重要性** - 什麼是Clean Code:易讀、易懂、易維護的程式碼 - 技術債務的概念與影響 - 童子軍規則:讓程式碼比接手時更乾淨 Good code: ```python 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: ```python 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: ```javascript // 良好的命名 let elapsedTimeInDays; let activeUsers = []; let calculateTotalPrice = (price, quantity) => price * quantity; ``` ```python def fetch_user_profile(): return user_profile_data def validate_user_credentials(): # 驗證使用者憑證 codes..... ``` Bad code: ```javascript // 糟糕的命名 let d; // 經過的天數 let u = []; // 使用者列表 let calc = (a, b) => a * b; ``` ```python def data(): return user_info def process(): # 處理某些東西 pass ``` - **函式設計原則** - 單一職責原則:一個函式只做一件事 - 函式長度控制:目標在20行以下 - 參數管理:最多3個參數的建議 - 避免副作用與Flag參數 ## 一個函式只做一件事 Good code: ```python # 遵循單一職責的函式 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: ```python # 違反單一職責的函式 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: ```python # 無副作用、單一職責的函式 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: ```python # 帶有副作用和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: ```python # 遵循降層原則的順序 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: ```python # 混亂的函式順序 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: ```c # 使用例外處理 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: ```c // 使用錯誤碼的方式 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: ```python 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: ```python 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: ```python 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: ```python 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: ```python 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: ```python # 直接創建物件,違反開放封閉原則 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: ```python 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: ```python 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: ```python # 重構後:清晰且易於維護的程式碼 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: ```python # 重構前:複雜且難以理解的程式碼 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: ```python # 正確的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: ```python # 錯誤的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與效能的權衡 - 常見效能反模式避免 - **建立個人程式碼品質標準** # 參考來源