本書談的是微服務架構,但要先把「架構」(architecture)本身講清楚。本節從外部黑盒視角開始,給出軟體架構的明確定義,再從三種觀點討論為何它重要。

把應用視為黑盒:操作與事件#

從外部看,一個應用之所以存在,是為了實作它對外可見的行為。可以用「黑盒模型」描述:應用實作一個或多個系統操作(system operation),並發布事件(event)。

  • 系統操作:可被呼叫的行為切片,類似「Application 物件」上的方法。FTGO 範例:createOrder()cancelOrder()findOrderHistory()
  • 事件:在應用內發生值得關注的事情(通常是某操作執行的結果)。FTGO 範例:OrderCreatedOrderCancelledOrderDelivered

Figure 3.1: An application implements system operations and publishes events

系統操作分為兩類#

  • commands:會改變狀態的操作,例如 createOrder()cancelOrder()
  • queries:只讀取資料的操作,例如 findOrderHistory()

呼叫方式有四種:

  • 真人使用者透過 UI 點擊。
  • 其他應用透過 API 呼叫。
  • 響應另一個應用發布的事件。
  • 響應時間流逝(例如定期批次)。

系統操作在定義架構時扮演核心角色:它們會「抗拒被拆」——分散式操作(跨多個服務,需要最終一致性與服務間通訊)遠比本地操作複雜。設計微服務架構時,需要在「更小的服務促進流暢交付」與「保持操作本地、簡單」之間反覆權衡(第 20 章詳述)。

系統事件的角色#

  • 事件通常代表業務實體(business entity)狀態變化的結果,例如 createOrder() 成功後發布 OrderCreated
  • 失敗也可能觸發事件,例如信用額度不足時發布 CustomerCreditLimitExceeded
  • 傳遞方式:組織內常用 message broker;對外組織常用 web hook(例如 Stripe 用 web hook 通知付款成功或失敗);對使用者也可能用行動推播。

軟體架構的定義#

關於「軟體架構」有許多定義,例如:

  • Martin Fowler 引用 Ralph Johnson:「Architecture is about the important stuff—whatever that is.」
  • Grady Booch:「Architecture represents the significant design decisions that shape a system, where significant is measured by the cost of change.」

本書最偏好的定義來自 Software Engineering Institute(SEI)的 Len Bass 等人:

一個運算系統的軟體架構,是用來推理該系統所需的一組結構;每個結構由軟體元素(elements)、元素之間的關係(relations)、以及它們的屬性(properties)組成。 ——Bass et al,《Documenting Software Architectures》

更白話地說:架構就是把應用拆成多個部分(elements),以及這些部分之間的關係(relations)

拆分(decomposition)很重要,有兩個原因:

  • 促成分工與知識分布:架構決定了多個團隊(可能各自具備專業知識)能多有效地共同開發應用。
  • 定義元素如何互動:元素之間的互動,決定了應用的執行期行為。

架構為何重要:三種觀點#

幾乎所有非平凡(non-trivial)的應用,都有一些只能由架構滿足的需求。對「這些需求是什麼」有三種觀點:

Figure 3.2: Three different perspectives on the purpose of architecture — non-functional requirements, architecturally significant requirements, quality attributes

觀點一:架構滿足非功能需求#

傳統觀點將需求分為兩類:

  • 功能需求(functional requirements):應用必須提供哪些功能與能力,通常以使用案例(use case)或 user story 表達——例如 FTGO 的「下訂單」「取消訂單」。
  • 非功能需求(non-functional requirements):應用「執行得多好」,以及「多容易被開發與維護」。

非功能需求又涵蓋:

  • 執行期行為:scalability、performance 等。FTGO 範例:每秒處理 233 個建立訂單請求,平均回應時間 356 毫秒。
  • 開發期需求:應用容不容易修改、部署。FTGO 範例:開發者做一個小變更後,40 分鐘內可部署到生產環境。

大多數功能需求其實用任何架構都能實作——即使是大泥球;但非功能需求與架構直接綁在一起。在當今高頻交付的需求下,開發期需求的重要性快速上升(第 5 章詳述)。

觀點二:架構滿足「架構顯著需求」#

近年研究(例如 Eckhardt 等人的「Are ‘Non-functional’ Requirements really Non-functional?」、Chen 等人的「Characterizing Architecturally Significant Requirements」)指出:

  • 並非所有非功能需求都會影響架構。
  • 有些功能需求其實會影響架構。
  • 某些非功能需求其實是包裝過的功能需求。

於是衍生出「架構顯著需求(architecturally significant requirement)」的概念——指真正會影響架構的需求。常見特徵:

  • 影響範圍廣
  • 風險高
  • 業務價值高

這個觀點的弱點是「主觀性高」——一個需求是否屬於「架構顯著」見仁見智,因此導致循環定義:「架構之所以重要,是因為它能滿足那些影響架構的需求。」

觀點三:架構滿足品質屬性(較精確,本書偏好)#

Bass et al. 在《Software Architecture in Practice》中強調:

一個系統能不能滿足其期望(或必要)的品質屬性,主要由架構決定。如果你只記得本書一件事,請記住這一點。

品質屬性(quality attribute,QA)的定義:

一個系統可被測量或測試的特性,用來指出該系統「在基本功能之外」滿足利害關係人需求的程度。

兩大類:

  • 開發期品質屬性:可修改性(modifiability)、可測試性(testability)、可部署性(deployability)。
  • 執行期品質屬性:可用性(availability)、效能(performance)、安全性(security)。

品質屬性的定義比「功能/非功能」更明確:performance 講系統的時序行為,modifiability 講系統部署後支援變更的能力,availability 講系統在故障中存活的能力,等等。

品質屬性場景:讓品質屬性變得可測試#

品質屬性需求通常以「場景(scenario)」表達,六個組件:

  • stimulus:在執行期到達應用、或開發期到達工程組織的事件
  • stimulus source:事件來源
  • response:回應 stimulus 而觸發的活動
  • response measure:活動的量化指標,例如延遲、吞吐量、變更時間,用來判斷架構是否滿足該品質屬性
  • environment:場景發生的條件
  • artifact:被該場景影響的系統部分

範例:

  • 可用性場景:當服務實例(例如 Order Service)失敗時,應用仍持續處理請求,並自動重啟該實例——這個場景隱含著多實例、負載平衡、可觀測性、自動重啟等架構特性。

Figure 3.3: An example availability scenario — application keeps handling requests when a service instance fails

  • 可修改性場景:開發者修改部分應用後,要在多少時間內部署完成——這個場景同時涵蓋變更便利性與部署管線執行時間。

Figure 3.4: An example modifiability scenario — how long it should take a developer to make and deploy a change

品質屬性場景的最大價值是可測試:你可以實際測量「開發者完成一次變更與部署需要多久」,也可以主動終止服務實例,觀察應用是否如期回應。

小結#

無論你採用哪種觀點(非功能需求、架構顯著需求、品質屬性),架構之所以重要,都因為它定義了應用大量的開發期與執行期屬性。第 5 章將詳述「流暢交付所需的系統品質屬性」,接下來則先看軟體架構的多維度本質。