Building Evolutionary Architectures : Support Constant Change 心得歸納5
作法
- 透過以下三個步驟建立演進式架構
1.找出會被演進影響的維度
- 哪些架構維度是架構師想保護的,通常有資料設計、安全防護、可擴展性...等
- 必須考慮組織內的其他團隊,包含商務、運維、安全防護和其他受影響的
- 此時Inverse Conway Maneuver會很有幫助,鼓勵成立多職責團隊
2.定義各個維度的適應度函數
- 單一維度經常有多個適應度函數,例如架構師在部屬管道設置一堆程式碼指標
- 適應度函數可以是自動化的,也可以是人工的
3.使用部屬管道將適應度函數自動化
- 於部署管道定義各種階段來套件適應度函數,並管理部署作法如機器供應、測試、和其他DevOps關注點
- 漸進變更是演進式架構的引擎
- 週期時間對漸進變更來說非常重要,週期時間長則專案交付新世代的速度下降,進而影響可演進性
- 也要注意許多適應度函數在架構的壓力點出現之前不會顯露
全新專案(也就是綠地專案或稱為Green Field)
- 容易找出和規劃適應度函數,且沒有既有專案的耦合點顧慮
改造既有的架構(棕地專案Brown Field)
- 在既有專案加入可演進性要考慮三元素 →
- 1.元件耦合
- 2.工程實踐法的成熟度
- 3.開發人員是否容易建立適應度函數
適度的耦合與內聚
- 元件耦合在很大程度上決定了技術架構的可演進性
- 然而如果資料schema是僵化的,既使採取最好的可演進技術架構也註定失敗
- 架構師還必須考慮並維護系統元件的功能內聚
- 元件的大小應符合問題的背景
- 例如重度執行交易的系統,當試著建立與這種問題背道而馳、完全解偶的架構都是白費心力
- i.e.
先了解商務問題,再選擇架構
我個人認為還要加上....
先了解商務問題並考量未來規劃,再選擇架構
工程實踐法
- 不採取持續交付,幾乎不可能做出演進式架構
- 建立演進式架構的最大障礙就是困難的運維工作,如果開發人員無法輕鬆地部署變更,那麼回饋周期的每一個部分都會受到阻礙
適應度函數
- 鼓勵架構師將各式各樣的架構驗證機制當成適應度函數
- 如服務層級的可擴展性協議,安全需求規則及其驗證機制
- 將架構驗證當成適應度函數並定義在自動化內時取得更高一致性
重構 vs. 重組
- Martin Flower的定義,重構是重新架構既有的電腦程式,但不改變它的外部行為的程序
- 團隊幾乎不會對架構進行重構,但他們會重組它,實質性地改變它的結構行為
- 架構麼試之所以存在,在一定程度上是為了某些架構特性變成app的主要特性
- 切換模式會切換優先順序,所以這不是重構
使用COST(Commercial Off The Shelf)的影響
- 大公司普遍會採用這類程式包軟體,但是這類產品會對建立可演進系統帶來挑戰,因為它們普遍沒有支援演進
- 漸進變更:多數缺乏產業標準的自動化與測試,只能隔離整合點形成一個黑盒子
- 適度耦合:通常系統不夠透明,不具有足夠彈性來完成工作,只能透過定義號的API協作(後面有相關的"反模式:最後10%陷阱")
- 適應度函數:因為不夠透明,難以添加適應度函數,最後只能靠整合測試,粒度很粗,甚至有不透明的資料庫生態系統
轉換架構
- 許多架構師被高度可演進的微服務架構吸引,將他當成轉換的目標,但是這種轉換往往非常困難,主要原因是有耦合存在
- 架構師往往無法倖免於"mete-work 比一班工作有趣"症候群,因而選擇時髦但不合適的架構風格,比如微服務
轉換步驟
- 架構師必須考慮耦合和內聚,找到適當平衡
- 如微服務有一項嚴格限制是堅持資料庫必須位於服務的有界背景之內
- (上面這句透過社群補充為服務對應單一資料庫,i.e.服務對應的資料不允許其他服務執行查詢以外的事項,以避免服務與資料的關係脫鉤)
- 在重構架構時,必須考慮所有受影響的維度
演進式架構建立指南
- 通常公司不喜歡講有效的東西除役,這更是讓整合架構難以升級
- 在既有的架構加入可演進性是一項挑戰
移除沒必要的可變性
- 現代DevOps用不可變的基礎設施(immutable infrastructure)取代雪花(snowflake)局部地解決了動態均衡問題
- 不可變的基礎設施指的是完全用程式定義的系統
- DevOps在運維忠引入聲明式(declarative)概念
- 在現代DevOps環境中,不採取自動化的方式將重要軟體部署到伺服器也是魯莽的行為
讓決策是可逆轉的
- 積極演進的系統必定會以意想不到方式故障,當發生故障時,開發者應設計新的適應度函數防止再度發生,但是該如何從失敗中恢復呢?
- 許多DevOps實踐法都允許進行可逆決策,也就是可撤銷的決策
- 例如藍/綠部署
- 開發人員經常使用功能開關來做出可逆決策,將它們釋出給一小部分用戶(稱為金絲雀部署)
建立防損毀層
- 當專案與某個外部程式庫"連線"太多時,就是抽象干擾反模式
- 敏捷架構師在做決策時,很重視最後責任時刻原則(Last Responsible Moment),用這個原則來對抗專案過早接受複雜性的風險
- 例如訊息佇列是常見的純統架構方案,團隊討論要不要加架構中加入開放原始碼佇列(open source queue)常陷入一個態度"既然最後一定會用一個訊息佇列處理很多東西,不妨現在就盡心規劃最喜歡的訊息佇列種類,之後再改善它",然後就產生技術債務,太早地引入複雜性,無意間背負技術債務
- (我個人覺得這呼應DevOps原則,因應複雜流程而引入複雜工具絕對是下下策,不如開頭就先梳理流程)
- 在上述情況較好的做法是,引入剛好就夠用的,並且將來可以視需求輕鬆地變更的東西(形成防損毀層)
- 使用防損毀層可促進可演進性,雖然架構師無法預測未來,但至少可以降低變更成本
案例:服務模板
- 服務模板是確保一致性的解決方案.它們是預先設置的公用基礎程式庫,例如服務發現、監視、log、數據、身分驗證/授權等
- 大型組織會成立共享基礎設施團隊來管理服務模板
- 是可以被認同的適度耦合
- 當開發者建立分層架構時,在每一層裡面進行更改都會變得容易,但是跨層的更改會遇到高度耦合
建立犧牲架構
- Twitter發布時是Ruby on Rails編寫,才能搶佔先市
- 但是後續無法應付日漸龐大的規模而重構(RoR被犧牲)
- 現在雲端環境讓犧牲架構更具吸引力
降低外部變更的影響
- 每一種開發平台都有外部依賴項目(工具,框架,程式庫等)
- 對演進式架構而言,管理這些不外的零件至關重要
- 外部程式庫會同時帶來好處和代價
- 如果上游需要的依賴項目突然消失,你應該拒絕那個變更!
- (如同我之前看到uncle bob演講說的,Framework作者愛著他們所做的Framework,但我們不需要!)
優先採取持續交付,而非快照
- 開發者之所以使用快照,是因為過去以來,都假設測試是困難費時的
- 因此開發者試圖將"會變動的內容"與"不會變動的內容"分開
- 在演進式架構中,我們預期所有的事情都不斷變化,並建立工程實務法和適應度函數來適應變化
- 例如當專案有良好的測試覆蓋率和部署管道時,開發者可透過自動化部署管道測試每一項變更
- 開發者沒有理由為專案的每個零件保留一個"特殊的"存放區
- 持續交付提出一種更微妙的方式來看待依賴關係,目前開發者只透過版本號碼來連接靜態依賴關係,但是對現代專案來說,這種做法是不足的,現代專案需要可代表臆測性(speculative)更新的機制(這段尚無比較好理解的解釋,待解)
其實整篇就是針對建立可演進式架構的純理論
在建置前可以事先考慮的範圍,先一步規劃
像是可以減少使用package等,擴展性極低,像是以前碰過的ESB等
以及延遲決策
而不是如金融業遵循總經理交辦要求本週上線等方式
還有怎樣的架構建立方式會比較容易地演進的一些方法論
有些真的在過往經驗上考慮不足的供未來參考