GO 中優(yōu)雅編碼和降低圈復雜度
theme: Chinese-red
本次主要是聊聊關于使用接口抽象和降低圈復雜度的方式
工作中,難免會遇到老項目老代碼,不僅僅需要我們維護,可能還需要我們在原來的垃圾代碼上進行新增功能或者是進行優(yōu)化調整
例如
現(xiàn)有的老代碼中關于用戶系統(tǒng)這一塊就已經(jīng)經(jīng)是搖搖欲墜,牽一發(fā)而動全身,并且去弄清其中的業(yè)務細節(jié),那可以說是很難撥開迷霧,甚至交接都是一句話的那種,更是難上加難
這種情況,相信每個公司都會存在,畢竟過去的需求,過去的標準,放到現(xiàn)在來看,啥也不是
若是很多代碼都是面向過程的,各種業(yè)務邏輯,非業(yè)務的邏輯都混合在一起,主流程上插入一些亂七八糟的邏輯,上下文并沒有啥關系的東西,一個函數(shù)上千行的代碼也是隨處可見,這種情況狗看了都搖頭
對業(yè)務函數(shù)需要做基本的封裝
首先咱們編碼前一定會去捋清楚基本的需求,設計,以及實現(xiàn)流程,對于需要用到的工具我們會對代碼結構進行分層
例如一些與業(yè)務主邏輯沒有什么關聯(lián)的功能就可以獨立封裝,便于維護和使用,例如:
- 工具包(例如語言中的各種計算,數(shù)據(jù)處理,加解密等等)
- 基本的 rpc 通信
- http 相關的各種通信方式
- 基本的中間件,攔截器,打點接口延時等等
- 數(shù)據(jù)庫操作(獨立封裝 DAO 層提供出來)
- 緩存操作
- 消息隊列
- ...等等
盡可能的將這些單獨的功能模塊拆解出去,獨立出來,單獨維護
對于那種沒有必要同步的功能,完全可以通過異步化來進行處理,異步的話相信你會很容易想到消息隊列來進行實現(xiàn)
自然實際項目中你能夠看到最開始可能也會這樣去做,但是隨著業(yè)務越來越復雜,這些獨立的模塊被各種包進行使用,甚至有的開始慢慢的弄成定制化的方式
例如
func OpenTenant(){
// 校驗基本租戶信息
// 檢查租戶是否特權,完成權限分配
// 檢查實際開戶的線路,分配各種租戶下的必備賬號
// 完成各種系統(tǒng)的對接交互
// 進行數(shù)據(jù)庫操作
// 返回結果
}
對于一個基本的開戶流程,我們或許可以在代碼中看到第一步做什么,第二步又做什么,第三步... ,然而每一個大步驟下面還有各種小步驟,每一個小步驟也會有自己的復雜邏輯
雖然有了基本的封裝,但是使用的時候,可能還是會寫到哪,需要啥就去按需定義啥
最終就會看到一個函數(shù)上千行,讓你去閱讀和維護,你內心能不拒絕嗎嗎?
發(fā)現(xiàn)對模塊進行獨立封裝還是不太夠,代碼里面太多的冗余代碼,這個時候咱們就可以使用接口來做抽象
用接口來做抽象
使用接口來做抽象的話,相當于是提前考慮好這一類的業(yè)務需要去考慮哪些問題,需要注意哪些場景,需要實現(xiàn)哪一些接口
不同的對象各自去實現(xiàn)自己的內容就可以了,單獨去維護自己的對象
例如上面的 A 系統(tǒng)的開戶流程
// 開戶 interface{}
type OpenTenant interface{
ValidateTenantInfo(xxx)xxx // 校驗基本租戶信息
CheckPrivilege(xxx) xxx // 檢查租戶是否特權,完成權限分配
CheckLine(xxx) xxx // 檢查實際開戶的線路
ProcessNeccessaryAccount(xxx) xxx //分配各種租戶下的必備賬號
ProcessNoticeMsg(xxx) xxx// 完成各種系統(tǒng)的對接交互
AddTenant(xxx) xxx// 進行數(shù)據(jù)庫操作
}
這僅僅是一個 demo,對于一個開戶 interface{} 來說,A 系統(tǒng)可以去實現(xiàn),B 系統(tǒng)仍然也可以去實現(xiàn),各自完成自己的內容,例如這樣
圖片
對于優(yōu)化代碼的話,我們就可以將上述的一些實現(xiàn)步驟,放到這個接口中來即可
咱們定義接口,更多的是去規(guī)范流程和便于維護,這樣還可以讓我們的程序往高內聚低耦合方面去靠,不同的對象之間,完全是安全的,自己玩自己的一套,只不過遵循的規(guī)范是一樣的的
盡可能降低圈復雜度
圈復雜度也可以理解為條件復雜度,是一種用來衡量代碼復雜度的標準
例如一些沒有判斷語句的代碼,圈復雜度就是 1
如果是 if...else 那么圈復雜度就是 2 ,簡單的就可以理解為涉及到判斷條件的數(shù)量,那么就 +1
例如有這樣的代碼
func testDemo() {
var op OpenTenant
switch TenantType {
case A:
op = a.New()
case B:
op = b.New()
case C:
op = c.New()
default:
...
}
op.ValidateTenantInfo()....
}
那么就如上demo ,來看,圈復雜度就是 4 ,其中有 3 個判斷條件和一個默認的正常順序,因此是 3 +1 = 4
這個時候,我們可以如何降低圈復雜度呢?
我們完全就可以使用表格的方式,訪問數(shù)據(jù)直接訪問表格就可以了,盡可能的減少這些判斷條件,例如我們就可以這樣來寫
var openTenantMap = map[string]openTenantObject{
A: a.New(),
B: b.New(),
C: c.New(),
}
func testDemo(){
op := openTenantMap[TenantType ]
...
op.ValidateTenantInfo()
...
}
這種方式,是不是就可以將圈復雜度降低到 1 了呢?而且看起來也優(yōu)雅了很多
總結
主要叮囑了我們維護和開發(fā)的時候,要重視封裝,重視抽象,重視降低圈復雜度
只要你用心去打磨,自然會變得越來越好
但是可別生搬硬套,畢竟一些定制化的需求,定制化的代碼你去做接口抽象是沒有啥意義的,一起加油吧,xdm
至此,本次就是這樣,希望能夠給你帶來一丁點幫助
歡迎點贊,關注,收藏
朋友們,你的支持和鼓勵,是我堅持分享,提高質量的動力
技術是開放的,我們的心態(tài),更應是開放的。擁抱變化,向陽而生,努力向前行。