code-simplification

code-simplification

熱門

簡化程式碼以提升可讀性。適用於重構程式碼以提升清晰度但不改變行為時。適用於程式碼可運作但難以閱讀、維護或擴展時。適用於審查累積了不必要複雜性的程式碼時。

7.7萬星標
0分支
更新於 2026/7/3
SKILL.md
readonlyread-only
name
code-simplification
description

簡化程式碼以提升可讀性。適用於重構程式碼以提升清晰度但不改變行為時。適用於程式碼可運作但難以閱讀、維護或擴展時。適用於審查累積了不必要複雜性的程式碼時。

程式碼簡化

靈感來自 Claude Code Simplifier 外掛。在此改編為模型無關、流程驅動的技能,適用於任何 AI 程式碼代理。

概述

透過降低複雜度同時保留精確行為來簡化程式碼。目標不是減少行數,而是讓程式碼更容易閱讀、理解、修改和除錯。每個簡化都必須通過一個簡單的測試:「新團隊成員理解這個版本的速度是否比原始版本快?」

使用時機

  • 功能已可運作且測試通過,但實作方式比需要的更繁重時
  • 程式碼審查中發現可讀性或複雜度問題時
  • 遇到深度巢狀邏輯、過長函式或不明確的名稱時
  • 重構在時間壓力下撰寫的程式碼時
  • 合併分散在多個檔案中的相關邏輯時
  • 合併引入了重複或不一致性的變更後

何時不該使用:

  • 程式碼已經乾淨且可讀——不要為了簡化而簡化
  • 你還不了解程式碼的作用——先理解再簡化
  • 程式碼對效能至關重要,且「更簡單」的版本會明顯變慢
  • 你即將完全重寫該模組——簡化即將廢棄的程式碼是浪費力氣

五大原則

1. 精確保留行為

不要改變程式碼的功能——只改變表達方式。所有輸入、輸出、副作用、錯誤行為和邊界情況必須保持完全相同。如果不確定某個簡化是否保留了行為,就不要做。

每次變更前先問:
→ 對每個輸入是否產生相同輸出?
→ 是否維持相同的錯誤行為?
→ 是否保留相同的副作用和順序?
→ 所有現有測試是否仍能通過且無需修改?

2. 遵循專案慣例

簡化意味著讓程式碼與程式碼庫更一致,而不是強加外部偏好。在簡化之前:

1. 閱讀 CLAUDE.md / 專案慣例
2. 研究相鄰程式碼如何處理類似模式
3. 比對專案的風格:
   - 匯入順序和模組系統
   - 函式宣告風格
   - 命名慣例
   - 錯誤處理模式
   - 型別註解深度

破壞專案一致性的簡化不是簡化——而是無謂的改動。

3. 清晰勝於巧妙

當簡潔版本需要停頓思考才能解析時,明確的程式碼優於緊湊的程式碼。

// 不明確:密集的三元鏈
const label = isNew ? 'New' : isUpdated ? 'Updated' : isArchived ? 'Archived' : 'Active';

// 清晰:可讀的對應
function getStatusLabel(item: Item): string {
  if (item.isNew) return 'New';
  if (item.isUpdated) return 'Updated';
  if (item.isArchived) return 'Archived';
  return 'Active';
}
// 不明確:鏈式 reduce 搭配內聯邏輯
const result = items.reduce((acc, item) => ({
  ...acc,
  [item.id]: { ...acc[item.id], count: (acc[item.id]?.count ?? 0) + 1 }
}), {});

// 清晰:命名中間步驟
const countById = new Map<string, number>();
for (const item of items) {
  countById.set(item.id, (countById.get(item.id) ?? 0) + 1);
}

4. 維持平衡

簡化有一個失敗模式:過度簡化。注意這些陷阱:

  • 過度內聯——移除為概念命名的輔助函式,反而讓呼叫點更難讀
  • 合併不相關的邏輯——兩個簡單函式合併成一個複雜函式,並非更簡單
  • 移除「不必要的」抽象——某些抽象是為了可擴展性或可測試性,而非複雜度
  • 追求行數最少——行數少不是目標,容易理解才是

5. 範圍限於變更部分

預設只簡化最近修改的程式碼。除非明確要求擴大範圍,否則避免順便重構不相關的程式碼。無範圍限制的簡化會造成 diff 雜訊,並增加非預期回歸的風險。

簡化流程

步驟 1:先理解再動手(Chesterton's Fence)

在變更或移除任何東西之前,先了解它為何存在。這就是 Chesterton's Fence:如果你在路上看到一道柵欄卻不知道為什麼在那裡,不要拆掉它。先了解原因,再決定原因是否仍然適用。

在簡化之前,先回答:
- 這段程式碼的責任是什麼?
- 誰呼叫它?它呼叫誰?
- 邊界情況和錯誤路徑是什麼?
- 是否有測試定義了預期行為?
- 為什麼當初會這樣寫?(效能?平台限制?歷史原因?)
- 檢查 git blame:這段程式碼的原始背景是什麼?

如果你無法回答這些問題,你還沒準備好簡化。先閱讀更多背景資訊。

步驟 2:識別簡化機會

掃描這些模式——每個都是具體的信號,而非模糊的氣味:

結構複雜度:

模式 信號 簡化方式
深度巢狀(3 層以上) 難以追蹤控制流程 將條件提取為守衛子句或輔助函式
長函式(50 行以上) 多重責任 拆分為專注的函式並使用描述性名稱
巢狀三元運算子 需要心智堆疊來解析 替換為 if/else 鏈、switch 或查詢物件
布林參數旗標 doThing(true, false, true) 替換為選項物件或獨立函式
重複條件 多處出現相同的 if 檢查 提取為命名良好的謂詞函式

命名與可讀性:

模式 信號 簡化方式
通用名稱 dataresulttempvalitem 重新命名以描述內容:userProfilevalidationErrors
縮寫名稱 usrcfgbtnevt 使用完整單詞,除非縮寫是通用的(idurlapi
誤導名稱 名為 get 的函式卻會修改狀態 重新命名以反映實際行為
解釋「做什麼」的註解 // increment countercount++ 上方 刪除註解——程式碼已經夠清楚
解釋「為什麼」的註解 // Retry because the API is flaky under load 保留這些——它們承載了程式碼無法表達的意圖

冗餘:

模式 信號 簡化方式
重複邏輯 多處出現相同的 5 行以上程式碼 提取為共用函式
死程式碼 無法到達的分支、未使用的變數、註解掉的區塊 移除(在確認確實是死程式碼後)
不必要的抽象 沒有增加價值的包裝 內聯包裝,直接呼叫底層函式
過度設計的模式 工廠的工廠、只有一個實作的策略模式 替換為簡單直接的方式
冗餘型別斷言 轉換為已推斷的型別 移除斷言

步驟 3:逐步套用變更

一次只做一個簡化。每次變更後執行測試。將重構變更與功能或錯誤修復變更分開提交。 一個同時重構和新增功能的 PR 其實是兩個 PR——請分開。

每個簡化:
1. 進行變更
2. 執行測試套件
3. 如果測試通過 → 提交(或繼續下一個簡化)
4. 如果測試失敗 → 還原並重新考慮

避免將多個簡化批次處理成一個未經測試的變更。如果出錯,你需要知道是哪個簡化造成的。

500 行規則: 如果重構會觸及超過 500 行,請投資自動化(codemod、sed 腳本、AST 轉換),而不是手動變更。這種規模的手動編輯容易出錯且審查起來很累人。

步驟 4:驗證結果

完成所有簡化後,退一步評估整體:

比較前後差異:
- 簡化後的版本是否真的更容易理解?
- 你是否引入了任何與程式碼庫不一致的新模式?
- diff 是否乾淨且易於審查?
- 團隊成員會批准這個變更嗎?

如果「簡化」後的版本更難理解或審查,請還原。並非每次簡化嘗試都會成功。

語言特定指引

TypeScript / JavaScript

// 簡化:不必要的 async 包裝
// 之前
async function getUser(id: string): Promise<User> {
  return await userService.findById(id);
}
// 之後
function getUser(id: string): Promise<User> {
  return userService.findById(id);
}

// 簡化:冗長的條件賦值
// 之前
let displayName: string;
if (user.nickname) {
  displayName = user.nickname;
} else {
  displayName = user.fullName;
}
// 之後
const displayName = user.nickname || user.fullName;

// 簡化:手動建立陣列
// 之前
const activeUsers: User[] = [];
for (const user of users) {
  if (user.isActive) {
    activeUsers.push(user);
  }
}
// 之後
const activeUsers = users.filter((user) => user.isActive);

// 簡化:冗餘的布林回傳
// 之前
function isValid(input: string): boolean {
  if (input.length > 0 && input.length < 100) {
    return true;
  }
  return false;
}
// 之後
function isValid(input: string): boolean {
  return input.length > 0 && input.length < 100;
}

Python

# 簡化:冗長的字典建立
# 之前
result = {}
for item in items:
    result[item.id] = item.name
# 之後
result = {item.id: item.name for item in items}

# 簡化:巢狀條件搭配早期回傳
# 之前
def process(data):
    if data is not None:
        if data.is_valid():
            if data.has_permission():
                return do_work(data)
            else:
                raise PermissionError("No permission")
        else:
            raise ValueError("Invalid data")
    else:
        raise TypeError("Data is None")
# 之後
def process(data):
    if data is None:
        raise TypeError("Data is None")
    if not data.is_valid():
        raise ValueError("Invalid data")
    if not data.has_permission():
        raise PermissionError("No permission")
    return do_work(data)

React / JSX

// 簡化:冗長的條件渲染
// 之前
function UserBadge({ user }: Props) {
  if (user.isAdmin) {
    return <Badge variant="admin">Admin</Badge>;
  } else {
    return <Badge variant="default">User</Badge>;
  }
}
// 之後
function UserBadge({ user }: Props) {
  const variant = user.isAdmin ? 'admin' : 'default';
  const label = user.isAdmin ? 'Admin' : 'User';
  return <Badge variant={variant}>{label}</Badge>;
}

// 簡化:透過中間元件傳遞 props
// 之前——考慮 context 或 composition 是否更適合。
// 這是需要判斷的——標記它,不要自動重構。

常見合理化藉口

合理化藉口 現實
「程式碼能運作,不需要動它」 難以閱讀的運作中程式碼,在出錯時會難以修復。現在簡化可以為未來每次變更節省時間。
「行數越少總是越簡單」 一行的巢狀三元運算子並不比五行的 if/else 簡單。簡單在於理解速度,而非行數。
「我順便快速簡化一下這個不相關的程式碼」 無範圍限制的簡化會造成 diff 雜訊,並增加非預期程式碼的回歸風險。保持專注。
「型別本身就是文件」 型別記錄結構,而非意圖。命名良好的函式解釋「為什麼」比型別簽名解釋「做什麼」更好。
「這個抽象以後可能有用」 不要保留推測性的抽象。如果現在沒用到,就是沒有價值的複雜度。移除它,需要時再重新加入。
「原始作者一定有他的理由」 也許。檢查 git blame——應用 Chesterton's Fence。但累積的複雜度通常沒有理由;只是壓力下迭代的殘留物。
「我可以在新增功能的同時重構」 將重構與功能開發分開。混合的變更更難審查、還原和從歷史中理解。

紅旗

  • 需要修改測試才能通過的簡化(你可能改變了行為)
  • 「簡化」後的程式碼比原始版本更長且更難理解
  • 根據個人偏好而非專案慣例重新命名
  • 因為「讓程式碼更乾淨」而移除錯誤處理
  • 簡化你尚未完全理解的程式碼
  • 將多個簡化批次處理成一個大型、難以審查的提交
  • 在未經要求的情況下重構當前任務範圍之外的程式碼

驗證

完成簡化流程後:

  • [ ] 所有現有測試無需修改即可通過
  • [ ] 建置成功,無新警告
  • [ ] Linter/formatter 通過(無風格回歸)
  • [ ] 每個簡化都是可審查的增量變更
  • [ ] diff 乾淨——沒有混入不相關的變更
  • [ ] 簡化後的程式碼遵循專案慣例(對照 CLAUDE.md 或同等文件檢查)
  • [ ] 沒有移除或削弱錯誤處理
  • [ ] 沒有留下死程式碼(未使用的匯入、無法到達的分支)
  • [ ] 團隊成員或審查代理會認為該變更是淨改善