建模對於大家來講並不陌生,而且建模的方法也有很多,如用例建模、四色建模、事件風暴等,但在日常工作中,大家又覺得建模挺虛的:怎麼把建模落到實際開發工作中。個人認為建模是分兩部分:第一部分是業務概念建模,對現實業務抽取核心概念構建出模型(知識層);第二部分是系統建模,系統建模是源於業務概念模型,遵循某些... ...
建模對於大家來講並不陌生,而且建模的方法也有很多,如用例建模、四色建模、事件風暴等,但在日常工作中,大家又覺得建模挺虛的:怎麼把建模落到實際開發工作中。個人認為建模是分兩部分:第一部分是業務概念建模,對現實業務抽取核心概念構建出模型(知識層);第二部分是系統建模,系統建模是源於業務概念模型,遵循某些原則最終形成開發可落地的模型(操作層)。在本文中,給出建模的底層邏輯:用圖形邏輯地表達現實業務的抽象,通過一些大家通識的技術案例講述建模的過程。
一、建模的底層邏輯
建模的作用不言而喻,它可以極大簡化大家對複雜事物的認識,讓人能在短時間內有全局視野看清楚業務,而且建模是用面向對象的思維分析事物,也容易轉化成類圖。用一個公式表達建模的底層邏輯:建模 = 圖形 + 邏輯 + 現實的抽象,用一句概括即是用圖形邏輯地表達現實業務的抽象,接下麵主要講述圖形、邏輯、現實的抽象這三部分的內容。
1.1 圖形
圖形即為UML圖形,下麵是6種對象間的關聯圖形,在建模中儘量遵循UML標準畫圖,方便大家理解。
-
繼承:子類繼承父類的特性,有的語言僅支持單繼承。
-
實現:子類實現父類定義的介面。
-
組合:一個類包含另外的類,但它強調的是一種強關聯關係。
-
聚合:也是表達一個類包含另外的類,但它的關聯關係比組合要弱。
-
關聯:通過一個類可以關聯到另外一個類,可分為單向關聯和雙向關聯,一般以類的成員變數體現。
-
依賴:比較弱的一類關聯關係,一般是以介面參數的形式體現。
1.2 現實的抽象
我們的現實業務有的是非常複雜的,如果涉及到專業領域概念,新手想入門是挺難的,當我們不清楚業務鏈路和邏輯時,直接看代碼實現時很難有全局的視野,不能夠串起全局業務間的內在聯繫。當我們切入到一個新領域中,並非短時間內就要成為該領域的專家,急需一種方法用20%的時間能夠掌握該領域80%的業務知識,一個可行的方法就是建模,通過對現實業務進行抽象,構建出全局業務概念模型,有了全局的認識,再去瞭解業務細節就會快得多。模型好比地圖,先做到心中有譜,再"按圖索驥",我們比較迷茫時,往往是看不到全局的"地圖",因此也就做不到心中有譜。我們要建模的對象即是問題域,我們並不需要覆蓋所有的點,而是基於核心的內容進行建模,Eric Evans 在建模書中提到一個觀點:建模是出於某種目的而概括地反映現實,這裡的概括就是抓住核心的意思。現實的抽象有三層意思:一類是直接映射,比如現實有一個杯子,那麼我們的模型中就有一個杯子;另一類是往上抽象一層映射,比如我們的組織中有一級結構、二級結構、三級結構等,那我們可以抽象成組合結構,形成父子節點的結構,這種抽象就更靈活了;最後一類是隱性抽象,前面兩類抽象比較容易做到,最難的是隱性概念抽象,它很大可能是之前不存在的,需要新造出一個概念,就像軟體設計中,通過新增加一層來實現解耦一樣,通過新造的概念串聯元素間的內在關聯關係,如下麵示例的中的"債權"概念。舉一個金融理財的案例,需要將投資的錢給到借款人那裡,然後借款人還款時將還款給到投資人,當投資人的錢給到借款人時,就產生了債權關係,因此有一個債權的概念,這記錄了投資人與借款人間的債務關係,債權就是一個橋梁。當借款還款時,對應的債權就會減少,當投資周期到了,債權就會進行債權轉讓,轉到下一個投資人身上,當前的債權關係就結束了,下圖雖然比較簡單,但對理解系統至關重要。
1.3 邏輯
邏輯即為因果,也即元素之間存在某種關係,如果兩個完全沒有關係的元素放在一些,就會顯得前因不達後果、風馬牛不相及,讓人不好理解。那麼對應到建模上,我們的模型應該是非常具有邏輯性的,從模型上能看出業務核心要素,要素與要素之間的關係是怎樣的。邏輯主要體現在時空兩個維度上:時間維度,一件事情節點完成之後,會影響後續的事情節點;空間維度,更多的體現在結構上,我們常說的空間結構就是這個意思。以時間維度為例,在電商結算中,當訂單支付成功後,結算收單,收單後接受到放款的執行指令,在放款之前需要計算出放款明細信息,如賣家應收到多少錢、公司應收到多少佣金等,最後是打款轉賬,這個過程就是按照時間節點不斷往後驅動,可抽象出如下圖的模型。
空間維度即是結構關係,比如下圖中的組織結構,像這樣的結構類型,我們還可以找到更多的實際案例,比如交易訂單有主子訂單結構,執行單包含多個執行明細信息,模型最終呈現出來的就是一個結構,從結構維度也可以將其分解出更小的粒度。
不管哪種建模的方法,最根本的還是體現出了建模的邏輯性,用例建模的邏輯性體現在能夠清晰地定義出用例場景,把所需要做的事講清楚;四色建模通過人、事、物、時間、地點維度描述清楚一件事;事件風暴通過時間軸勾畫出核心關鍵的事件。當我們構建不出模型時,並不是我們缺少建模的方法,而是建模的邏輯性上有問題,建模缺的不是方法而是經驗和實踐。我們不能神化建模,建模是很純粹的,就是為了簡化對複雜事物的認識,並且模型能夠映射到實際開發的模型中。
二、建模的方法
建模的方法有很多種,方法多並不意味著建模的難度會很低,相反建模的門檻很高,對抽象思維要求非常高,而且建模並沒有標準的答案,因此很多人覺得沒啥意思。其實這裡面有兩部分:一部分是源於業務概念的抽象,它需要對業務的理解和抽象,往往大家在這一部分覺得沒啥意思;另一部分是在業務概念模型的基礎上,結合設計原則,最終設計出合理的系統模型,這部分是考驗大家的設計功底。下麵列舉2種實踐中常用的方法,這些方法並非是新的方法,是在日常工作中不斷總結、實踐出來的,具有更便捷實用性。
2.1 定義法
定義法建模的核心思想是通過簡潔的一句話描述事物,然後根據定義進行建模,雖然方法聽起來很簡單,但真正用熟還需要大量的實踐。
2.1.1 命令設計模式建模
命令模型在23種模式中,相對還有點複雜的模式,有一句話描述命令設計模型:A下達了命令,B接受到命令後按要求執行。將A抽象成命令發起者,B抽象成命令接受者,因此很容易找出有三個對象:命令發起者、命令接收者、命令。接下來就分析這三個對象間的關係:
- 命令發起者與命令的關聯:命令是命令發起者發起的,因此命令發起者是要感知到命令的,具體地表現就是命令發起者是要包含命令的。
- 命令接收者與命令的關係:命令接收者是具體執行命令的對象,到底是命令接收者關係命令,還是命令關聯命令接收者呢?這個可以看誰變化的可能性比較大,應該用穩定的對象包含易變的對象,根據現實經驗,命令相對穩定,而命令接收者是易變的,比如做菜,今天是張三做,明天可能就換成了李四了。
-
命令發起者與命令接收者的關係:它們之間是不會產生直接有關聯的,是通過命令進行解耦的,命令發起者定義做什麼,命令接收者完成具體的工作。
最終命令設計模式的概念模型如下圖所示。
2.1.2 導航欄建模
店鋪導航欄平時大家在瀏覽店鋪時常遇見,可以點擊不同的導航Tab看到不同的商品,比如新品、爆品等。用一句話描述導航欄:導航欄是由若幹個導航Tab組成,點擊導航Tab渲染出對應的頁面。很容易分析出有兩個對象:導航欄、導航欄Tab,但在導航欄Tab中還隱含了另外一個對象:導航欄Tab規格信息,這個規格信息描述了Tab的顏色、排序、跳轉鏈路等信息,因此我們可以很容易畫出導航欄的概念模型圖。
很可能有些人覺得這個例子太簡單了,如果你按照這種思路分析業務對象,是有別於傳統面向過程分析的,比如導航Tab該不該展示是由它自己負責的,並不是在一個大的方法里控制的。
2.2 因果法
因果法的本質同事件風暴建模一樣的,在用熟的基礎上按照自己的習慣進行運用,不管什麼方法,只有內化成自己的方法才有用。它的核心是基於一個對象不斷往前和往後找因果關聯對象,最終構建出完整的業務概念模型。
2.2.1 Spring容器建模
Spring IOC容器對大家並不陌生,以這個案例描述因果建模的方法。首先Spring IOC是一個工廠,因此有一個BeanFactory對象,同時它會包含業務Bean對象,因此最簡單的一個Spring IOC 概念模型如下圖所示。
接下來就需要不斷追溯了,Bean是怎麼到Bean工廠中的呢?應該有一個Bean註冊器,在上圖的基礎上,再完善下。
再想這個Bean是怎麼來的呢?即哪些業務對象會標識成要放到Bean工廠中的,會有一個掃描器掃描業務對象,發現有標識@Componet、@Service等註解的類需要放到Bean工廠中,因此這裡面就會有三個對象:BeanDefinitionReader、BeanDefinition、BeanDefinitionRegistry,迭代後的Spring IOC概念模型如下圖所示。
雖然這是一個簡陋的Spring IOC概念模型圖,但它還是把Spring IOC核心包含的對象展示出來了,結合現實需求,我們還可以加一些對象進來,比如考慮擴展性,會有BeanFactoryPostProcessor等。這裡僅僅是一個業務概念模型,具體到系統模型需要結合設計原則來設計,如Bean工廠在實際中會拆分成多級Bean工廠繼承的關係。
三、建模案例
根據第二節中講的方法,下麵通過三個技術案例描述在實際學習中的運用,通過模型可以快速讓我們理解技術涉及的原理,當我們有了基礎理解後,再去看技術框架源碼時也會快得多。
3.1 非同步事件建模
非同步事件對於開發來講並不陌生,將事件定義與事件執行進行解耦,用一句話描述非同步事件:事件發佈者發佈一件事件後,經由事件分發器分發後,找到對應的事件監聽器處理。這裡面就包含了四個對象:事件發佈者、事件分發器、事件監聽器、事件。事件發佈者是將事件發佈到事件分發器上,因此事件發佈者是需要關聯事件和事件分發器;事件分發器通過事件類型匹配,匹配上事件後調用對應的事件監聽器進行處理,因此事件分發器包含了多個事件監聽器。非同步事件的概念模型圖如下圖所示。
在Spring事件廣播器中,有添加事件監聽器,以及通過事件查找到對應的事件監聽器進行處理。
3.2 切麵建模
切麵編程在實際工作中應用得也比較多,比如在服務上增加橫切功能,如日誌列印、方法耗時統計等,接下來用因果建模法對切麵進行建模。最開始有一個目標對象,即為我們要增加橫切功能的對象,那麼怎麼表達這個橫切功能呢?至少要包含三種信息:誰需要被增強?;增強的邏輯是什麼?;什麼時候增強?,描述誰需要被增強的對象抽象成切點。增強的時間節點抽象成通知。因此可得出初步的模型。
目標對象與切麵是怎麼關聯上來的,相當於在目標對象的方法前後要額外增加一段邏輯,可以通過代理來實現,因此有一個代理對象,它會鏈接目標對象和切麵,最終切麵業務概念模型如下圖所示。
當熟悉了切麵業務概念模型後,再去看Spring AOP的源碼會容易些,模型就是簡化認識,提煉出核心關鍵的事物要素。
3.3 ORM框架建模
ORM是將傳統SQL映射到對象上,更符合面向對象的習慣。同樣我們使用因果建模的方法,ORM框架在底層最終還是要執行具體的SQL,因此將SQL語句抽象成Mapper,資料庫配置信息抽象成配置信息,有了這兩個配置信息,自然有對應的解析配置的類,初步的模型如下。
將執行SQL的過程抽象成會話,會話會執行SQL,將執行SQL的對象抽象成SQL執行器,在SQL執行過程中,需要做兩件事:一件是參數解析;另一件是結果解析。最終的ORM框架概念模型如下圖所示。
在執行器中,我們可以看到有配置信息、參數信息。
四、建模經驗總結
4.1 能清晰地描述事物建模就成功了一半
建模是將混沌的事物抽象成有序關聯事物的過程,混沌到有序,因此我們需要梳理清楚事物間的關聯關係,如果我們都不能夠清晰地描述事物,是很難建模的。不能夠描述清楚事物,說明我們自己都還沒有理清內在的關聯關係,也就做不到抽象出有序的模型。在日常工作中,可以嘗試用幾句描述一件事,看大家能不能理解到。在學校老師經常讓我們概括文章的中心思想,就是鍛煉這種建模能力,通過幾句話把文章的核心內容勾畫出來。我們在軟體建模也是一樣的,通過幾句話把業務的涉眾、業務結構、業務目標、核心關註點表達出來,然後通過業務概念模型呈現出來。
4.2 通過描述事物的結構是建模常用的方法
模型最終呈現出來的是一個圖,這個圖往往是有清晰的結構,比如房屋模型,它就有自己的結構:坐北朝南,有大廳、睡房、廚房、洗手間等,軟體模型也是一樣的,在2.1.2節中舉了一個店鋪導航欄的例子,如下圖所示,當我們看到店鋪導航欄時,可以想像下它是怎樣的結構。
在實際的業務中,有兩類模型:一類是偏結構型的模型;另一類偏行為型的模型,從個人接觸到的業務看,結構型的模型偏多,比如訂單有主子訂單模型。我們也可以嘗試從結構的角度去定義事物。
4.3 建模要區分知識層和操作層
模型一般有兩層:一層是知識層;另一層是操作層,知識層中包含的概念是通識的概念,往往是面向使用者,比如我們在使用AOP切麵編程時,可以用@Aspect、@PonitCut、@Before等註解時,它們就是屬於知識層,知識層的內容抽象層次比較高,大家比較容易理解,我們所做的業務運營工作台也是做的知識層的內容,比如配置頁面模板、站點配置等,這些可枚舉的維度都是知識層。另一層是操作層,操作層是支撐知識層的,還是AOP為例,底層有對註解的解析、動態代理的生成等;再比如Spring IOC中,有各類Bean的註解,在操作層中,有BeanDefinition的載入、識別、解析、Bean實例化、Bean初始化等,操作層中的實現也並非面向過程的設計思維,它也包含了抽象設計和遵循某些設計原則,這一點在下一節中會專門講到,同樣的設計,張三和李四可能不一樣,正所謂"文無第一,武無第二",大家的設計理念、角度不一樣,技術設計本應如此,就像一百個廚師做同樣的菜,做出來的菜也有一百個樣。如果知識層偏表達,那麼操作層就是偏實現支撐,這兩類的視角也是不一樣的,知識層更抽象,而往往我們開發人員更關心的是操作層中的具體實現類,缺乏抽象意識,這也是我們自己心中非常清楚,但別人很難理解,需要轉換視角,思考通識的知識層有什麼。
五、小結
在文章中主要講述了建模的一些方法,方法雖然簡單,但用熟還是需要大量的實踐經驗,建模分為兩個階段:第一個階段是業務概念建模,它無關於技術,是通識的建模(知識層);第二個階段是系統建模,基於業務概念建模的基礎上,考慮具體的技術實現(操作層),遵循某些設計原則構建可落地的模型。建模的確會簡化對複雜事物的認識,以學習技術框架為例,如果一頭扎進源碼中,很難有全局觀,相反如果我們從全局對技術框架有一定的理解,再去看源碼也會快很多。
作者:高福來(不拔)
本文來自博客園,作者:古道輕風,轉載請註明原文鏈接:https://www.cnblogs.com/88223100/p/Software-Engineering-Bottom-Logic-Series_The-bottom-logic-of-modeling.html