2023 年 6 月,Chris Richardson 拜訪羅馬萬神殿(Pantheon,約建於西元 126 年):一座近 1900 年仍持續使用、保存最完整的羅馬古蹟之一,如今同時是教堂與觀光景點。軟體應用卻不像實體建築——即使需求永遠不變,也必須持續更新技術棧,彷彿昨天的建材今天突然停止運作。
可演化性(Evolvability) 反映「升級應用技術棧的容易程度」。它在某種意義上是可修改性的特例,但有獨特之處:
- 技術棧升級往往是橫切性(cross-cutting)的變更,影響範圍可能極大。
- 例如升級一個被多個子領域使用的函式庫,會牽動所有子領域的團隊。
- 還有計畫外的升級,例如新發現的安全漏洞需要立即升級。
- 升級的驅動力通常來自客戶需求以外的因素(供應商支援、市場演進、安全)。
認識技術棧#
應用的技術棧(technology stack)是用來建構與執行應用的所有技術的集合,主要分為:
- 應用技術:函式庫、框架、程式語言執行時(runtime)。
- 基礎設施服務:資料庫、message broker 等。
- 開發工具:測試框架(JUnit)、建置工具(Gradle)、CI/CD 工作流(GitHub Actions)等。
- 部署環境:雲端基礎設施(AWS/Azure)、容器技術(Docker、Kubernetes)、雲端服務(包括基礎設施服務與 logging/monitoring 等可觀測性工具)。
幾乎所有元素都有版本(例如以 semantic versioning 表示),所以技術棧本質上是一組「技術 + 版本」;同一種技術可能同時存在多個版本。

Figure 5.8: An application's technology stack — libraries, frameworks, languages, infrastructure, deployment environments
元件 vs 技術棧#
複雜應用通常擁有多個技術棧:
- 每個元件可有自己的私有技術棧:函式庫、框架、語言執行時、私有的基礎設施服務、特定的開發工具。
- 也可有跨元件共用的技術棧:例如共用的 message broker、開發工具、部署基礎設施等。
範例:
- Customer Service 用 Java 22 + Spring Boot 3.5.3 + Postgres(新標準)。
- Order Service 用 Java 17 + Spring Boot 3.1.2 + MySQL,額外用 Redis 做快取。
- 兩者皆共用 Apache Kafka。
微服務的關鍵效益之一,正是讓每個元件可使用不同(版本的)技術。
技術之間的三種關係#
- Requires:某技術(版本)需要另一個技術(版本)。例如 Spring Boot 3.x 需要 Java 17。
- Excludes:選擇某技術可能就排除了其替代品。例如同一元件只能有單一語言執行時、單一應用框架;classpath 也只能容納單一版本的函式庫。
- Provides:某技術提供另一技術的特定版本。例如雲端供應商以 IaaS/PaaS 形式提供基礎服務,但可能只支援特定版本(甚至不是最新),日後也可能下架舊版本。

Figure 5.9: Three types of relationships between technologies — requires, excludes, provides
因為這些關係,組裝技術棧像在拼拼圖:Java 元件常有上百個傳遞依賴,你得找到一組彼此相容的版本——Maven 傳遞依賴尤其棘手。這個問題不只發生在 Java——例如 Kubernetes 升級可能會被某個 Terraform provider 卡住,因為它仍要求舊版。
技術會持續演化#
每個技術都遵循生命週期:
- 引入(Introduction):早期採用者與遠見者使用。
- 廣泛使用(Widely used):主流或某利基使用。
- 淘汰(Phased out):完全消失,或淪為僅有少數使用者的「殭屍技術」。

Figure 5.10: Over time, technologies and technology versions come and go (introduction → widely used → phased out)
技術版本也有類似但更短的生命週期(Java 每 6 個月一個版本,各版本只獲得有限期間的廠商支援)。
對齊「組織重要度」與「市場重要度」#
一個技術在市場上的重要度,決定了支援、修補、學習資源、人才供給的可得性。
組織內部對某技術的重要度,應該與其在市場上的重要度對齊;不對齊就是風險。
兩種風險:
- 使用已被淘汰或不再受廠商支援的技術。
- 沒有採用已成為主流、已被良好支援的技術。

Figure 5.11: A technology's importance in your organization should align with its importance in the market
必須持續升級#
至少需要做到:
- 持續升級函式庫、框架版本。
- 升級語言執行時、基礎設施服務、部署環境。
- 定期評估是否該替換成新一代技術。
升級工作量差異極大:
- 微小:完全向後相容的小版本升級。
- 中等:Spring Boot 2 → 3,需要連同 Java 17、Jakarta EE 9,把所有
import javax.改成import jakarta.,瑣碎但量大。 - 巨量:整個語言或框架的更換。Python 2 在 2020 年 EOL 後,組織不得不遷移到 Python 3,部分仰賴遷移工具,但若依賴的函式庫尚未支援 Python 3,就要等待或設法移除依賴。
漏洞需要立即行動:2021 年 Log4j 漏洞(CVE-2021-44228)允許遠端程式執行,全球組織被迫立即升級。這類事件無法預期,只能仰賴「平時就有快速升級能力」。
採用新技術需要可控的實驗#
升級函式庫小版本風險低,採用全新技術風險高——LinkedIn 上對某技術的吹捧無法替代你的實際驗證。
採用 Rust 的三種選項:
- 寫幾個玩具應用:不夠真實,沒有上線經驗。
- 花一年打造複雜應用上線:真實但風險巨大,可能花了 6 人年才發現自己更喜歡有 GC 的語言。
- 用 Rust 實作並部署一個子領域:真實且風險低,只需投入幾個人月。
第三種選項幾乎永遠是最佳選擇——這也是多元件架構在「實驗新技術」上能帶來的具體好處。
可演化性的場景#
四種典型的技術棧升級:
- 為了實作功能,團隊主動升級。
- 為了與市場對齊,定期升級。
- 漏洞修補,沒得商量,必須快。
- 為了評估新技術,做低成本但真實的實驗。
第 1、2 種升級若會造成多個團隊的工作堆積,組織可能會遲遲不做。第 4 種需要特定架構支援。
通用要求:
- 團隊能升級自家子領域所用的技術棧元素,不必經常與其他團隊協調。
- 組織能快速、輕鬆地把函式庫升到受支援版本。
- 組織能快速、輕鬆地修補含漏洞的函式庫。
- 升級工作能漸進式分批進行。
- 團隊能進行低成本但真實的新技術實驗。
具體場景:
- Orders team 想升級 Order Management 用的某函式庫,不需與其他團隊協調。
- 安全團隊收到 0-day 漏洞通報,需升級函式庫(無程式碼變更),一天內完成測試與部署——隱含著對可測試性與可部署性的要求。
- 全應用範圍的函式庫升級,可逐團隊進行,每個團隊改、測、部各自子領域。
- Oracle → Postgres 遷移,各團隊把自家子領域改用 Postgres,僅需與營運(管理資料庫基礎設施)協調。
- 某團隊想評估 Rust:用 Rust 實作或重寫一個子領域,部署上線評估,整體成本控制在幾個人月。
設計高可演化性的架構#
對「由多團隊開發的大型應用」而言,高可演化性需要多元件架構(multi-component architecture)。
多元件架構的好處:
- 限縮多數技術棧升級的影響範圍:私有技術棧的升級只影響該元件。
- 降低漏洞影響:若漏洞函式庫只被部分元件使用,只需升級這些元件。
- 拆解大型升級:框架或語言升級可被切成「每個元件各自升級」的小任務,可與其他 flow item 交錯進行。
- 支援低成本、真實的技術實驗:用候選技術實作一個子領域,部署為獨立服務即可。

Figure 5.12: A multi-component architecture significantly improves an application's evolvability
多元件架構的代價#
同樣的升級,有時要對每個元件做一遍——例如 Spring framework 小版本升級。
緩解做法:
- 寫腳本自動化跨 Git repo 的變更。
- Microservice Chassis 模式(第 17 章):集中化建置邏輯、共通基礎設施程式碼與依賴版本管理,讓某些升級簡化為改一處即可。