“在光速交付軟件功能特性的時候,研發(fā)人員通常選擇不去全局思考便動手實現(xiàn),缺乏周邊人員對齊,沒有對利益相關(guān)者進行充分的訪談就開工了。而用例其實是設計的起點,如果連系統(tǒng)用例都不清楚,又何談實現(xiàn)的是個正確的系統(tǒng)呢。而在我工作的過程中,有的高級工程師對用例2字都未聽說過,或者選擇在心里過一遍用例,而不是邊思考邊畫出來。那么是時候講講用例的重要性,以及為何一定要把它畫出來了。”
以下大部分來自于我的讀書筆記,以及個人思考總結(jié)。
業(yè)務邏輯
什么是業(yè)務邏輯?程序中真正用于賺錢或省錢的過程,無論是計算機執(zhí)行的過程還是人工執(zhí)行(我認為可以總結(jié)為直接創(chuàng)造價值的,而非高可靠,安全,韌性等)。例如銀行貸款,讓計算機計算利息,還是人用計算器計算不重要。關(guān)鍵業(yè)務邏輯通常需要處理數(shù)據(jù)。這些就是關(guān)鍵業(yè)務數(shù)據(jù)。由于邏輯和數(shù)據(jù)緊密相關(guān),因此可以放在一個對象處理,即業(yè)務實體
用例
有的業(yè)務邏輯必須要自動化,而不能靠人工執(zhí)行,即只有作為自動化的一部分才有意義。本質(zhì)是關(guān)于如何操作一個自動化自動的描述,它定義了:
用戶輸入
得到的輸出
產(chǎn)生輸出所需要采取的處理步驟
如上所述,用例控制著業(yè)務實體之間的交互方式。
用例不該描述用戶界面,即不描述用戶和系統(tǒng)間接口,輸入流和輸出流。
業(yè)務實體不知道哪個用例在控制他們(依賴反轉(zhuǎn)原則DIP),底層的用例需要了解高層實體
例子
原始需求:
運維團隊需要高效管控賬號,需要將賬號的申請自動化,減少人工的參與以提升工作效率。
另一方面研發(fā)需要賬號登錄控制臺查看資源,也需要用戶密碼憑證以讓程序操控資源
用戶故事示例:
通過用戶訪談,提煉用戶故事等手段,將上述內(nèi)容轉(zhuǎn)化為用例視圖,我們看下采訪后總結(jié)的用戶故事
作為運維人員,需要控制他人web console的使用權(quán)限,僅賦予研發(fā)只讀權(quán)限,以保證資源的安全
作為研發(fā)人員,需要創(chuàng)建臨時賬號,以登錄到web console進行問題定位和跟蹤
作為研發(fā)人員,需要申請賬號,以配置給程序使用,操作系統(tǒng)的API
用例視圖示例:
說明誰要使用系統(tǒng),以及他們使用系統(tǒng)做什么,是需求分析階段的輸出件。以用例作為設計的驅(qū)動,驅(qū)動后續(xù)的設計,隨時回顧自己的設計是否能支撐用例,保證部署視圖,邏輯視圖,開發(fā)視圖,運行視圖正確性
用例對架構(gòu)設計和業(yè)務展開的支撐
什么是軟件架構(gòu):
軟件架構(gòu)設計的主要目標是支撐軟件系統(tǒng)的全生命周期,設計良好的架構(gòu)可以讓系統(tǒng)便于理解、易于修改、方便維護,并且能輕松部署。軟件架構(gòu)的終極目標就是最大化程序員的生產(chǎn)力,最小化系統(tǒng)的總運營成本。你需要考慮這些事情
開發(fā)
部署
運行:架構(gòu)設計的影響比較小(架構(gòu)掌控不了代碼執(zhí)行效率),一般都可以通過增加硬件解決(短期,后期基于業(yè)務驅(qū)動再優(yōu)化),因為硬件比人力便宜,基于投入產(chǎn)出比,所以才優(yōu)先把優(yōu)化重心放在別處。即便如此,架構(gòu)應該讓開發(fā)對系統(tǒng)的運行過程一目了然,即用例,功能,必備行為,簡化他們對系統(tǒng)的理解,為的是為開發(fā)和維護提供幫助
設備無關(guān)性:滿足開閉原則,高層策略與底層實現(xiàn)細節(jié)分離
維護:成本最高,探秘成本是找到新增功能和修復問題的最佳方式和位置。風險成本是上述修改時,總是衍生新的問題。架構(gòu)的目的是降低兩部分成本
軟件至于硬件最大的不同是什么?是不斷地,快速的變化
軟件架構(gòu)必須支持以下幾點(獨立性):
系統(tǒng)的用例:架構(gòu)必須能支持其自身的設計意圖,架構(gòu)必須為其用例提供支持,因此這是架構(gòu)師首要關(guān)注的問題
系統(tǒng)的運行:如果系統(tǒng)每秒處理1000個請求,架構(gòu)的設計就必須能支持這種級別的吞吐和響應時間
系統(tǒng)的維護
系統(tǒng)的開發(fā):康威定律任何一個組織在設計系統(tǒng)時,往往都會復制出一個與該組織內(nèi)溝通結(jié)構(gòu)相同的系統(tǒng)。這是因為團隊要獨立的完成工作,所以需要隔離良好,可獨立開發(fā)的組件。
系統(tǒng)的部署:便捷性,不該依賴成堆的腳本和配置
保留可選項:
實現(xiàn)以上的平衡很困難,比如我們無法預知系統(tǒng)的所有用例,運行條件,開發(fā)團隊的結(jié)構(gòu),或者系統(tǒng)的部署要求。即便提前了解,隨著演進,需求會不斷發(fā)生變化。即目標是模糊多變的。
采用一些原則可以有助于解決平衡問題。將系統(tǒng)劃分為隔離良好的組件,盡可能的為未來保留盡可能多的可選項
用例解耦:
按層解耦是水平切分,用例則是垂直切分。所以UI,業(yè)務邏輯,數(shù)據(jù)庫等需要按照用例進行解耦。按照變更原因的不同進行垂直切分,就可以持續(xù)的加入新的用例,而不影響老的
解耦的模式:
所有這些解耦對架構(gòu)目標“系統(tǒng)運行”的意義:
分層解耦可以讓組件在不同服務器部署(服務數(shù)據(jù)庫的分層隔離,這有點像SOA,即面向服務的架構(gòu))
按用例,比如不同吞吐的用例可以分開,高吞吐,低吞吐,那么對帶寬不同訴求的組件也可以分開部署在多個服務器上
總之按用例解耦有利于系統(tǒng)的運行(其實這就是微服務)
開發(fā)和部署的獨立性:
當你依據(jù)用例和水平分層解耦后,自然就支持了獨立的開發(fā)互不干擾
消除重復的代碼前要分清真假重復:
真重復:每次變更都必須應用到所有副本
假重復:不同的演進路徑,包括變更理由,迭代節(jié)奏
因此當我們打算合并看似相同的用例時,一定要謹慎否則將來拆分會更難。總之不要因為為了減少重復代碼而合并用例。同理,當水平分層時可能看到數(shù)據(jù)庫結(jié)構(gòu)或者API接口類似就要合并。一定要考慮演進路徑
再談解耦模式:
用例分層的方式很多,比如
源碼解耦(單體架構(gòu)):模塊依賴關(guān)系,一個模塊變更不會導致其他模塊變更
二進制解耦(部署):可能是jar,ddl,Gem,共享庫,只是可獨立部署的單元
執(zhí)行單元解耦(微服務架構(gòu)):網(wǎng)絡通信
項目初期難以確認哪種適合自己,甚至隨著項目的成熟,所謂最適合的模式會出現(xiàn)變更
將系統(tǒng)解耦推行到“一旦有需要就可以隨時轉(zhuǎn)變?yōu)榉盏某潭燃纯伞保@讓系統(tǒng)盡量長時間地保持單體結(jié)構(gòu),以便盡可能保留可選項
因此做到源碼解耦就夠了,隨著項目發(fā)展可以隨時快速拆分。
設計良好的架構(gòu)能允許從單體架構(gòu)開始,逐漸演進為獨立的單元,甚至微服務,也允許回退到單體架構(gòu)。
可悲的故事
從純客戶端轉(zhuǎn)型BS架構(gòu),技術(shù)滿腦子的如何構(gòu)建大規(guī)模服務器集群,選型了三層的“架構(gòu)”(不是真正的架構(gòu),只是一種三層部署拓撲,這也是災難的根因),那么UI,中間件,數(shù)據(jù)庫都可以分別部署了,假設要添加一個字段,每個層都要改。結(jié)果是開發(fā)期根本沒有大型服務器可用,也沒能銷售一個需要大規(guī)模服務器的系統(tǒng)。所有文件都跑在一臺服務器上,維護成本卻很高。—草率的決定無謂的將開發(fā)成本放大數(shù)倍
一個管理租賃車隊的本地業(yè)務,找來的新架構(gòu)師認為運作這個小小的業(yè)務需要企業(yè)級的面向服務的“架構(gòu)”。如果想在銷售記錄添加一個聯(lián)系人要經(jīng)過復雜的處理過程,而且了測試這個復雜的過程,要運行消息總線等一些列基礎服務。— 太草率的采用SOA體系的工具,大量人力耗費在實現(xiàn)SOA架構(gòu)本身
成功的故事
堅信產(chǎn)品不應該讓用戶下載超過一個jar的文件,稱為“下載即可執(zhí)行”這一條規(guī)則就指導了之后的很多決策。
決策1:自研web服務器,沒有使用開源的,因為編寫一個基本功能的web服務器非常簡單,且延遲了技術(shù)決策
決策2:避免考慮數(shù)據(jù)庫,采用數(shù)據(jù)庫無關(guān)的設計,只需要接口屏蔽。實現(xiàn)內(nèi)存數(shù)據(jù)存儲哈希表。當系統(tǒng)需要持久化,再次考慮是否用mysql,最后認為哈希表寫入文件更簡單,精力繼續(xù)放在開發(fā)新功能上。三個月后得出了一個結(jié)論,文件存儲就足夠好了,完全不需要mysql(減少mysql的引入這就減少了大量的維護成本,表結(jié)構(gòu),三方件,密碼管理,查詢問題,數(shù)據(jù)庫服務器,可靠性等與業(yè)務價值沒有直接關(guān)系的成本)。直到有一天一個客戶自己需要將數(shù)據(jù)寫入mysql,他用了一天就實現(xiàn)了mysql存儲。軟件包分發(fā)后,沒人實際用到mysql,連寫這個mysql實現(xiàn)的客戶都沒有。
在早期,他們在業(yè)務邏輯和數(shù)據(jù)庫間畫了一條邊界線,防止了業(yè)務邏輯對數(shù)據(jù)庫產(chǎn)生依賴,使用文件系統(tǒng)做實驗,反倒發(fā)現(xiàn)是更好的方案,而這也不會造成使用mysql的障礙。即通過劃清邊界,推遲和延后細節(jié)性的決策。以節(jié)省大量時間、避免大量問題。這就是助益
架構(gòu)設計的主題:
A use case driven approach中的觀點:系統(tǒng)架構(gòu)應該為用例提供支持。架構(gòu)的設計圖應該凸顯用例。
架構(gòu)設計和技術(shù)手段,框架無關(guān),他們都是手段。而不是架構(gòu)設計中包含的內(nèi)容。
架構(gòu)設計的核心目標:
圍繞用例展開設計,脫離框架,執(zhí)行環(huán)境等因素描述用例。在確保用例需要的前提下,盡可能保留自由的技術(shù)選型。
框架不是信條:
選擇框架要思考如何保護自己(就是用例,團隊等等,不要綁定到框架上),保持對用例關(guān)注,不要被框架主導設計
用例對單元測試的價值:
針對用例進行單元測試
總結(jié)
可以看到用例可以成為你后續(xù)很多架構(gòu)決策的重要依據(jù)。是否應該用SOA架構(gòu),還是微服務架構(gòu)還是單體架構(gòu)?
用例的另一個價值
新來的程序員是否能從設計中一眼就看出來系統(tǒng)名稱?新人也應該先了解系統(tǒng)的用例,而不是技術(shù)實現(xiàn)。先不要考慮技術(shù)細節(jié),以后再決定應該怎么做。
原文鏈接
https://mp.weixin.qq.com/s?__biz=Mzg2OTU0MzE1Mg==&mid=2247483816&idx=1&sn=7c877744e6cb0d30642d6e001ce1d639&chksm=ce9a3c37f9edb521a8ce07359db952e73ef1fef6f3f8e62e5900dbf8876f84d673ca9d8f4119&token=1791162348&lang=zh_CN#rd