木沉 阿里技術
首次上線應用,面對業務框架搭建你是否曾感到無從下手?維護線上應用,面對大量歷史包袱你是否正避坑不及深陷泥潭?為何同樣是業務應用,不同人的設計風格千差萬別?為何最初的設計經過多個迭代後總是面目全非?新人來到團隊,怎樣才能快速瞭解業務,不被大量技術細節折磨?如果你也有這些困擾,希望本文能提供些許幫助。
一 初衷
1 細節割裂架構
業界的成熟應用框架有很多。無論是SpringMVC/SpringBoot還是SofaBoot,都對工程結構給出了明確的規範約定,職責邊界看似非常清晰。但在實踐中,再簡單的業務應用都避免不了業務邏輯分散各處,打破module邊界出現隱式耦合的現象。分散的業務細節必然導致應用架構的割裂,如果沒有持續的重構調整,最終總會變得複雜臃腫(當然,是持續有新需求的前提下),老人沉默新人流淚,只能依靠天降猛男重做2.0。究其原因,個人認為主要在於:
框架靈活性過高:應用框架給出的是工程規範,而非業務設計規範,為開發者保留了非常大的靈活性,一個業務功能可以有很多種實現方式。 架構約束力不足:業務架構的搭建和維護是在不同時段由不同人分別投入的結果,設計思維的不同,自我要求的不同,專案進度壓力的不同,都會對應用的現狀產生影響。若以法律和道德的關係做類比,通用框架約束了技術編碼的“法律”底線,而設計原則就是開發人員對自身的“道德”要求。在簡單的業務場景下,滿足需求是第一優先順序,設計能力的訴求並不突出。但在多方協作的業務團隊下(真實情況大多如此),沒有統一的“道德標準”,將很難形成合力完成複雜專案。《Java開發手冊》(阿里巴巴Java開發規約)在推進編碼標準的道路上邁出了很大一步,極大提升了工程人員的專業素質,大大提高了“道德共識”。那麼在業務架構設計的領域裡,是否至少能在某個問題域內,也建立一套面向業務研發同學的“設計規約”。
2 技術沉澱流失
另一方面,進入阿里巴巴後,自身研發經歷雖然並不多,但接觸過不少優秀設計。這些產出無論是否最優方案,都體現出了技術同學對優秀設計的美好願望和強大落地能力,也確實在一定的歷史時期內高效地保障了業務發展。然而,令我困惑的是,儘管每個業務專案和業務產品都能沉澱出一些可複用的元件或框架,參與研發的同學也能總結出一套面向未來需求的設計原則和實踐經驗,但這些財富始終難以維護和傳承。可能的原因有(對前端/測試/資料/平臺等研發經歷不太瞭解,這裡僅針對一線業務研發):
堅持設計成果而非設計原則:有成功經驗的研發同學,傾向於用曾經的架構設計來套用當下的業務場景。這種思路本身沒有對錯,但如果釘不配錘,往往會在短期內引入大量額外成本,反倒喪失了原本的設計優勢。面對具體問題域,只有堅持一貫的設計原則,在需求分析的過程中結合諸多因素進行動態權衡,才能打造真正符合當下和未來需求的設計。 喜歡造新輪子而非持續重構:研發同學的設計原則和程式碼潔癖可能是一種“玄學”,對前人程式碼的不待見倒是更具確定性的常態,其實這不難理解。即使都是DDD流派,方案溝通時也未必互相認可;即使經過讓步對架構設計達成一致,編碼實現的風格也是各領風騷。理解前人的設計思路和程式碼癖好更重要,還是按時完成業務需求更重要?按自己擅長的設計風格重寫更簡單,還是在他人的“過時”設計上持續重構最佳化更簡單?靠文件傳承而非工具化複用:對新人來說,文件裡的再多建議和快速上手指南,都比不上一個開箱即用的工程DEMO;在成熟應用上持續開發的人,不會因為歷史文件上大寫的注意事項就抵抗住臨時程式碼換取早點下班的現實誘惑,除非應用工程中有編譯/部署失敗的強制約束讓你不得不放棄。相比於缺少“設計規約”導致的低效協作,已經沉澱的“規約原型”被輕易拋棄更加令人可惜。業務研發的日常工作,本質上是拆解問題域的複雜性,用分層解耦/工具化/平臺化/業務抽象的多種思路將子問題逐個擊破。如果部分子問題已被很好解決,為何不站在前人肩上?放棄造不造新“輪子”的糾結心態吧,或許我們更需要搭“積木”的心態。
二 思路:業務架構設計規約
標準:統一業務設計框架,用標準化架構簡化技術細節沉澱:從業務場景中持續沉澱“積木”重構:持續重構“積木”,減少重複建設整合:基於業務服務編排引擎快速整合1 標準——減少細節
理想情況下,業務技術只需關注領域建模,但現實中卻不得不考慮更多通用的技術細節。以供應鏈金融場景下簡化版的應收賬款發行流程為例,需要考慮的有:
領域建模:應收賬款領域模型及其行為的設計流程編排:流程模型的設計及發行流程的狀態機設計資料轉換:領域模型<->資料模型及流程模型<->資料模型的雙向轉換併發控制:業務鎖機制的設計業務冪等:流程中各業務環節的冪等控制異常處理:異常捕捉,錯誤碼約定監控報警:摘要日誌,異常日誌,邊界日誌其他在以上未完全列舉的幾項中,除了“領域建模”以外,基本都是與具體業務無關,但對於一個穩定可靠的業務應用不可缺失的部分。如果能建立一套標準化的框架方案,用統一的規範解決掉業務無關的大量細節,是否就能讓業務技術同學真正的專注於“領域建模”?
2 沉澱——能力複用
沉澱和複用是技術群最常出圈的幾個詞,可見認同度之高。能力複用不侷限於形式和粒度,能夠切實降低技術成本,提高業務擴充套件性,就是不錯的沉澱,可作為“積木”供後續使用。以螞蟻鏈應用技術團隊場景為例,近年來沉澱的能力包括但不侷限於:
技術類
工程規範系列:約束編碼規範和邊界介面定義風格,日誌列印,異常處理,倉儲行為,狀態機等等讀寫分離機制:遮蔽交易類需求與查詢類需求對資料模型的設計衝突,降低設計複雜性,提升查詢效能和靈活性業務類
網銀核身:提高網銀核身簽名在不同業務流程中的擴充套件性合約上鍊:提高智慧合約對接在不同業務流程中的擴充套件性平臺類
配置中心:靈活定義和管理業務流程需要的各類配置項產品中心:平臺功能打包和隔離,實現業務流程的全域性檢視3 重構——持續最佳化
沉澱來源於業務需求,卻常常落後於新需求。對於設計者以外的人來說,維護他人的“積木”常常會踩到不少坑,反倒不如自己重寫。這也是為何每個團隊都在說沉澱,但能夠橫向複用,甚至在同一個團隊內持續複用的能力都少之又少。雖然這個現象沒有完美解法,但個人建議採取以積極的心態看待這些“積木”:
分析歷史背景,瞭解“積木”出現的技術和業務背景明確該能力能夠解決的問題,和不適用的場景分析當下業務需求,是否可以重構該能力後直接複用與創作者溝通,評估重構落地方案這裡沒有強調重構複用和重寫這兩種方案的ROI對比,是因為個人看來,即使前者成本更高,重構的過程對個人技術成長和團隊文化統一都是有利的。相對於不斷推翻和發明新“積木”,持續最佳化的過程,是對自己和他人經驗的不斷回顧和反思,看清歷史的坑,才能避免新風險的出現。
4 整合——靈活搭建
標準能夠落地,除了有足夠趁手的“積木”庫外,更重要的一點,是要有靈活便捷的“粘合劑”,以完成業務功能的快速搭建和靈活調整。在供應鏈金融的場景下,業務需求主要體現為各種各樣的業務流程,比如發行/轉讓/清分等等。為了簡化“積木”搭建,靈活複用底層能力,我們基於以下目標,設計了面向業務的服務編排引擎:
標準化:遵循設計規約,將業務無關的通用技術細節遮蔽外掛化:對“積木”友好,可持續沉澱和複用新能力業務化:面向業務,有業務描述能力的流程編排配置化:透過配置即可完成流程編排,最好能做到視覺化配置5 產品——業務大圖
“積木”+“粘合”能夠滿足技術落地的低成本高擴充套件,但從業務視角,還需要一個全域性大圖來描繪業務線的全域能力和功能流程。本文中暫不涉及。
三 實踐:業務架構標準方案
如前所說,只靠文件形成的共識,對技術沒有足夠的約束,極難維持。因此,我們基於上述規約的各項原則,搭建了一套標準化的業務架構設計方案,透過元件化工具化的方式約束業務應用,形成團隊共識。一個標準的業務應用架構如下:
1 元件——規範技術細節
透過元件化約定,約束通用技術細節的行為,包括但不侷限於:
交易模型
描述業務流程的核心交易模型,用於管控狀態推進,維持與業務模型的關聯。
倉儲行為
資料持久層的通用行為,包括鎖定查詢/插入/更新/普通查詢等。
事務模板
定義事務邊界,確保模版內業務邏輯的事務一致性;支援冪等能力。
通用業務模板
定義業務邏輯邊界,無事務性保障,但包含了異常處理/日誌埋點等通用能力。
通用查詢模板
定義查詢邏輯邊界,與通用業務模板類似,但主要面向單項/批次/分頁等查詢場景。
訊息
對訊息中介軟體的簡單封裝,適配業務應用規約,降低配置成本。
排程
對排程中介軟體的簡單封裝,適配業務應用規約,降低配置成本。
服務開放
api元件規範對外服務能力,透過註解識別服務定義和服務實現,自動生成介面文件,描述介面引數/返回/業務域/錯誤碼等等。
其他——日誌/異常處理/請求引數/返回型別
這裡不做展開。
以上是所有業務應用都會遇到的技術細節,用元件遮蔽細節的思路也沒有複雜之處,我們想要表達的重點是:儘可能沉澱和複用技術元件,儘可能使用他人的成果,不要重複搭建,把重心放到業務上!
2 領域——專注業務建模
再次強調,對業務技術來說,業務建模是核心,業務建模是核心,業務建模是核心!本文的初衷和方案都是為了讓開發解放出來,直面核心業務的設計和思考。本小節僅給出領域產出的基本要求,後續在【案例分析】再做詳述。
領域實體
建模的核心是抽象出領域實體及其關聯關係,不同的業務場景和設計思路,會有很大差異,最終會體現為一到多個領域模型。需要明確在不同業務流程下,各交易模型內需要包含的領域模型(比較抽象,後續在【案例分析】再做詳述)。
領域倉儲
定義資料模型,及其與領域模型的對應關係(各種converter)。基於上文提到的倉儲元件,配置資料庫表和連線,實現鎖定查詢/插入/更新/普通查詢等業務行為。
領域服務
基於業務行為,抽象出原子化的領域服務能力。該服務無需關注資料倉儲,無需關注業務流程,僅抽象出領域實體的原生能力。以上文中提到的應收賬款模型為例,至少需要包含:
應收賬款的建立應收賬款的拆分/流轉應收賬款的銷燬等等基本行為。
交易實體
用於承載交易流程的業務實體,上文中交易模型的業務例項,內部關聯一到多個領域實體。
交易倉儲
用於管控交易實體以及內部各領域實體的倉儲行為。
3 服務編排引擎 —— 積木+粘合
但凡涉及複雜業務流程的應用,都需要引入流程引擎來編排狀態機的流轉。業界有很多成熟的流程引擎框架,也有很多足夠可用的簡化版本。但如前文所說,這類通用引擎的優點也是其最大的弱點:過強的靈活性無法對設計風格形成約束,大量業務細節會分散在不同狀態節點間,不直觀也難維護。從自身需求出發,我們設計了面向業務的服務編排引擎,以遵循業務設計規約的方式約束技術,以直觀的形式描述業務流程。與傳統流程引擎相比,其業務友好性主要體現在:
約束業務模型:需明確指定業務交易模型/狀態及倉儲定義,遵循業務設計規範託管倉儲行為:只需配置業務模型及倉儲實現,無需再關注資料持久化的時機和細節編排領域服務:透過轉接層,將領域服務開放到引擎中自由編排。領域的原子能力是引擎編排的最小執行單位靈活增減狀態:流程中的狀態遷轉和業務行為均可被靈活插拔支援“積木”擴充套件:將可複用的領域服務組合打包,形成固定模式,作為“積木”在其他流程中重複使用總的來說,服務編排引擎基於通用元件遮蔽技術細節,重點專注於業務行為的編排和複用,對“積木”進行“粘合”,以編排出符合業務需求的業務流程。
四 總結
本文從業務技術團隊的現實痛點出發,嘗試以業務架構設計規約(理論標準)結合業務架構標準方案(工程約束)的思路統一團隊的技術風格,將技術同學從細節中釋放出來,專注於技術能力的積累和對業務價值的思考。希望傳達的想法有:
用標準約束技術細節:降低業務設計的靈活性,也是為了減少成本用技術工具而非文件推行標準:持續沉澱的元件,勝過沒有約束力的文件持續重構而非造新輪子:正視自己和他人曾經的產出,持續改進能帶來成長重視業務建模:好好思考業務和行業吧,用DDD武裝自己,提升建模思維和能力