在第一次舉辦meetup後,社群的志工團隊開始逐漸招募成型,我們不斷的在想著怎麼樣可以讓這樣剛萌生的熱可以延續下去,從1/26到3月份我關注到一個狀況,每天都有不斷收到的加入社群的請求,這是一件鼓舞社群志工團隊的很重要的訊息,有人有興趣來探索與了解,都是將我們推進的動力。
不過,有一個不容易解決的困擾那就是社群成員的組成的多元性,不知道是大家謙虛還是什麼原因,加入社群的提問問題之一是 “您對DDD的認識程度,請自評1~5”
0 or 1 似乎是大家對此的公約數 ?
為了想要更全面的關注社群夥伴,在本次的議程安排上真的是想破頭了!
這次的議程包括了有
- DDD with Clean Architecture, Arthur Chang
- 團隊協作實戰DDD, Jed Lin
- Essential capabilities behind Microservices, Kim Kao
以下我分別對這些議程做些我在僅有的參與過程中的回顧,礙於篇幅關係若你對這些主題有興趣可以直接點閱簡報,並且找到DDD社群與大家交流。
Clean Architecture with DDD
DDD with clean architecture - Slides on Slideshare
作為社群發起人之一的Arthur 為了要更添加主題的討論層次,也盡量與當天講者們的話題不要完全重複,把主題定為成揉合Clean Architecture的DDD的探討,雖然在開場時他特別說到 :
我今天講的主題應該算是 Clen Architecture 101…
但就整體的內容廣度來說,我相信之後要安排(X)推坑(O)進行各種環節的系列深入話題交流應該也是沒問題的。
這次在Arthur的議程中談到了架構因子(架構因子來自於 溫昱 的一本書:一線架構師),喚醒你對做架構設計時可能需要去思考的諸多變因與影響來源,尤其在組織結構上的影響也多是如此,另外一個很重要的思考點是 :
維度
對於系統來說影響到一個軟件架構的維度有4:
- Component 的擴充考量
- Layer 的擴充考量
- 多個系統之間協作的擴充考量
- 基於時間變化的挑戰
時間,是一個驅動業務變革的主因,也同時經常因為如此導致不可逆的架構轉變,甚至產生了業務項目重點的”軸變”。某些企業可能會在經營主要業務之餘開始去嘗試其他的更多市場機會,一但在某個試點的項目中開始獲得成效而最終發現這個新項目成了這企業的救命符時,這時候對此企業來說他的核心關注價值重點,已經發生了商業價值上的軸轉,這時候果斷的企業主很可能就會思考把重點領域關注做出翻轉,進而獲取更重要的價值與經營。
團隊協作實戰DDD
團隊協作實戰DDD - Slides on Slideshare
另外要特別感謝 Jed Lin花了很多時間的準備,早在社群成立非常早的初期,我就不斷的打擾(O)邀請(X)他,務必請他能盡量抽出時間與大家分享在過去的工作中的實際開發經驗,而事實上 Jed 本人也表示 :
在受到邀請時就已經開始準備這主題了
在這個主題當中,Jed把軟體設計本身看待成解決業務問題與技術問題為起點,鼓勵大家更多的關注在業務本身,同時在面對領域模型捕捉的部分,揉入了 Impact Map以及 User story mapping的面向做引導,這手法你我不陌生,但是你可能過去沒有特別去思考過這方式,而今你可以試著想想或體驗她。Eric Evans在當初撰寫與推廣DDD的時候其實在運作手法上並沒有特別的陳述有哪些實作可行的方式,而現在你可去嘗試你任何可能可以達到團隊共創以及使用統一語言來達到交流與共同理解的方法,那麼它就是一個高效有意義的方法。
有了建模基礎之後,我們經常在過去的開發經驗中被要求提交系統分析規格書,或者系統設計規格書,尤其如果你是跟我一樣做了很多年的SI背景經驗的人,你很能理解撰寫這些 “一次性文件”代表的浪費與痛苦。
Jed在這次的議程中,也鼓勵大家多試著以 Specification by Example,搭配初步捕捉的領域模型概念進行代碼開發,進行邏輯驗證,團隊可以依此進行設計與調整,從而更多試著思考捕捉出來的各個子領域之間的關係確認。
Essential capabilities behind Microservices
這個主題是我近來非常喜歡的話題,可能也一部分跟現在工作環境有關,當接觸的人群多了,我發現很多人不管是什麼樣的角色(業務人員,銷售,技術團隊,廣告…)都對微服務有著熱血情懷,總會期望可以在這身上獲得些幫助。
這是一種投射作用,我們肯定能理解到技術幫助業務的相輔相成,但是在當你認真想踏入微服務的設計與實踐維運的路之前,可能或許聽聽我的這篇文章,能給你一些不同的觀點:
Essential Capabilities behind Microservices - Slides on Slideshare
簡報重點捕捉
企業對系統的期待是賺錢,儘管就你專業的技術優秀人才眼中來看,他是多麽的紊亂不堪,沒有統整性與可讀性,讓你要花上很多心力去理解你才能去真正的維運。
可是你一直想要把它給改成你眼中井然有序,易於變革與調整的微服務體系,其實從賺錢的角度來看你只是把它給擺整齊而已。
當然這樣說是有點太過,可是這是要提醒你如果你帶來的各種變革無法為你的企業帶來至少同等的價值(賺錢能力)或甚至更好的表現,那麼你還真的一定得需要這麼做嗎?
常見的面對將老系統轉型成微服務時的挑戰都列在上頭了,總是沒有人能對老舊系統的一切有所掌握有所認知,牽涉的關係人太過於龐大,如果我們是要走一個 “Big Ban”的變革,一次性的全面改變,那麼往往失敗率高過天際。
為了讓大家走入我心裡頭的世界,我再一次的與大家探討什麼是微服務?
那或許是個美好的青春(謊言)年代,當年Docker甫一推出搭配著 Chris Richardson的推廣,一開始有不少人直覺認為或許Docker 就是微服務的體現,而到了現在很有可能有人會跟你說 :
No ! Kubernetes才是微服務
但,真是如此嗎? 對於微服務的理解應當從其定義開始:
如果,你能夠獨自的處理好運算與存儲的的需要,並且不依賴於其他服務的能力,那麼你可以做到你應有的內聚”業務能力”。這段話我的理解是這樣,但是說的簡單做的難,我們看看如果一個典型的遺留系統要轉型可能會遇到的問題是哪些?
你一定經歷過這樣的會議室紛爭,到底該由誰或什麼方法來決定系統的劃分,不管你會經典的方法論從名詞開始捕捉,或者你是在場之中經驗老道的佈道師,可能還更好一點的是你們是個擁抱團隊共識的團隊。
但更多常見的狀況是你老闆說了算,你沒有太多的話語權,面對這樣的場景你是只能徒呼負負或者當一天和尚敲一天鐘的前進? 光是這第一步就會讓很多人卻步是否還要再思考微服務!
好不容易從各種挑戰中度過了初步概念的劃分之後,迎接而來的是現實世界的技術困難點,過去一體成型的老系統,要做身份驗證授權幾乎是session/cookie的天生戰場,你能通過已經非常成熟的應用技術來完成它。可是一但走到了原生的分散式系統的場域裡頭,這些大而全的一體式驗證授權已經沒辦法再用上,你需要自己重新建構一個非常高可用的驗證授權系統,或者仰賴第三方的服務,甚至直接使用雲服務供應商的應用,因為:
要搭建一個SLA要求非常高的系統,又是作為驗證授權的入口基礎應用,要花費的心力是非常驚人的!
再談服務的註冊與發現,從過去到現在我最喜歡或者說我受到最大影響的,無非是在 Java EE Pattern當中的 Service Locator pattern,當時因為有個JNDI可以充當服務的註冊與發現的集中管理點,很自然的就知道要在上頭去做各種搭建應用。
但是脫離了JNDI之後,還是有不少的作法與對應的優缺點,從Client sie的查找來說,不易於因應服務器端產生的變化,像是ip換了或者其他原因。
從DNS層次上來解,解放了Client端的對Server端的無感知的困擾,但是DNS在 propagating的時間上的影響會容易在你對時間要求有高效需求時,DNS更新的時間長短與頻率是另一個你擔憂的話題。
其他更新的部分,則是通過容器編排管理相關的技術來實現它,這些不在本次討論的細節中,可以知道現在諸多的技術體系實作都能滿足,但以下這個問題可能是最難一下作出決斷的 :
關於持久化每個服務當中須保存的資料,如果按前文提到的維基百科的定義,每個應用需要有自己的運算與存儲能力與職責,那我原本一個系統的拆分成5個,10個,我是不是真的拆分成5 ~ 10個 資料庫 ?
先看看,假設你不拆的情況下,只用一個或一組資料庫叢集的問題是什麼? 如果你的實作語言平台與資料庫的連線是有 Connection Pool的設計的,而預設你可能每一次帶起應用程序時會直接keep 100 or 150+ 的 connections,當你面對服務帶起數量眾多時,你家的DBA會不知所措因為數量太龐大!
此外所有的請求量體也都打在同一個主資料庫上,面對讀取,可能有其他方式可以解決,但是寫入的壓力卻是不曾少過,更重要的是你的資料庫依然成的單點失敗的絕佳瓶頸王(恭喜登頂!! )
那如果我心一橫,直接開多個資料庫呢? 下個月你看到帳單或者你採購發申請送出去時,不是你老闆 fire你,就是你 fire你自己了,高成本的花費只為了滿足你的所謂微服務設計,很難得到價值感上的認同。
為了要更好的去把服務拆分避免高價的資料庫投資,或許NoSQL是一個選項,尤其現在有很多產品是提供了基於http請求的設計方式,每個table的存取與其他table無關,在使用擴展上相對的容易得多,同時也帶來了很多在開發與運維的好處,像是更新應用程式版本時對應變動的schema,你從此不在擔心哪個天兵給了你 alter table statement,卻沒給你 rollback的指令集與暫存異動資料的 DML statements。
當然附帶的問題也少不了,無法處理多條件因子的複合式查詢等等問題也油然而生,我們也無法就因為這樣從全然的資料庫全數擁抱轉換到NoSQL去。
其實,這一切還有個挑戰,就是跨服務請求的交易補償。雖然很多人都說當你有跨交易的請求鍊時,是否就該多思考一下你這服務的邊界的設計有沒有問題,出發點立意良善但實則要小心看待這是不是一種把責任置身事外的看法。
很多時候你的系統的交互可能來自於多方的協作,又或者是在你的業務場景當中就是真的區分出了不同上下文並落在不同的子領域當中,這形成了天然的系統邊界以及交易範疇的區隔,你就是必須把手弄髒,想辦法去處理這些的分散式的交易困擾。
在一般的情況下,以上面這個旅遊的概念為例:
清明假期快到了,我想要訂閱一個旅遊套餐,讓我帶著我的家人一起出國旅遊,我想要訂酒店,訂機票,以及租賃適合的旅行車讓我完成一趟滿意的旅遊體驗,以這樣的業務場景下,一個好的旅遊訂單,應該要完成上面這三件事情。
如果我們在程式碼實作時,很可能會在程式當中去撰寫 假設呼叫remote A 成功時我該如何,失敗時我又該如何,在一個相對少數的業務交互的場景下,你的判斷流程其實簡單可控,但是如果你一次的業務行為會參與到更多的外部服務的呼叫時,把完整的失敗的補償作業給想清楚,從程式碼層次來說是辛苦的多了,而且不小心就遺漏了。
面對分散式交易,當然我們有個簡單易用的解決方案 — 2phase commit !
但是這樣的技術體系在價格上是昂貴的,面對交易量體較大或者參與交易的數據體較多時效率也差一些,尤其如果你把系統搭建在雲服務供應商之上,授權費的算法也是很可觀,所以或許你可以考慮使用另一個作法,除了避免程式碼撰寫上的複雜,也可以略過2 phase commit的成本 :
Saga pattern in microservices
關於 Saga已經出來很長一段時間了,有興趣的人可以直接google找到很多的介紹,我在這裡提到的做法是通過 AWS 的 Step Functions來作流程業務上的編排:
在每一個較大的服務應用中,以上述的案例為例,訂酒店,訂機票與租車之間本身並沒有所謂的業務發生的順序限制,但是只要有任何一個事情無法完成,那就必須都全數取消訂單,才能確保我的旅遊體驗的價值可被實現。
如果,你能試著把這些業務訴求給流程化編排,那麼循著上圖的流程線你可以發現到,最後一個被運行的租車工作,只要他確認完成,那就全數訂票作業完成,若租車這件事情無法成立,則循序的去取消租車,取消機票安排,以及取消訂房等事宜。
你可以通過這樣的事件編排,去把複雜的問題處理抽離開來,這樣你只要對你既有的業務應用設計做兩件事:
成功時,我該如何; 失敗時,我又將如何 ~
這樣的設計思維,簡化了你對外部系統的依賴思考,這樣的設計方式才是真正的”與外部解耦”,因為你始終只關注在當前上下文的能力層次,更關注於內聚力的體現。
Step Functions是一個基於JSON文件的描述流程編排的服務,你不需去學習BPEL, BPMN等多種複雜的表示法,只需要會寫JSON 你就可以開始使用。
代碼範例參考 - Implement Saga Pattern by StepFunctions + lambda
重點歸納
做系統設計始終沒有軟體界的C4可以使用,你在作微服務拆分時需要針對價值驅動,前面提了這麼多現實考量會讓人有選擇障礙時,你必須挑選真的值得你來面對分散式交易下的 :
- 追蹤交易鏈路問題
- 監控業務行為log
- 拆分資料庫之後的選擇問題,多資料庫或者部分選擇成本低廉的替代選項
- 跨服務間的交易補償
- 甚至可能永遠想不完整的交易補償業務流程
- 真的能維持原本的業務應用水準?
所以,在做技術選擇之前,你可以試著以領域驅動設計的話題去擁抱業務團隊,通過事件風暴大家一起集體思考,哪些核心價值需要被體現,而且沒有他鐵定行不通的部分優先來做逐步的拆分,一次性的全上往往帶來的是災難,這跟絕大多數的引領變革的團隊是同樣的道理的。
祝福大家在擁抱挑戰引領變革的同時,小步前進體驗當前痛苦並動手改善得到團隊的真正肯定與重視。
活動後的週日總是帶著未盡的熱情,榻上翻轉難眠啊 ~