本章是 Part II 的開篇,建立了整個品質屬性討論的 共通語言分析框架。作者從功能性(functionality)與品質屬性(quality attributes)的關係切入,指出功能性不決定架構,品質屬性才是驅動架構決策的關鍵力量。隨後提出以 品質屬性場景(quality attribute scenarios) 作為統一的需求描述格式,並介紹 策略(tactics)架構模式(architectural patterns) 作為實現品質屬性的設計手段,最後說明如何透過 策略導向問卷(tactics-based questionnaires) 進行輕量級的架構分析。本章為後續 Chapter 4–14 各品質屬性的深入討論奠定了基礎。

功能性與架構的關係#

功能性(functionality)是系統完成其預期工作的能力。在所有需求中,功能性與架構的關係最為特殊:

  • 功能性不決定架構:同一組功能需求可以對應無數種架構設計。功能可以用任何方式分割,並指派給不同的架構元素。
  • 如果只關心功能性,根本不需要拆分系統:一個巨大的單體(monolithic blob)就能完成所有功能。我們之所以將系統拆分成模組、層級、服務、資料庫等協作元素,是為了 可理解性 與其他品質屬性。
  • 功能性透過責任分派實現:將責任(responsibilities)指派給架構元素,產生最基本的架構結構——模組分解(module decomposition)

作者偏好使用「責任」(responsibility)一詞取代「功能需求」(functional requirement)。例如:「這組責任的時序限制是什麼?」「預期對這組責任做什麼修改?」這樣的提問方式更精確、更具可行動性。「功能需求」一詞雖廣為人知,但在需要精確定義時,應改為談論具體的責任集合。

品質屬性的三個常見問題#

軟體社群自 1970 年代起便在研究品質屬性,但大多數討論存在三個問題:

  1. 定義不可測試:說一個系統「可修改」是沒有意義的。每個系統對某些變更是可修改的,對另一些則不是。其他品質屬性亦然。
  2. 歸類之爭無益:阻斷服務攻擊(denial-of-service attack)究竟屬於可用性、效能、安全性還是易用性?四個社群都會主張擁有權,但這種分類辯論對架構師設計解決方案毫無幫助。
  3. 術語不一致:效能社群說「事件」(events),安全社群說「攻擊」(attacks),可用性社群說「故障」(faults),易用性社群說「使用者輸入」(user input)——它們可能指的是同一件事。

這三個問題的解方分別是:使用 品質屬性場景 來統一描述(解決前兩個問題),以及用 共通形式 來呈現各屬性社群的核心概念(解決第三個問題)。

品質屬性可分為兩大類:

  • 執行期屬性(runtime):可用性(availability)、效能(performance)、易用性(usability)等
  • 開發期屬性(development-time):可修改性(modifiability)、可測試性(testability)、可部署性(deployability)等

品質屬性之間 永遠存在交互影響——某一屬性的實現可能對其他屬性產生正面或負面的影響。幾乎所有品質屬性都會對效能產生負面影響。例如:

  • 可移植性(portability)的主要技術是隔離系統相依性,但這會引入額外的處理程序或程序邊界,從而影響效能
  • 安全性的加密與認證機制會增加處理時間
  • 可用性的冗餘機制會增加系統複雜度

架構設計本質上就是做出適當的 權衡(tradeoffs),在相互競爭的品質屬性之間取得平衡。

品質屬性場景#

作者提出以 六要素場景(six-part scenario) 作為所有品質屬性需求的統一描述格式,解決術語不一致和定義不可測試的問題。

場景的六個組成部分#

  1. 刺激(Stimulus):到達系統或專案的事件。在效能中是「事件」,在易用性中是「使用者操作」,在安全性中是「攻擊」,在可修改性中是「變更請求」。
  2. 刺激來源(Stimulus Source):產生刺激的實體(人、電腦系統或其他角色)。來源會影響系統的處理方式——受信任使用者的請求與不受信任使用者的請求會受到不同程度的審查。
  3. 回應(Response):刺激到達後系統執行的活動。這是架構師需要滿足的責任。例如效能場景中系統需處理事件並產生回應;可修改性場景中開發者需實施修改且不造成副作用。
  4. 回應度量(Response Measure):回應發生時的可量測指標,用以測試場景是否達成。效能可量測延遲或吞吐量;可修改性可量測實施、測試和部署所需的人力或時間。
  5. 環境(Environment):場景發生時的情境條件。可以是執行期狀態(正常運作、過載、降級模式),也可以是非執行期狀態(開發中、測試中、充電中)。環境設定了場景的上下文——程式碼凍結後到達的修改請求,處理方式可能與凍結前不同。
  6. 構件(Artifact):刺激的目標對象。可以是整個系統、系統集合,或系統的特定部分。資料儲存的故障處理可能不同於元資料儲存的故障處理。

Figure 3.1: The parts of a quality attribute scenario

通用場景與具體場景#

作者區分了兩種場景層次:

  • 通用場景(General Scenarios):與具體系統無關,可適用於任何系統。本書在 Chapter 4–13 中為每個品質屬性提供了通用場景,用於引導腦力激盪與需求引出。
  • 具體場景(Concrete Scenarios):針對特定系統量身定製,是將通用場景加以具體化的結果。實務經驗顯示,讓利害關係人 從通用場景出發進行調整,比讓他們憑空撰寫場景要容易得多。

Figure 3.2: A general scenario for availability

雖然在品質屬性思考的早期階段常會省略六個部分中的一兩個,但完整的六要素框架能迫使架構師考慮每個面向是否相關,避免遺漏關鍵約束條件。

書中舉了一個 Lawrence Livermore 國家實驗室的案例來說明品質屬性的情境依賴性:這個組織的網站上到處提及「security」,但在架構分析時,利害關係人卻從未提及安全性需求。原因很簡單——他們的系統不連接外部網路,且有鐵絲網和持槍守衛保護。這說明 軟體架構師未必需要承擔每一個品質屬性的責任,品質屬性的重要性完全取決於系統的具體情境。

透過架構模式與策略實現品質屬性#

策略(Tactics)#

策略是一種影響品質屬性回應的 設計決策——它直接影響系統對某個刺激的回應。策略可以為一個設計賦予可移植性,為另一個賦予高效能,為第三個賦予可整合性。

Figure 3.3: Tactics are intended to control responses to stimuli

架構模式(Architectural Patterns)#

架構模式描述一個在特定設計情境中反覆出現的設計問題,並提出經過驗證的架構解決方案。模式通常包含多個設計決策,實際上往往 綑綁了多個策略,因此常在品質屬性之間做出權衡。

策略與模式的關係#

作者指出三個使用策略的理由:

  • 模式是許多架構的基礎,但有時沒有現成模式能完整解決問題。例如,你可能需要的是「高可用、高安全的 Broker 模式」,而非教科書上的標準 Broker 模式。策略提供了一種系統性的方式來 增補既有模式 以填補缺口。
  • 若不存在適用模式,策略允許架構師從「第一原理」(first principles)構建設計片段,並理解所產生的設計片段之特性。
  • 策略使設計和分析過程更加 系統化,在一定限度內提供結構化的思考方式。

架構退化與技術債#

雖然本書將模式和策略描述為有意識的基礎設計決策,但現實中架構往往是許多小決策和商業力量 逐漸演化 的結果。作者指出,架構品質往往會隨時間 逐漸退化——這就是所謂的「千刀萬剮」(death by a thousand cuts):

  • 開發者在新增功能與修復缺陷時,可能因為不理解系統結構、時程壓力或架構不夠清晰而做出次佳決策
  • 原本還能接受的可修改性會逐漸惡化;效能、可用性、安全性等品質同樣會因開發者專注於眼前任務而退化
  • 這種退化就是一種 架構債(architecture debt),屬於技術債的一種形式(詳見 Chapter 23)
  • 應對方式是 重構(refactoring)——可以為了安全性(將模組依安全屬性分組)、效能(移除瓶頸)或可修改性(提取重複功能為獨立模組以提高內聚力)等目的進行重構
  • 程式碼重構是敏捷開發的常見實踐,用於清理重複或過度複雜的程式碼,但這個概念同樣適用於 架構層級的元素

即使有卓越的安全架構,如果員工容易受到網路釣魚攻擊或不使用強密碼,架構的價值也會大打折扣。品質屬性的實現往往同時涉及 流程面架構面 的決策。

策略的設計運用#

系統設計由一系列決策組成,其中一些決策控制品質屬性回應,另一些確保系統功能的實現。策略並非本書發明的新概念,而是對優秀架構師實務做法的 萃取與系統化整理。使用策略時的要點:

  • 策略需要精煉(refined):例如「排程資源」(schedule resources)這個效能策略需要精煉為具體的排程方式,如最短作業優先(shortest-job-first)或輪替法(round-robin)。
  • 策略的適用性取決於情境:例如「管理取樣率」(manage sampling rate)在某些即時系統中適用,但在資料庫或股票交易系統中——丟失任何事件都是不可接受的——則不適用。
  • 存在「超級策略」(super-tactics):如封裝(encapsulation)、限制相依性(restricting dependencies)、使用中介者(using an intermediary)和抽象共用服務(abstracting common services),這些策略幾乎出現在所有模式的實現中。例如,負載平衡器(load balancer)就是一個同時扮演中介者角色和執行排程策略的元素;監控(monitoring)則出現在能源效率、效能、可用性和安全性等多個品質屬性中。
  • 策略是設計基元(design primitives):不應期望某個策略只屬於單一品質屬性,它們會在設計的不同面向中反覆出現。正因為策略如此基礎且無處不在,架構師值得深入了解它們。

策略導向問卷:分析品質屬性的設計決策#

策略導向問卷(tactics-based questionnaires) 是架構師在設計過程各階段評估品質屬性實現程度的分析工具。分析品質屬性的實現程度是架構設計任務中至關重要的一環,而且不應等到設計完成後才開始——在軟體開發生命週期的許多階段都有進行品質屬性分析的機會。分析的準確度和信心程度會隨著可用製品的成熟度而變化,但無論設計處於什麼狀態,策略導向問卷都能幫助獲取有關架構實現品質屬性能力的洞察。

使用方式#

問卷中每個問題需記錄四項資訊:

  • 是否支持(Supported):架構是否支持該策略
  • 風險(Risk):使用或未使用該策略的明顯風險(H / M / L)
  • 設計決策與位置(Design Decisions and Location):實現策略的具體設計決策,以及在程式碼中的位置
  • 理由(Rationale):設計決策的理由與假設

四個步驟#

  1. 對每個策略問題,在「Supported」欄填入 Y 或 N
  2. 若為 Y,描述具體設計決策及其在架構中的位置(如哪些模組、框架或套件實現了此策略)
  3. 在「Risk」欄標示風險等級(H = 高、M = 中、L = 低)
  4. 在「Rationale」欄描述決策理由及其對成本、時程、演進等方面的影響

這種問卷式方法雖然看似簡單,卻非常強大。完成一個品質屬性的問卷通常只需 30 到 90 分鐘,但能迫使架構師退一步思考全局,並快速發現架構的優勢與弱點。

討論問題#

本章提出的思考問題包括:

  • Use case 與品質屬性場景之間的關係為何?如何在 use case 中加入品質屬性資訊?
  • 某個品質屬性的策略集合是有限的還是無限的?
  • 如何為一個 ATM 系統列舉責任集合,並提出對應的設計方案?
  • 使用策略導向問卷分析你熟悉的架構,能獲得什麼洞察?

本章小結#

  • 功能需求透過在設計中納入適當的責任集合來滿足;品質屬性需求則由架構的結構與行為來滿足。
  • 品質屬性需求常被捕捉得不完善。建議使用六要素的 品質屬性場景 來描述:刺激來源、刺激、環境、構件、回應、回應度量。
  • 架構策略是影響單一品質屬性回應的設計決策;架構模式則描述特定情境中反覆出現的設計問題及其經過驗證的解決方案。模式可被視為策略的「綑綁」(bundles)。
  • 架構師可透過 策略導向問卷 這種輕量級分析技術,在極短時間內洞察架構的優缺點。