iT邦幫忙

2026 iThome 鐵人賽

DAY 13
0
Claude AI

資深工程師的 Claude Code 工作筆記系列 第 13 篇

Day 13:學到的東西沒寫回規則檔,等於白學了一次

  • 分享至 

  • xImage
  •  

Day 11 講怎麼把一個問題真正、徹底地查清楚,Day 12 講怎麼讓 code review 的過程可以被查核。這兩件事分開來看都已經是完整的一段,做完之後,還缺最後一步。修完的 bug、審過的程式碼,教訓如果只留在腦子裡或這次的對話紀錄裡,下次遇到類似的情況,還是只能從零開始猜、從頭想一遍。真正把這件事做完,是把學到的東西寫回一個下次真的會被讀到的地方,這一步沒做,前面查得再仔細、審得再認真,都只解決了這一次,下次遇到同樣的狀況,還是得從頭再走一遍完全一樣的路。

這件事我一開始沒有特別當一回事,總覺得查清楚原因、改對地方就算結束了。後來發現同一類的狀況隔了一段時間又出現,重新查一次才想起來,這個成因其實上次就已經搞清楚過了,只是那次的理解沒有留下任何看得到的紀錄,全部留在當下的記憶裡,時間一久,記憶自然就模糊了,最後只剩下一種似曾相識的感覺,卻說不出具體是哪裡見過。這種重複繞同一圈的經驗多了幾次之後,我才真正把「寫回去」這件事,當成跟查清楚原因、改對地方同樣重要的一個步驟,而不是可有可無、隨時可以省略的收尾動作。

教訓要有去處,不是隨手寫進同一個檔案就好

我自己一開始也犯過一個很直覺的錯,覺得只要把教訓寫下來就夠了,隨手加進最常看的那份規則檔裡。這樣做一開始沒什麼問題,教訓不多的時候,混在一起也還讀得下去。累積久了才發現,教訓其實有完全不同的性質,全部塞進同一個地方,反而讓真正重要的東西被埋起來。

有一種教訓是每次都該檢查的,這種內容不管做什麼都會用到,值得放在最容易被看到的地方。有一種是特定情境才需要查的,平常用不到,真正卡住的時候才翻出來看,這種放在跟前者一樣顯眼的地方,只會讓每次都要看的內容變得又臭又長。還有一種是已經被更好的做法取代、不該再照著做的舊教訓,這種留著不刪,會讓人誤以為現在還適用,反而造成混亂。

這三種去處的差別,說穿了是使用頻率跟時效性完全不一樣。第一種每次都用得到,放錯地方會拖慢每一次的閱讀速度。第二種用得到的頻率很低,但一旦用到,往往是卡在一個很棘手的狀況,這時候如果混在大量平常就會看到的內容裡,反而不容易找到。第三種最麻煩,它不是不重要,是重要性已經過期了,留著不處理,比完全沒寫過還危險,因為它會讓人誤以為這仍然是現在該遵守的做法。

把教訓分成這三種去處之後,我才真正理解為什麼一開始那種隨手記法會出問題。不是教訓本身寫得不好,是把三種不同性質的東西混在同一份檔案裡,強迫每次閱讀的人得自己分辨哪些現在用得到、哪些只是參考、哪些其實已經過期,這件事本來就該在寫下去的當下做掉,不該丟給每次讀的人重新判斷一次。

這種分類的責任本來就該落在寫下去的那個當下,而不是留給日後翻閱的人,背後的道理跟前面講過的分層資源分配是同一件事,把該做的判斷提前做掉,後面每一次使用的成本就會變低。反過來,如果每次寫教訓的時候都圖方便,全部塞進同一個地方,等於是把分類這件事的成本,轉嫁給未來每一次要用到這份紀錄的人,看起來當下省了一點點力氣,長期算下來反而更貴,貴很多。

判準是這條規則有沒有來歷,不是聽起來重不重要

分好去處之後,還有一個更難的問題,同一份規則檔放久了,會累積很多條看起來都很正經的規則,哪些該留、哪些該砍,光憑感覺很難判斷。我自己現在會用一個具體的判準,這條規則有沒有明確的來歷,也就是背後有沒有一次真實發生過的事情,逼著這條規則被寫下來。

這個判準是我在一次重新盤點整份規則檔的過程中慢慢想出來的。那次盤點原本只是想把明顯過時的內容清掉,結果發現真正難處理的,不是那些一看就知道過時的部分,是一大批寫得四平八穩、看起來很有道理,卻怎麼想都想不起來當初為什麼要寫的規則。這些規則既不算錯,也說不上哪裡不好,但留著又講不出具體的理由,這種曖昧不明的狀態,才是最耗費判斷力的地方,比那些一眼就能判定該砍的內容棘手得多。

有來歷的規則,就算讀起來平淡無奇,也值得留著。像是不要把某個機密資訊直接寫進版本控制,這種規則單看文字很像廢話,但只要背後真的有一次因為疏忽而外洩的事故,這條規則就有存在的理由,不能因為它看起來太基本就順手砍掉。反過來,有些規則寫得語氣很重、看起來很像不能省略的鐵律,一查才發現背後沒有任何具體事件支撐,只是當初隨手寫了一句聽起來謹慎的話,這種規則留著除了讓整份檔案顯得更嚴肅,實際上沒有真正在保護什麼。

這種只靠語氣撐場面、不靠實質內容說服人的規則特別容易累積,因為寫下這種規則的當下,感覺上總是「寧可講重一點,以防萬一」,沒有人會覺得多加一句強調的話有什麼壞處,這種想法乍聽之下很合理,實際上卻是後來規則檔越疊越肥的一個重要成因。壞處要等到規則多到一定數量之後才會顯現,讀的人分不清楚哪些是真正踩過雷才留下的警示,哪些只是順口加重語氣,久而久之會對整份規則檔的用詞產生一種疲乏,連真正重要的那幾條,也會被同樣用力的語氣淹沒,反而失去該有的警示效果。

這種疲乏效應讓我想起小時候聽過的那個大家都很熟悉的喊狼來了的故事,用力的語氣就像那聲呼喊,第一次喊出來確實有效,喊的次數多了、又不是每次都真的有狼,聽的人自然會慢慢調低警覺的程度。規則檔裡的強調用詞也是同樣的道理,每一條都用最強烈的語氣寫,效果不會疊加,只會讓所有的強調一起貶值,到最後真正該被特別留意的那一條,反而淹沒在一片同樣用力的措辭裡,沒有辦法跳出來,這也是為什麼我現在寫新規則的時候,會刻意把語氣壓低,把強調留給真正值得強調的那一小撮內容。

這個判準最大的好處,是把一件原本很主觀的事情變得可以查核。以前判斷一條規則該不該留,靠的是讀起來順不順、感覺重不重要,這種判斷每個人標準都不一樣。換成問「這條規則有沒有來歷」之後,答案變成可以去查的,去問當初為什麼寫這一條,查得到就留,查不到就是候選刪除的對象,不會再淪為單純的語感判斷。

我自己會在每一條新加進去的規則後面,順手補一句這條規則的來歷,簡短寫清楚是哪一次的什麼狀況逼出了這條規則。這個習慣一開始感覺是多此一舉,畢竟寫下規則的當下,來龍去脈都還記得很清楚,沒有必要特地寫出來。實際上這句話的價值不是給當下的自己看,是給幾個月後、已經忘記細節的自己看,沒有這句話,日後回頭審查的時候,只能靠猜,猜錯了就可能把一條真正有用的規則誤判成可以刪除的候選。

這句話該寫多具體,我自己抓的標準是,要具體到讓幾個月後看到的自己,能夠判斷這件事現在還會不會發生。只寫「這裡曾經出過問題」這種籠統的說法,等於什麼都沒寫,因為看的人沒辦法據此判斷現在的狀況跟當初有沒有不同。反過來寫得太瑣碎,把當初的每個細節都鉅細靡遺地記下來,又會讓這句話本身變得又臭又長,違背了精簡的初衷。抓住中間那個剛好夠用的分寸,需要一點練習,但這個分寸抓對了,之後每一次重新審查規則檔,都會輕鬆很多,省下來的時間會遠遠超過當初多花的那一點力氣。

光看差異看不出對錯,得真的驗證行為

判斷完該留該砍之後,我不會就這樣直接動手刪,會先做一輪驗證。單純比對刪掉前後這份規則檔本身的差異,只能看出文字變了,看不出實際行為有沒有跟著改變。真正該驗證的是,刪掉這條規則之後,原本靠這條規則才能避免的行為,會不會真的又跑出來。

這件事讓我想起前面幾天講過的道理,光靠推論判斷一件事會不會出問題,跟實際跑一次去驗證,可靠程度差很多。刪掉一條規則之前,我會有把握地推論它應該是多餘的,但這個把握終究只是一個假設,不是驗證過的結論,得真的找一個對應的情境跑一次,看行為會不會偏離,才能真正確定這條規則能不能安全拿掉。

這種推論上的把握特別容易讓人誤判,因為推論本身讀起來很順,邏輯上也說得通,會給人一種已經想清楚的錯覺。實際上邏輯通順跟真的驗證過,完全是兩件事,邏輯通順只代表這個假設內部沒有明顯矛盾,不代表它符合真實世界的狀況。這個道理聽起來簡單,但真正要在刪除一條規則之前多做這一步驗證,需要一點自制力,因為多數時候推論本身看起來已經足夠有說服力了,很容易讓人跳過驗證直接動手。

這種驗證做起來比單純看文字差異麻煩很多,需要重新設計一個能觸發那個行為的情境,再確認拿掉規則之後結果有沒有變。麻煩歸麻煩,這一步不能省略,因為規則檔存在的目的從來不是文字本身工整好看,是要讓實際的行為維持在該有的樣子,只驗證文字、不驗證行為,等於只做了一半。

我自己會把這種驗證當成一種投資,設計驗證情境確實要花額外的時間,但這個情境一旦設計出來,之後每次調整同一份規則檔,都可以重複拿來用,不是一次性的成本。累積久了,這些驗證情境本身會變成一份針對這份規則檔的迴歸測試,之後不管是加規則、刪規則、還是調整規則的措辭,都可以先跑一次這些情境,確認沒有把原本該擋住的行為意外放行,這件事跟前面除錯那幾天講過的重現方法,其實是同一種思路的延伸應用,只是應用的對象從程式邏輯換成了規則本身。

精簡是必要的,但精簡工具本身也有盲點

規則檔用久了一定會越疊越肥,這件事我覺得不用等到真的變成問題才處理,一開始就該預期它會發生,定期回頭精簡。精簡的做法我自己會設一個大概的行數上限,超過就回頭把最少用到的部分抽出去放到另一個引用檔,主檔只留一行指路,這樣主檔不會無限膨脹,需要細節的時候還是找得到。

設這個上限的時候,我特別提醒自己不要把精簡做成單純的刪減。抽出去的內容還是有價值,只是使用頻率不夠高,不值得放在每次都要讀的主檔裡,精簡真正的意思是把低頻的內容搬到一個需要的時候還找得到的地方,不是把它們直接丟掉。如果精簡變成單純地刪東西,遲早會刪掉某些其實還有用、只是最近沒用到的內容,等到真的需要那份細節的時候,才發現已經找不回來了,這種損失往往要過很久之後才會被發現,發現的時候通常也已經來不及了。

抽出去的內容我會統一集中放在幾個依主題分類的引用檔裡,不會散落在各個角落,也不會這次抽到這個資料夾、下次抽到另一個資料夾,這樣主檔裡那一行指路的說明才有意義,找的人照著指路的說明去,一定找得到,不會發生指路指到一半、內容其實藏在別的地方的情況。這種集中管理聽起來是個小細節,實際上決定了精簡之後這份規則檔還能不能被信任,指路指錯的次數多了,之後大家乾脆不相信這些指路的說明,那精簡這件事等於白做了。

這件事最近我自己也認真測試過一套專門幫忙做這種精簡跟審核的官方工具,測試完最有價值的心得,不是它抓出了什麼該砍的東西,是它讓我看清楚這類工具本身的極限在哪裡。它確實抓到了幾種常見的問題,語氣過度強調的用詞、已經退役卻還留著的舊版本專屬做法、容易誘導模型硬掰理由的範例,這些都抓得很準。但遇到兩條規則彼此打架、該用哪一條當標準這種情況,它會自己選一邊,不會誠實地把衝突攤出來讓人決定。

我特地設計了一個埋著好幾種問題的測試檔案去驗證這件事,裡面故意混了語氣過重的規則、早就該淘汰的舊做法、還有一組互相矛盾的規則當對照組,每一種問題都刻意混在看起來很正常的段落中間。工具在前面幾種類型上表現得非常好,抓得又快又準,但一遇到那組互相矛盾的規則,它沒有指出這裡有衝突需要人決定,而是自己選了看起來比較合理的那一條,把另一條當成該刪的對象處理掉。如果我沒有事先知道這裡刻意埋了一組衝突,很可能就會照單全收,讓工具替我做了一個它其實沒有資格做的決定。

設計這個測試檔案的過程,我特別注意要讓那組衝突的規則,單獨看都很合理,寫得都四平八穩,只有放在一起比較的時候,才看得出彼此矛盾。這種安排是刻意的,因為現實中真正麻煩的衝突,通常就是這種樣子,每一條單獨看都沒有問題,問題是兩條同時存在、卻指向不同方向的時候,才會顯現出來。如果測試裡的衝突太明顯,任何工具都能輕易抓到,就沒辦法真正驗證出這類工具的極限在哪裡。

這次測試也讓我重新思考,為什麼一套官方出品、設計得已經很仔細的工具,還是會在這種地方露出破綻。仔細想過之後覺得這不是工具做得不夠好,是這類判斷本身的性質決定了它天生就沒辦法被完全自動化,換一套更聰明的工具去做,遇到同樣的衝突,恐怕還是會遇到同樣的困境。判斷兩條規則哪一條該優先,牽涉到的是對整體目標的理解,是這個規則檔服務的對象到底更在意哪一種風險,這種理解沒辦法只靠讀規則檔的文字本身推得出來,工具能看到的終究只有文字,看不到文字背後那個更大的脈絡。

這件事讓我對「用工具幫忙維護規則檔」這件事的期待重新校準了一次。工具能做的是找出明顯的候選項,省下人工一條條翻找的力氣,但真正涉及取捨、涉及兩種立場互相衝突該聽誰的判斷,工具沒辦法幫我做決定,硬要它做,它只會選一個看起來合理的答案,不會老實說這裡其實有分歧。這種時候還是得靠人自己攤開來看,工具的建議只能當作起點,不能當作終點,這個角色的定位越清楚,工具用起來反而越安心。

這個發現讓我更謹慎地看待任何一份工具自動產出的建議清單,不管是審核規則檔還是別的場景都一樣,這種謹慎不是要否定工具的價值,是提醒自己工具給出的每一項建議,背後的可靠程度並不均等。清單裡列出來的每一項,背後判斷的困難程度其實差很多,有些是一翻兩瞪眼、規則本身沒有爭議的機械性判斷,有些是牽涉到取捨、沒有標準答案的判斷,工具給出建議的時候,通常不會區分這兩種,全部用同樣篤定的語氣呈現。這也是為什麼我現在看到任何自動產出的建議,會先問自己這一項屬於哪一種,再決定要不要直接採納,還是得自己重新想一次。

特例跟長期規則要分開,不是每次踩坑都該加一條規則

累積教訓的過程走了一段時間之後,我也犯過另一種錯,每次踩到坑,第一反應就是把這次的具體狀況寫成一條新規則加進去,做久了規則檔裡塞滿了各種只在極少數情況才會發生的特殊案例,讀起來又長又瑣碎,真正該遵守的核心原則反而被淹沒在一堆邊角案例裡。

這種見坑就補一條規則的反應,其實是一種很自然的心理,剛踩完坑、印象最深刻的時候,會很想確保這件事以後絕對不會再發生,寫一條規則感覺是最直接的保證,好像寫下去的當下,這個問題就真的被解決了。問題是這種當下的迫切感,跟這件事實際上未來會不會再發生,是兩件不完全相關的事,情緒上的迫切不代表發生機率真的很高,靠情緒強度來決定要不要升格成規則,判斷出來的結果常常不準。

後來我會先讓自己冷靜下來,多等一下,問一個問題再決定要不要加,這件事以後還會不會再發生,還是這次剛好是一種很少見的組合。真的會反覆發生的,才值得升格成一條長期規則。只是這次剛好運氣不好撞上的特殊狀況,我會傾向記錄下來當作參考案例,放在前面提過的那個「需要時再查」的分類裡,不會直接寫成一條大家每次都要遵守的規則。

這個小習慣改變之後,我發現規則檔成長的速度明顯慢了下來,但這不代表教訓變少了,只是大部分的教訓都先進了參考案例那個分類,只有真正反覆出現的才會被拉出來升格。這種篩選機制讓每次都要看的核心規則維持在一個可以負擔的長度,同時也沒有真的丟掉任何一次踩坑的紀錄,只是把它們放進了不同的優先層級,需要的時候還是找得到,不需要的時候不會一直干擾視線,這個效果一開始完全沒有預期到,算是這套分類方式意外帶來的一個額外好處,比原本設想的目的還要更有價值。

這個判斷本身從來沒有絕對正確的答案,有時候一開始覺得是特例,後來發現同樣的狀況又出現了第二次、第三次,這時候就該把它從參考案例升級成正式規則。我會把這件事當成一個持續在調整的過程,不是寫一次就永遠不變,規則檔的內容本來就該隨著實際發生的事情動態調整,寫死不動反而才是問題。

判斷一件事算不算反覆發生,我自己會設一個很粗略的門檻,同一類狀況出現第二次的當下,就先在心裡標記起來,出現第三次就正式升格,不會等到累積更多次才處理。這個門檻訂得低一點,代價是偶爾會把一個其實只是巧合連續發生兩次的狀況誤判成該升格的規則,但比起等到累積很多次才發現這其實是常態、卻已經在這段時間反覆吃過同樣的虧,這個代價我覺得划算得多,寧可偶爾升格得早了一點,也不要一直放任同樣的虧反覆吃下去。

誠實承認規則檔本身也可能是錯的

有一件事我覺得特別值得放在最後講清楚,維護規則檔這件事,最容易被忽略的風險,不是漏寫了什麼,是規則檔本身跟現實脫節了卻沒有人發現。規則裡提到的某個做法、某個工具,可能早就已經不存在了,但因為沒有人特別去查證,規則檔還是照著舊的說法寫,讀的人照著做,才發現根本行不通。

我自己現在會把這件事當成一條不能妥協的紅線,發現規則檔寫的東西跟實際狀況對不上,不會照著錯的內容硬做,也不會自己憑感覺腦補一個版本硬掰過去,會直接標記出這個矛盾,回頭去查證哪個才是對的。規則檔的權威性建立在它跟現實一致這件事情上,一旦兩者對不上,就必須修正,不能將錯就錯地繼續照著執行。

這條紅線之所以重要,是因為規則檔跟現實脫節這件事,通常不會一次就爆發成大問題,是一點一點累積的。第一次遇到對不上的地方,可能只是某個工具改了名字,規則檔還寫著舊名字,影響不大。但如果每次遇到這種小落差都選擇照著錯的內容硬做,或者自己腦補一個順理成章的版本蒙混過去,這種落差會越滾越大,等到規則檔已經有一大半跟現實脫節,要修正的成本會遠遠超過當初每一次小落差發生時就順手修正的成本,這種代價的落差,越拖到後面越懸殊。

回頭看這一整套維護的過程,跟前面幾天講過的每一件事,其實都是同一種紀律的不同應用,只是套用的場景不一樣。查核事情有沒有真的對,不能只看表面說法,要去驗證背後的實際狀態,這件事在除錯的時候是這樣,在審查程式碼的時候是這樣,在維護規則檔的時候,一樣是這樣。差別只是這次要查核的對象,換成了規則檔本身。

這件事也讓我意識到一個有點矛盾卻很真實的處境,規則檔存在的目的,是幫忙把過去驗證過的判斷保留下來、減少下次重新想一遍的成本,但規則檔本身也需要被驗證,也可能過時、也可能出錯。它既是幫忙做判斷的工具,同時也是需要被判斷的對象,這兩個身分同時成立,不會因為它叫做規則檔就自動免於被檢驗。願意把這種雙重身分老實承認下來,我覺得才是真正把整套維護的紀律走完,而不是把規則檔當成一份寫完就可以高枕無憂的定案。

這種雙重身分的處境,其實也適用在很多其他看起來很有份量、很有權威的東西上,任何一份被拿來當作判斷依據的文件,本身都不是憑空豁免於被檢驗的,它的權威性不是與生俱來的,是靠持續跟現實對照、持續被驗證,才慢慢累積出來的。一旦停止這種持續對照,權威性就會開始悄悄流失,就算表面上看起來還是那份寫得很仔細、很正式的文件,實際上早就已經跟不上現實了,只是還沒有人去戳破這件事而已。

我自己會定期把整份規則檔攤開來重新看一次,不是逐條檢查有沒有錯字,是站在一個比較陌生的角度重新問,這份檔案現在講的東西,跟我實際在做的事情,還對得上嗎。這種重新檢視的頻率不需要太高,但一定要真的排進行事曆裡,不能只靠感覺哪天想到才做,因為靠感覺想到的次數,往往比規則檔實際偏離現實的速度慢得多,等真的想到要檢查的時候,落差可能已經累積了不少。

這種定期檢視我會刻意排在一個跟平常忙碌的工作節奏錯開的時間點,避開手上正忙著趕一件事的時候,因為那種狀態下很容易為了趕快做完,隨便掃過去就說沒問題,甚至沒認真讀完就先給自己一個過關的結論。找一個相對空閒、可以慢慢讀的時段,才有辦法真的用陌生的角度重新審視,而不是帶著「趕快結束這件事」的心情草草了事,這個安排看起來只是時間管理上的小技巧,實際上直接影響了這種檢視能不能真正發揮效果。


上一篇
Day 12:一個人靠判斷就能停,團隊得靠流程才能真的信
下一篇
Day 14:原來我摸出來的這套習慣,官方已經寫成一份六階段的完整地圖
系列文
資深工程師的 Claude Code 工作筆記 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言