分散式系統關注點——「高內聚低耦合」詳解
如果這是第二次看到我的文章, 歡迎 訂閱我的公眾號(跨界架構師)喲~
本文長度為 3012字 ,建議閱讀 8 分鐘。
堅持原創,每一篇都是用心之作~
下面的這個場景你可能會覺得很熟悉( Z哥我又要出演了 ):
Z哥:@All 兄弟姐妹們,這次我這邊有個需求需要給「商品上架」增加一道稽核,會影響到大家和我互動的介面。大家抽空配合改一下,明天一起更新個版本。
小Y:哥,我這幾天很忙啊,昨天剛配合老王改過促銷!
小X:行~當一切已成習慣。
作為被通知人,如果在你的現實工作中也發生了類似事件,我相信哪怕嘴上不說,心裡也會有不少想法和抱怨:“md,改的是你,我也要釋出,好冤啊!”。
這個問題的根本原因就是多個專案之間的耦合度過於嚴重。
越大型的專案越容易陷入到這個昭潭中,難以自拔。
而解決問題的方式就是進行更合理的分層,並且持續保證分層的合理性。
一提到分層,必然離不開6個字「 高內聚 」和「 低耦合 」。
什麼是高內聚低耦合
在z哥之前的文章中有多次提到, 分 布式系統的本質就是「分治」和「冗餘」 。
其中, 分治就是“分解 -> 治理 -> 歸併”的三部曲 。「高內聚」、「低耦合」的概念就來源於此。
需要注意的是,當你在做「分解」這個操作的時候,務必要關注每一次的「分解」是否滿足一個最重要的條件: 不同分支上的子問題,不能相互依賴,需要各自獨立 。
因為一旦包含了依賴關係,子問題和父問題之間就失去了可以被「歸併」的意義。
比如,一個「問題Z」被分解成了兩個子問題,「子問題A」和「子問題B」。但是,解問題A依賴於問題B的答案,解問題B又依賴於問題A的答案。這不就等於沒有分解嗎?
題外話 : 這裡的“如何更合理的分解問題”這個思路也可以用到你的生活和工作中的任何問題上。
所以,當你在做「分解」的時候,需要有一些很好的著力點去切入。
這個著力點就是前面提到的「耦合度」和「內聚度」,兩者是一個此消彼長的關係。
越符合高內聚低耦合這個標準,程式的維護成本就越低。為什麼呢?因為依賴越小,各自的變更對其他關聯方的影響就越小。
所以,「高內聚」和「低耦合」是我們應當持續不斷追求的目標。
題外話 : 耦合度,指的是軟體模組之間相互依賴的程度。比如,每次呼叫方法 A 之後都需要同步呼叫方法 B,那麼此時方法 A 和 B 間的耦合度是高的。
內聚度,指的是模組內的元素具有的共同點的相似程度。比如,一個類中的多個方法有很多的共同之處,都是做支付相關的處理,那麼這個類的內聚度是高的。
怎麼做好高內聚低耦合
做好高內聚低耦合,思路也很簡單: 定職責、做歸類、劃邊界 。
首先,定職責就是定義每一個子系統、每一個模組、甚至每一個class和每一個function的職責。
比如,在子系統或者模組層面可以這樣。
又比如,在class或者function層面可以這樣。
我想這點大家平時都會有意識的去做。
做好了職責定義後,內聚性就會有很大的提升,同時也提高了程式碼/程式的複用程度。
至此,我們才談得上「單一職責( SRP )」這種設計原則的運用。
其次,做歸類。梳理不同模組之間的依賴關係。
像上面提到的案例1可以歸類為3層:
-
基礎層:商品基礎服務、會員基礎服務、促銷基礎服務
-
聚合層:購物車服務、商品詳情服務、登陸服務
-
接入層:快閃店API、綜合商城API
案例2也可以歸類為3層:
-
資料訪問層:訪問會員表資料、訪問會員積分表資料、訪問會員等級表資料
-
業務邏輯層:會員登陸邏輯、會員使用積分邏輯、會員升級邏輯
-
應用層:接收使用者輸入的賬戶密碼、接收使用者輸入的使用積分數、接收使用者的付款資訊
最後就是劃邊界。好不容易梳理清楚,為了避免輕易被再次破壞,所以需要設立好合理清晰的邊界。
否則你想的是這樣整齊。
實際會慢慢變成這樣混亂。
那麼應該怎麼劃邊界呢?
class和function級別。這個層面可以透過codereview或者靜態程式碼檢測工具來進行,可以關注的點比如:
-
呼叫某些class必須透過interface而不是implement
-
訪問會員表資料的class中不能存在訪問商品資料的function
模組級別。可以選擇以下方案:
-
給每一種型別的class分配不同project,打包到各自的dll( jar )中
-
每次程式碼push上來的時候檢測其中的依賴是否有超出規定的依賴。例如,不能逆向依賴( 檢測dal是否包含bll );不能在基礎層做聚合業務( 檢測商品基礎服務是否包含其他基礎服務的dll(jar) )。
系統級別。及時識別子系統之間的呼叫是否符合預期,可以透過接入一個呼叫鏈跟蹤系統( 如,zipkin )來分析請求鏈路是否合法。
讓邊界更清晰、穩定的最佳實踐
很多時候不同的模組或者子系統會被分配到不同的小組中負責,所以z哥再分享幾個最佳實踐給你。它可以讓系統之間的溝通更穩定。
首先是: 模組對外暴露的介面部分,資料型別的選擇上儘量做到寬進嚴出 。比如,使用long代替byte之類的資料型別;使用弱型別代替強型別等等。
舉個「寬進嚴出」的例子:
//使用long代替byte之類的資料型別。
void Add(long param1, long param2){
if(param1 <1000&& param2 < 1000){ //先接收進來,到裡面再做邏輯校驗。
//do something...
}
else{
//do something...
}
}
其次是: 寫操作介面,接收引數儘可能少;讀操作介面,返回引數儘可能多 。
為什麼呢?因為很多時候,寫操作的背後會存在一個潛在預期,是「準確」。
準確度和可信度有著很大的聯絡,只有更多的邏輯處理在自己掌控範圍內進行才能越具備「可信度」( 當然是職責範圍內的邏輯,而不是讓商品服務去計算促銷的邏輯 )。反之,上游系統一個bug就會牽連到你的系統中。
而讀操作背後的潛在預期是:「滿足」。你得提供給我滿足我當前需要的資料,否則我的工作無法開展。
但是呢,在不同時期,客戶端所需要的資料可能會發生變化,你無法預測。所以呢,不要吝嗇,返回引數儘可能多,用哪些,用不用是客戶端的事。
還可以做的更好的一些,就是,在可以滿足的基礎上支援按需獲取。客戶端需要返回哪些欄位自己透過引數傳過來,如此一來還能避免浪費資源做無用的資料傳輸。
題外話 : 對外露出的介面設計,可以使用http + json 這種跨平臺 + 弱型別的技術組合,可具備更好的靈活性。
實際上,一個程式大多數情況下,在某些時刻是客戶端,又在某些時刻是服務端。站在一個完整程式的角度來提煉引數設計的思路就是: “ 吃”的要少,“產出”的要多 。
題外話 : 有一些設計原則可以擴充套件閱讀一下。
單一職責原則SRP(Single Responsibility Principle)
開放封閉原則OCP(Open-Close Principle)
裡式替換原則LSP(the Liskov Substitution Principle LSP)
依賴倒置原則DIP(the Dependency Inversion Principle DIP)
介面分離原則ISP(the Interface Segregation Principle ISP)
總結
本文z哥帶你梳理了一下「高內聚低耦合」的本質(來自於哪,意義是什麼),並且分享了一些該怎麼做的思路。
可以看到「高內聚」、「低耦合」其實沒有這個名字那麼高階。哪怕你現在正在工作的專案是一個單體應用,也可以在class和function的設計中體會到「高內聚」、「低耦合」的奧妙。
來來來,接下去馬上開始在專案中「刻意練習」起來吧~
「易伸縮」篇的相關文章:
作者:
Zachary
出處: https://www.cnblogs.com/Zachary-Fan/p/highcohesionlowcoupling.html
如果你喜歡這篇文章,可以點一下左下角的「 大拇指 」。
這樣可以給我一點反饋。: )
謝謝你的舉手之勞。
▶關於作者:張帆(Zachary,個人微訊號:Zachary-ZF)。堅持用心打磨每一篇高質量原創。
定期發表原創內容:架構設計丨分散式系統丨產品丨運營丨一些思考。
如果你是初級程式設計師,想提升但不知道如何下手。又或者做程式設計師多年,陷入了一些瓶頸想拓寬一下視野。歡迎關注我的公眾號「 跨界架構師 」,回覆「 技術 」,送你一份我長期收集和整理的思維導圖。
如果你是運營,面對不斷變化的市場束手無策。又或者想了解主流的運營策略,以豐富自己的“倉庫”。歡迎關注我的公眾號「 跨界架構師 」,回覆「 運營 」,送你一份我長期收集和整理的思維導圖。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31544142/viewspace-2564934/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 高內聚低耦合
- Java 工程解耦即高內聚低耦合Java解耦
- 分散式系統關注點——初識「高可用」分散式
- 高內聚,低耦合的實現方式
- 分散式系統關注點——360°全方位解讀「快取」分散式快取
- 分散式系統關注點(19)——深入淺出「非同步」分散式非同步
- 分散式系統關注點——想通關「限流」?只要這一篇分散式
- 分散式系統關注點——如何去實施「負載均衡」?分散式負載
- 分散式系統關注點——先寫DB還是「快取」?分散式快取
- 分散式系統關注點(22)——360°的全方位監控分散式
- 精通介面隔離原則,輕鬆實現高內聚、低耦合架構架構
- 如何設計一個高內聚低耦合的模組——MegEngine 中自定義 Op 系統的實踐經驗
- 高聚合低耦合 - theregister
- 分散式系統關注點(20)——阻塞與非阻塞有什麼區別?分散式
- 分散式 - 分散式系統的特點分散式
- 分散式系統關注點(18)——「快取穿透」和「快取雪崩」到底啥區別?分散式快取穿透
- 分散式系統關注點——僅需這一篇,吃透「負載均衡」妥妥的分散式負載
- 分散式系統關注點——99%的人都能看懂的「熔斷」以及最佳實踐分散式
- 詳解分散式系統本質:“分治”和“冗餘”分散式
- 高層次下的分散式系統分散式
- 什麼是分散式系統!以及分散式系統架構的優缺點!分散式架構
- 分散式系統「伸縮性」大招之——「水平&垂直切分」詳解分散式
- 高併發架構系列:分散式鎖的由來、特點及Redis分散式鎖的實現詳解架構分散式Redis
- 分散式系統分散式
- UITableView佔點陣圖的低耦合性設計UIView
- 詳解Redis分散式鎖Redis分散式
- 分散式系統2:分散式系統中的時鐘分散式
- 32_分散式文件系統_document查詢內部原理圖解揭秘分散式圖解
- 分散式系統:系統模型分散式模型
- 分散式監控系統ganglia的詳細配置分散式
- 分散式系統–>(關於系統應用的基本概念)分散式
- 分散式系統(三)——分散式事務分散式
- 30_分散式文件系統_document增刪改內部原理圖解揭秘分散式圖解
- [分散式]分散式計算系統淺析分散式
- 讀構建可擴充套件分散式系統:方法與實踐03分散式系統要點套件分散式
- Dionaea低互動式蜜罐部署詳解
- 分散式系統的跟蹤系統分散式
- Webpack(含 4)配置詳解——關注細節Web