從使用者需求、談架構設計(二)- Clean Architecture 一個整潔的架構篇
前言
前一篇文章中『從使用者需求、談架構設計』,筆者以一個房貸線上申請系統的例子,關於一個從使用者需求、來談架構設計的一個比較實際的例子,當時,筆者以 UML/OOAD 常見的循環星型分析法,帶著各位由系統分析開始、如何串聯到系統設計、並解釋因為從系統設計開始,便可牽涉到 Platform/OS/Framework/程式語言 等等,而在 UML 這裡也有模型驅動架構 MDA (Model Driven Architecture) 可以補助,課程中,我也利用的這樣的概念,將 Domain Class Diagram 帶入細部 Class Diagram 分析時,拆解為兩塊,一個是 BO (Business Objects) 另一個是 VO (View Objects),接著,並實際的撰寫程式,並實作出最小可行性產品。
在今天的這一篇文章裡,我將利用在 Clean Architecture 書中的一個整潔的軟體架構的概念,將我三年前所設計的 EasyArchitect Framework 來做一個應證,從頭來探討軟體開發、從需求面開始、你的需求大方向的掌握度其實會決定你的架構設計的方向性是否恰當、符合所需、不是過度設計的架構。好,我們接著往下看。
需求掌握度
圖(一)、Impacts Mapping to User Story Mapping
圖片來源:https://www.slideshare.net/chassa/2014-0618srdimpact-mapsstorymapsen
為什麼談需求的掌握度?訪間,許多軟體開發方法告訴你的大部分是,何時該做什麼、那些角色該關注什麼?有哪些會議?什麼時候招開?該注意什麼?以敏捷創建使用者故事地圖(User Story Mapping)來說,它敏捷需求規劃中的一個流行方法。用戶故事地圖可以將你的 Backlog 變成一張二維地圖,而不是傳統的簡單列表。用戶故事地圖可以讓你更容易看清 Backlog 的全貌。這概念真的非常好,因為它幫助你有更好的進行疊代的增量式開發,同時確保早期的發布,可以驗證整體架構和解決方案,為傳統的開發計劃提供了一個更好的替代工具。
且創建 User Story Mapping 可以有七~八個步驟,因為篇幅關係我不在這一一說明,第一個步驟是招集 3-5 對產品熟悉的人一起討論,並讓每個人在便簽紙上寫下自己認為重要的「所要做的事情」也就是用戶任務(User Task)。每個人都用同樣顏色的便簽來書寫自己的用戶任務描述。
到這個階段時期都不太會有問題,但大家不要忘了,這是當 Product Owner 有掌握住客戶所需要價值的精隨時,那麼後續的需求的收集、用戶任務(User Tasks)組成所謂的『用戶活動(User Activity)』才是真正有價值的,別忘了我們做軟體、撰寫程式中就是要給客戶使用的,能夠替客戶創價值的軟體,才是對客戶有用的軟體,這也才是能夠讓客戶買單、收到錢的軟體,因此,3-5然撰寫 User Task 時,不用自己的想像在寫,應該是你要去跟客戶確認。
所以 PO 要聽得懂客戶帶底在說什麼,Product Backlog 的全貌才是正確的全貌
3-5 人討論的發想,不是自己想像客戶要什麼!是你要去問客戶
軟體架構與成本的關係
也許有些人會好奇,到底軟體架構與成本有著什麼樣的關係?事實上,這關係可大了,在 Clean Architecture 的第 17 章、(畫線、邊界) 裡,提到了兩個悲慘的故事,就是因為架構師過早決定一個軟體的架構,只為了先快速交付給客戶或市場一個版本,而悲慘的結局就會是,當你交付 Release 2 ~3…. 直到 5, 6 版時,所增加的開發工作可能高出 40 倍!為什麼呢?我們來看下面圖(二)、每次交付的程式碼修改成本
圖(二)、每次交付後程式碼修改成本
圖片來源:http://agileage.blogspot.com/2011/07/slow-and-dirty-rant-by-jason-gorman-at.html
圖(二)中的一個爛攤子的例子便是在 Clean Architecture 中,所禪述的一個過早決定架構設計並提前快速交付後,後續的 Release 成本便呈現急速的倍數成長,因為架構師本來的目的應該是要盡量減少建置和維護軟體所需的人力資源,如中會如此耗盡人力資源的原因是什麼呢?其實就是『耦合』這件事情,特別就是過早決定一些不成熟的事情,哪一種決定是不成熟的呢?比如與系統『業務需求 (Use Case) 』無關的決定、像是使用何種框架、使用哪一種 UI?(MVC/ASP.NET Web Form/WPF?)、哪一種資料庫 等等
註:在 UML 裡的 Use Case 的『系統邊界 Boundary』剛好能夠協助我們定義清楚『系統邊界』
如何最小化人力資源
前面我們提到,架構師應該是要能夠盡量減少需要維護、建置軟體所需的成本,其實,就是因為『耦合性』,所以在一開始,不應該過早決定一些事情。在 Clean Architecture 的(第 17 章節、邊界)、中,約 137-138 頁裡,提到了一個失敗的案例,一個關於 P 公司過早決定使用三層式架構,以及過早決定一種 SOA 的平台技術,導致一個欄位的修改,必須從 UI 開始 、修改 ServiceRegistry、一路改到 Middleware 的 ServiceContract,因為你必須送一個有效訊息到後端的 ServiceContract,因為 UI 與 Middleware 的 WSDL 耦合得太緊,UI 也已經與 WSDL 耦合再一起,已經無法修改為其它種的協定,導致有一個修改也將導致大量的 WSDL 的重新佈署。
好,所以,那成功的軟體架構是什麼?在 Clean Architecture 一書裡的解釋其實就是畫線、或者說分界,其實白話的講,就是關注點分離的開發,UI 與 控制邏輯、Business Rule 的耦合性先定義清楚的介面 (Interfaces),因為在開發的過程中,我們知道業務規則,也許是一部份,但我們先保留接口,當我需要資料存取時,也許是 MySQL、或者是 TxtFile、但還不知道,但 Business Rule 並不需要資料來源實際的儲存體是什麼?他只需要知道 IReposiroty 提供什麼介面即可,甚至我可以先做個假物件 (Fake Object),我一樣可以開發、並撰寫程式。即便我後端需要一個 Web API,但在我還未實作這個 Web API 時,我一樣可以撰寫一個具備 UI 的基本互動性功能。
另外一提,在看 Clean Architecture 的時候,我才發現,其實先前,筆者開發的 Web API 的框架其實早就做到這些要件了,我們使用 JSON 作為前端 UI 與 服務端 Web API (Services Layer) 傳遞主要標準,所以對我們來說,你使用 ASP.NET MVC/Web Form 或這甚至是 WPF 或 WinForm 應用程式,對我來說都只是一種 UI 而已,完全不影響 Web API 層的設計,而服務層在這個框架 Easy Architect 上,完全使用動態的掛載 BO (Business Object) 的方式,可在不停機的狀況下佈署新增功能,而且 BO 元件完全使用 AOP 機制來掛載各種功能,比如:Log 機制、Exception Handler 機制、與權限控管,所以 BO 的開發人員可完全專注在商業邏輯的開發,也降低開發的門檻,並以此作為統企業內部的開發方式,與團隊共同規範。
所以,當時,我們企圖達成的效益如下:
- 降低企業開發負擔、降低軟件開發成本
- 統一並規範企業內的開發方式
- 維持單一的開發環境與版本
- 便於系統維護、交接
- 提高開發組件的重用性與傳遞性
- 採用一致的開發技術與架構,避免遭遇技術瓶頸、減少管理問題、 降低管理成本
- 維持服務器端之商業邏輯的一致性與重用性,並確保品質
- 且降低開發人員 Skill Set、甚至有 C# 開發經驗者便可以撰寫 BO,因此便於開發委外開發、招募、與訓練
- 提供一個基礎之開發平台,以達成:
- 建立可抽換之應用程式模塊(不需要重新 re-Build,即可更新應用系統)
從 User Stories Mapping 來探討你的軟體架構
上面,剛剛我們討論了軟體架構設計中、成本與如何使一個軟體架構設計來有效的降低、最小化你的人力資源,現在,我們再回歸到一個(軟體/產品)開始進行開發時,使用者需求如何收集?因為用戶故事地圖要能夠被精準的抓出來,前提是,你(訪談者/SA/PO/PM)你要聽得懂客戶在說什麼?
需求訪談,準備哪些東西?
- 事前準備工作有哪一些?
- 事先作好功課,不是到了客戶端,才想要了解什麼
- 事先做了功課,並將不了解、需要詢問/釐清的部分,事先整理好一份清單
- 了解需求談對象的主要產品?公司背景、營運項目、主要營收、商業智慧 為何?
- 要做的系統內容、需求名稱、項目為何?
- 快速記錄需求的工具
- 筆記本
- 如果使用筆電,使用月方便的工具越好、能夠快速紀錄為主,比如:OneNotes、MindMap 等等
- 平板電腦
- 錄音筆
訪談者帶回需求,回到公司並且整理過、產出 Product Backlogs 後,這個時候,才是真正進入到敏捷需求規劃中的一個流行方法,前面一直提到的『用戶故事地圖』,將你的 Product Backlog 展成一張二維地圖。
作法如下圖(三)所示,敏捷建議 3-5 人為一個小組的編制,過多或過少都不好。
圖(三)、建立用戶故事地圖 User Story Mapping 的基本步驟
這是一般敏捷常見的做法,使用 3-5 人小組來創建用戶任務(User Tasks),至於為什麼是 3-5 人,因為人數過多不容易取得共識,人數太少又沒辦法有充足的討論而遺失一些重點,當所有組別討論出用戶任務後,在使用不同顏色的便利貼、排列在下方,並對每個組別進行命名,接著,然後再對這些便利貼進行排序,通常較重要的會先指出來,如果有些 User Task 大家無法決定其順序,那麼代表它可能不是那麼重要。
圖(四)、用戶故事地圖 User Story Mapping 與 規範
圖片出處:https://seanvantyne.com/2017/08/20/user-story-maps/
如何將用戶故事地圖推展到 Modeling 分析工具裡?
在實際的應用系統開發領域裡,有許多朋友常常問我,為什麼你使用 敏捷 或者 Scrum 後,卻還要繼續使用 UML?我便反問他,難道敏捷有約束你,要使用何種 Tools 來進行軟體系統的開發嗎?敏捷要告訴你用什麼樣的 Patterns 來設計你的系統?讓你的系統有足夠的擴展性、延展性、或擴充性?敏捷是種文化,這完全是兩者不搭嘎的事情,甚至還有朋友說他們公司導入敏捷後,就不寫任何文件了,讓我擔心你們是怎麼 Run 敏捷的?
在我上一次的『決戰 OOAD 系列課程 – 使用 UML』課程中,我解釋了一種方法,一種如何將你最後產出的『用戶活動 (User Activity)』與 最後更加細節的『用戶故事 (User Story)』推展至 Use Case 中,有興趣的讀者可參考我另一篇文章『決戰 OOAD 系列(一):使用 UML 分析的黃金三角』,下圖即展示這種情況的用法。
圖(五)、將用戶故事地圖 User Story Mapping 推展至 UML 的 Use Case
如果運用得當,User Activity 甚至可以對應為 Use Case 的主要事件流,因為一個用戶故事 User Story 代表一件使用者所關心的事情、User Activity 則代表可對使用者產生價值的用戶活動,這個活動對 Use Case 的來講,因為一個 Use Case 也代表著一件使用者關心的事情,一個 Use Case Diagram 最好只有一個『使用案例的主要事件流』,這我在決戰 OOAD 系列課程中,講得非常的清楚,所以,在我的團隊,是這樣順利的與 Modeling Tool 相結合,並使用在架構設計上。
一個整潔的架構 Clean Architecture
前面我們提到,一個良好的架構設計不該在一開始決定不應該決定的事情,譬如:UI 類型、使用的 Web 伺服器類型、或資料庫,而且應該要有基本可獨立開發的分層、低耦合。
圖(六)、一個整潔的架構 Clean Architecture
圖片來源:https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html
在 Clean Architecture 一書中,在第 22 章、提到一個整潔的架構,它應該具備以下特徵:
- 獨立於框架:也就是說,一個好的軟體架構不應該相依於一些功能強大的軟體程式庫,因為這樣會讓你這個軟體架構的擴充性受制於那個產品。
- 可測試:好的軟體框架應該要可以在沒有 UI、Web Service/Web API、資料庫 的時候進行測試,也就是類似在,有妥善的介面 (Interfaces) 下,應該可以撰寫 Isolation Unit Test 的概念
- 獨立於 UI:好的框架應該獨立於 UI,也就是不受至於 UI,我可使用任何一種 UI,我可以更改使用任何一種 UI,比如:ASP.NET MVC/Web Form/WPF 、而不需要修改我的商業邏輯
- 獨立於資料庫:在你的商業邏輯上,我可以任意抽換為 Mango DB、MSSQL Server、Oracle 等,也就是你的業務規則不應該綁訂資料庫。
- 獨立於任何外部代理:也就是說,你的業務規則應該不受外界的介面所影響。
而今天,我將用我先前所開發的 EasyArchitect 的 Web API Framework 的框架來進行開發,這個框架,在我看完 Clean Architecture 之後才驚覺,原來我三年前所開發的這個 Web API Framework 原來已經具備了 Clean Architecture 裡所提的低耦合性、與關注點分離等特性,如果就上面的五大特性來加以說明 EasyArchitect 的話,那麼可以這樣來說明:
獨立於框架:EasyArchitect 完全使用原生 .NET Framework 所開發,除了 ASP.NET MVC 相關的 NuGet Packages 外,完全不相依現有其他產品。
可測試:它的 BO (Business Object) 的開發方式完全分層、隔離,可在沒有 UI、Web Service/Web API、資料庫 的時候進行測試
獨立於 UI:EasyArchitect 的 BO 即是(業務邏輯/商業邏輯)的撰寫處,交換的資料格式為 JSON,所以與 UI 沒有任何相依存在,且 EasyArchitect 針對不同的 UI 提供不同的 Backed End Service Client 的連線代理,有 ASP.NET Web 版的、WPF 版、也有 Front-End Framework 的 JavaScript 版,所以 UI 也完全不需要知道後端是何種的提供者。
獨立於資料庫:EasyArchitect 只提供 Clean Architecture 中所提的 綠色圈圈以內 Controller 與 Gateway、包含 Use Case/Entities,而保留接口給後端的 Repository 使用,所以常搭配我自行開發的 MyORM 來進行開發,因為全隔離,所以你要使用 Entity Framework 或是原生 ADO.NET 自行開發都可以。
獨立於任何外部代理:EasyArchitect 的 BO 元件動態 Assembly.Load() 載入方式,幾乎獨立於各種平台,因此不一定要在 IIS 下執行,任何能夠掛載 .NET 應用程式的 Host 並且支援 Assembly.Load() 讀取方式便可掛載,執行商也邏輯的程式碼,交換的資料都是 JSON 格式。
開始進行實務開發
假設,我現在有一個需求,建置一個銀行行員內部系統的『審核新進員工資料畫面』,這個需求非常簡單,在釐清 User Activity 後,有一個需求是,行員可以在員工管理系統裡,查詢新進、未審核的員工資料,我們將它對應到 Use Case 的『使用案例的主要事件流』,得到如下圖 Use Case:
圖(七)、UC_01_審核新進員工資料
但是必須時做到以下幾點:
1. 商業邏輯層獨立於 UI,我可以使用不同的 UI 實作不同裝置上的 UI 並存取相同的業務邏輯
2. 撰寫業務規則程式碼的開發人員,只需要專注在商業邏輯
3. 容易佈署
首先,我們以下面步驟來進行:
一、建立、區分方案資料夾
二、建立BO元件
三、建立 DataAccess 專案
四、建立 WebHost 專案
五、建立 VO (Entities) 專案
六、撰寫 BO 元件的程式碼
七、在 WebHost 專案安裝 EasyArchitect.Client.BackendServices.jQuery 的 NuGet 元件
八、撰寫 View
九、撰寫 .js 檔案
這邊我們使用 Vue.js 搭配 Backend Client Service for jQuery 來對伺服器的商務邏輯(BO, Business Object)來做存取,我們只需要撰寫程式碼如下:
總結:
經過這幾個步驟,我們輕易可以撰寫出基本需求的應用程式,且兼具足夠的可維護性、彼此之間沒有強烈的耦合性、具有非常高的彈性、開發時關注點又極端的分離、互不受干擾。
另外、這邊的開發均大量的使用了我自己自定義的 Visual Studio Project Template,先前我也有線上課程在講授這個部分,有興趣的朋友們可以參考線上課程:『如何利用範本精靈 (C# Project Template) 簡化重複開發工作』
相關文章:
關於 Gelis:
資深 .NET 技術顧問
FB 社團 (軟體開發之路):
https://www.facebook.com/groups/361804473860062/
FB 粉絲團 (Gelis 的程式設計訓練營):
https://www.facebook.com/gelis.dev.learning/
我講授過的課程 SlideShare:
https://www.slideshare.net/GelisWu
以下是我經營的項目與內容:
(1). 企業內訓課程
(2). 專業顧問
企業內訓課程:
1. .NET Core 3.1 從入門到進階
先前實體課程連結
2. 跨平台的 Web API Framework 框架設計
先前實體課程連結
3. 決戰 OOAD 系列課程 - 使用 UML
先前實體課程連結
4. 單元測試 UnitTest 與 Moq 物件實務課程
先前實體課程連結
5. 快速開發系列 - C# Project Templates 範本設計
留言
張貼留言