代碼共享是個經常遇到的問題,DRY原則要求盡可能的共享復用代碼,但復用就意味着依賴,如果復用代碼修改可能會導致你的模塊出現問題。是否能處理好代碼共享問題是衡量一個開發人員是否合格的指標之一。沒有意識復用代碼,不恰當復用代碼導致不必要的依賴都在現在的項目中也經常遇到。作為技術管理者或有經驗的老員工有必要指導新人做好代碼復用,作為用不好的新人,要虛心學習提升自己。
共享工程、共享jar、代碼復制或重造輪子、合並工程是常見共享處理方法。
微服務被稱為“無共享”架構,實際上,我更傾向於把它看作是一種“盡可能少共享”的架構,因為微服務之間不可避免的總會存在某種程度的代碼共享。例如,與其使用一個負責身份驗證和授權的安全服務,你可能會更傾向於將安全功能相關的代碼封裝為一個 JAR 文件,例如
security.jar
,並提供給所有服務使用。如果安全性的保證是在服務內處理的,那么這種方式通常是一個很好的做法,因為它避免了每個請求都需要對安全服務發起遠程調用,從而提高了系統的性能和可靠性。然而,如果這種方式被濫用,那最終你將會碰到依賴的噩夢,如圖 3-1 所示,其中每個服務都依賴於多個自定義的共享庫。
這種級別的共享不僅打破了服務間的邊界上下文,同時也引入了其他一些問題,包括總體可靠性,變更控制,可測試性和可部署性。
依賴過多
讓我們回顧一下大多數面向對象軟件應用的開發過程,不難發現共享帶來的問題,特別是從單體應用架構遷移到微服務架構的時候。在大多數單體應用中,最重要的事情之一就是代碼復用和共享。圖 3-2 展示了在大多數單體應用架構中都會共享的兩種構件(抽象類和公共的工具類)。
雖然創建抽象類和接口是大多數面向對象編程語言的常見實踐,但當我們將單體應用中某個模塊拆分為微服務時,這種實踐會存在問題。自定義的共享類和工具類也存在類似的問題,例如共用的日期,字符串,計算等工具類。對於可能被潛在的數百個服務共享的代碼你將作何處理呢?
微服務架構模式的主要目標之一就是盡可能的減少共享,這有助於保證每個服務的邊界上下文,從而換來快速的測試和部署能力。使用微服務,所有這些都可以歸結為變更控制和依賴關系。服務間依賴越多,想要隔離服務的變化就越困難,從而很難單獨對一個服務進行測試和部署。服務間共享越多,依賴也就越多,從而導致了脆弱的系統,它難以測試和部署。
代碼共享的技巧
避免這種反模式最好的方法就是服務間不共享代碼,但這說起來容易,做起來難。正如我在本文開頭實事求是的講,總會有一些代碼需要共享。那么這些代碼要怎么放置呢?
圖 3-3 展示了解決代碼共享問題的四個基本技巧:共享工程,共享函數庫,代碼復制和服務合並。
共享工程的使用將會在共享工程中的公共源代碼和每個服務工程之間形成編譯期的綁定。雖然這使得軟件開發和改動變得簡單,但它是我最不喜歡的共享技巧,因為它在運行時會引入潛在的問題,使得應用程序變得不那么健壯。共享工程技巧的主要問題是溝通和控制,我們很難知道共享模塊的變動及其原因,也很難控制我們服務是否需要特定的更改。想象一下,當你正准備發布你的微服務時,卻發現有人對共享模塊作了重大修改,從而迫使你不得不對服務代碼作改動和重新測試,然后才能進行部署。
如果你想要共享代碼,更好的方式是使用共享函數庫(例如 .NET assembly 或者 JAR 文件)。但這種方式使得開發更加困難,因為任何對共享庫中模塊的改動,開發人員都必須首先打包函數庫,然后重啟服務,最后重新測試。然而共享庫的優點是我們可以對庫進行版本控制,從而更好的控制服務的部署和運行時的行為。如果共享庫作了修改和版本化,那么服務的所有者可以決定何時合並該修改到服務中。
微服務架構中常見的第三種技巧是違反 DRY(Don't Repeat Yourself)原則,它在需要特定功能的所有服務中復制共享模塊。雖然這種復制技術有風險,但它避免了依賴共享,並保留了服務的邊界上下文。當復制的共享模塊需要改動時,尤其是修復某個缺陷時,這種技巧就會出現問題。這種情況下,所有服務都要進行修改。因此這種技巧只對非常穩定的,幾乎不會再改動的共享模塊有用。
有時可能使用的第四種技巧是服務合並。假設兩個或三個服務共享一部分相同的代碼,而這些公共模塊需要經常改動。由於這幾個服務在公共模塊改動時也都要跟着測試和部署,所以你可以把這些服務和公共模塊整合到一個服務中,從而移除依賴的庫。
關於共享庫的一個建議是避免把所有共享的代碼合並成單一的共享庫,例如
common.jar
。使用common.jar
你很難知道你的服務是否需要集成共享代碼以及何時使用。更好的方法是把共享庫拆分成具有獨立上下文的多個庫。例如創建基於上下文的security.jar
,persistence.jar
和dateutils.jar
等。這能夠把不經常改變的代碼和頻繁改動的代碼分離開,從而更容易認清每次更改的上下文,以及決定是否要立即把更改的內容集成到我們的服務中。03 | 微服務反模式與缺陷:代碼共享反模式