🎯 什麼情境該想到我

當你「現在的架構開始拖慢每一次改動,但你不確定該不該動它」的時候。

⚙️ 怎麼用(步驟 / 公式)

意圖:讓架構隨組織當下的需求演進,用可以隨時停下的漸進手段換掉緊耦合的部分,而不是賭一次性大改寫。

第一步:先破除「單體=壞」的迷思

  • 書中寫得很明白:單體架構本身並不天生是壞的——事實上,它常常是組織在產品生命週期早期的最佳選擇。(L7107–7108)
  • Randy Shoup 的判準:沒有一種架構對所有產品、所有規模都完美;任何架構都只是滿足某一組目標或需求與限制(上市時間、開發功能的容易度、擴展性等)。產品功能幾乎必然隨時間演進,架構需求當然也會跟著變。(L7109–7114)
  • 支撐新創的單體架構(快速原型、可能大幅轉向策略),和「要支撐數百個團隊、每個團隊都要能獨立交付價值給客戶」的架構,本來就是不同的東西。(L7120–7128)
  • 被單體拖累但成功重新架構的公司:eBay 的 C++ 單體(2001)、Amazon 的 OBIDOS 單體(2001)、Twitter 的 Rails 前端單體(2009)、LinkedIn 的 Leo 單體(2011)。這些架構在幫他們達成 product/market fit 上極為成功,但在規模化時把他們推到組織失敗的邊緣;重新架構之後不只活下來,還在市場上贏了。(L7098–7105)

第二步:用絞殺者應用模式(strangler application)漸進推進(L7190–7249)

  • 名字由 Martin Fowler 在 2004 年造出,靈感來自澳洲的絞殺榕:種子在無花果樹的上層枝幹發芽,一路往下長到扎進土裡,多年後長成奇異美麗的形狀,同時勒死並殺掉寄主。
  • 核心操作:把既有功能放到一個 API 之後,讓它維持不變;用想要的新架構實作新功能,必要時回頭呼叫舊系統。
  • 所有服務都透過 versioned APIs 存取(也叫 versioned services 或 immutable services)。版本化讓我們可以改服務而不影響呼叫端——要改參數就開新的 API 版本,再把依賴的團隊遷過去。
  • 紅線:如果讓新的 strangler application 又和其他服務緊耦合(例如直接連到另一個服務的資料庫),就沒有達成重新架構的目標。
  • 被呼叫的服務若沒有乾淨定義的 API,就替它做一個,或至少把溝通的複雜度藏在一個有乾淨 API 的 client library 裡。
  • 反覆解耦下去,舊的遺留應用會逐漸縮小功能面,甚至可能在所有需要的功能都遷移完之後完全消失。
  • 反模式警告:不要只是把既有功能在新架構或新技術上「重做一遍」。既有系統的怪癖常讓業務流程遠比必要的更複雜,重做就會把這些怪癖一起複製過去。應該研究使用者,把流程重新設計成更簡單、更順暢的達成方式。Fowler 的佐證:關鍵系統的重寫「總是比看起來複雜得多、且滿是風險。大切換日逼近、壓力上來;新功能(永遠都有新功能)大家喜歡,但舊東西也得留著,連舊的 bug 往往都得加回重寫後的系統裡。」
  • 節奏:和任何轉型一樣,先追求 quick wins、交付早期的增量價值,再繼續迭代。用前期分析找出「用新架構就能有效達成某個業務成果的最小一塊工作」。

第三步:用資料判斷什麼時候該動手——Blackboard Learn 案例(2011,L7252–7297)

  • 背景:Blackboard 2011 年營收約 6.5 億美元;旗艦產品 Learn 是安裝在客戶端的套裝軟體,J2EE 程式碼庫可回溯到 1997 年,首席架構師 David Ashman 說「我們的程式碼庫裡到現在還嵌著 Perl 程式碼的碎片」。光是從整合流程拿到回饋就要 24 到 36 小時。
  • 關鍵證據:Ashman 從版控倉庫拉出回溯到 2005 年的兩張圖——上圖是單體倉庫的程式碼行數,下圖是程式碼 commit 數。問題浮現了:commit 數開始下降,而程式碼行數持續上升,客觀顯示引入程式碼變更正變得越來越困難。Ashman 說:「對我而言,這代表我們必須做點什麼,否則問題只會越來越糟,看不到盡頭。」
  • 結果:2012 年他推動用絞殺者模式重新架構,做出他們內部稱為 Building Blocks 的東西,讓開發者能在與單體程式碼庫解耦、透過固定 API 存取的獨立模組裡工作,不必再持續與其他開發團隊溝通協調。

原文:「What works at scale 1x rarely works at scale 10x or 100x.」(Randy Shoup,L7114)

原文:「Monolithic architectures are not inherently bad—in fact, they are often the best choice for an organization early in a product life cycle.」(L7107–7108)

原文:「we are not achieving our re-architecting goals if we allow our new strangler application to get tightly-coupled into other services (e.g., connecting directly to another service’s database).」(L7217–7219)

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 「架構讓人痛」不等於「該拆微服務」。先問現在是什麼規模、要滿足哪一組需求與限制;產品早期的單體常常就是正解。(L7107–7114)
  • 絞殺者要真的獨立才算數。新做的部分若直連別人的資料庫,等於換了地方繼續緊耦合,前功盡棄。
  • 不要把重寫當成絞殺者。重寫的風險是舊功能、甚至舊 bug 都得補回去,還要面對大切換日的壓力;絞殺者的價值正在於避開大切換。(L7231–7244)
  • Blackboard 的兩張圖是判斷方法,不是通用門檻——你要看的是「commit 數的趨勢是否與程式碼量脫鉤」,而不是抄它的數字。

🔗 相關工具