不使用DDD的後果:為什麼我們停止了向微服務的遷移? - Steven Lemon

banq發表於2019-08-11

最近,我們的開發團隊在功能交付計劃方面略有突破。技術領導層決定,這次將我們的單片單體架構分解為微服務是最好的時機。經過一個月的調查和準備,我們卻取消了這項遷移,而是決定堅持使用我們的單體巨石系統。

對我們來說,微服務不僅不會幫助我們; 還會傷害我們的開發程式。微服務作為理想的架構售給我們可能已經一年了。所以我們很驚訝地發現它並不適合我們。我認為提交一份關於我們經驗的案例研究以及為什麼我們的團隊決定反對他們肯定會很有意思。

識別問題和早期妥協

我們非常依賴第三方,我們的應用程式是現有外部產品頂部的自定義UI,整合了我們的一些自定義業務規則並提供了一個觸控友好的使用者介面。我們的客戶是一個UWP應用程式,我們有一系列後端服務,可以在我們的域和第三方域之間進行轉換。

建立在第三方之上的方式影響了我們如何將我們的域劃分為微服務。例如,我們的應用程式偶爾必須在域之間轉換功能。使第三方域的一部分行為並感覺它是我們UI中不同域的一部分。

當我們在前端和第三方之間提供單體一個大的服務時,這種轉換並不是那麼糟糕。但是,當我們嘗試將域拆分為單獨的微服務時,領域切換會給我們帶來很大的困惑。

我們的微服務是否遵循與第三方相同的視角切分方式?我們如何在兩個服務中複製前端的一個功能?我們是否根據我們的域劃分了微服務,並且需要從第三方的兩個獨立區域獲取一個微服務。

我們經常與外部團隊合作,一個功能要求雙方進行更改。第三方是另一個團隊。密切合作意味著我們必須與他們的釋出過程保持同步。微服務的一個好處是每個團隊都可以負責獨立釋出他們的服務,而不需要與其他團隊協調。不僅跨團隊協調發布,而且跨公司協調發布使我們無法獲得這些優勢。

微服務的核心思想之一是拆分只負責某個單獨層的獨立團隊。在微服務架構中,每個團隊負責解決其業務問題的完整棧。對我們來說,由於我們的一個層是一個完全獨立的公司,這種重組是不可能的。

我們無法充分隔離每個微服務

我們無法在我們的單體中發現任何明顯的候選服務可被分解為微服務。因此,我們開始在我們的域模型之間繪製任意行,從中我們得到了我們要建立的微服務列表。但是,一旦我們開始調查,我們發現很多共享的業務邏輯很快就會在分離的微服務域之間的隱式耦合。進一步嘗試將這些微服務細分為越來越小的部分,但這使得我們在各處都有更多的耦合,引入了訊息匯流排,以及從一個服務到十個或更多微服務的潛在大爆炸。

一切都是如此耦合而且難以分解的原因是我們試圖分離的單體只能滿足一個業務問題。我們的客戶端應用程式的總體設計目標之一是將第三方基礎應用程式中的不同概念結合在一起。我們正在建立跨越域和分組功能的工作流,以方便使用者。從本質上講,使用者介面過去四年一直在推動所有事情。

在某個地方,我們誤解了微服務應該如何被隔離,並低估了選擇服務之間正確邊界的重要性。我們打破單體的唯一方法意味著實現標準“功能”將涉及同時更新多個微服務。每個功能都需要不同的微服務組合,這阻止了任何微服務都被一個團隊擁有。

分享微服務

我們有大約12名開發人員分佈在2個功能團隊和一個支援團隊中。工作波動很大,沒有團隊被鎖定到應用程式的任何區域。讓兩個團隊同時觸及程式碼的相同區域並不罕見。我們無法將任何潛在微服務的所有權分配給單個團隊。

在考慮建築風格時,考慮Conway康威定律很有用。它宣告您的軟體架構是以模仿您的組織和團隊結構的方式發展。如果你有一堆獨立的團隊處理不同的業務問題,那麼很多獨立的微服務都是有意義的。否則,幾個團隊共享功能的方式更合適。

該平臺尚未準備好

各種問題意味著至少在6個月內,我們將在IIS中的整體塊旁邊託管我們的新微服務。我們無法訪問許多與微服務相關的標準工具,如容器,Kubernetes,服務匯流排,API閘道器等。沒有這些工具會使微服務更難以相互通訊。因此,我們決定每個微服務都會複製任何共享邏輯以及來自儲存層的常見讀取和轉換。因為我們無法正確隔離任何服務,這意味著我們將留下大量重複。例如,我們確定了一個特別複雜且必不可少的業務邏輯,必須在4個計劃的微服務中進行復制貼上和維護。

我們對未來沒有清晰的瞭解

開發團隊對接下來的6個月有一個粗略的想法,並沒有關於超出這個範圍的資訊。此外,業務經常改變它的想法。更改中間功能的要求並不少見。這種不確定性使得建立微服務變得更加困難,因為我們無法預測即使在短期內會出現什麼新的連結。計劃的微服務之間的連線和耦合會增長嗎?我們是否需要花幾個月的時間再次將他們重新加入?我們已經嘗試在今年早些時候建立一個證明概念微服務,但只是因為業務改變了它的要求而使它無法解決。

時間緊迫

我們只有一個小的時間視窗,在這段時間內匆忙地將大的整體分成我們需要的微服務列表。我們沒有任何額外的時間讓我們反思我們創造的東西或者如果需要改變路線。沒有計劃B的。我們將被困在我們創造的任何東西上。由於我們在規劃階段發現了許多問題和挑戰,更不用說實施階段了,這引起了開發團隊的極大關注。

缺乏經驗

使風險和時間壓力更加複雜,負責架構或實施微服務架構的人員都沒有任何特定的先前經驗。由於沒有很多標準工具可供使用而加劇了這一點,這意味著我們將自己實施該平臺。與一些有微服務經驗但沒有參與的人交談,引發了更多的危險訊號。我們無法界定在基礎設施或在域模型之間分界的後果。

到目前為止,我們的計劃涉及許多妥協,這些妥協偏離了標準的微服務模式,時間緊迫。沒有專家指導,很有可能犯下許多錯誤,並且很難學習。開發團隊看起來很緊張。

我們想要再次實現什麼目標?

一旦一切都開始變得艱難,前進的道路開始迷失,我們停下來,意識到我們不知道為什麼我們這樣做了。我們沒有列出我們的痛點,我們也沒有清楚地瞭解這將有助於解決我們所遇到的任何痛點。更糟糕的是,微服務可能正在為我們創造一整套新問題。

我們開始強調這些問題,我們應該獲得哪些好處,以及我們要解決的問題是什麼?我們設定越來越多的會議試圖弄清楚,每個咖啡休息時間和開發人員之間的每次談話都在討論和質疑微服務,我們仍然無法直接回答原因。

事實證明,我們確實有其他更緊迫的痛點,在向微服務的驅動遷移中被忽略了。不幸的是,我們可能已經沒有時間來充分解決這些問題,這意味著我們既沒有微服務也沒有其他任何東西。

有什麼潛在的好處?

一旦我們意識到我們不知道為什麼我們要走向微服務,我們暫停並開始自己調查微服務通常提供的好處。

自治​​​​​​​

微服務允許您的團隊控制提供功能所需的完整堆疊。這種分離的好處是減少了與其他團隊的協調量。你不會影響他們的工作,他們不會影響你的工作。

允許您的團隊專業化

在單體巨石中,任何團隊都可以最終處理任何事情。任何特徵或區域的所有權都不是指定的。每個團隊擁有自己的服務,他們可以在特定的業務關注點上建立專業知識。他們瞭解其領域中的業務規則和要求。他們知道他們的軟體棧是如何構建和實現的,並且在進行更改時可以更有信心。

更容易擴充套件

使用微服務,您可以根據其效能需求擴充套件每個服務。使用整體,雖然您也可以在更多伺服器上水平擴充套件,但您無法將整體的每個元件彼此分開。此外,微服務這種細粒度使得根據需要更容易地上下調整服務。也許你預計會有一些額外的負載,或者在解決效能問題時需要一些喘息空間。

更容易回滾

如果每個功能僅需要更改單個微服務,則可以回滾該功能而不會影響其他團隊的工作。此外,微服務有助於減少單個故障可能導致的系統數量。

更容易釋出,更容易更頻繁地釋出

如果您擁有廣泛的系統,則每個版本都會變得耗時且有風險。迴歸測試需要涵蓋很多內容,限制了您的釋出節奏。您可能需要從多個人簽名並在每個版本中涉及的所有團隊之間進行協調。您從未聽說過的團隊中的錯誤或迴歸可以保留您需要的時間敏感功能。微服務限制了變更範圍,減少了團隊之間所需的協調量。團隊可以按照他們自己的時間表釋出,而不是受到單體巨石的節奏約束。

使用最合適的技術

微服務使您的團隊能夠為他們的團隊選擇最合適的技術以及他們試圖解決的問題。也許他們可以使用現代技術,而單體巨石可能難以升級並停留在過時的平臺上。

更容易升級

在最好的情況下,升級大型應用程式使用的框架永遠不會有趣或沒有風險。當您需要協調跨多個團隊的廣泛,相互關聯的變更時,要困難得多。較小的隔離服務使您可以選擇僅升級需要更新的服務,或者允許您一次執行一個服務和一個團隊的升級。

防止變化

應用程式的不同部分以不同的速率變化。您的大多數應用程式可能在幾個月甚至幾年內沒有被更改。將很少更改的程式碼與經常變動的區域分開,可以降低意外迴歸的風險。

較小​​​​​​​

較小的服務更容易推理和理解。此外,僅由一個團隊進行更改意味著其設計保持一致。它更小的尺寸使得更容易進行廣泛的重構。相比之下,單體巨石可能具有不一致的進化架構,因為不同團隊的觀點會導致其隨時間變化。

結論的好處

採用微服務有很多潛在的好處。但是,我們能夠獲得任何一個嗎?

最終,我們無法改變的部分架構和我們必須做出的妥協破壞了這些好處。微服務是一個在所有團隊之間共享的浮動池,並且功能在多個共享微服務之間分散,這意味著我們失去了隔離的好處:減少了協調,專業化和從中獲得的好處。微服務之間的差異,變得不利而不是一種力量了。每個功能都需要了解新的微服務如何工作以及其他團隊對其做出的改變。我們對第三方的依賴阻止了我們改善依賴程度並降低了我們從獨立擴充套件服務中獲得的收益。

權衡利弊

用大象槍殺死一隻蒼蠅

採用微服務並不是免費的。您需要解決許多其他問題。我們需要重新審視我們之前在我們的單體巨石中提出的許多問題。例如,我們需要解決或重新審視:日誌記錄,監控,異常處理,容錯,回退,微服務到微服務通訊,訊息格式,容器化,服務發現,備份,遙測,警報,跟蹤,構建管道,釋出管道,工具,共享基礎架構程式碼,文件,擴充套件,時區支援,分階段部署,API版本控制,網路延遲,執行狀況檢查,負載平衡,CDC測試,容錯,除錯以及在我們的本地開發環境中開發多個微服務。

更糟糕的是,如果沒有準備好微服務平臺,我們就必須為自己完成上述許多工作。我們已經遇到了痛點並且難以轉向微服務; 我們確定我們不會受益於遷移到微服務的優勢,我們有一長串額外的工作來建立和維護以支援微服務。

微服務僅限名稱

下圖展示了我們當前的整體結構,我們的計劃架構以及微服務的外觀比較。在結構上,我們的新架構仍然非常類似於我們的巨石,所有的東西仍然緊密地聯絡在一起。我們是否應該使用微服務標籤來描述我們在做什麼?

(banq注:中間的圖新架構其實是傳統SOA,服務中耦合了業務邏輯,從職責角度看,服務只是協作者,不是業務決定者,DDD領域模型才是決定者,飯店的服務員能做決定嗎?當然當你退菜時,她會馬上說菜已經在燒,不能退了,根本不會去業務決定者廚房那裡看看,在這個案例中,第三方3id Party是業務決定者,如果業務決定者沒有進行領域或有界上下文切分,也就是大廚沒有分工,你責難服務員有意思嗎?)

不使用DDD的後果:為什麼我們停止了向微服務的遷移? - Steven Lemon

我們的巨石那麼糟糕嗎?

我們使用monolith(單體/巨石/整體)就像一個載入的術語。好像說“巨石”意味著一些可怕的東西,“微服務”意味著一些好東西。一旦我們看過刻板印象和品牌,開發團隊對我們的“巨石”幾乎沒有什麼問題。它可能是我們整個系統中最無痛的部分之一。開發和擴充套件是直截了當的,因為它主要是對第三方的直通。我們不需要花太多時間來研究它。我們有一個出色的CI / CD設定,這使得它易於部署和回滾。我們的分支和測試策略確保了很少將其投入生產的問題。

意識到我以前曾經使用過微服務

在這一點上,我意識到我確實有過以前角色的微服務經驗。我們從來沒有把它稱為微服務,它可能沒有遵循微服務的所有“規則”,但它確實解決了同樣的問題並給了我們同樣的好處。

我們是一個由約200名開發人員組成的團隊中的一個小團隊。也許5%的後端工作都在公司共享的巨型元件中,這是一個龐大的C#應用​​程式。剩下的時間,我們在兩個Node服務中工作。

我們不喜歡在巨石中工作。它的工作速度很慢,編譯和執行測試,架構變化到不可知,隨機的東西不斷出現在構建步驟中。多次我們為客戶提供了一項高優先順序的工作,因為一個我從未聽說過的團隊在功能上退步了。由於需要在整個公司內進行協調,因此定期技術更新需要數月時間。在我們等待完全獨立的團隊的批准時,拉動請求可能會持續數週。

同時,我們的兩項服務都很小; 我們完全控制了他們的開發,架構和部署。一旦我們遇到效能問題,我們就會將生產中的例項數量增加一倍,直到我們解決了潛在的問題。我們很少與其他團隊協調。在TypeScript中提供我們的服務使我們的主要前端開發人員團隊在前端和後端使用相同的語言。最重要的是,它允許我們在我們的客戶端和後端驗證和報告服務中包含我們複雜的規則計算引擎。我們的團隊專注於一個非常狹隘的業務問題,我們都成為了專家。

不僅僅是技術問題

我們對微服務的研究越多,對技術的關注就越少,對結構化團隊和進入它們的工作的關注就越多。我們錯誤地將微服務視為純粹的技術問題嗎?

對於沒有答案的大局,有很多問題。

*重組團隊是否致力於將實際問題分開?

*我們可以乾淨地劃分我們的域和微服務之間即將推出的功能嗎?

*是否會為所有團隊提供足夠的工作,或者團隊是否會無法工作?

*團隊是否會受到大量高優先順序工作的攻擊,而這些工作是他們無法分享的?

*同樣的問題是否會讓我們難以分割我們的巨石還會阻止我們的管理層分割新工作?*他們對這種轉變的興趣是什麼?

從a到b

我們計劃進入微服務是一個巨大的爆炸。每個人都停止了幾個月的功能工作,並開始拆分我們的巨石。儘管許多先決條件還沒有準備好。我們正在迫使前進,而不是等待出現的需要或自然候選人出現。

這不僅是從a到b的非常好的方式,但它也是倒退的。首先建立所有微服務,然後為它們設定基礎架構,並完全忽略構建團隊和傳入工作的方面。相反,如果我們開始通過圍繞專門的業務問題重組我們的團隊,然後準備好基礎設施,我們就可以自然地出現微服務的舞臺。如果出現任何新的業務問題,可以將它們直接放入新服務中。

通過強制微服務,這意味著我們還必須預先選擇每個微服務的大小。關於每個微服務的大小(或小),存在許多相互矛盾的建議。一些文章建議每個微服務對於一個團隊應該足夠大。其他人建議每個微服務應該足夠小,你可以將結構保持在頭腦中,甚至可以在兩週內重寫它。其他建議他們應該是每個業務關注的大小。領導決定根據我們的域模型拆分我們的微服務,然後在出現任何問題時將它們分開。這導致了上面提到的許多問題,團隊和功能需要共享微服務。事後看來,如果我們讓其他所有東西到位後微服務自然出現,

取消

我們的團隊不斷髮現越來越多的問題。創造更多妥協並進一步降低收益。從開始實施我們的微服務的第一個sprint開始四天,我們仍然無法確定任何收益,並且問題和缺點的列表足夠長,足以形成這篇相當長的部落格文章的種子。我們召開了一次會議,儘管領導層需要,但微服務的答案卻寫在每個開發人員的臉上。我們對微服務的遷移被取消了。

那我們做了什麼呢?

轉向微服務的熱情意味著尚未對替代方案進行調查。只有在我們放棄微服務之後,我們才能調查其他選擇。最終,我們開始將解決方案分解為現有巨石中的單獨專案,而不是將我們的巨型單元分離為單獨的服務。這種劃分為我們提供了一些額外的結構,更好地指示了存在耦合和重複的位置,而沒有微服務的額外重量和挑戰。

此外,這種結構將使我們的領域模型更加清晰,使我們能夠更容易地評估任何未來微服務的候選者。如果某些事情確實是一個合適的候選人,那麼該專案就可以從我們的整體中“脫離”到一個微服務中,而不必被解開。

結論

領導力確定了微服務的方向,而沒有考慮應用的挑戰和狀態。在評估之後,我們發現微服務不適合我們,並且需要重大妥協。妥協使我們失去了任何好處,並意味著轉向微服務是一種淨損失。已經決定使用微服務而不評估團隊結構和傳入工作等非技術問題。經過數月的調查和工作,我們放棄了這個專案,並花了剩餘的時間對我們的“巨石”進行一些小的重構。

banq評:沒有從業務下手,而只是從技術架構入手,方向錯誤,條條大路通羅馬,但是去羅馬還是去希臘的方向選擇才是更重要的。

相關文章