概述#

本章提出了軟體架構之所以重要的 13 個理由,作者稱之為「十三點清單(List of Thirteen)」。即使讀者已經相信架構的重要性,這 13 個理由仍然可以被視為在專案中有效運用架構的 13 種方式,或是用來說服組織投入架構資源的 13 種論據。

本章的 13 個理由構成了整章的大綱,每一個理由都對應一個小節。這些理由涵蓋了技術面與非技術面,全面說明架構在軟體開發生命週期中的關鍵角色。


2.1 抑制或促成系統的品質屬性#

系統能否達到所期望的品質屬性(Quality Attributes),在很大程度上取決於其架構。作者強調:

如果你只能從這本書記住一件事,那就記住:系統的品質屬性主要由架構決定

書中列舉了多個品質屬性與架構決策的對應關係:

  • 高效能(Performance):需要管理元素的時間行為、共享資源的使用,以及元素間通訊的頻率與資料量
  • 可修改性(Modifiability):需要謹慎分配職責給各元素,並限制元素之間的耦合(coupling),使大多數變更只影響少數元素
  • 高安全性(Security):需要管理和保護元素間的通訊,控制哪些元素可以存取哪些資訊,並可能引入授權機制等專用元素
  • 安全性(Safety):需要在架構中設計安全防護與復原機制
  • 可擴展性(Scalability):需要將資源的使用局部化,避免引入瓶頸,並採用結合負載平衡的元素複製(replication)策略
  • 可部署性(Deployability):需要管理元素間的互動,使其盡可能獨立,並設計能在不影響其餘系統的情況下進行小量變更

作者也提醒,架構並非品質的唯一決定因素。正如他們玩笑地說:「架構所賦予的,實作可能拿走(What the architecture giveth, the implementation may taketh away)」。從架構設計到編碼、實作和測試,生命週期各階段的決策都會影響系統品質。


2.2 推理與管理變更#

可修改性(Modifiability) 是如此重要的品質屬性,以至於作者特別為它保留了獨立的篇幅。軟體開發社群正逐漸認知到一個事實:約 80% 的軟體系統總成本發生在初始部署之後。大多數程式設計師的工作是在既有架構和既有程式碼的限制下進行維護與修改。

每個架構都會將可能的變更劃分為三個類別:

  • 局部變更(Local change):只需修改單一元素即可完成。例如:在定價邏輯模組中新增一條業務規則
  • 非局部變更(Nonlocal change):需要修改多個元素,但基本架構方法不變。例如:新增業務規則後,還需在資料庫新增欄位,並在使用者介面上顯示結果
  • 架構層級變更(Architectural change):影響元素間的根本互動方式,可能需要全面修改系統。例如:將系統從單執行緒改為多執行緒

一個有效的架構,應使最常見的變更為局部變更,從而使其容易實施。非局部變更雖不理想,但至少可以分階段有序地推出。

架構師的職責包括:決定何時變更是必要的、判斷哪條變更路徑風險最低、評估提議變更的後果,以及仲裁變更請求的優先順序。若不注意維持架構的概念完整性(Conceptual Integrity),幾乎必然會累積架構債務(Architecture Debt)


2.3 預測系統品質#

架構不僅賦予系統品質屬性,而且是以可預測的方式這樣做的。

這並非理所當然。如果沒有這個特性,設計架構就會變成一連串隨機的設計決策,之後建構系統、測試品質屬性,然後聽天由命。幸運的是,我們可以僅基於架構評估來預測系統品質

  • 如果我們知道某些架構決策會導致特定的品質屬性,我們就可以做出這些決策並合理預期獲得相應的品質
  • 事後檢驗時,我們可以判斷這些決策是否已被做出,並有信心地預測架構將展現相應的品質

即使不進行定量分析建模,基於品質屬性影響來評估決策的原則,對於及早發現潛在問題也是非常有價值的。


2.4 利害關係人之間的溝通#

架構是一種抽象(Abstraction),它代表系統的簡化模型,可以讓團隊成員共同理解。架構是大多數(甚至所有)利害關係人可以用來建立共識、協商和溝通的共同抽象

不同的利害關係人關注系統的不同面向:

  • 使用者:關心系統是否快速、可靠、在需要時可用
  • 客戶(付費方):關心架構能否在預算和時程內實作
  • 管理者:關心架構是否允許團隊在紀律和控制下大致獨立地工作
  • 架構師:關心實現上述所有目標的策略

架構提供了一種共通語言,讓不同的關注點可以在智識上可管理的層次上被表達、協商和解決。

書中引用了一個經典案例:在一場政府軟體專案審查會議中,一位使用者代表在架構簡報時打斷了架構師,詢問「按下模式選擇按鈕會發生什麼?」。這個問題並非架構問題,但架構的圖形呈現激發了新的思考和討論,讓與會者花了 45 分鐘辯論系統在各種狀態下的正確行為——這是一場在需求制定階段就應該發生的對話。這個故事說明了架構作為溝通工具的獨特價值:以新的視角呈現系統,會刺激思維並讓新的問題浮出水面。


2.5 早期設計決策#

軟體架構是關於系統的最早期設計決策的具體呈現,這些早期綁定對系統的後續開發、部署和維護有著巨大的影響。架構也是這些重要設計決策可以被審視的最早時機

作者以繪畫做比喻:藝術家在動筆前就決定了畫布材質和媒材(油畫、水彩、蠟筆),一旦開始作畫,每一筆的位置、粗細和形狀都強烈影響最終作品的樣貌。每個決策都約束了後續的許多決策。

架構中體現的早期設計決策包括:

  • 系統將在單一處理器上執行,還是分布在多個處理器上?
  • 軟體是否分層?如果是,有幾層?各層的職責為何?
  • 元件之間是同步還是非同步通訊?透過控制流還是資料流互動?
  • 流經系統的資訊是否加密?
  • 使用哪個作業系統?
  • 選擇哪種通訊協定?

改變這些早期決策會產生漣漪效應——許多後續決策也必須跟著改變。雖然有時架構必須重構或重新設計,但這不是輕率進行的任務,因為「漣漪」可能變成「雪崩」。


2.6 對實作的約束#

架構定義了一組對實作的約束(Constraints on Implementation)。如果希望實作符合架構,那麼:

  • 實作必須包含架構所規定的元素集合
  • 這些元素必須以架構規定的方式互動
  • 每個元素必須對其他元素履行架構規定的職責

一個經典的例子是架構師為參與某項較大功能的各軟體元件分配效能預算(Performance Budget)。如果每個軟體單元都在預算之內,整體交易就能滿足效能需求。各元件的實作者可能不知道整體預算,只知道自己的分配額度。

反過來說,架構師不需要精通所有演算法設計或程式語言的細節——但必須了解足夠多,以確保不會設計出難以建構的東西。


2.7 對組織結構的影響#

架構不僅規定了系統的結構,這個結構還會刻印在開發專案的組織結構中(有時甚至影響整個組織的結構)。

大型專案的分工方式通常是將系統的不同部分分配給不同的團隊。這種工作分解結構(Work-Breakdown Structure) 會影響到:

  • 計畫、排程和預算的單位
  • 團隊間的溝通管道
  • 配置管理和檔案系統的組織方式
  • 整合與測試計畫
  • 維護活動中團隊的組成(如資料庫團隊、業務規則團隊、UI 團隊等)

建立工作分解結構的副作用是凍結了某些架構面向。負責某個子系統的團隊可能會抵制將其職責分散到其他團隊。如果這些職責已在合約中正式化,變更可能代價高昂甚至引發法律糾紛。因此,一旦架構達成共識,基於管理和商業原因,要大幅修改它的成本非常高。


2.8 支援增量式開發#

架構一旦定義,就可以作為增量式開發(Incremental Development) 的基礎。

  • 第一個增量可以是一個骨架系統(skeletal system),包含基礎設施(元素如何初始化、通訊、共享資料、存取資源、報告錯誤、記錄活動等),但尚無大部分應用功能
  • 基礎設施的建構和應用功能的建構可以同步進行:設計並建構一小段基礎設施來支持一小段端到端功能,然後重複此過程
  • 許多系統以骨架系統方式建構,可透過外掛(Plug-ins)、套件(Packages)或擴充(Extensions) 來擴展功能,例如 R 語言、Visual Studio Code 和大多數網頁瀏覽器

這種做法在 2000 年代初期因 Alistair Cockburn 的「行走骨架(Walking Skeleton)」概念而受到關注,近年來更被採用 MVP(最小可行產品) 作為風險降低策略的團隊所採用。

增量式開發的好處包括降低專案風險。如果架構是針對一系列相關系統設計的,基礎設施可以跨系統重複使用,降低每個系統的成本。


2.9 成本與排程估算#

成本與排程估算是專案經理的重要工具。架構師的職責之一是在專案生命週期早期協助專案經理建立這些估算。

  • 由上而下的估算(Top-down):對設定目標和分配預算有用
  • 由下而上的估算(Bottom-up):基於對系統各部分的理解,通常比純粹由上而下的估算更準確

最佳的成本與排程估算通常來自由上而下估算與由下而上估算之間的共識。由架構師和專案經理產生的頂層估算,與開發者產生的底層估算之間的討論與協商,能創造出比任何單一方法更準確的估算。

需求的審查和驗證也很重要——對範圍的前期了解越多,估算就越準確。


2.10 可轉移、可重複使用的模型#

在生命週期中越早應用重複使用,獲得的效益越大。雖然程式碼重複使用有其好處,但架構重複使用對於具有類似需求的系統能提供巨大的槓桿效果。

產品線(Product Line) 或產品家族是使用同一組共享資產建構的一系列系統,其中最核心的資產就是為整個家族需求設計的架構。產品線架構定義了:

  • 所有成員固定不變的部分
  • 各成員之間可變動的部分

產品線已被證明在上市時間、成本、生產力和產品品質方面能帶來數量級的效益提升


2.11 架構允許整合獨立開發的元素#

以架構為基礎的開發,重點從編寫程式碼轉移到組合或組裝可能獨立開發的元素。架構定義了可以被整合進系統的元素,並根據元素與環境的互動方式、控制流的接收與釋放、資料的消費與產生、通訊協定等來約束可能的替換或新增。

獨立開發元素的例子包括:

  • 商業現成元件(COTS)
  • 開源軟體
  • 公開可用的應用程式
  • 網路服務

使用獨立開發元素的效益:

  • 縮短上市時間:使用現成方案比自行建構更快
  • 提高可靠性:廣泛使用的軟體應該已經修正了大部分錯誤
  • 降低成本:供應商可以將開發成本分攤到客戶群
  • 增加彈性:非特殊用途的元件通常有多個來源可選擇,增加談判籌碼

開放系統(Open System) 定義了一組軟體元素的標準——它們的行為方式、互動方式、資料共享方式等。目標是鼓勵多個供應商提供元素,避免供應商鎖定(Vendor Lock-in)


2.12 限縮設計替代方案的詞彙#

隨著有用的架構解決方案被收集起來,我們會發現:自願將選擇限制在相對少量的經過驗證的元素及其互動方式中,可以最小化系統的設計複雜度。

軟體工程師不是藝術家——創意和自由不是首要考量。工程是關於紀律(Discipline),紀律的一部分來自於將替代方案的詞彙限縮到經過驗證的解決方案。

限縮設計詞彙到經過驗證的解決方案可帶來以下好處:

  • 增強重複使用
  • 更規律、更簡單的設計,更容易被理解和溝通,帶來更可靠可預測的結果
  • 更容易分析,信心更高
  • 更短的選擇時間
  • 更高的互操作性

經過驗證的設計解決方案包括策略(Tactics)模式(Patterns),這些將在本書第二部分廣泛討論。前所未有的設計是有風險的,經過驗證的設計則是可靠的。這並不意味著軟體設計不能創新,但創新應該是在現有解決方案不足以解決問題時才追求,而非為了新奇而創新。


2.13 培訓的基礎#

架構——包括描述元素如何互動以實現所需行為——可以作為新專案成員認識系統的第一份入門材料

  • 模組視圖(Module Views):展示專案結構、誰負責什麼、哪些團隊被分配到系統的哪些部分
  • 元件與連接器視圖(Component-and-Connector Views):解釋系統如何運作和完成工作
  • 分配視圖(Allocation Views):讓新成員知道自己被分配的部分如何融入專案的開發或部署環境

2.14 總結#

軟體架構因廣泛的技術和非技術原因而至關重要。十三點清單的完整列表如下:

  1. 架構會抑制或促成系統的驅動品質屬性
  2. 架構中的決策讓你能夠推理和管理變更
  3. 架構分析能早期預測系統品質
  4. 文件化的架構能增進利害關係人間的溝通
  5. 架構承載最早期、最根本、最難變更的設計決策
  6. 架構對後續實作定義了一組約束
  7. 架構決定了組織的結構,反之亦然
  8. 架構可以作為增量式開發的基礎
  9. 架構是讓架構師和專案經理推理成本與排程的關鍵工件
  10. 架構可以作為可轉移、可重複使用的模型,構成產品線的核心
  11. 以架構為基礎的開發將注意力集中在元件的組裝而非僅僅是建立
  12. 透過限縮設計替代方案,架構有效引導開發者的創造力,降低設計和系統複雜度
  13. 架構可以作為培訓新團隊成員的基礎