iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
Software Development

AI 時代的 Clean Code:30 天讓 AI 產出的程式碼可讀、可驗證、可維護系列 第 8

Day 8|同一項需求交給下一個 AI Agent,三種函式結構會走出哪條修改路徑?

  • 分享至 

  • xImage
  •  

安安~我是ChiYu~

昨天,我從三份函式拆分結果中選了 Stepdown 版本。

ProcessOverdue 現在可以由上而下讀成四個步驟:找出逾期候選、逐筆處理、儲存狀態、回傳結果。入口變清楚了,但一份結構是否真的好用,不能只看今天讀起來順不順,還得看下一項需求進來時,修改會自然落在哪裡。

接下來接手的 Agent 都是全新 Session,沒有上一輪對話,只能從目前的函式、型別、測試與 Repository 規則重建設計意圖。

我先建立三種外部行為相同的函式結構,再把同一個新欄位交給九個全新 Session。九次都把需求做對,資料卻走出不同路徑;其中一種結構甚至出現兩種都說得通的放法。

我最後接受 CQS 結構,不是因為它符合的原則比較多,而是這次新增的資料,剛好在同一個批次責任裡產生、判斷與使用。今天要回答的問題就是:函式結構,會不會改變下一個 Agent 眼中的合理修改位置?

〈函式的啟發式原則〉:參數、CQS、例外、DRY 與副作用要一起取捨

《無瑕的程式碼 第二版》的〈函式的啟發式原則〉提供很多檢查函式的方法。這次我挑出直接碰到逾期流程的五個主題:參數、Command–Query Separation、例外、DRY 與副作用。

  • 參數:數量變多時,要檢查函式是否承擔太多責任;把參數搬進建構式或參數物件,不代表依賴真的消失。
  • Command–Query Separation(CQS):Query 回答問題,Command 改變狀態。呼叫端應該能從介面看出哪一種行為會發生。
  • 例外:可預期失敗、未知錯誤與取消,必須保留不同語意,不能為了介面整齊全部壓成同一個 false
  • DRY(Don't Repeat Yourself):要消除的是同一份知識的重複,不是把兩段剛好相似的 Code 硬綁在一起。
  • 副作用:函式除了回傳結果以外,是否會修改 Entity、發送通知或寫入資料庫,應該讓呼叫端看得出來。

這五項原則不會永遠指向同一個答案。零參數可能只是把依賴搬家;硬把 Command 改成沒有回傳值,可能讓呼叫端拿不到通知結果;為了消除表面重複而建立共用抽象,也可能綁錯規則。

書中還談到結構化程式設計,也就是讓控制流程主要由順序、條件判斷與迴圈組成,避免任意跳躍。三份候選的控制流程很接近,因此這項觀念只作為閱讀背景,不列入本次實驗變因。

我的比較標準不是「哪一份同時符合最多原則」,而是:目前需求下,哪一種結構最容易看懂行為、資料與副作用,也最容易承接下一次修改?

CLEAN 原則

N — Non-Surprising Behavior 符合預期:函式可以重新整理,系統不能偷偷換答案

N — Non-Surprising Behavior 符合預期 先固定外部可觀察行為。三份候選可以調整參數、區域變數與內部型別;失敗、取消、重跑、通知與儲存順序不能改變。任何一項答案漂移,該候選就不進入結構比較。

這次需要固定的答案如下:

Gateway 回傳 true
→ 繼續處理
→ SaveChangesAsync
→ 200 OK

Gateway 回傳 false
→ notificationFailureCount 加一
→ 繼續處理其他項目
→ SaveChangesAsync
→ 200 OK

未知 Exception
→ 中止後續流程
→ 不執行 SaveChangesAsync
→ ASP.NET Core 回傳 500

OperationCanceledException
→ 原樣向上傳遞取消
→ 不執行 SaveChangesAsync

這四種結果的語意不同。Gateway 回傳 false,表示這次通知嘗試未成功,但整批工作仍可繼續;未知例外代表系統發生非預期故障;取消則是外部明確要求停止,不能被轉成一般失敗後繼續執行。

已經是 Overdue 的項目再次執行時,不會再增加 processedCount,但仍要再次通知。每筆處理也有固定順序:先修改 EF Core 追蹤中的 Entity,再呼叫 Notification Gateway;等整批通知完成,才執行一次 SaveChangesAsync

我先用鎖定行為測試固定這份矩陣,再讓 Agent 整理函式。公開 Evidence 保存測試與驗證輸出;正文則沿著這些固定答案比較結構。

第一階段先建立三種外部行為相同的函式結構

三份候選使用相同基準、Codex GPT-5.6-SOL-HIGH、修改範圍、測試與行為限制,只有 Prompt 強調的函式原則不同。第一階段負責建立可比較的結構,第二階段再用新需求檢查修改路徑。

我刻意不替原則計分。參數比較少、CQS 比較完整,或方法名稱比較明確,都只能說明一部分;真正的差異,要等新資料進來後才看得見。

降低方法參數,並把摘要規則集中管理

第一種 Prompt 要求降低 Helper 的表面參數數量,並集中三項摘要統計。輸出因此多了一個只存活於單次 Request 的 OverdueBatchProcessor

var processor = new OverdueBatchProcessor(
    dueIncompleteWorkItems,
    notificationGateway,
    cancellationToken);

var processingSummary = await processor.ProcessDueIncompleteWorkItemsAsync();

ProcessDueIncompleteWorkItemsAsync 變成零參數,但 dueIncompleteWorkItems、Gateway 與 CancellationToken 沒有消失,只是一起搬到 OverdueBatchProcessor 的建構式。

它也新增 OverdueProcessingSummary.Record,集中三項統計規則:

public OverdueProcessingSummary Record(OverdueProcessingResult result) =>
    new(
        OverdueStatusChangeCount + (result.StatusChangedToOverdue ? 1 : 0),
        NotificationAttemptCount + 1,
        NotificationFailureCount + (result.NotificationSucceeded ? 0 : 1));

這份候選把統計規則收進 Summary。後續需求進來後,我會檢查新資料是否也自然屬於 Summary,還是應該留在批次流程。

統計規則有了固定位置,同時新增 Processor、Summary 與 Result 三個私有型別。方法簽章雖然變短,讀者仍要進入處理器才能看見原本的依賴。這正好提醒我:參數數量在這裡只能拉警報,不能直接證明責任已經變少。

拆開狀態查詢與狀態修改(CQS)

第二種任務要求 Agent 拆開「是否需要改狀態」的 Query 與「真的改狀態」的 Command,但不能為了嚴格 CQS 丟掉 Notification Gateway 的 bool 結果。

重構後的主要迴圈是:

foreach (var workItem in dueIncompleteWorkItems)
{
    if (RequiresOverdueStatusChange(workItem))
    {
        ChangeStatusToOverdue(workItem);
        overdueStatusChangeCount++;
    }

    var notificationSucceeded = await notificationGateway.SendOverdueAsync(
        workItem,
        cancellationToken);

    notificationAttemptCount++;

    if (!notificationSucceeded)
    {
        notificationFailureCount++;
    }
}

RequiresOverdueStatusChange 只回答問題,ChangeStatusToOverdue 才修改 Entity。狀態判斷、狀態修改、外部通知與統計仍留在同一段批次流程裡。

SendOverdueAsync 會產生副作用,也會回傳結果。呼叫端需要這個 bool 更新失敗統計,因此這裡保留意圖明確的回傳值。若只追求「Command 不回傳資料」的形式,反而會丟掉流程需要的資訊。

讓方法名稱揭露副作用,並建立內部執行結果

第三種任務要求 Agent 先列出狀態修改、通知、儲存與 HTTP Response 的實際順序,再讓主要方法名稱直接說出副作用。

Agent 把批次方法改名為 ApplyOverdueStatusesAndAttemptNotificationsAsync,並建立私有的 OverdueProcessingResult

var processingResult = await ApplyOverdueStatusesAndAttemptNotificationsAsync(
    dueIncompleteWorkItems,
    cancellationToken);

var processingSummary = new ProcessOverdueResponse(
    processingResult.OverdueStatusChangeCount,
    processingResult.NotificationAttemptCount,
    processingResult.NotificationFailureCount);

方法名稱明確揭露「修改逾期狀態」與「嘗試通知」兩個副作用。私有 Result 把內部執行結果與 HTTP Response DTO 分開;DTO 是描述 API 要交換哪些資料的物件。

目前只有一個 API 使用這份結果,兩個型別暫時擁有相同欄位,Action 還要多做一次映射。未來若出現排程工作或其他輸出介面,這層隔離才可能回收成本。

三份候選都做對,第一眼仍看不出下一次修改的成本

三份候選都守住固定行為,也通過相同驗證。完成第一階段時,我偏向 CQS,因為它用較少的新概念拆開查詢與修改;但這仍只是當下的閱讀感受,還不足以決定哪一份最好維護。

所以我沒有停在「看起來比較乾淨」,而是加入一項後續需求,直接觀察下一個 Agent 怎麼改。

第二階段用新欄位逼出資料所有權與傳遞成本

新需求只增加一個 Response 欄位:

Response 新增 failedNotificationWorkItemIds。只收集 Notification Gateway 回傳 false 的工作項目 ID,並依實際通知嘗試順序排列。

這個欄位需要同時取得 workItem.IdnotificationSucceeded。Agent 必須決定失敗 ID 要留在批次方法、單筆 Result、Summary,還是經過內部 Result 映射到公開 Response。

本文所說的「資料所有權」,指的是哪個函式或型別負責產生、保存、修改與傳遞這份資料。

需求同時鎖定以下條件:

  • false 才能收集 ID,未知例外與取消不能被當成一般通知失敗。
  • ID 順序必須和通知嘗試順序一致,不能事後另外排序。
  • 沒有失敗時回傳空陣列,不能是 null 或省略欄位。
  • 已經是 Overdue 的項目仍會再次通知,也可能出現在失敗 ID 裡。
  • 新資料若穿過函式、結果型別與公開 Response,每一層都必須保持相同語意。

為什麼三種結構都要重複執行三次?

單次輸出可能只是 Agent 的偶然選擇,因此每種結構都重複執行三次。九個匿名 Worktree 隱藏 Branch、Tag、Commit Message 與 Git 歷史,Agent 只能閱讀目前的 Code、測試與 Repository 規則。

三次重複用來觀察同一結構是否出現不同合理路徑,不構成統計證明。我關心的是「修改位置是否反覆出現」,不是替模型算出一個穩定機率。

先冷讀再實作,把「看懂」和「改對」拆開

Cold Read(冷讀) 是讓全新 Agent 只閱讀目前的 Code、測試與 Repository 規則,在不修改檔案的情況下重建行為與資料流。

每個 Session 第一回合先冷讀,第二回合再沿用相同 Context 實作需求,用來分開觀察「是否理解現況」與「理解如何轉成修改」。

第一回合 Prompt:只冷讀,不准改 Code

你正在參加 Day 8 的匿名函式結構交接實驗。模型與 Reasoning effort 已由外部 CLI 固定,請勿用模型自述或全域設定覆蓋執行條件。

這一回合只做冷讀,禁止修改、建立或格式化任何檔案,也不要執行 Build、Test、Smoke。請勿讀取 Git branch、log、tag、reflog、commit message 或其他歷史資料;判斷只能來自目前 Worktree 的 AGENTS.md、Production Code、測試與指令碼。

請先閱讀 AGENTS.md,接著定位 POST /api/work-items/process-overdue、ProcessOverdueResponse、通知 Gateway、EF Core 儲存位置,以及所有 ProcessOverdue 行為測試。讀完後依序回答:

1. Notification Gateway 回傳 false 時,流程是否繼續、是否儲存、HTTP 結果為何?
2. Notification Gateway 拋出未知 Exception 時,哪一個後續副作用不會執行,HTTP 結果為何?
3. Notification Gateway 拋出 OperationCanceledException 時,取消如何傳遞,資料是否儲存?
4. 已經是 Overdue 的工作項目再次執行時,是否仍會通知,哪些統計會改變?
5. 請列出查詢候選、修改 tracked Entity、通知、SaveChangesAsync 與建立 HTTP Response 的實際先後順序。
6. 若 Response 新增 failedNotificationWorkItemIds,內容只收集 Gateway 回傳 false 的工作項目 ID,並依通知嘗試順序排列,你初步判斷最少要修改哪些 Production symbols?請只說位置與資料流,不要設計或實作答案。

每題都要附上檔案路徑、method 或 type 名稱,以及足以重查的短證據。最後列出實際讀取的檔案與仍不確定的地方,然後停止。不要提出候選類型、啟發式原則名稱或優劣排名。

前五題要求 Agent 重建正常失敗、未知錯誤、取消、重跑與副作用順序。第六題才加入新需求,記錄它認為資料最少要穿過哪些位置。

第二回合 Prompt:沿用同一個 Session 實作

接續剛才的冷讀,現在實作同一項後續需求。不要讀取 Git branch、log、tag、reflog、commit message 或其他歷史資料;候選身分不屬於任務資訊。

## 新行為

POST /api/work-items/process-overdue 的 JSON Response 新增 failedNotificationWorkItemIds:

- 型別為工作項目 Guid ID 的陣列。
- 只收集 Notification Gateway 回傳 false 的工作項目。
- 排列順序必須和該次 Notification Gateway 的實際嘗試順序相同。
- 沒有通知失敗時回傳空陣列,不能省略欄位或回傳 null。
- 已經是 Overdue 的項目仍須再次通知;若該次回傳 false,也要收進陣列。

## 必須保持的既有行為

- Gateway 回傳 false:增加失敗統計、繼續處理,整批完成後儲存並回傳 200 OK。
- 未知 Exception:原樣向上傳遞給 ASP.NET Core,形成 500,不得執行 SaveChangesAsync。
- OperationCanceledException:原樣向上傳遞,資料不得儲存。
- 每筆仍先修改 EF Core tracked Entity,再呼叫通知;全部通知完成後才執行一次 SaveChangesAsync。
- 既有 Route、Status Code、其他 JSON 欄位、通知次數與統計語意保持不變。

## 修改邊界

- 只允許修改:
  - src/WorkItems.Api/Contracts/WorkItemContracts.cs
  - src/WorkItems.Api/WorkItemsController.cs
- 測試已鎖定,不得修改、刪除或跳過測試。
- 不得新增檔案、套件、Schema、Service、Repository、Interface、Outbox 或架構層。
- 公開 DTO 新增的參數必須補繁體中文 XML 文件。
- 不要 Commit。

完成後執行 Repository 指定的 Locked Restore、Release Build、9 項 Test、Format、NuGet Vulnerability Audit、HTTP Smoke 與 git diff --check。

最後回報:實際修改的 symbols、資料如何穿過函式與結果型別、是否修正了冷讀判斷、測試或 Build 共跑幾次、完整驗證結果,以及剩餘風險。

這兩份 Prompt 沒有告訴 Agent 應該套用 CQS、DRY 或哪一種設計模式。三份結構已經存在,Agent 只能從目前的 Code 找到自己認為合理的延伸方式。

冷讀都能重建既有行為,差異出現在新資料要放哪裡

九個 Session 都正確重建以下行為:

  • Gateway 回傳 false 時,流程會繼續、儲存並回傳 200 OK
  • 未知例外會中止流程,不執行 SaveChangesAsync,最後形成 500
  • 取消會向上傳遞,資料不會儲存。
  • 已經 Overdue 的項目仍會通知,但不再增加 processedCount
  • Entity 修改、通知、整批儲存與 HTTP Response 的先後順序沒有被誤解。

前五題沒有拉開差異。九個 Session 都通過既有行為的理解門檻;真正的分歧出現在第六題,也就是新資料該由誰負責。

CQS 與揭露副作用的結構,各自讓三次冷讀得到相同資料路徑;集中摘要規則的結構則留下兩種合理解釋。這表示資料所有權仍有歧義,但不能直接把「出現分歧」當成結構品質排名。

九次實作都做對,三種結構仍帶出不同修改路徑

九份輸出都只修改允許的 Production 檔案,主流程複驗後也沒有發現行為漂移。

下面直接比較資料由誰收集、會穿過哪些型別,以及目前新增了哪些結構成本:

函式結構 失敗 ID 由誰收集與傳遞 三次執行的結果 目前要支付的成本
降低參數並集中摘要 批次方法或單筆 Result 都可能收集,最後交給 Summary 產生兩種都符合鎖定需求的資料路徑 Repository 必須再說清楚 Summary 是否擁有完整批次結果
拆開查詢與修改(CQS) 批次方法直接收集,再建立公開 Response 三次都走相同路徑 資料路徑直接,但只適合目前資料都在同一責任裡的情境
揭露副作用並建立內部 Result 批次方法收集,先放進內部 Result,再映射到公開 Response 三次都走相同路徑 多一層映射;有第二種輸出介面時才較容易回收這項成本

這張表不是要找最少型別的版本,而是把每一份資料要穿過的責任攤開。以目前只有一個 HTTP 輸出的情境來看,CQS 路徑最直接;若後面真的出現第二個消費者,答案就可能改變。

集中摘要規則後,Agent 對資料所有權有兩種合理解釋

其中兩次,Agent 沒有改動單筆 OverdueProcessingResult,而是在批次迴圈另外建立集合:

workItem.Id + NotificationSucceeded
→ failedNotificationWorkItemIds
→ OverdueProcessingSummary.ToResponse(...)
→ ProcessOverdueResponse

另一次,Agent 認為 Summary 應該完整擁有這次處理結果,因此把 ID 一路往下傳:

workItem.Id
→ OverdueProcessingResult
→ OverdueProcessingSummary.Record(...)
→ OverdueProcessingSummary
→ ProcessOverdueResponse

兩種路徑都通過鎖定行為。分歧來自 Repository 沒有定義 OverdueProcessingSummary 只負責統計,還是要擁有完整批次結果。

型別越多,可合理放置資料的位置也越多。Repository 沒有資料所有權規則時,人類與 Agent 都可能做出不同選擇。

降低參數並集中摘要後的修改路徑

圖:集中摘要規則減少重複,但若資料所有權未定義,Agent 仍可能把失敗 ID 放在不同層次。

CQS 結構把失敗 ID 留在原本就握有兩份資料的位置

CQS 候選的批次方法原本就同時握有 workItem.IdnotificationSucceeded,公開 Response 也由這個方法建立。

三次實作都收斂成相同資料路徑:

var failedNotificationWorkItemIds = new List<Guid>();

foreach (var workItem in dueIncompleteWorkItems)
{
    // 狀態判斷與修改維持原邏輯

    var notificationSucceeded = await notificationGateway.SendOverdueAsync(
        workItem,
        cancellationToken);

    notificationAttemptCount++;

    if (!notificationSucceeded)
    {
        notificationFailureCount++;
        failedNotificationWorkItemIds.Add(workItem.Id);
    }
}

return new ProcessOverdueResponse(
    overdueStatusChangeCount,
    notificationAttemptCount,
    notificationFailureCount,
    failedNotificationWorkItemIds.ToArray());

這次 CQS 的資料路徑最直接,因為失敗 ID 的判斷、收集與 Response 建立都在同一個批次責任裡。這項優勢來自目前只有一個 HTTP 輸出,以及新資料正好在此產生與使用;需求改變後,結論也可能改變。

CQS 結構的修改路徑

圖:CQS 讓查詢與修改責任分開;這次失敗 ID 留在同時握有 ID 與通知結果的批次方法。

內部 Result 固定多一次映射,但也預留了另一種輸出邊界

揭露副作用的結構中,私有 OverdueProcessingResult 與公開 ProcessOverdueResponse 原本都只有三項統計。新需求進來後,失敗 ID 必須先放進內部 Result,再由 Action 映射到公開 Response:

workItem.Id + NotificationSucceeded
→ OverdueProcessingResult.FailedNotificationWorkItemIds
→ ProcessOverdue Action
→ ProcessOverdueResponse.FailedNotificationWorkItemIds

目前只有一個 HTTP 輸出,每新增一個欄位,內部 Result 與公開 DTO 都要同步修改。

未來真的出現排程工作、訊息處理程式或其他輸出介面時,內部 Result 才能隔離 HTTP 格式;在那之前,多一次映射就是目前要支付的成本。

揭露失敗與副作用後的修改路徑

圖:內部 Result 讓副作用結果能跨輸出邊界重用,但目前要多支付一次映射與同步成本。

缺少完整 Token 資料,這篇不拿生成成本替結構排名

Input Token 是 Agent 接收到的 Prompt、Code 與工具輸出等 Context 總量;Reasoning Token 是模型推理用量;Cached Input 則是執行環境重複利用的既有輸入。

Day 8 的公開 Evidence 沒有保存九次 Session 的完整 Token 數字,各次工具呼叫與 Cache 命中也不同,因此本文不比較 Token,更不宣稱 CQS 比較省。可以重查的結果只有資料路徑與三次修改的一致性。

這次選 CQS,是因為資料目前都屬於同一個批次責任

目前我接受 CQS 結構。workItem.IdnotificationSucceeded 原本就在同一個批次方法裡,失敗 ID 可以直接收集並建立 Response,不必穿過額外的 Result 或 Summary;三次匿名實作也都找到相同位置。

我不是因為 CQS 這個名稱比較經典,也不是因為 Diff 最短才接受它。真正的理由是:目前只有一種輸出,新資料也只服務同一個批次流程。此時先建立額外結果邊界,只會提前支付同步成本。

Diff 長度與符合幾項原則只當參考,不參與最後裁決。

不過,這個選擇只適用於目前的 Repository、逾期流程與後續需求。把三份候選放回不同情境,答案就會改變:

目前的變更壓力 較適合的方向 Agent 動手前要確認什麼
資料只服務單一批次流程,而且判斷、收集與回傳都在同一個修改點 拆開查詢與修改(CQS) Query 與 Command 的責任是否清楚,Command 的回傳結果是否真的被流程使用
同一份批次摘要會被多個步驟使用,或統計規則有自己的改變理由 集中摘要規則 建構式依賴是否只是搬家,摘要型別是否真的擁有這些資料
同一段業務流程要供 API、排程工作或其他輸出介面使用 建立內部執行結果 隔離輸出格式的價值,是否足以支付欄位同步與映射成本

這張表記錄三種結構的選擇條件。Agent 要先確認資料由誰產生、誰會使用,以及需求會穿過哪些邊界,再決定保留直接資料路徑、Summary 或內部 Result。

把三種選擇條件整理成 Function Heuristics Handoff Policy

AGENTS.md 若只列出「少參數、遵守 CQS、避免重複、妥善處理例外、注意副作用」,Agent 仍不知道原則衝突時怎麼選。

Function Heuristics Handoff Policy 是跟著 Repository 保存、讓 Agent 依資料所有權與使用情境選擇結構的規則。我先整理成可放進 AGENTS.md 的示範版本,延續前面逐篇累積 Repository Policy 的做法;規則穩定後,再抽成 Skill。

## Function Heuristics Handoff Policy

- 重構前先列出外部契約、可預期失敗、未知 Exception、取消、重跑與副作用順序;任何函式整理都不得改變這些答案。
- 參數數量只作為檢查訊號。依賴搬到建構式、欄位或參數物件時,不得回報成依賴已消失。
- Query 應只回答問題,Command 應揭露副作用;若流程需要 Command 的結果做後續決策,可以保留意圖明確的回傳值。
- DRY 只合併會因同一理由一起改變的知識;相同語法或資料形狀,不足以支持共用抽象。
- 資料只服務單一流程,而且產生與使用位於同一個責任時,優先保留直接資料路徑。
- 同一份摘要由多個步驟使用,而且統計規則具有獨立變更理由時,可以建立摘要型別;必須回報依賴與資料所有權。
- 同一段業務流程要供多種輸出介面使用時,可以建立不依賴 HTTP DTO 的內部 Result;必須列出映射位置與同步成本。
- 完成後回報實際資料路徑與新增邊界;若需求跨越公開契約、交易、資料一致性、通知或新架構邊界,停止並交回 User 決定。

實務上,我不會讓每次開發任務都跑九次。三次重複只是今天用來觀察模型變異,日常流程可以留下四個步驟:

  1. 先讓 Agent 冷讀並說出行為與副作用順序。
  2. 給一項具體變更,不用抽象的「請寫得更乾淨」。
  3. 用鎖定行為測試保護系統答案。
  4. Review 資料穿過哪些責任邊界,不只看最後是否全綠。

User 把注意力留給資料所有權、架構與產品邊界;Helper 的實作細節則交由 Policy 約束 Agent。

重現實驗與完整證據

如果已經 Clone 公開的 API Demo,可以切到三種函式結構共同的實驗起點:

git fetch origin --tags
git switch --detach day-08-function-heuristics-baseline
git rev-parse HEAD

最後一行應該顯示:

ed5272222c6c415bb6750ae6933c5a495f21e146

本系列接下來採用 CQS 結構,並加入 failedNotificationWorkItemIds。接受版本固定在 Commit 73d29ed2a36b80f1dd436ab2d3f155b5f4ff201f/Annotated Tag day-08-agent-handoff

第一階段的完整 Prompt、量測與驗證結果收在 Day 8 函式啟發式 Evidence

第二階段的控制條件、兩份 Prompt、九次 Agent 回覆與 GitHub Diff 收在 Day 8 匿名交接 Evidence

函式結構會改變下一個 Agent 眼中的合理修改路徑

回到開頭,九個 Fresh Session 都理解並完成了需求,卻不是沿著同一條資料路徑前進。函式結構沒有替 Agent 決定唯一答案,但它會讓某些修改位置看起來更自然,也會讓某些資料多穿過幾層型別。

參數、CQS、例外、DRY 與副作用提供的是一組判斷問題,用來確認依賴、資料與失敗路徑該放在哪裡。N — Non-Surprising Behavior 符合預期 則先守住系統答案,避免結構比較混入功能漂移。

這次資料的產生、判斷與使用都位於同一個批次責任,所以我選擇 CQS 的直接資料路徑,而不是提前建立尚無第二個使用情境的抽象。

今天選定函式結構後,明天接著比較 Agent 一次重寫,和拆成可獨立驗證、Commit、Revert 的小步驟。問題會從「資料該放哪裡」轉向「修改走偏時,能不能只退回出錯的那一步」。


上一篇
Day 7|AI 把函式拆得越小,就越符合 Clean Code 嗎?三種拆分方式實測
下一篇
Day 9|AI Agent 一次重寫或分段 Commit:哪個容易還原,哪個完成後更好讀?
系列文
AI 時代的 Clean Code:30 天讓 AI 產出的程式碼可讀、可驗證、可維護13
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言