您好,登錄后才能下訂單哦!
本篇文章為大家展示了if-else coder是如何升級,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
我經常說,我們不要做一個 if-else coder。這里的 if-else,不是說我們在 coding 的時候不能使用 if-else,而是說我們不應該簡陋地用 if-else 去實現(xiàn)業(yè)務的分支流程,因為這樣隨意的代碼堆砌很容易堆出一座座“屎山”。
業(yè)務的差異性是 if-else 的根源。以零售通的商品業(yè)務為例。不同的處理場景,其業(yè)務邏輯實現(xiàn)是有差異性的。如下圖所示,商品業(yè)務的差異性,主要體現(xiàn)在商品類型、銷售方式和倉儲方式的不同。
這三個維度上的差異組合起來,有 2 3 2 = 12 之多。這就是為什么在老代碼中,到處可以看到 if(組合品) blabla,if(贈品) blabla,if(實倉) blabla 之類的代碼。
那么,要如何消除這些討厭的 if-else 呢?我們可以考慮以下兩種方式:
多態(tài)擴展:利用面向對象的多態(tài)特性,實現(xiàn)代碼的復用和擴展。
代碼分離:對不同的場景,使用不同的流程代碼實現(xiàn)。這樣很清晰,但是可維護性不好。
1. 多態(tài)擴展
多態(tài)擴展可以有繼承和組合兩種方式。繼承勿用多言,組合有點像策略模式,也就是把需要擴展的部分封裝、抽象成需要被組合的對象,然后對其進行擴展,比如星環(huán)的能力擴展點就是這種方式。
這里,我們舉一個繼承的例子,商品在上架的時候要檢查商品的狀態(tài)是否可售,普通商品(Item)檢查自己就好了,而組合商品(CombineItem)需要檢查每一個子商品。
用過程式編碼的方式,很容易就能寫出如下的代碼:
public void checkSellable(Item item){ if (item.isNormal()){ item.isSellable(); //省略異常處理 } else{ List<Item> childItems = getChildItems(); childItems.forEach(childItem -> childItem.isSellable()); //省略異常處理 } }
然而,這個實現(xiàn)不優(yōu)雅,不滿足 OCP,也缺少業(yè)務語義顯性化的表達。更好的做法是,我們可以把 CombineItem 和 Item 的關系通過模型顯性化的表達出來。
這樣一來,一方面模型正確的反應了實體關系,更清晰了。另一方面,我們可以利用多態(tài)來處理CombineItem和Item的差異,擴展性更好。重構后,代碼會變成:
public void checkSellable(Item item){ if (!item.isSellable()){ throw new BizException("商品的狀態(tài)不可售,不能上架"); } }
2. 代碼分離
所謂的代碼分離是指,對于不同的業(yè)務場景,我們用不同的編排代碼將他們分開。以商品上架為例,我們可以這樣寫:
/** * 1. 普通商品上架 */ public void itemOnSale(){ checkItemStock();//檢查庫存 checkItemSellable();//檢查可售狀態(tài) checkItemPurchaseLimit();//檢查限購 checkItemFreight();//檢查運費 checkItemCommission();//檢查傭金 checkItemActivityConflict();//檢查活動沖突 generateCspuGroupNo();//生成單品組號 publishItem();//發(fā)布商品 } /** * 2. 組合商品上架 */ public void combineItemOnSale(){ checkCombineItemStock();//檢查庫存 checkCombineItemSellable();//檢查可售狀態(tài) checkCombineItemPurchaseLimit();//檢查限購 checkCombineItemFreight();//檢查運費 checkCombineItemCommission();//檢查傭金 checkCombineItemActivityConflict();//檢查活動沖突 generateCspuGroupNo();//生成單品組號 publishCombineItem();//發(fā)布商品 } /** * 3. 贈品上架 */ public void giftItemOnSale(){ checkGiftItemSellable();//檢查可售狀態(tài) publishGiftItem();//發(fā)布商品 }
這種方式,當然也可以消除 if-else,彼此獨立,也還清晰。但復用性是個問題。
3. 多維分析
細心的你可能已經發(fā)現(xiàn)了,在上面的案例中,普通商品和組合商品的業(yè)務流程基本是一樣的。如果采用兩套編排代碼,有點冗余,這種重復將不利于后期代碼的維護,會出現(xiàn)散彈式修改(一個業(yè)務邏輯要修改多處)的問題。
一個極端情況是,假如普通商品和組合商品,只有 checkSellable() 不一樣,其它都一樣。那毫無疑問,我們使用有多態(tài)(繼承關系)的 CombineItem 和 Item 來處理差異,會更加合適。
而贈品上架的情況恰恰相反,它和其他商品的上架流程差異很大。反而不適合和他們合用一套流程代碼,因為這樣反而會增加他人的理解成本。還不如單獨起一個流程來的清晰。
那么,問題來了,我們什么時候要用多態(tài)來處理差異,什么時候要用代碼分離來處理差異呢?
接下來,是我今天要給你著重介紹的多維度分析問題的方法論之一:矩陣分析法。
我們可以弄一個矩陣,縱列代表業(yè)務場景,橫列代表業(yè)務動作,里面的內容代表在這個業(yè)務場景下的業(yè)務動作的詳細業(yè)務流程。對于我們的商品業(yè)務,我們可以得到如下的矩陣:
通過上面的矩陣分析,我們不難看出普通品和組合品可以復用同一套流程編排代碼,而贈品和出清品的業(yè)務相對簡單,更適合有一套獨立的編排代碼,這樣的代碼結構會更容易理解。
1. 多維度的重要性
上面的案例不是我編造出來的,而是我在和張文(我同事)討論應該用哪種方式去處理業(yè)務差異的真實故事。
我記得在和大學討論完,開車回去的路上,我一直在想這個問題,然后在第二個路口等紅燈的時候,突然有一個靈感冒出來。我抑制不住興奮,一邊開車,一邊發(fā)消息給張文說:“我想到了一個很 NB 的方法論,能解決在‘多態(tài)擴展’和‘代碼分離’之間如何做選擇的問題”。
其實,我知道我興奮的不僅僅是解決了這個問題。我興奮的是,我第一次真正領悟到了多維度思考的重要性。從而有機會從一個“單維度”生物,升級成一個“多維度”思考者。媽媽再也不用擔心我被“降維打擊”了 :)
結構化思維有用、很有用、非常有用,只是它更多關注的是單向維度的事情。比如我要拆解業(yè)務流程,我要分解老板給我的工作安排,我要梳理測試用例,都是單向維度的。
而復雜性,通常不僅僅是一個維度上的復雜,而是在多個維度上的交叉復雜性。當問題涉及的要素比較多,彼此關聯(lián)關系很復雜的時候,兩個維度肯定會比一個維度要來的清晰,這也是為什么說矩陣思維是比結構化思維更高層次的思維方式。
實際上,我們從漢語的詞匯上,也不難看出一個人的思維層級,是和他的思考維度正相關的。當我們說這個人很“軸”、“一根筋”的時候,實際上是在說他只有一維的線性思維。所以,觀察事物的視角越多,維度越豐富,其思維層級也會越高。
2. 無處不在的多維思考
有了這些感悟,我開始系統(tǒng)的整理關于多維度思考分析的資料,發(fā)現(xiàn)這種思考方式真是無處不在。發(fā)現(xiàn)的越多,我越是感慨,為什么如此重要的思維方式,我到現(xiàn)在才領悟到。
1)波士頓矩陣
比如,在做產品分析的時候,有對產品發(fā)展前景進行分析的波士頓矩陣。
2)訂單要素分析
當年,我在 1688 做交易下單業(yè)務的時候,有非常多的下單場景,每種場景下,買家享受的權益是不一樣的(如下表所示)。我們當時也是使用了矩陣去表達這個復雜的關系,只是當時還沒有想到要將其提升到方法論的高度。
3)數(shù)據(jù)交叉分析
在數(shù)據(jù)分析中,維度分析是非常重要的,特別是維度很多的時候,我們可以通過皮爾遜積矩相關系數(shù),做交叉分析,從而彌補獨立維度分析沒法發(fā)現(xiàn)的一些問題。
簡單相關系數(shù)矩陣
4)分析矩陣
最近我碰巧看到 Alan Shalloway 寫的《設計模式解析:Design Patterns Explained》,這是一本非常經典的關于 OOP 的書,里面的第十六章就是專門講“分析矩陣”的,作者創(chuàng)造這個方法論的初衷也是因為業(yè)務涉及的要素太多,信息量太大,他需要一種組織海量數(shù)據(jù)的新方式。
我和 Alan 的路徑不一樣,但是都得出了同樣的結論。由此可見,這種矩陣分析的方式的確是對復雜業(yè)務進行分析的一把利器,業(yè)務場景越多,交叉關系越是復雜,越需要這樣的分析。
5)組織陣型
生產關系決定生產力,對于一個管理者來說,如何有效的設置組織結構是決定團隊是否能高效協(xié)作的關鍵。所以我們可以看到公司里面,每年都有比較大的關于組織結構和人員安排的調整。
對于技術團隊來說,我們習慣于按領域劃分工作范圍,這樣做的好處是責任到人、職責清晰。然而,領域只是一個維度,我們工作通常都是以項目的形式的開展,而項目通常是貫穿多個領域的。所以,在做團隊組織規(guī)劃的時候,我們可以通過業(yè)務領域和業(yè)務項目兩個維度去看。
比如,在我負責的商品團隊,我會按照如下的形式去做職責劃分。
6)時間維度
除了工作,生活中也到處可見多維思考的重要性。
比如,我們說浪費可恥,應該把盤子舔的很干凈,豈不知加上時間維度之后,你當前的舔盤,后面可能要耗費更多的資源和精力去減肥,反而會造成更大的浪費。
我們說代碼寫的丑陋,是因為要“快速”支撐業(yè)務,加上時間維度之后,這種臨時的妥協(xié),換來的是意想不到的 bug,線上故障,以及無止盡的 996。
7)RFM 模型
簡單的思考是“點”狀的,比如舔盤、代碼堆砌就是當下的“點”;好一點的思考是“線”狀,加上時間線之后,不難看出“點”是有問題的;再全面一些的思考是“面”(二維);更體系化的思考是“體”(三維);比如,RFM 模型就是一個很不錯的三維模型??上У氖?,在表達上,我們人類只能在二維的空間里去模擬三維,否則四維可能會更加有用。
在前言部分,我已經說過了,多維分析是對之前方法論的升級。加上以前的方法論,完整的方法論應該是“業(yè)務理解-->領域建模-->流程分解-->多維分析”。
為了方便大家理解,下面我把這些方法論做一個簡單的串聯(lián)和解釋。
1. 業(yè)務理解
理解業(yè)務是所有工作的起點。首先,我們要找到業(yè)務的核心要素,理解核心概念,梳理業(yè)務流程。
比如,在零售通的商品域,我們要知道什么是商品(Item),什么是單品(CSPU),什么是組合品(CombineItem)。在下單域,我們要知道訂單(order)的構成要素是商品、優(yōu)惠、支付。在 CRM 領域,我們要理解客戶、機會、聯(lián)系人、Leads 等等。
這里,我想再次強調下語言的重要性,語言是我們思考的載體,就像維特根斯坦說的:“凡是能夠說的事情,都能夠說清楚”。
你不應該放過任何一個模糊的業(yè)務概念,一定要透徹的理解它,并給與合理的命名(Ubiquitous Language)。唯有如此,我們才能更加清晰的理解業(yè)務,才能更好的開展后續(xù)的工作。
2. 領域建模
在軟件設計中,模型是指實體,以及實體之間的聯(lián)系,這里需要我們具備良好的抽象能力。能夠透過龐雜的表象,找到事務的本質核心。
再復雜的業(yè)務領域,其核心概念都不應該太復雜,抓住了核心,我們就抓住了主線,業(yè)務往往都是圍繞著這些核心實體展開的。
比如,商品域雖然很復雜,但其核心的領域模型,無外乎就如下圖所示:
3. 流程分解
關于流程分解,在《阿里高級技術專家方法論:如何寫復雜業(yè)務代碼?》里面已經有非常詳細的闡述,這里就不贅述了。
簡單來說,流程分解就是對業(yè)務過程進行詳細的分解,使用結構化的方法論(先演繹、后歸納),最后形成一個金字塔結構。
比如,在商品領域,有創(chuàng)建商品、商品上架、上架審核、商品下架、下架審核、修改商品、刪除商品等一系列動作(流程),每個動作的背后都有非常復雜的業(yè)務邏輯。我們需要對這些流程進行詳細的梳理,然后按步驟進行分解。最后形成一個如下的金字塔結構:
4. 多維分析
關于多維分析,我以二維的矩陣分析為例,我想我前面應該已經說清楚了。
業(yè)務的復雜性主要體現(xiàn)在流程的復雜性和多維度要素相互關聯(lián)、依賴關系上,結構化思維可以幫我們梳理流程,而矩陣思維可以幫助我們梳理、呈現(xiàn)多維度關聯(lián)、依賴關系。二者結合,可以更加全面的展現(xiàn)復雜業(yè)務的全貌。從而讓我們的治理可以有的放矢、有章可循。
既然是方法論,在這里,我會嘗試給出一個矩陣分析的框架。試想下,如果我們的業(yè)務很簡單,只有一個業(yè)務場景,沒有分支流程。我們的系統(tǒng)不會太復雜。之所以復雜,是因為各種業(yè)務場景互相疊加、依賴、影響。
因此,我們在做矩陣分析的時候,縱軸可以選擇使用業(yè)務場景,橫軸是備選維度,可以是受場景影響的業(yè)務流程(如文章中的商品流程矩陣圖),也可以是受場景影響的業(yè)務屬性(如文章中的訂單組成要素矩陣圖),或者任何其它不同性質的“東西”。
通過矩陣圖,可以清晰的展現(xiàn)不同場景下,業(yè)務的差異性?;诖?,我們可以定制滿足差異性的最佳實現(xiàn)策略,可能是多態(tài)擴展,可能是分離的代碼,也可能是其它。
這就是矩陣分析的要義,其本質是一種多維度思考的方法論。
最后,我想說世界是熵增的(即萬物都在緩慢的分崩離析),控制復雜度是我們這些從業(yè)者無法推卸的責任和使命。
軟件行業(yè)的發(fā)展才幾十年,還是一門年輕的學科,軟件工程就像一個剛學會走路的小孩,還很不成熟,有時還很幼稚。
但畢竟還是有幾十年的沉淀,還是有一些好的方法和實踐可以參考,我的這些總結沉淀只是在前人的基礎上,多走了一點點而已。但就是這一點點,也實屬來之不易,其中冷暖,只有自己能體會??梢哉f,這一路走來,是一場對心力、腦力和體力的持續(xù)考驗。
心力是指不將就的匠心,不妥協(xié)的決心,不滿足的好奇心、以及不放棄的恒心。
腦力是指那些必要的思維能力、學習能力、思考能力、思辨能力。
之所以說“業(yè)務理解-->領域建模-->流程分解-->多維分析”是體力,是因為實現(xiàn)它們就像是在做填空題,只要你愿意花時間,再復雜的業(yè)務都可以按部就班的清晰起來。
梳理清晰了,再配合 COLA 的指導,我們就有可能寫出清晰、易讀的代碼,就有可能從一個 if-else coder 升級為一個 complexity conquer。
上述內容就是if-else coder是如何升級,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業(yè)資訊頻道。
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。