# AI 寫 code 越快，越需要軟體工程基本功

> Specs to code 說只要寫規格、壞了就重新生成，結果只換來一堆沒人能維護的 code。整理 Matt Pocock 講的五種 AI 翻車模式，聊 TDD、深模組這些基本功怎麼幫你把 agent 管好。

- URL: https://pizzanote.dev/zh-tw/ai/software-fundamentals/
- Published: 2026-10-18
- Updated: 2026-10-18

## 前言

這一兩年 AI 寫 code 越來越強，業界開始有人說，軟體工程那些老東西是不是可以丟了。最誇張的是一派叫「specs to code」：工程師只要寫好規格，剩下交給 AI 產 code；程式壞了也不用看 code，改規格、再生成一次就好，把 AI 當成編譯器。

聽起來很美好，但真的這樣玩過就會發現，一直重新生成，最後只會得到一坨沒人能維護的 code XD

我之前常常把客戶的需求整段貼給 Claude Code，做出來不對，第一個反應也不是去看 code，而是補一句需求，再叫它重做一次。重做個三、四輪，功能好像都有了，但同一件事有兩三種寫法散在不同檔案，最後要改一個小地方，連 AI 自己都改錯 XD

Matt Pocock 在 AI Engineer 有一場演講〈[Software Fundamentals Matter More Than Ever](https://www.youtube.com/watch?v=v4F1gFy-hqg)〉，把 AI 常見的翻車方式整理成五種，每一種都能在一本放了很多年的經典裡找到解法。

## 便宜的是 code，貴的是爛 code

Specs to code 背後的假設是「code 很便宜」，反正 AI 一秒產一大堆，壞了就丟。

但《The Pragmatic Programmer》很早就講過軟體熵（software entropy）：事情放著只會越來越亂。每次只顧眼前那一個改動、不管整體設計，codebase 就會一路爛下去，而且回不去。

John Ousterhout 在《A Philosophy of Software Design》裡對複雜度的定義也很直白：任何讓系統難以理解、難以修改的結構都算。一個改了就會出 bug 的 codebase，就是爛 codebase。

AI 只有在好改的 codebase 裡，生產力才會很驚人。所以軟體工程的基本功，現在比以前任何時候都重要。

## AI 翻車的五種姿勢

| AI 的症狀 | 人要補上的基本功 |
|---|---|
| 做出來的東西跟你腦中想的完全兩回事 | 先建立共同的設計概念，開工前讓 AI 把你問到底 |
| 回答又臭又長，講的詞你都聽不太懂 | 定義一份共同語言（ubiquitous language），讓雙方講同一套詞 |
| Code 看起來對，一跑就壞 | 用 TDD 把步伐縮小，回饋一次只接一點點 |
| AI 在 codebase 裡迷路，搞不懂現有邏輯 | 把一堆淺模組收成深模組，介面簡單、複雜藏在裡面 |
| 產出翻倍，人卻累到不行 | 介面自己設計，實作當灰箱丟給 AI |

左邊這些症狀，用過 agent 的人應該都遇過。右邊沒有一個是新東西。

## 先吵一架，再開工

AI 做出來跟你想的不一樣，通常是你們腦中的東西沒對齊。Fred Brooks 在《The Design of Design》裡講過「設計概念」（design concept）：幾個人一起設計系統時，大家腦中共享的那個東西，很難整份寫進一份 Markdown 裡。你跟 AI 一起設計也一樣。

AI 的毛病是太急，你話還沒講完它就開始產 plan。比較好的做法是反過來，叫它先別動手，一直追問你，把設計樹的每個分支、每個決定都問清楚，問個四十到一百題都很正常。等雙方真的有共識了，再把結論寫成 PRD 或 issue。

![兩種開工方式：直接開工是丟一段需求，AI 馬上產 plan，照自己的假設寫下去，做出來跟你想的兩回事；先吵一架是讓 AI 一直追問四十到一百題，把共識寫成 PRD 或 issue 再開工](/images/posts/software-fundamentals/grill-zh-tw.svg)

另一個問題是雞同鴨講。AI 解釋自己在做什麼的時候，常常用一堆你們專案裡根本沒人在用的詞，就像資深工程師想跟完全不懂技術的領域專家解釋晶片架構一樣。這正是 DDD 想解決的問題，做法也很 DDD：把專案裡的核心名詞和定義整理成一張表，放進一個 Markdown 檔，每次規劃都叫 AI 先讀。詞對齊了，它的 thinking 會短很多，做出來的東西也比較貼近原本的 plan。

這個部落格從 Sanity 搬到 Markdown 的時候，要決定的事多到嚇人：主網域用哪一個、網址要不要帶語言、中英文用不用同一個 slug、tag 要幾篇以上才值得開一頁。這些如果沒先問清楚，AI 會自己挑一個看起來合理的答案寫下去，等你發現的時候，網址早就被 Google 收錄了。

術語也是。PizzaNote 有 topic（前端、AI、生活）也有 category（像 SEO），category 還掛在 topic 底下，但文章 frontmatter 裡寫的 `category` 其實放的是 topic。這種專案裡的歷史包袱，沒寫成一張表，AI 每次都要重新猜一次。

> 推薦 Matt Pocock 開源的 [skills](https://github.com/mattpocock/skills)，可以直接裝進 Claude Code。[grill-me](https://github.com/mattpocock/skills/blob/main/skills/productivity/grill-me/SKILL.md) 會一直追問到沒有它自己偷偷假設的地方；ubiquitous language 會掃 codebase，幫你產出術語表；improve codebase architecture 會找出可以收成深模組的地方。

## 車速不能超過車燈

就算你給了 AI TypeScript 型別檢查、讓它開瀏覽器、還準備好自動化測試，它寫出來的 code 還是常常跑不起來。

《The Pragmatic Programmer》有個比喻很傳神：outrunning your headlights，車開得比車燈照得到的地方還快。回饋的頻率，就是你開發速度的上限。AI 的習慣是一口氣噴一大堆 code，最後才想到要跑測試，這樣不翻車才奇怪。

TDD 就是幫 AI 裝煞車。先寫一個小測試、讓它通過、再重構順便想一下設計，一次只走一小步。

![兩種寫 code 的節奏：一次噴幾百行、最後才跑測試，留下一堆不知道從哪修的 bug；或是測試、通過、重構一小步一小步重複，哪一步壞了馬上知道](/images/posts/software-fundamentals/headlights-zh-tw.svg)

我自己也被車燈照不到的地方撞過。PizzaNote 改版的時候，AI 幫我把標題換成整套中文 webfont，畫面很漂亮，在電腦上看也沒問題，結果手機的 LCP 直接飆到 12 秒。後來改成 build 的時候只抓文章用到的字做子集，還在 prebuild 加了一個 `check-content`，標題太長、描述長度不對就跳警告。現在 AI 寫完文章，build 一跑就知道有沒有超標，不用等上線才發現。

## 介面你顧，實作它寫

AI 很擅長生出一堆淺模組（shallow module）：每個模組功能少少的，介面卻很複雜，東一塊西一塊。AI 自己在這種架構裡探索，也一樣會迷路，搞不懂誰依賴誰。

Ousterhout 給的解法是深模組（deep module）：把一大包複雜的功能藏在一個很簡單的介面後面。AI 不用懂深模組裡的每一行，只要透過乾淨的介面跟它互動、在邊界上寫測試就好。把相關的 code 找出來收進深模組，系統就會變得很好做 TDD，AI 也比較不會迷路。好測的 codebase，一定也好維護。

![淺模組和深模組：淺模組介面寬、裡面沒做多少事，依賴纏成一團，AI 跟著迷路；深模組用很窄的介面藏住一大包實作，介面和測試邊界由人設計，實作交給 AI](/images/posts/software-fundamentals/modules-zh-tw.svg)

第五個問題也是從這裡解：產出翻倍，人卻累到不行。會累是因為你想把每個實作細節都塞進腦袋，跟 AI 一起同步，等於在 micro-manage 它。模組化本來就是為了降低認知負擔，所以把深模組當成灰箱（gray box）就好，介面和測試邊界你自己設計，裡面的實作交給 AI。金流這種真的不能錯的核心邏輯除外。

寫 PRD 的時候也一樣，重點寫模組要怎麼變、介面長怎樣，不要寫一堆實作細節。這也是 Kent Beck 說的，每天投資一點在系統設計上。

PizzaNote 裡就有一個這樣的例子。每一頁的 SEO 設定都只呼叫一個 `pageMetadata`，傳標題、描述、網址和分享圖進去就好；canonical、hreflang、x-default、OG、Twitter card 這些細節全部藏在裡面。我在意的是這個介面好不好用、輸出的標籤對不對，裡面怎麼組，交給 AI 寫就好。要加新頁面的時候，AI 也只要照著呼叫，不用每頁重寫一次 SEO。

## 給剛入行的你

如果你是非本科、或剛開始寫程式，上面那些深模組、DDD 可能有點遠。日常用 AI 的時候，我覺得記住三件事就夠了。

第一，把 AI 當成一個很聰明、但剛報到的工讀生。跟 AI 溝通其實跟跟人溝通一樣，交辦事情的時候問問自己：指令夠不夠清楚？他知道怎麼做才算你要的嗎？很多時候不能只丟一個模糊的目標過去，要告訴他怎麼做、給他一份 step-by-step 的 plan，開工前先讓他把所有疑問都丟出來，就跟前面的 grill-me 一樣。

第二，自己要有領域知識，不要當傳聲筒。真實的軟體公司裡，不會讓客戶直接去指揮工程師，也沒有工程師會看著 Google Play 的一星評論通靈修 bug。中間一定有懂 domain 的 PM 或資深同事，把問題翻成清楚的需求。跟 AI 合作的時候，那個人就是你。有了領域知識，你才會從單純下指令的使用者，變成跟 AI 協作的人；從回報 bug 的測試員，變成設計系統的人。

第三，把回饋迴圈建起來。寫程式一定會有 bug。除錯的流程其實很固定：蒐集錯誤資訊、找出原因、用對的方式修、再測一次。讓 AI 直接讀得到 terminal 或錯誤平台的訊息，再叫它寫出正確的測試來驗證，除錯時間真的會少很多。

## AI 衝前線，你畫地圖

Specs to code 最致命的地方，是讓我們不再投資系統設計。

Matt 的比喻是，AI 就像前線的士官（sergeant on the ground），大量改動、繁瑣實作都可以丟給它。但上面總要有一個人看整張地圖、決定往哪打，那個人是你。要做好這件事，靠的就是軟體工程界磨了二十幾年的基本功。

你還是可以讓 AI 一次幫你產幾百行 code，享受 vibe coding 的快感。但是，下次按「重新生成」之前，先把書架上那本《The Pragmatic Programmer》拿下來翻一下，好嗎？

## 參考資料

- Matt Pocock，〈[Software Fundamentals Matter More Than Ever](https://www.youtube.com/watch?v=v4F1gFy-hqg)〉，AI Engineer
- Matt Pocock，[mattpocock/skills](https://github.com/mattpocock/skills)（GitHub）
- David Thomas、Andrew Hunt，《The Pragmatic Programmer》
- John Ousterhout，《A Philosophy of Software Design》
- Frederick P. Brooks，《The Design of Design》
- Eric Evans，《Domain-Driven Design》
