分類: 實戰案例

  • 舊系統整合場景下,會用 vs 不會用 Claude Code 的差距

    重點摘要

    • 舊系統整合最大的陷阱:Claude 看不到舊系統,但舊系統的約束決定了新功能能不能用
    • 不會用的人:讓 Claude 在沒有舊系統上下文的情況下做新功能,結果接不上去
    • 會用的人:先讓 Claude 讀關鍵接口,CLAUDE.md 記錄現有約束,設計文件定義接合點
    • 三個場景示範:醫療 HIS 接 LINE 掛號、舊報表接新數據、舊 ERP 接電商平台

    上一篇文章講的是新功能開發。但現實是,大多數人面對的不是一張白紙,而是一個已經在跑的舊系統。

    舊系統整合比全新開發難十倍,不是因為技術更難,而是因為有一大堆隱性約束 Claude 不知道。格式、命名、邊界、不能動的地方,這些都在舊代碼裡,Claude 看不到就無從遵守。

    這篇用三個場景直接模擬:有舊系統在的情況下,會用和不會用 Claude Code 的差距。

    根本差距:Claude 的上下文只有你給它的部分

    Claude Code 非常聰明,但它只知道你告訴它的東西。在全新專案,你說什麼格式就用什麼格式,問題不大。在整合舊系統時,如果你沒有把舊系統的關鍵結構告訴它,它會做出一個邏輯正確但無法接上的東西。

    這不是 Claude 的問題,是你的輸入不完整。

    舊系統整合的核心挑戰是:讓 Claude 在動手之前,先理解它不能動的邊界在哪裡。

    場景一:醫院 HIS 系統加掛 LINE 預約掛號

    情境

    一家地區醫院用了十年的 HIS 系統(Windows Server + MSSQL),所有掛號邏輯都在 stored procedures 裡。現在要加 LINE Chatbot 讓患者能線上預約,但 HIS 系統不能動,只能從外部透過 API 呼叫它。

    不會用的人怎麼做

    幫我寫一個 LINE Chatbot 預約掛號系統,要能讓患者選科別、選醫師、選時段。

    Claude 做出一個完整的 LINE bot,資料庫設計清楚,對話流程順暢。

    開始對接 HIS 系統時,問題一個接一個:

    • HIS 的患者 ID 是 8 位數字,Claude 設計的是 UUID — 整個 primary key 要換
    • HIS 的診次代碼格式是 YYYYMMDD-科別碼-序號(例如 20260325-INT-001),Claude 自己設計了完全不同的格式
    • HIS 只接受 stored procedure 呼叫,不開放直接讀表,Claude 設計的是直接 SELECT
    • 科別代碼是 HIS 裡的維護資料(內科=INT、外科=SUR),Claude 用了自己的命名

    每一個問題單獨看都能修,但修完之後發現下一個格式又不對。最後花了兩天在做格式轉換,而不是做功能。

    結果:開發 3 天,對接 2 天,還有格式轉換層要長期維護。

    會用的人怎麼做

    第一步:先讓 Claude 讀懂舊系統的接口

    把 HIS 系統對外開放的 SP 簽名整理成文件,餵給 Claude:

    請先閱讀以下 HIS 系統的接口文件,
    告訴我你對這個系統的理解,特別是資料格式和呼叫限制,
    再討論 LINE bot 的架構設計。
    
    --- HIS 接口文件 ---
    sp_GetAvailableSessions
      @DeptCode NCHAR(3)      -- 科別碼,參照 tb_Dept.DeptCode
      @DateFrom NCHAR(8)      -- YYYYMMDD 格式
      @DateTo   NCHAR(8)
      回傳: SessionId NCHAR(16), DoctorName, SessionDate, RemainSlots
    
    sp_CreateBooking
      @PatientId NCHAR(8)     -- 8位數字,不足補0
      @SessionId NCHAR(16)    -- 從 sp_GetAvailableSessions 取得
      @Phone     NVARCHAR(20)
      回傳: BookingNo NCHAR(12), Status (SUCCESS/FULL/DUPLICATE)
    
    sp_CancelBooking
      @BookingNo NCHAR(12)
      @Reason    NVARCHAR(100)
    ---

    第二步:CLAUDE.md 記錄現有系統的約束

    ## 整合約束(HIS 系統,不可更動)
    - PatientId:8 位數字字串,不足補 0(例如 "00012345")
    - SessionId:格式為 YYYYMMDD-DeptCode-NNN(例如 "20260325-INT-001")
    - 所有 HIS 呼叫只能透過 stored procedure,不允許直接查表
    - 科別代碼參照 tb_Dept,常用:INT=內科、SUR=外科、PED=小兒科
    
    ## 新系統原則
    - LINE bot 層只做對話邏輯
    - HIS 接口層做格式轉換(HisAdapter class)
    - 不在 LINE bot 層直接呼叫 HIS

    第三步:設計文件定義接合點,不是重新設計格式

    # 功能:LINE 掛號 → HIS 預約對接
    
    ## 接合點(Integration Points)
    LINE 用戶選擇診次 → HisAdapter.getAvailableSessions(deptCode, dateRange)
      → 呼叫 sp_GetAvailableSessions
      → 回傳格式轉為 LINE flex message 可用的結構
    
    用戶確認掛號 → HisAdapter.createBooking(lineUserId, sessionId, phone)
      → 查詢或建立患者檔(PatientId)
      → 呼叫 sp_CreateBooking
      → 處理 FULL / DUPLICATE 回傳狀態
    
    ## 不碰的東西
    - HIS 資料庫 schema 完全不動
    - 所有 PatientId 維持 8 位補零格式
    - SessionId 格式完全繼承 HIS
    
    ## Done When
    - HisAdapter 有完整的 unit test(mock SP 回傳)
    - LINE bot 不包含任何 HIS 格式邏輯(全在 Adapter)

    結果:1.5 天完成,無格式轉換層,後續維護只在 HisAdapter 這一層。

    場景二:舊版股市報表腳本接新即時數據

    情境

    一個量化分析師用了三年的 Python 腳本,每天手動下載 CSV,跑一堆計算,輸出報表。現在要改成自動化:自動爬取數據、自動計算、推播到 Line Notify。但舊腳本的計算邏輯非常複雜(含自訂指標、過去三年調整過的參數),不能改,只能把數據來源換掉。

    不會用的人怎麼做

    幫我把這個股市分析腳本改成自動化,自動抓數據然後推 LINE 通知。

    Claude 看了舊腳本,做了一個新的自動化版本。看起來很整齊,比舊腳本乾淨很多。

    跑了一週,發現結果跟舊版不一樣:

    • 舊腳本的 RSI 計算用的是 Wilder 平滑法,Claude 預設用了 SMA 版本,數值不同
    • 舊腳本對成交量有一個「過去 20 日剔除最高最低各兩天後的平均」的自訂邏輯,新版沒有
    • 舊腳本在除權息日前後有特別處理,新版沒有
    • 欄位名稱被 Claude 重新命名了(舊版 vol_adj 在新版變成 adjusted_volume),下游所有 Excel 公式全壞

    分析師說:「它幫我重寫了,但重寫出來的東西跟我的不一樣,我現在不知道以哪個為準。」

    結果:新舊結果不一致,花了一週在驗算差異,反而比手動下載多花時間。

    會用的人怎麼做

    關鍵原則:計算邏輯一行都不能動,只換數據來源。

    第一步:讓 Claude 讀懂舊腳本,先提取它的業務邏輯

    請閱讀這個舊腳本,告訴我:
    1. 它依賴哪些輸入欄位(欄位名稱和格式)
    2. 有哪些自訂計算邏輯(非標準指標)
    3. 最後輸出哪些欄位
    
    不要修改任何東西,只告訴我你的理解。

    這一步讓 Claude 自己找出所有隱性依賴,避免後面遺漏。

    第二步:CLAUDE.md 把舊腳本的約束凍結

    ## 舊系統相容性約束(不可更動)
    - 所有輸出欄位名稱必須與 legacy_report.py 完全一致
      (vol_adj、rsi_wilder、price_adj 等,不得重新命名)
    - RSI 計算必須使用 Wilder 平滑法(非 SMA),與舊版等價
    - 成交量平均:去掉最高最低各 2 天後的 16 日均量
    - 除權息調整邏輯:參見 legacy_report.py 第 87-134 行,禁止修改
    
    ## 本次修改範圍
    - 只修改數據來源層(DataFetcher class)
    - 所有計算邏輯保持不變
    - 輸出格式和欄位名稱保持不變

    第三步:設計文件只描述「換什麼」,明確說「不換什麼」

    # 功能:數據來源自動化
    
    ## 要換的
    舊:手動下載 CSV 放在 ./data/ 目錄
    新:DataFetcher 自動從 TWSE API 抓取,存成相同格式的 DataFrame
    
    ## 不換的
    - 所有 calculate_*() 函數:一行都不動
    - 所有欄位名稱
    - 輸出的 Excel 格式和公式
    
    ## 驗證方式
    用同一天的歷史數據,新舊兩版並排執行,
    所有欄位數值差異必須在浮點誤差範圍內(< 0.0001)

    「驗證方式」這一段給了 Claude 一個清楚的完成定義:不是「看起來跑得動」,而是「跟舊版數字一樣」。

    結果:1 天完成,新舊並排驗算通過,分析師信心十足上線。

    場景三:舊訂單系統接新電商平台(Shopee / momo)

    情境

    一家中型品牌商有自己的後台訂單系統(自建,PHP + MySQL,跑了七年),現在要同時開 Shopee 和 momo 的店,訂單要自動回拋到自建系統,庫存要即時同步。自建系統的代碼文件不齊全,但不能大改,只能在外面包一層。

    不會用的人怎麼做

    幫我串接 Shopee 和 momo 的訂單,自動同步到我們自己的系統。

    Claude 寫了一個整合服務,讀 Shopee/momo 的 webhook,轉換格式,打進自建系統的 API。

    測試時發現:

    • 自建系統的商品 SKU 格式是 PRD-XXXXXXXX,但 Shopee 上的 SKU 是當初手動輸入的,有些根本對不上
    • 自建系統的訂單狀態只有 5 種,Shopee 有 12 種,Claude 的對照表做了一半,有幾個狀態沒處理
    • momo 的訂單金額包含平台折扣,自建系統的商品價格是定價,兩邊金額對不上帳
    • 自建系統在創建訂單時會觸發一個庫存扣減的觸發器,Claude 不知道這件事,導致庫存被扣兩次

    最後一個問題最嚴重:庫存被扣兩次,一直到實際出貨才發現。

    結果:開發 4 天,測試又 3 天,上線後還是出現庫存問題。

    會用的人怎麼做

    舊系統不熟,先讓 Claude 幫你挖清楚它的邊界。

    第一步:讓 Claude 讀舊系統,主動找隱性行為

    請閱讀這個訂單系統的代碼,特別注意:
    1. 創建訂單時會觸發哪些副作用(觸發器、事件、其他表的更新)
    2. 庫存扣減在哪裡發生(是 API 層還是資料庫層)
    3. 訂單狀態的完整清單和流轉規則
    
    告訴我所有你發現的隱性行為,不要開始寫任何代碼。

    「隱性行為」這個說法很重要。Claude 在讀舊代碼時會主動找資料庫 trigger、事件監聽器、side effect,這些是最容易被遺漏的整合風險。

    第二步:用 Plan Mode 規劃整合架構,重點在「邊界」

    【背景】
    自建訂單系統(PHP + MySQL),創建訂單時資料庫層會自動扣減庫存(trigger)。
    Shopee 和 momo 各有自己的訂單狀態體系。
    
    【目標】
    Shopee/momo 新訂單自動進到自建系統,庫存只扣一次,狀態對照完整。
    
    【約束條件】
    - 自建系統的 trigger 不能改(沒有完整文件,風險太高)
    - SKU 對照表需要人工確認後再上線(不能用 Claude 猜測)
    - momo 的折扣金額要分開記錄,不能直接入自建系統的商品價
    
    請制定整合架構計劃,
    特別說明如何避免庫存被扣兩次,
    等我確認計劃後再開始實作。

    Plan Mode 裡,Claude 提出了三個方案,推薦的是:新建一個 OrderBridge 服務,只負責格式轉換和狀態對照,在呼叫自建系統 API 之前先把庫存檢查做在 Bridge 層(避免 API 呼叫失敗後 trigger 已執行的問題)。

    第三步:設計文件把 SKU 對照、狀態對照、金額拆分全部定義清楚

    ## SKU 對照策略
    - 對照表存在 sku_mapping 資料表,人工審核後才生效
    - 找不到對照的 SKU:訂單進 pending_review 佇列,不自動處理
    - 禁止猜測或模糊匹配
    
    ## 訂單狀態對照(Shopee → 自建)
    UNPAID        → 不同步(等付款)
    READY_TO_SHIP → processing
    SHIPPED       → shipped
    COMPLETED     → completed
    CANCELLED     → cancelled
    其他狀態      → 記錄 log,不同步,發警報
    
    ## momo 金額處理
    momo_original_price → 自建系統 unit_price
    momo_discount       → 另存 discount_record 資料表
    momo_final_price    → 自建系統 actual_amount
    (三個欄位分開記錄,不做合併計算)

    結果:2 天完成 OrderBridge,庫存零重複扣減,SKU 對照人工審核後上線,穩定運行。

    舊系統整合的核心技巧整理

    技巧 怎麼做 目的
    先讓 Claude 讀現有接口提供 API 簽名、schema、關鍵函數,要求 Claude 說出理解後再動手讓 Claude 在正確的上下文下設計,不做無效假設
    要求 Claude 找隱性行為明確說「找出所有 trigger、side effect、副作用,不要開始寫代碼」在整合前把地雷挖出來,不是做完才踩到
    CLAUDE.md 凍結不能動的邊界在 CLAUDE.md 明確寫「不得修改 X 格式 / Y 欄位名稱 / Z 計算邏輯」Claude 不會因為「更整齊」而擅自重新命名或重構
    設計文件定義接合點,不定義格式設計文件描述「新舊系統在哪裡接觸」,格式繼承舊系統,不重新設計避免做一個格式轉換層長期維護
    驗證方式要對比舊系統Done When 裡明確說「與舊系統同樣輸入,輸出結果必須一致」讓 Claude 自己驗算新舊等價性,不是跑起來就算完成

    一個可以直接用的提示模板

    每次要在舊系統上加新功能,用這個模板啟動:

    【現有系統】
    [描述現有系統的技術棧和關鍵接口,附上接口文件或關鍵代碼片段]
    
    【要加的功能】
    [一句話描述]
    
    【不能動的邊界】
    - [現有系統的格式、欄位名稱、計算邏輯等不能更動的項目]
    - [如果有 DB trigger 或其他隱性行為,也列在這裡]
    
    【請先做這兩件事,再開始設計】
    1. 告訴我你對現有接口的理解(特別是你覺得可能影響整合的部分)
    2. 指出你看到的整合風險(格式衝突、重複操作、狀態對照缺口)
    
    確認理解正確後,我們再討論設計。

    這個模板做了三件事:把舊系統的上下文給 Claude、凍結不能動的邊界、要求 Claude 在動手前先說出它的理解和風險判斷。

    常見問題

    Q:舊系統的代碼很亂,文件也沒有,怎麼辦?

    先讓 Claude 讀代碼,問它「這個系統對外暴露了哪些接口?資料庫有哪些關鍵的 table 和 trigger?」讓 Claude 幫你反向整理出一份接口文件,確認沒有遺漏後再進行整合設計。不要跳過這一步,這是整合成功的前提。

    Q:整合的範圍不確定,不知道要動到哪裡?

    先用 Plan Mode,給 Claude 目標和約束,讓它畫出影響範圍。Plan Mode 的價值在複雜整合場景特別高,因為它會列出所有相關的文件和狀態流,讓你確認範圍是否正確,再決定怎麼切入。

    Q:新功能做完,但舊系統有些邏輯說不清楚,怕 Claude 做錯?

    這種情況用「新舊並排驗算」:先在測試環境讓舊版和新版用同樣輸入各跑一次,比較輸出。在設計文件裡明確寫出這個驗證條件,Claude 就會把「新舊等價」列為完成定義的一部分。

    從不會用到會用:舊系統整合的具體升級路徑

    舊系統整合的升級路徑跟全新開發不太一樣:問題不是「我沒說邊界條件」,而是「Claude 根本不知道舊系統長什麼樣」。所以升級的重點是:在動手前把舊系統的關鍵資訊餵給 Claude

    第一步:今天就能做到(一個句子)

    在你的提示前面加上這段:

    我有一個現有系統,新功能必須跟它相容。
    
    現有系統的關鍵格式:
    [把你知道的接口格式、欄位名稱、資料格式貼在這裡]
    
    新功能不能更動上面這些格式。先告訴我你的理解,再開始設計。

    就算你只知道一部分格式,先寫一部分。有比沒有好。

    醫療 HIS 整合:Level 0 → Level 1

    不會用(Level 0) 初步會用(Level 1)
    幫我串接 HIS 系統做 LINE 掛號(見下方)
    我有一個舊的 HIS 系統(不能修改),需要在外面接一個 LINE 掛號 bot。
    
    HIS 現有接口(Stored Procedure):
    sp_GetAvailableSessions(@DeptCode NCHAR(3), @DateFrom NCHAR(8), @DateTo NCHAR(8))
    sp_CreateBooking(@PatientId NCHAR(8), @SessionId NCHAR(16), @Phone NVARCHAR(20))
      回傳 Status: SUCCESS / FULL / DUPLICATE
    
    格式約束(不能改):
    - PatientId 是 8 位數字字串,不足補 0
    - 所有呼叫只能透過 stored procedure,不能直接查表
    
    請先告訴我:
    1. 你對這個 HIS 接口的理解
    2. 你覺得 LINE bot 和 HIS 之間需要什麼樣的轉換層
    
    確認後再討論架構設計。

    舊報表腳本接新數據:Level 0 → Level 1

    我有一個舊的 Python 分析腳本,計算邏輯不能動,只要換掉數據來源(從手動 CSV 改成自動抓取)。
    
    舊腳本的輸入依賴(這些欄位名稱不能改):
    - date (YYYY-MM-DD)
    - open, high, low, close, volume
    - vol_adj(自訂欄位:去掉最高最低各2天的16日均量)
    
    計算邏輯不能動的原因:
    - RSI 用的是 Wilder 平滑法(非標準 SMA),三年來的報告都是這個版本
    - 改了數值會跟歷史記錄不一致
    
    請先告訴我:
    1. 你理解哪些東西不能動
    2. 你打算怎麼讓新舊版本在同樣輸入下輸出一致的結果
    
    確認後再開始實作數據來源層。

    舊 ERP 接電商平台:Level 0 → Level 1

    我有一個舊的訂單系統(PHP + MySQL),要串接 Shopee 的訂單進來。
    舊系統不能大改,只能在外面包一層。
    
    已知的舊系統行為:
    - 創建訂單時,資料庫層有 trigger 會自動扣庫存
    - 訂單狀態:pending / processing / shipped / completed / cancelled(只有這五種)
    
    Shopee 訂單狀態有 12 種,需要做對照。
    
    我擔心的問題:
    - 庫存被扣兩次(trigger + 外面的 API 都扣)
    - 狀態對照不完整,有些 Shopee 狀態沒有對應的舊系統狀態
    
    請先幫我分析這兩個風險,告訴我你的處理方案,再開始設計架構。

    注意最後一段:把你擔心的問題說出來。這讓 Claude 優先處理你知道有風險的地方,而不是從它認為重要的地方開始。

    第二步:下週可以做到(CLAUDE.md 記錄舊系統約束)

    舊系統整合的 CLAUDE.md 要特別加一個「整合約束」區塊:

    # 整合約束(現有系統,不可更動)
    
    ## [系統名稱] 的格式規範
    - [欄位名稱] 的格式:[說明]
    - [接口規範]:[說明]
    - 禁止直接操作資料庫,只能透過 [API / SP / 特定方法]
    
    ## 已知的隱性行為
    - [觸發器 / 事件 / side effect 描述]
    - 注意:[操作 X] 會同時觸發 [Y],不要重複執行
    
    ## 新功能的邊界
    - 只修改 [Adapter / Bridge / 特定模組],不動舊系統
    - 欄位名稱繼承舊系統,不重新命名

    每次發現一個新的隱性行為(觸發器、計算邏輯、格式特例),就加進這個區塊。它會越來越完整,讓你以後的整合工作越來越省力。

    第三步:一個月後的進化

    進化 A:在開始任何整合前,先讓 Claude 找隱性行為

    請閱讀 [現有系統代碼/文件],找出所有:
    1. 資料庫 trigger 和它的作用
    2. 創建/更新/刪除記錄時的 side effect
    3. 對外暴露的接口(API / SP / 事件)和它們的格式
    
    告訴我你找到的所有隱性行為,不要開始設計,先讓我確認。

    這個步驟在整合開始前把地雷挖出來,比做完後踩到省 10 倍時間。

    進化 B:複雜整合用 Plan Mode,重點讓 Claude 畫出影響範圍

    【現有系統】[描述]
    【目標】[一句話]
    【不能動的邊界】[列清楚]
    
    請制定整合計劃,特別標出:
    - 會影響到的現有功能
    - 每個整合點的風險
    - 我需要在上線前人工驗證的項目
    
    等我確認計劃後再開始實作。

    進化 C:設計文件加「新舊等價性驗證」

    舊系統整合的完成定義,永遠要加這一條:

    ## 驗證方式
    用同一份歷史輸入,新舊兩版並排執行,
    [關鍵輸出欄位] 的結果差異必須在 [可接受範圍] 內。
    新版上線前,提供新舊對比報告。
    階段 做什麼 關鍵句
    Level 0直接說要串接什麼
    Level 1(今天)把舊系統格式和約束說清楚「這些格式不能改,告訴我你的理解再開始」
    Level 2(下週)CLAUDE.md 記錄舊系統約束和隱性行為每次整合後補一條「已知隱性行為」
    Level 3(一個月後)先讓 Claude 挖地雷,再 Plan Mode 確認影響範圍「找出所有隱性行為,不要開始設計」
  • 會用 vs 不會用 Claude Code:醫療、股市、電商三場景對比

    重點摘要

    • 差距不在「會不會用 AI」,在「有沒有給 AI 做事的結構」
    • 不會用的人:一句話丟需求 → 結果跑偏 → 多輪修正 → 累積沮喪
    • 會用的人:CLAUDE.md + 設計文件 + 分段驗證 → 第一次就對
    • 三個真實場景(醫療 / 股市 / 電商)示範具體差距

    「Claude Code 對我沒用,我試過,它做出來的東西都不對。」

    這句話我聽過很多次。幾乎每次深入問,問題都不在 Claude,在提問的方式。

    這篇文章用三個真實的軟體開發場景,直接模擬「不會用的人」和「會用的人」各自怎麼做,讓你看清楚差距在哪裡。

    核心差距:有沒有給 AI 做事的結構

    不會用 Claude Code 的人,把它當成「很聰明的搜尋引擎」,問一句,期待完美答案。

    會用的人,把它當成「需要完整簡報才能開工的新進工程師」:你給的資訊越清楚,他做出來的東西越準確。

    差距的本質是:你的輸入有沒有結構

    場景一:醫療預約系統(門診掛號)

    痛點

    診所要做線上掛號,需要處理:醫師排班、假日停診、同時段人數上限、患者重複掛號防止。每個規則都有例外,例外裡還有例外。

    不會用的人怎麼做

    直接開口:

    幫我寫一個門診預約系統的 API,要能掛號、取消、查詢。

    Claude 給了一個乾淨的 REST API,CRUD 完整,code 看起來不錯。

    開始整合後發現問題一個接一個:

    • 沒處理同時段上限(診所每診次只收 20 人,API 沒有 capacity 邏輯)
    • 沒有重複掛號檢查(同一個患者可以掛同一診次兩次)
    • 沒有假日判斷(系統不知道什麼是醫院休診日)
    • 時區沒處理(台灣 UTC+8,stored as UTC,前端顯示全錯)

    開始補需求:「喔對,要加上每診次人數上限」→ Claude 修改。「還有重複掛號要擋掉」→ Claude 再改。「假日要停診」→ 再改。每次修改都可能動到之前改好的邏輯,三輪之後代碼開始難以追蹤。

    結果:8 小時,仍有未發現的 bug,信心不足。

    會用的人怎麼做

    第一步:CLAUDE.md 裡早就寫好領域規則

    ## 醫療領域規則
    - 所有時間以 UTC+8 儲存,API 回應包含 timezone 欄位
    - 患者 ID 採用身分證字號格式,需驗證格式(字母+9位數字)
    - 診次 (session) 為最小預約單位,每診次有 capacity 上限
    - 相同患者在同一診次只能有一筆有效預約
    
    ## 錯誤處理標準
    - 業務邏輯錯誤:HTTP 422 + { code, message, field }
    - 驗證錯誤:HTTP 400 + 同上格式

    第二步:先寫設計文件(20 分鐘)

    # 功能:門診掛號 API
    
    ## 輸入
    { patientId: string, sessionId: string }
    
    ## 驗證順序(按此順序,遇錯即停)
    1. patientId 格式是否合法
    2. sessionId 是否存在且為未來時間
    3. 該診次是否已達 capacity
    4. 該患者是否已有此診次的有效預約
    
    ## 邊界條件
    - capacity 滿:422,code: SESSION_FULL
    - 重複掛號:422,code: DUPLICATE_BOOKING
    - 患者格式錯:400,code: INVALID_PATIENT_ID
    - 診次已過去:422,code: SESSION_EXPIRED
    
    ## Done When
    - 所有邊界條件有單元測試
    - integration test 驗證完整掛號流程
    - 0 TypeScript errors

    第三步:分段給任務

    請先閱讀 CLAUDE.md 和這份設計文件。
    閱讀完告訴我你的理解,特別是驗證順序的邏輯,再開始實作。
    先只實作 validateBooking() 函數和對應單元測試,不要動 API 層。

    確認驗證邏輯正確後,再說「現在依照這個驗證函數實作 POST /bookings endpoint」。

    結果:2.5 小時,第一次就通過所有測試,零修改。

    場景二:股市回測系統

    痛點

    想驗證一個交易策略:當 5 日均線上穿 20 日均線時買進,死亡交叉時賣出。聽起來簡單,但台股有漲跌停、只能在交易日交易、最小交易單位是 1000 股、手續費和證交稅要扣掉,每個細節都會影響回測結果。

    不會用的人怎麼做

    幫我寫一個台股回測程式,策略是 5 日均線上穿 20 日均線買進,死叉賣出。

    Claude 給了一個 Python 回測,用 pandas 計算均線,邏輯清楚。跑了一下,報酬率看起來很漂亮。

    仔細看才發現:

    • 買賣都用收盤價,但實際上收盤價買不到(要用隔日開盤)
    • 沒有漲跌停限制,假設任何價格都能成交
    • 沒扣手續費(0.1425%)和證交稅(0.3%)
    • 沒有最小交易單位,0.1 張也買
    • 跑到非交易日(週末)的資料也在交易

    這些問題加起來,讓回測結果虛報了約 30–40%。一個看起來賺錢的策略,修正後可能是虧損的。

    結果:6 小時修修改改,最後不確定結果是否可信。

    會用的人怎麼做

    設計文件把所有台股規則先寫清楚:

    # 功能:台股均線策略回測引擎
    
    ## 市場規則(必須完整實作)
    - 交易日:排除週末 + 台灣國定假日(用 holidays-tw 套件)
    - 成交價:訊號發生在收盤,執行在「隔一個交易日開盤價」
    - 漲跌停:每日最大漲跌幅 ±10%,超過範圍無法成交,標記 LIMIT_HIT
    - 最小交易單位:1000 股,不足整張無法下單
    - 手續費:買賣各 0.1425%(可設定),最低 20 元
    - 證交稅:賣出 0.3%(ETF 為 0.1%)
    
    ## 回測輸出格式
    {
      total_return_pct: float,    # 扣除所有費用後
      trades: [{ date, action, price, shares, cost, tax, net_pnl }],
      unfilled: [{ date, reason }],   # LIMIT_HIT 等無法成交紀錄
      sharpe_ratio: float,
      max_drawdown_pct: float
    }
    
    ## 邊界條件
    - 漲停無法賣出(LIMIT_HIT_SELL)
    - 跌停無法買入(LIMIT_HIT_BUY)
    - 資金不足一張:跳過,記錄 INSUFFICIENT_FUNDS
    - 最後持倉:回測結束日強制以收盤價平倉

    提示方式:

    請先閱讀這份設計文件,告訴我:
    1. 成交時間點的邏輯(訊號日 vs 執行日)你的理解
    2. 漲跌停時的處理流程
    
    確認理解正確後,先只實作 TaiwanMarketRules 類別和測試,
    包含漲跌停判斷、交易日判斷、手續費計算三個方法。
    不要實作策略邏輯或回測引擎。

    結果:3 小時,回測結果可信,且有完整的無法成交紀錄供分析。

    場景三:電商金流串接(綠界 ECPay)

    痛點

    要串接台灣最常用的金流服務商,支援信用卡一次付清 + ATM 虛擬帳號。牽涉到加密簽章驗證、非同步回調(ReturnURL / OrderResultURL)、以及各種付款失敗情境。

    不會用的人怎麼做

    幫我串接綠界金流,支援信用卡和 ATM 付款。

    Claude 寫了一個串接,看起來完整。測試環境跑起來。上線後三天,開始收到客訴:

    • 付款成功但訂單沒更新(沒有正確處理綠界的非同步通知)
    • ATM 超時未付款,訂單卡在「待付款」沒有自動取消
    • CheckMacValue 驗簽偶發失敗(特殊字元的 URL encode 方式不對)
    • 退款流程完全沒實作(以為付款和退款是同一組 API)

    每個問題單獨看都能修,但修一個又會影響另一個。金流 bug 是最難測試的,因為要模擬真實付款行為。

    結果:上線後 bug,緊急修補兩天,損失用戶信任。

    會用的人怎麼做

    先用 Plan Mode 讓 Claude 梳理所有狀態流:

    【背景】
    我要串接綠界 ECPay,使用 Node.js + PostgreSQL,
    CLAUDE.md 中規定所有金流操作要記 audit log。
    
    【目標】
    支援信用卡一次付清和 ATM 虛擬帳號,訂單狀態要與付款狀態完全同步。
    
    【約束條件】
    - 不能有「已付款但訂單未更新」的狀態
    - ATM 超過 3 天未付款自動取消訂單並釋放庫存
    - CheckMacValue 驗簽失敗必須記錄並告警
    
    請制定實作計劃,列出所有需要處理的狀態流轉,
    等我確認計劃後再開始實作。

    Claude 在計劃中列出了 14 個狀態節點,包含「非同步通知重複到達」、「驗簽失敗的處理」這些不明顯的情境。確認計劃後再開始做。

    設計文件特別標明的邊界條件:

    ## 邊界條件(金流特有)
    - ReturnURL(非同步)和 OrderResultURL(同步)可能「都」被呼叫
      → 用 idempotency key 確保同一筆交易只更新一次訂單
    - CheckMacValue 驗簽:URL encode 順序必須按綠界規範(非標準 encodeURIComponent)
      → 測試案例需包含含特殊字元的 MerchantTradeNo
    - ATM 逾期:用 pg-cron 排程,不要依賴前端觸發
    - 退款:獨立 API,與付款 API 完全分離,需要人工審核 flag

    結果:4 小時,上線零 bug,audit log 完整。

    差距總結

    面向 不會用的人 會用的人
    提示方式「幫我做 X」「背景 + 目標 + 約束條件 + 邊界條件」
    領域規則每次用到才補說寫進 CLAUDE.md,一次設定永久生效
    邊界條件做完後才發現沒處理設計文件裡最前面就列清楚
    複雜任務一次丟,結果跑偏再修Plan Mode 確認方向,分段執行
    驗證方式全部做完再整體測試每段完成後先確認,錯誤早期發現
    對話輪數8–15 輪2–4 輪
    結果品質能跑,但邊界不完整完整,測試覆蓋所有邊界

    為什麼大多數人卡在「不會用」

    不是因為懶,是因為直覺錯了。

    我們習慣搜尋引擎:問一句,得到答案。Claude Code 不是搜尋引擎,它是一個需要簡報才能開工的工程師。你給的資訊越完整,它做出來的東西越準確。

    轉換這個直覺需要時間,但一旦轉過來,你就不會想回頭了。

    從下一個任務開始,試著在開口前先回答三個問題:

    1. 這個功能的輸入和輸出各是什麼格式?
    2. 哪些邊界條件會讓它失敗?
    3. 我怎麼確認它做對了?

    把這三個問題的答案寫下來,你的 Claude Code 使用效果會立刻不一樣。

    常見問題

    Q:每次都要先寫設計文件,不會很花時間嗎?

    一份最小版設計文件 20 分鐘。省下的多輪修改至少 2–4 小時。這筆帳很好算。

    小功能(一個函數、修一個 bug)不需要設計文件,直接做。設計文件是為了「有多個邊界條件、或跨越兩層以上架構」的任務。

    Q:CLAUDE.md 不是每個專案都要重寫一遍嗎?

    寫一次,維護成本低。每次發現 Claude 做了一個你不喜歡的決定,把那條規則加進 CLAUDE.md,下次就不會再發生。它是越用越省力的資產。

    Q:我的需求很複雜,文件要寫到多詳細?

    詳細到「可以讓另一個工程師依照這份文件實作,不需要問你問題」。如果你寫完文件還是覺得有地方模糊,那就是還有沒想清楚的需求,先想清楚再開始比較省事。

    從不會用到會用:各情境的具體升級路徑

    看完上面三個場景,你可能知道差距在哪,但還不知道今天要改什麼。這一節給你一條明確的路,從第一步到進階,每步都有可以直接複製的東西。

    第一步:今天就能做到(不需要任何準備)

    在你現在的任何提示最後加上這一句:

    先告訴我你的理解和假設,再開始實作。

    就這一句。它會讓 Claude 在動手前先說出它的假設,你可以在它寫出一堆錯誤代碼前糾正它。成本 0,效果立竿見影。

    三個情境的具體升級示範:

    醫療場景:Level 0 → Level 1

    不會用(Level 0) 初步會用(Level 1)
    幫我寫門診預約系統(見下方)
    幫我寫門診掛號的 API。
    
    輸入:{ patientId: string, sessionId: string, phone: string }
    輸出:{ bookingNo: string, status: "SUCCESS" | "FULL" | "DUPLICATE" }
    
    必須處理:
    - 同一診次超過容量上限 → 回傳 FULL
    - 同一患者重複掛同一診次 → 回傳 DUPLICATE
    - 所有時間以 UTC+8 處理
    
    先告訴我你的理解,特別是這三種情況你打算怎麼處理,再開始實作。

    改變了什麼:加了輸入輸出格式、三個邊界條件、確認步驟。這 5 分鐘的準備,省掉事後發現「沒處理重複掛號」的 2 小時修改。

    股市場景:Level 0 → Level 1

    幫我寫台股均線回測。策略:5日均線上穿20日均線買進,死叉賣出。
    
    台股特有規則(全部都要實作):
    - 訊號發生在收盤,執行在隔交易日開盤價(不是同日收盤)
    - 漲跌停 ±10%,超過無法成交,記錄 LIMIT_HIT
    - 手續費:買賣各 0.1425%,最低 20 元
    - 證交稅:賣出 0.3%
    - 最小交易單位 1000 股,不足不下單
    
    先告訴我這些規則你的理解,特別是成交時間點的邏輯,再開始寫。

    電商金流場景:Level 0 → Level 1

    幫我串接綠界 ECPay,支援信用卡一次付清。
    
    必須處理的情況:
    - ReturnURL(非同步)和 OrderResultURL(同步)可能都會被呼叫,
      同一筆交易只能更新訂單一次(要有 idempotency 機制)
    - CheckMacValue 驗簽失敗:記 log,不更新訂單,回傳 0|Error
    - 付款成功後訂單狀態必須立刻更新
    
    先告訴我你打算怎麼處理「非同步和同步通知都到達」這個情況,再開始實作。

    第二步:下週可以做到(CLAUDE.md)

    把你的領域規則寫成一個檔案,放在專案根目錄,命名 CLAUDE.md。之後每次對話都不用再重複說這些規則。

    先從最小版開始,15 分鐘寫完:

    # 專案規則
    
    ## Tech Stack
    [填你用的技術]
    
    ## 這個領域的特殊規則
    [把你每次都要補充說明的規則寫在這裡]
    例:
    - 台股交易日排除週末 + 台灣國定假日
    - 醫療系統所有時間 UTC+8
    - 金流驗簽失敗一律記 log 不更新訂單
    
    ## 代碼標準
    [你每次都要糾正的習慣寫在這裡]
    例:
    - 禁止 any 類型
    - 每個函數必須有對應測試
    - API 錯誤格式統一:{ code, message, field }
    
    ## 邊界條件規則
    [這個專案特有的邊界處理方式]

    寫好之後,下次開口前說「請先讀 CLAUDE.md」或什麼都不用說(Claude Code 會自動載入)。

    第三步:一個月後的進化(設計文件 + Plan Mode)

    當你習慣 Level 1 之後,下一步是在動手前多寫一份設計文件。這份文件不是給人看的,是給 Claude 看的,20 分鐘寫完,節省的是事後 4–6 小時的修改。

    設計文件的最小格式:

    # 功能:[名稱]
    
    ## 輸入 / 輸出
    輸入:[JSON 範例]
    輸出:[JSON 範例]
    
    ## 邊界條件(必須處理)
    - [條件 A] → [預期行為]
    - [條件 B] → [預期行為]
    
    ## 完成定義
    - [ ] 所有邊界條件有對應單元測試
    - [ ] TypeScript 0 errors

    有了設計文件之後,任務的啟動提示變成:

    請先閱讀 CLAUDE.md 和 [設計文件名]。
    閱讀完告訴我你的理解,特別是邊界條件部分。
    確認後先只實作 [最小單元],不要動其他層。

    當任務更複雜(跨 5 個以上文件、不可逆的架構改動),改用 Plan Mode 啟動:

    請先制定實作計劃,列出方案選項和取捨,等我確認後再開始執行。
    階段 做什麼 時間投資 節省的來回
    Level 0直接說需求00
    Level 1(今天)加輸入/輸出/邊界 + 確認步驟5 分鐘/次2–4 輪
    Level 2(下週)CLAUDE.md 寫入領域規則15 分鐘(一次性)每次省 1–2 輪
    Level 3(一個月後)設計文件 + Plan Mode20 分鐘/功能第一次就對
  • 舊系統不死,AI 讓它進化:不重寫也能持續成長

    重點摘要

    • 舊系統不是問題,缺乏 AI 輔助才是問題——AI 讓「不重寫、持續演進」成為可行選項
    • 歷史證明:超過 80% 的「重寫計畫」以失敗或兩個系統都要維護收場
    • AI 最確定的價值是讀懂舊代碼、補文件、補測試,讓團隊敢繼續開發
    • 「AI 能不能讓大規模翻新變安全」——這是尚待驗證的命題,不宜過度樂觀

    你的公司有一套跑了十年的系統。它能動,它撐起了整個業務,但沒有人敢碰它。文件不齊、邏輯散落在各處、原始開發者早就離職了。每次有人提議「重寫」,討論就會陷入沉默——因為大家心裡都知道,這條路走過很多次,沒幾次是成功的。

    AI 的出現,讓這個困境有了新的解法。但不是你想像中的那種解法。

    為什麼重寫這麼難?歷史給了殘酷的答案

    軟體界有個著名的現象叫做 Second System Effect(第二系統效應),由《人月神話》作者 Fred Brooks 提出:工程師在重寫時,往往會把所有「本來想做卻沒做」的功能都塞進去,結果新系統比舊系統更複雜、更難維護。

    但更根本的問題是:舊系統裡有隱藏的業務邏輯,它們沒有寫在文件裡,只存在於代碼的行為中——某個奇怪的判斷式、某個例外處理、某個只在特定情境才觸發的路徑。這些邏輯,是十年來無數個「為什麼這樣做?」的答案。

    重寫計畫的典型失敗模式

    • 兩個系統並行期拉太長:新舊系統同時維護,工程師精力分散,bug 在兩邊都出現
    • 上線那天發現漏了邏輯:舊系統某個角落的行為,新系統根本沒有對應
    • 商業壓力中斷重寫:計畫進行到一半,業務需求改變,只能把新舊系統黏在一起
    • 重寫後反而更慢:新架構雖然「漂亮」,但少了十年累積的效能優化細節

    這不是悲觀,這是現實。重寫不是不可能,但它的成功率遠低於大多數人的預期。在 AI 出現之前,面對舊系統,企業只有兩條路:硬撐,或者賭一把。

    AI 帶來了第三條路:輔助成長

    AI 最確定的價值,不是幫你重寫系統,而是讓「不重寫、持續演進」這件事變得可持續。

    過去,舊系統的最大問題不是代碼本身,而是「沒有人理解它」。原始開發者離職了,知識沒有傳承;文件過時了,沒有人有時間更新;要改一個功能,必須花三天理解上下文,才敢動一行代碼。

    AI 改變了這個方程式。

    AI 能為舊系統做什麼?

    挑戰 過去的困境 AI 輔助後
    理解舊代碼 要花幾天甚至幾週閱讀 AI 幾分鐘內產出架構圖和流程說明
    補充文件 沒時間寫、寫了也快過時 AI 根據現有代碼生成,每次修改後更新
    補充測試 舊系統通常 0 測試,改動沒有安全網 AI 針對現有行為補寫測試,改動有保護
    修復 bug 怕改了 A 壞了 B,只敢最小化改動 AI 追蹤影響範圍,降低連帶破壞風險
    新人上手 要跟著老人學幾個月才敢動 AI 隨時解釋任何一段代碼的邏輯和背景
    新增功能 不知道該插在哪裡,怕破壞現有邏輯 AI 建議最小侵入式的擴充點

    實際做法:AI 如何輔助舊系統成長

    第一步:讓 AI 讀懂系統,產出活的文件

    不要急著改代碼。第一件事是讓 AI 理解現有系統,然後把理解結果固化成文件。

    # 讓 AI 讀整個 codebase,產出架構說明
    # 在 Claude Code 中,直接描述你的需求:
    
    「請閱讀這個專案的所有代碼,並產出:
    1. 系統架構圖(模組與模組之間的關係)
    2. 核心業務流程說明(從使用者角度描述主要流程)
    3. 高風險區域列表(邏輯最複雜、最不敢動的地方)
    4. 技術債清單(有哪些地方明顯需要改善)」

    這份文件不是給外部人看的,是給你的團隊每天使用的工作手冊。它會隨著系統改動而更新——這一點很重要,因為過去文件之所以沒用,是因為沒有人有時間維護它。AI 讓維護文件的成本降低了 90%。

    第二步:為現有行為補測試,建立安全網

    舊系統的問題不是「代碼爛」,而是「沒有測試保護」。任何一個修改都是在沒有安全網的情況下走鋼絲。

    AI 可以閱讀現有代碼,理解它的行為,然後為這些行為寫測試——即使這些行為從來沒有文件。

    # 範例:讓 AI 為現有函式補測試
    「這個函式 calculateDiscount() 已經跑了八年,
    請分析它的所有分支條件,為每個分支寫一個測試案例,
    包括正常情況、邊界值和異常情況。
    不要改動現有邏輯,只補充測試。」

    有了測試,團隊才敢改動。改動有安全網,系統才能持續演進而不是不斷累積技術債。

    第三步:最小侵入式地新增功能

    新增功能不等於重構整個模組。AI 擅長找到「最小侵入式的擴充點」——在不動現有邏輯的前提下,把新功能插進去。

    這個原則來自 Open/Closed Principle(開放封閉原則):對擴充開放,對修改封閉。即使舊系統沒有遵循這個原則,AI 也可以建議如何在外圍包一層,讓新功能不影響舊邏輯。

    第四步:漸進式現代化,而非大爆炸式重寫

    如果真的有部分需要改善,AI 輔助的方式是:一次只動一個模組,改完之後讓它穩定跑一段時間,確認沒有問題再動下一個。

    這不是「重寫」,這是「漸進式現代化」。兩者的關鍵差異:

    重寫 漸進式現代化
    範圍 全部 一次一個模組
    風險 集中在上線日 分散,每步都可以回滾
    業務中斷 長期並行維護兩個系統 系統持續運作,局部更新
    AI 的角色 「幫我重新實作這一切」 「幫我安全地改善這一塊」

    那麼,「重寫」這條路呢?

    這是一個需要誠實面對的問題。

    過去的答案很清楚:重寫計畫成功率低,風險高,通常不是好選擇。大多數成功的案例,仔細看都是「漸進式替換」而不是「一次性重寫」。

    AI 會改變這個答案嗎?

    這是一個尚待驗證的命題。AI 確實讓理解舊系統更容易,讓知識遷移成本降低,理論上應該讓重寫的準備工作做得更完整。但「做得更完整的準備」不等於「執行時不會出問題」。隱藏的業務邏輯、時序問題、效能細節——這些在代碼裡只有在跑了幾百萬筆資料之後才會浮現。

    更誠實的說法是:

    • AI 讓「輔助成長」這條路變得可行——這是現在就可以驗證的事
    • AI 讓「重寫」變得更安全——這是有可能的,但還需要更多實際案例來驗證
    • AI 能取代「漸進式替換」的謹慎原則——不太可能,這個原則的價值在於限制風險暴露,而不是技術能力

    所以,如果有人告訴你「有了 AI,重寫就不危險了」——保持懷疑。如果有人告訴你「AI 讓你不需要擔心舊系統的技術債了」——同樣保持懷疑。

    如何判斷你的系統需要什麼?

    面對舊系統,用這個框架來判斷方向:

    優先考慮 AI 輔助成長,如果:

    • 系統仍然在提供商業價值,只是難以維護
    • 核心業務邏輯複雜,沒有人完整理解
    • 團隊規模小,無法支撐兩個系統並行
    • 業務需求變化頻繁,不能停下來等重寫完成

    可以考慮漸進式替換(不是重寫),如果:

    • 某個模組已經明顯成為瓶頸,且邊界清晰
    • 有足夠的測試保護現有行為
    • 可以部署影子流量,讓新舊模組並行驗證
    • 有明確的回滾機制

    謹慎考慮大規模重寫,只有當:

    • 現有系統在技術上已經無法繼續擴充(不只是難,而是真的不可能)
    • 有足夠的資源支撐至少 18 個月的並行期
    • 有完整的行為規格文件(或 AI 幫你產出的等效文件)
    • 組織願意接受在過渡期期間功能停滯

    結語:舊系統不是問題,缺乏支援才是

    回到最初的問題:那套跑了十年的系統,它的問題不是年齡,而是孤立。沒有人理解它,沒有測試保護它,沒有文件說明它,改動它需要承擔巨大的個人風險。

    AI 能做的,是讓這個系統不再孤立。它可以成為每個工程師的「老前輩」——隨時解釋任何一段邏輯,隨時分析改動的影響,隨時生成測試保護現有行為。

    這不是重寫的故事,這是陪伴成長的故事。

    至於重寫——如果未來真的需要,AI 會讓你準備得更充分。但那是另一個故事,而且它的結局還沒有寫完。

  • 【進階維運】iDempiere 效能優化與 Partition Table:DBA 完全攻略

    iDempiere 效能優化與 Partition Table:DBA 完全攻略

    iDempiere 運行久了,資料量增長會影響效能。本文從 DBA 角度分析效能優化策略,包含 Partition Table、索引設計、慢查詢分析與備份計畫。

    (閱讀全文…)

  • 【整合與部署】iDempiere REST API 完全攻略:認證、CRUD、DocAction

    iDempiere REST API 完全攻略:認證、CRUD、DocAction

    iDempiere REST API 讓你可以用 HTTP 方式整合外部系統,執行 CRUD 操作與觸發 DocAction。本文涵蓋認證設定、常用操作範例,以及 Python 完整程式碼。

    (閱讀全文…)