品質是團隊的責任,不只是測試的責任。

品質的定義與責任#

品質不是測出來的,而是設計和開發出來的。品質保障是整個團隊的責任,不只是 QA 的責任。

寶玉在《軟體工程之美》中強調:

很多團隊認為「測試保證品質」,這是錯誤的。測試只能發現問題,不能保證品質。品質來自每一個環節的認真對待。

品質的成本#

flowchart TD
    subgraph P [💰 預防成本 - 最低]
        P1[程式碼規範]
        P2[設計評審]
        P3[培訓]
        P4[工具投入]
    end

    subgraph E [💵 評估成本]
        E1[程式碼評審]
        E2[測試執行]
        E3[品質審計]
        E4[監控告警]
    end

    subgraph I [💸 內部失敗成本]
        I1[Bug 修復]
        I2[返工重做]
        I3[延期]
        I4[團隊士氣]
    end

    subgraph O [💔 外部失敗成本 - 最高]
        O1[客戶投訴]
        O2[賠償損失]
        O3[品牌受損]
        O4[信任喪失]
    end

    P -->|投資不足| E
    E -->|發現不及時| I
    I -->|流入生產| O

    style P fill:#c8e6c9
    style E fill:#fff9c4
    style I fill:#ffe0b2
    style O fill:#ffcdd2

在早期發現和修復問題的成本最低。投資於預防,而不是事後補救。

品質成本曲線與何時停止測試#

要把上面的成本概念用於決策,得先釐清一個常被混淆的事實:

測試本身不修復任何問題,它只蒐集資訊。 真正花錢的是「修 bug」與「bug 流入生產造成的損失」。因此「該測到什麼程度」本質上是一個資訊價值問題:再測一輪,能讓我多知道多少、避免多大的損失?

測試投入與發現的缺陷之間呈現邊際效益遞減:前期少量測試就能掃出大量明顯缺陷,越往後每多找到一個缺陷所需的成本越高。

flowchart LR
    A[測試投入增加] --> B[初期: 大量缺陷被發現<br/>單位成本低]
    B --> C[中期: 缺陷發現速度趨緩]
    C --> D[後期: 投入大增<br/>僅找到罕見缺陷]
    D --> E{再測的資訊價值<br/>是否高於成本?}
    E -->|是| A
    E -->|否| F[停止測試 / 轉移到下個風險點]

何時停止測試? 不存在「測完」這回事,只有「值不值得再測」。可參考以下判準:

判準說明
邊際資訊價值再測一輪能降低的風險,已低於這輪測試的成本
缺陷發現曲線趨平新缺陷發現率明顯下降,趨近水平
風險已落在閾值內剩餘風險對業務可接受(高風險區域已優先測過)
成本/時程約束在既定資源下,把剩餘預算投到更高風險區域的回報更高

「追求 100% 覆蓋率」常落入後期的高成本低回報區。把最後那幾趴的力氣,轉投到尚未覆蓋的高風險路徑或預防活動上,整體 ROI 通常更高。

測試與程式碼品質#

品質保障建立在堅實的測試與程式碼審查實踐之上:

  • 測試金字塔、覆蓋率、案例設計:詳見 測試基礎
  • 自動化測試、CI/CD 整合、報告與度量:詳見 測試實踐
  • Code Review 檢查清單與文化建立:詳見 Code Review

靜態分析#

常用的靜態分析工具

  • 語法檢查(ESLint、Pylint)
  • 類型檢查(TypeScript、mypy)
  • 安全掃描(SonarQube、Snyk)
  • 複雜度分析

把靜態分析整合到 CI 流程中,問題程式碼不允許合入。這比事後發現問題成本低得多。

上線與發布#

發布策略#

寶玉介紹的發布方式:

滾動發布(Rolling Update)

  • 逐步替換舊版本
  • 過程中新舊版本共存
  • 可以隨時回滾

藍綠部署(Blue-Green Deployment)

  • 準備兩套環境
  • 切換流量到新環境
  • 問題時快速切回

金絲雀發布(Canary Release)

  • 先給小部分使用者使用新版本
  • 觀察指標正常後逐步擴大
  • 發現問題只影響少量使用者
選擇建議:
├── 小更新:滾動發布
├── 大更新:金絲雀發布
├── 關鍵系統:藍綠部署
└── 多種組合使用

灰度發布實踐#

灰度的維度

  • 按使用者 ID(內部使用者優先)
  • 按地區(某個城市先上)
  • 按比例(5% ➡️ 20% ➡️ 50% ➡️ 100%)
  • 按設備(iOS 先上,Android 後上)

灰度過程中的監控

  • 錯誤率
  • 響應時間
  • 業務指標
  • 使用者反饋

灰度不是萬能的。如果問題在灰度階段沒發現,全量後可能更難發現。灰度階段要認真監控。

安全實踐#

安全左移#

寶玉提出「安全左移」的概念:

安全問題越早發現成本越低。不要等到上線前才做安全測試。

各階段的安全實踐

階段安全活動
需求安全需求分析、威脅建模
設計安全設計評審
開發安全編碼規範、程式碼審查
測試安全測試、滲透測試
部署配置審查、漏洞掃描
運維監控、響應、更新

常見安全問題#

OWASP Top 10(簡化版):

注入攻擊:
├── SQL 注入
├── 命令注入
└── 防護:參數化查詢、輸入驗證

認證問題:
├── 弱密碼
├── Session 管理
└── 防護:多因素認證、安全會話

敏感資料:
├── 資料洩露
├── 傳輸不加密
└── 防護:加密存儲、HTTPS

訪問控制:
├── 越權訪問
├── 權限繞過
└── 防護:嚴格權限檢查

永遠不要信任使用者輸入。所有外部輸入都要驗證和過濾。

生產事故處理#

事故響應流程#

喬新亮分享的事故處理原則:

flowchart TD
    subgraph D [🔔 發現階段]
        D1[監控告警] --> D2[快速確認問題]
        D3[使用者反饋] --> D2
        D4[內部發現] --> D2
    end

    subgraph R [⚡ 響應階段]
        R1[組織響應團隊] --> R2[判斷影響範圍]
        R2 --> R3[決定處理策略]
        R3 --> R4[對外溝通]
    end

    subgraph H [🔧 處理階段]
        H1[🚨 止血優先] --> H2[修復問題]
        H2 --> H3[驗證恢復]
        H1 -.- H1a["恢復服務最優先"]
    end

    subgraph P [📝 檢討階段]
        P1[時間線梳理] --> P2[根因分析 5 Why]
        P2 --> P3[改進措施]
        P3 --> P4[經驗分享]
    end

    D --> R --> H --> P

    style D fill:#ffebee
    style R fill:#fff3e0
    style H fill:#e8f5e9
    style P fill:#e3f2fd

事後檢討#

檢討的目的是學習和改進,不是追責。如果檢討變成追責會議,以後就沒人敢報告問題了。

好的檢討會議

  • 聚焦系統和流程,而非個人
  • 鼓勵誠實說出問題
  • 產出具體的改進措施
  • 跟進改進的執行

無責事後檢討(Blameless Postmortem)#

「無責」不是「無責任」,而是把焦點從「犯了錯」轉移到「什麼樣的系統與流程讓這個錯誤得以發生而未被攔截」。它的前提是心理安全(psychological safety):團隊成員相信誠實揭露問題不會招致懲罰或羞辱。

無責文化是一種理性的工程選擇,而非「對人寬容」。一旦檢討變成問責會議,最直接的後果不是「大家更小心」,而是下次出事沒人敢第一時間上報——隱瞞會把一個小事故拖成業務災難。資訊的自由流動,遠比追究單一個人更有價值。

有責文化(要避免)無責文化(要建立)
「是誰把它推上線的?」「為什麼這個變更能在沒有把關下進到生產?」
結論是「某人要更小心」結論是「補上自動檢查 / 防呆機制」
當事人防衛、避重就輕當事人安心還原完整時間線
問題被掩蓋,下次重演問題被攤開,系統被改善

設計檢討會議以維持心理安全

  • 開場明確聲明「目的是學習,不追責」,並由帶頭者以身作則
  • 用被動、對事的語言(「變更未被攔截」而非「某某沒檢查」)
  • 由當事人主述時間線——他最清楚現場,且這代表團隊信任他
  • 把每條改進措施綁定到「系統/流程」而非「某人要更努力」

根因分析:5 Whys 的技巧與陷阱#

5 Whys 是最常用的根因分析法:對問題反覆追問「為什麼」,直到觸及可從制度上修復的根因。

事故:使用者下單後庫存超賣
├── 為什麼超賣?        → 兩個請求同時扣到同一筆庫存
├── 為什麼會同時扣?    → 扣庫存沒有加鎖/沒用原子操作
├── 為什麼沒加鎖?      → 開發時不知道此路徑會被並發呼叫
├── 為什麼不知道並發?  → 設計評審沒涵蓋並發場景
└── 為什麼評審沒涵蓋?  → 缺少並發風險的評審檢查項   ← 可修復的根因

修復點落在最後一層(補上評審檢查項 + 加上原子扣減),而不是停在「開發要更小心」。

5 Whys 的常見陷阱

  • 單線歸因:真實事故常是多因交織,硬要追成一條鏈會漏掉其他成因——必要時用魚骨圖(fishbone)或 5 Whys 多分支展開。
  • 過早停在「人」:問到「某人疏忽了」就收手,等於把根因鎖定在個人,違背無責精神;應繼續追問「為什麼這個疏忽能造成事故」。
  • 答案是猜的:每一層「為什麼」都應有證據(日誌、時間線)支撐,而非腦補。
  • 追問次數教條化:「5」只是經驗值,達到可行動的系統性根因即可停,不必硬湊或硬砍。

檢討報告模板

mindmap
  root((檢討報告))
    📋 事故概述
      時間
      影響範圍
      持續時間
    ⏱️ 時間線
      詳細的事件發展過程
    🔍 根因分析
      直接原因
      根本原因(用 5 Why 分析)
    📊 影響評估
      業務影響
      使用者影響
    🛠️ 改進措施
      短期修復
      長期改進
      責任人和時間表

本章要點#

  1. 品質是團隊責任:不只是測試的責任
  2. 測試金字塔:大量單元測試,適量整合測試,少量 E2E
  3. Code Review:發現問題、共享知識、建立文化
  4. 灰度發布:逐步上線,邊發布邊監控
  5. 安全左移:越早發現安全問題成本越低
  6. 檢討不追責:目的是學習和改進