iT邦幫忙

2026 iThome 鐵人賽

DAY 23
0
Claude AI

從現場踩坑到 AI 工具 — IT Diagnostic Agent 開發實錄系列 第 23

Day 23 — 破壞性操作要確認,唯讀操作不用

  • 分享至 

  • xImage
  •  

系列:從現場踩坑到 AI 工具 — IT Diagnostic Agent 開發實錄


這組原則不是我坐下來想出來的

昨天那個琥珀色,是一組決策原則在 UI 上的落地。

但這組原則的來源不是我某天靈感一來寫下的設計哲學。它是被逼出來的

因為 GSD 是 Interactive 模式(Day 21),它會不斷停下來問我:

  • 這個功能要做到什麼程度?
  • 這裡要不要加確認步驟?
  • 這個改動範圍要多大?
  • 回饋訊息用哪種形式?

而 GSD 通常會標示一個 Recommended 選項。

一開始我照著 Recommended 選。選了幾次之後我發現不對——它推薦的是「一般情況下的最佳實踐」,但我的專案有一些它不知道的特殊約束。

於是我被迫把「我到底在乎什麼」想清楚。

那組原則就是這樣長出來的:不是設計出來的,是在一連串二選一裡被迫顯形的。


完整的決策原則清單

我把當時逐步確立的原則整理出來:

1. 不能破壞既有功能 — 只要有迴歸風險,就選保守選項

2. 破壞性操作要確認,唯讀操作不用 — 覆寫 / 取代 / 刪除要有保護;讀取 / 查詢 / 匯出不需要

3. 內容與介面分離 — 使用者只能編輯診斷內容,UI 字串鎖定

4. 純靜態零依賴 — 不引入任何需要建置流程的東西

5. 手機版垂直堆疊 — 任何新版面都要在窄螢幕上能用

6. 雙語一致 — 任何新文字都要中英文同步

7. 持續性回饋 — 用常駐的 div,不用 toast

8. 每個階段核准前要仔細驗證 — 不能只看 GSD 說「完成」

9. 當 Recommended 跟第 1 或第 2 條衝突時,選更保守的那個

第 9 條是元規則——它決定了當 AI 的建議和我的原則打架時誰贏。


第 2 條原則的實際實作,比我原本以為的有層次

我原本以為第 2 條就是一句話:破壞性操作加一個 confirm(),唯讀操作不加。

一條 if-else 的複雜度。

但我後來回去看實際跑在線上的程式碼,發現它不是二分的,而是三個層級

層級 1:刪除 → 阻斷式確認對話框

刪除 GUIDES Book 和刪除節點,都有真正的 confirm()

if (!confirm('確認刪除 GUIDES Book「' + title + '」?' + refText)) return;

if (!confirm('確認刪除節點「' + name + '」及其所有連線?')) return;

注意兩個細節:

  • 會把名稱帶進訊息裡。不是「確定要刪除嗎?」,是「確認刪除節點『網路故障』及其所有連線?」。使用者看得到自己在刪什麼。
  • 會提醒連帶影響。刪節點會連帶刪掉所有連線,這件事寫在確認訊息裡,不是讓使用者自己發現。

層級 2:匯入 / 覆寫 → 沒有 confirm,但有三重保護

這是讓我意外的地方:匯入功能沒有 confirm() 對話框。

它用的是三個不同的機制:

(a)琥珀色警示按鈕 — 昨天那個 #d97706。這是事前的視覺警告,在你按下去之前就一直在那裡。

(b)層層驗證,通過才動資料

// 1. 能不能解析成 JSON
try { data = JSON.parse(e.target.result); }
catch(err) { showImportFeedback(L().importErrJson, 'error'); return; }

// 2. 版本號對不對
if (data.version !== 1 && data.version !== 2) {
  showImportFeedback(L().importErrVersion, 'error'); return; }

// 3. 必要欄位在不在
if (!data.guides || !data.nodes || !data.nodes.zh || !data.nodes.en) {
  showImportFeedback(L().importErrFields, 'error'); return; }

// 4. v2 的樹狀結構完整嗎
if (data.version === 2 && (!data.tree ||
    !Array.isArray(data.tree.nodes) || !Array.isArray(data.tree.edges))) {
  showImportFeedback(L().importErrFields, 'error'); return; }

四道檢查,全部通過才會碰到現有資料。 每一道失敗都有各自的錯誤訊息,而且是雙語的。

(c)Reset to Defaults 提供退路 — 就算真的匯入了不想要的東西,有一個按鈕可以回到預設值。

層級 3:唯讀 → 什麼都不加

匯出、瀏覽、走決策樹——零阻力。


為什麼匯入不用 confirm?我事後想通了

當時的選擇可能有一部分是直覺,但回頭看它是對的,而且理由很具體。

Confirm 對話框有一個致命弱點:點擊盲視(click-through blindness)。

任何做過 IT 的人都見過這個現象。使用者看到彈窗,手已經按在「確定」上了。彈窗出現的次數越多,它被閱讀的機率越低。

在 IT 支援的世界裡,這是我們天天在對抗的東西——「你有看到那個警告訊息嗎?」「有啊,我按確定了。」

顏色不會被點掉。

那個琥珀色按鈕一直在那裡。它不打斷你,但它一直在告訴你「這個跟旁邊那個不一樣」。

所以兩者的性質完全不同:

Confirm 對話框 警示色
時機 動作之後、執行之前 動作之前,一直都在
形式 中斷 環境訊息
弱點 會被習慣性點掉 會被視覺習慣淡化
適合 不可逆、單點的操作 可逆、需要事前提醒的操作

刪除是不可逆的,適合中斷式的 confirm。
匯入有 Reset 退路,適合事前的警示色 + 硬驗證。

原則沒有變,實作的形式跟著風險性質調整了。


所以第 2 條原則的正確版本應該是

我原本寫的是:

破壞性操作要確認,唯讀操作不用

實際實作出來的是:

保護的強度,要跟「不可逆性」成正比,而不是跟「是不是破壞性」成正比。

操作 破壞性? 可逆? 保護方式
刪除節點 阻斷式 confirm + 說明連帶影響
匯入覆寫 是(Reset) 警示色 + 四道驗證 + 持續回饋
匯出
走決策樹

「破壞性」是一個二元標籤,「不可逆性」是一個連續量。而保護機制應該對應後者。

這是我在寫這篇文章時才想清楚的事——實作已經跑在線上好幾週了,但我一直以為那只是一條簡單的 if-else。


第 7 條原則:為什麼用常駐 div 而不用 toast

順便講這一條,因為它跟第 2 條同源。

Toast(浮動提示,幾秒後自動消失)是現在很流行的回饋形式。GSD 大概也推薦過它。

我選了常駐的 div。理由是同一個邏輯:

如果訊息會自己消失,那它就不算真的告知過使用者。

匯入失敗的錯誤訊息,使用者可能需要五秒才看完、需要複製起來貼給我看、需要對照著檢查自己的 JSON。

一個三秒後消失的錯誤訊息,等於沒有錯誤訊息。

這在 IT 支援上是老經驗了:使用者回報問題時最常說的一句話是「它有跳一個東西,但我來不及看」。

我不想讓我自己的工具製造這種對話。


結構化地看這組原則

可控 vs 不可控

我控制不了 GSD 推薦什麼。我控制得了自己的元規則(第 9 條)。

有一條明確的元規則,比逐次判斷可靠得多。 因為逐次判斷會累、會鬆懈、會在第二十次的時候順手選了 Recommended。

核心 vs 外部

核心是「不能弄壞使用者的資料」。confirm 對話框、警示色、驗證邏輯,全部是外部手段。

手段可以換,核心不能換。 這就是為什麼匯入功能可以不用 confirm——它換了手段,沒換核心。

靜態 vs 動態

第 2 條原則本身是靜態的。但「什麼保護強度算適當」要根據不可逆性動態判斷。

原則要簡單到記得住,判斷要細緻到用得上。 這兩件事不衝突,但不能混為一談。


這組原則的真正價值:它讓我可以放手

寫到這裡我意識到這組原則最大的用處,不是防止 bug。

是它讓我敢把實作交出去。

如果沒有這九條,我每次面對 GSD 的提問都要從零開始想「這樣做會不會有問題」。那樣的協作成本高到不如自己寫。

有了這九條,大部分選項在三秒內就能判斷。而剩下那些三秒判斷不了的,才是真正需要我動腦的地方。

明確的原則,是委派的前提。 不管你委派的對象是 AI 還是人。


今天的反思

我做了二十年 IT,這九條原則裡沒有一條是我在這個專案裡新學到的。

「刪除要確認」、「錯誤訊息不能自己消失」、「不確定就選保守的」——這些是任何做過維運的人都會有的直覺。

但把直覺寫成明文,是完全不同的一件事。

而逼我寫下來的,是一個會不斷問我「A 還是 B」的 agent。

AI 協作的一個副作用是:它會逼你把你自己的原則說清楚。 因為它不能像人類同事那樣,靠著跟你共事三年來猜你在乎什麼。

它只能照你說的做。所以你必須說得出來。


明天預告: 前面三天講的都是寫程式。但我用 Claude 做的事情不只寫程式——包括你正在讀的這三十篇文章,它們的草稿、修正、版本管理,全部都在同一個協作流程裡。


作者:Rich Chang | IT 基礎建設工程師 | 越南・柬埔寨・台灣


上一篇
Day 22 — 為什麼我在對話裡下的指令,下一輪就被覆蓋了?
下一篇
Day 24 — 我用 Claude 管理這 30 篇文章的草稿
系列文
從現場踩坑到 AI 工具 — IT Diagnostic Agent 開發實錄29
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言