元件(Component)概述#
Component 是 module 的物理呈現形式。開發者以不同方式打包模組,依平台而異:Java 的 jar、.NET 的 dll、Ruby 的 gem 等。本章探討元件的範圍、識別流程與設計方法。
Component Scope(元件範圍)#
元件可依粒度分為多種層級:
- Library(函式庫):最簡單的元件包裝,通常與呼叫程式碼運行在同一記憶體空間,為編譯期依賴
- Layer / Subsystem(層或子系統):架構中的較大單位,作為許多 event processor 的可部署單位
- Service(服務):運行在自己的位址空間中,透過 TCP/IP 或 REST、message queue 等協定通訊
- Distributed service(分散式服務):包含自己的模組和資料庫,形成獨立的可部署單元

Figure 8.2: A microservice might have so little code that components aren't necessary
元件構成架構中的基本模組化建構區塊。架構師的首要決策之一,就是決定架構中元件的頂層分區方式(top-level partitioning)。
Architect Role(架構師角色)#
架構師負責定義、精煉、管理和治理架構中的元件:
- 與 business analysts、subject matter experts、開發者、QA、enterprise architects 協作
- 整合架構特性與需求,建立初始設計
- 元件通常是架構師直接互動的最低層級
- 架構師應避免過度微管理——class 和 function 的設計應交由 tech leads 和開發者負責
- 識別元件是新專案的首要任務之一
Architecture Partitioning(架構分區)#
架構師建立元件時的分區方式有兩種主要策略:

Figure 8.3: Two types of top-level architecture partitioning: layered and modular
Technical Partitioning(技術分區)#
依技術能力組織元件:Presentation、Business Rules、Service、Persistence 等。
優點:
- 清楚分離自訂程式碼
- 與分層架構模式緊密對齊
- 組織原則為 separation of technical concerns(技術關注點分離)
缺點:
- 全域耦合度較高——Common 或 Local 元件的變更可能影響所有其他元件
- 開發者可能需要在 common 和 local 層重複 domain 概念
- 資料層級的耦合通常較高,日後遷移至分散式架構較困難
Domain Partitioning(領域分區)#
受 Domain-Driven Design 啟發,依業務領域或 workflow 組織元件。
優點:
- 更貼近業務功能的建模方式
- 便於運用 Inverse Conway Maneuver 建立跨功能團隊
- 與 modular monolith 和 microservices 架構風格更加對齊
- 訊息流符合問題領域
- 易於遷移資料和元件至分散式架構
缺點:
- 自訂程式碼可能出現在多個地方

Figure 8.5: Where domains/workflows appear in technical- and domain-partitioned architectures
業界近年明顯趨向 domain partitioning,尤其是在 monolithic 和 distributed 架構中。但兩種方式各有取捨——請回想軟體架構第一法則:一切都是 trade-off。

Figure 8.6: A domain-partitioned design for Silicon Sandwiches

Figure 8.7: A technically partitioned design for Silicon Sandwiches
Conway’s Law#
設計系統的組織…其產出的設計會複製該組織的溝通結構。
技術分區傾向讓同類技術人員集中(後端一組、DBA 一組、前端一組),而 domain partitioning 則鼓勵跨功能團隊。Inverse Conway Maneuver 建議同時演進團隊與組織結構,以促進理想的架構。
Developer Role(開發者角色)#
- 開發者將架構師設計的元件進一步細分為 classes、functions 或 subcomponents
- Class 和 function 設計是架構師、tech leads 和開發者的共同責任,但以開發者為主
- 開發者不應將架構師的初始設計視為定論,而應視為初稿,在實作過程中持續迭代和精煉
Component Identification Flow(元件識別流程)#
元件識別是一個迭代過程,包含以下步驟的循環:
- Identify Initial Components(識別初始元件):根據 top-level partitioning 類型決定初始元件,再將領域功能對應上去
- Assign Requirements to Components(將需求指派給元件):對齊需求或 user stories,可能需要建立新元件、合併或拆分現有元件
- Analyze Roles and Responsibilities(分析角色和職責):確保粒度與角色、行為匹配
- Analyze Architecture Characteristics(分析架構特性):考慮架構特性如何影響元件劃分和粒度
- Restructure Components(重組元件):基於回饋持續迭代改進
從初始元件集合一步到位達成良好設計的機率極低。迭代是關鍵——設計軟體充滿未知問題,持續回饋和重組才能趨近最佳設計。

Figure 8.8: Component identification cycle
Component Granularity(元件粒度)#
找到元件的適當粒度是架構師最困難的任務之一:
- 粒度太細:元件間通訊過多
- 粒度太粗:內部耦合過高,導致 deployability、testability 和模組化問題
Component Design(元件設計)#
沒有「正確」的元件設計方法,存在多種技術,各有不同的 trade-offs。
Discovering Components(發現元件)#
Entity Trap(實體陷阱)#
一個常見的反模式:架構師為每個 entity 建立一個 Manager 元件(如 AuctionManager、ItemManager、BidManager),本質上只是資料庫的 object-relational mapping。
Entity trap 表示缺乏對應用程式實際 workflow 的思考。這種設計產生的元件粒度過粗,對開發團隊在程式碼結構和打包方面毫無指導意義。若系統只需簡單的 CRUD 操作,使用 Naked Objects 等框架即可,不需要完整架構。

Figure 8.9: Building an architecture as an object-relational mapping (Entity Trap)
Actor/Actions Approach(角色/行為方法)#
- 最初由 Rational Unified Process 定義
- 識別系統的 actors(角色)和其可執行的 actions(行為)
- 適用於所有類型的系統,單體或分散式皆可
- 在需求明確定義角色和行為時特別有效
Event Storming#
- 源自 Domain-Driven Design (DDD),與 microservices 相輔相成
- 架構師假設系統使用 messages/events 進行通訊
- 團隊確定系統中會發生哪些事件,基於需求和角色建構元件
- 特別適合使用事件和訊息的分散式架構
Workflow Approach(工作流方法)#
- 更通用的替代方案,不要求使用 DDD 或 messaging
- 圍繞 workflows 建模元件
- 識別關鍵角色、角色參與的 workflows,圍繞活動建構元件
以上技術沒有優劣之分,各有不同的 trade-offs。使用 waterfall 流程的團隊可能偏好 Actor/Actions;使用 DDD 和 microservices 的團隊則適合 event storming。
案例研究:Going, Going, Gone 的元件發現#
使用 Actor/Actions 方法分析 GGG 系統:
角色與行為#
- Bidder(競標者):觀看即時影像串流、觀看即時出價串流、下標
- Auctioneer(拍賣師):輸入現場出價、接收線上出價、標記商品售出
- System(系統):啟動拍賣、處理付款、追蹤競標者活動
識別出的元件#
- VideoStreamer:向使用者串流即時拍賣影像
- BidStreamer:即時串流出價資訊(與 VideoStreamer 共同提供唯讀檢視)
- BidCapture:擷取競標者和拍賣師的出價
- BidTracker:追蹤出價並作為記錄系統
- AuctionSession:啟動/停止拍賣、處理付款與結算
- Payment:第三方信用卡付款處理

Figure 8.10: Initial set of components for Going, Going, Gone
依架構特性調整#
分析架構特性後,架構師決定將 BidCapture 拆分為:
- Bid Capture:處理線上競標者出價(需高 scalability、elasticity)
- Auctioneer Capture:處理拍賣師出價(需高 reliability、availability)
拆分原因:拍賣師和線上競標者對 scalability、reliability、availability 的需求截然不同。

Figure 8.11: Incorporating architecture characteristics into GGG component design
Architecture Quantum Redux:Monolithic vs. Distributed#
Architecture quantum 定義了架構特性的範圍,進而引導架構師做出一個重要決策:架構應該是單體還是分散式?
- Monolithic(單體):單一可部署單元,所有功能在同一 process 運行,連接單一資料庫。包含 layered monolith 和 modular monolith。
- Distributed(分散式):應用程式由多個服務組成,各自運行在獨立的 ecosystem 中,透過網路協定通訊。
決策依據#
- 若系統只需單一 quantum(一組架構特性),monolithic 架構即可滿足需求
- 若不同部分需要不同的架構特性(如 GGG 案例),則需要 distributed 架構來容納差異
能在設計流程早期透過 architecture quantum 分析來判斷 monolithic vs. distributed 的基本設計特性,是使用 quantum 分析架構特性範圍和耦合度的重要優勢之一。