Files
Obsidian-Main/00.00 Inbox/clean code.md
Awin Huang a7ab71b61d vault backup: 2025-08-04 18:02:21
Affected files:
00.00 Inbox/clean code.md
2025-08-04 18:02:21 +08:00

633 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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與效能的權衡
- 常見效能反模式避免
- **建立個人程式碼品質標準**
# 參考來源