前些時候,我們團隊所輔導 (並主導其中的核心開發)某家頗具知名規模的商務網站,該公司經營者總覺得他們原來的開發產出速度緩慢,希望能借重我們在實務開發上的經驗,而能改善開發製程,加速開發上的產出。
我發現到 (應該也可說是意料中事),即使是擁有10幾個以上開發人員的大型網站系統開發,其所謂的系統分析/設計的開發模式仍是採以最典型的 Client/Server 方式。Client 端(也就是 Web 端)主要採以畫面為主的需求分析;Server 端則以資料庫的資料模型為設計核心。
簡單的說,這類開發模式是屬於「資料導向 (data-oritented)」,直覺且簡單,系統規模小且營運需求並不常變動,這樣是行得通的,而且在系統開發的初期會是相當快速的;但當營運規模大得經常會要求系統快速配合商務運作,「資料導向」的開發模式卻往往耗在所謂的「共用性整合」議題上太多等待時間了,那種有著「剪不斷、理還亂」的感覺,不僅讓人苦惱,也是引起紛爭的主要來源。
其實原因也很單純,「資料導向」實際上早已悖離了軟體開發的第一個最基本原則:「封裝 (encapsulation)」。過早揭露資料與邏輯的細節,而使得系統的複雜度提升。
所以,該如何改善開發製程呢?當然就要懂得如何遵守「封裝」的設計原則,而採以 MVC (Model-View-Control)的架構則會是遵循封裝原則的第一個必要手段。
不過要釐清這裡所謂的「MVC」,可不是 Java Struts 或 ASP.NET 的 MVC 框架;系統廠商所提出的 MVC 框架,那是針對 Web 瀏覽器與伺服端如何控管 WebPage 狀態,是關於如何於 Stateless (無狀態)的 UI 設計議題所提出的解決方案 (solution domain)。
而關於企業層級 (enterprise)系統的 MVC 架構,則是回歸到問題領域 (problem domain)上,如何在呈現 (presentation)與業務邏輯 (business logic)兩個層級間,能有效隔離兩者的耦合性 (coupling)。
基於上述的開發原則,我們對開發流程的調整,其實就是在 client (Web UI)與 Server (Model)之間,規劃了控制層 (control layer),藉以隔離中介 Client/Server 的直接耦合;Web UI 團隊與 Model 團隊係以平行分工開發 (parallel development),各自依據其職掌-Web UI 專注畫面呈現與動態技術的實作;Model 專注於系統功能的實現 (realization)。兩者均只與控制層所設計的規格 (也可稱之為功能介面)溝通,所以誰不需等待另一方的產出,如此也就不用初期就耗在所謂共用性議題的等待上。
再者依照敏捷 (agile)的開發精神,整個開發產出係採以 I&I 漸增與漸進 (Iterative & Increment),期待作持續性的整合 (continuous integration,以版本控制系統如 Git 作為整合的儲庫)。最好是每日就作整合,最遲不要超過一個星期。
關於敏捷式的平行開發流程 (agile parallel development process),我們利用 Eriksson-Penker Business Extensions 語法 (俗稱火箭圖)所規劃的開發流程總覽 (overview)如下圖1。然後關於 Web UI、Control、Business Model 這三個層塊,再各自以 UML 活動圖 (activity diagram)來表述它們細部的開發活動,參考下圖 2~3。
(點擊圖片鏈接看原圖)圖1、敏捷式平行開發流程模型-Overview
下圖2 由資深的 SD 或架構師 (architect)依照如從使用案例 (use case)所得來的需求分析結果,來設計功能性的控制物件 (functional control object)。其實功能性控制物件早已揭露於「設計樣式 (design pattern)」一書,它係稱之於 Facade 物件,也就是擔任一種門面、封裝角色的物件。
控制物件只是定義源自於需求分析所得來的系統功能。實作上很單純,就是僅以 PO (pure object) 物件實作 (在 Java 稱為 POJO、在 C#.NET 稱為 POCO)而已。而關於規格就僅是定義類別內的 function (或稱為 method) name、參數、回傳值而已。
所以,Web UI 與 PO 物件溝通協定為何?一般連結方式、Web Service、RESTful (Representational state transfer),那會視採用技術框架、實際環境、效能安全性等議題綜合考量,不過卻與控制層物件的規格設計並無太大關聯-一個是設計議題;一個是實作技術問題。
至於 PO Control 物件與 Model 物件,一般均是部署於同一實體機器上,所以也不太需考量溝通協定的問題,比較要注意的是關於參數回傳值這個議題上。其實兩大陣營也已經有了共識-採取以資料物件 (data object)作為層與層之間的傳遞值,我們把這類物件稱為 DTO (Data Transfer Object) 物件。
至於圖內活動有稱之為 VDB 物件的設計,那是因應 .NET 較早些的規格-DataSet 物件,把資料庫複製一小部分至記憶體內,所以我們稱它為「虛擬DB (Virtual DB)」物件,其實作用也只是與資料物件一樣,只擔任資料傳遞值的角色。
規格的設計與實作非常單純,就只是反映需求分析的結果而已。所以 MVC 這三大層往往控制層的產出會先出來,這也是為何控制層得以中介隔離 UI 與 Model 層的關鍵。
最後要注意的一點是,一定要為每一個控制物件撰寫功能性的測試程式,而且是規格設計自己撰寫,並且馬上就要隨著控制程式被實作。這是一種非常重要的習慣甚或是要求,如此才得以確保所定義的規格能正確符合需求。
下圖3 為 Web UI 端的開發活動,這裡是採以網站為主要經營的企業所最在乎的環節。其實 Web UI 只有兩個重點:如何達成使用者滿意的視覺化操作,也就是關於 Style (風格)的美觀設計;另一重點則是擺於實作的動態技術上 (如使用泛 Javascript 技術),如何有效的呈現複雜的資料。
不要加諸 Web UI 額外的責任,最常見的是還要 UI 設計人員負責部分業務邏輯的實現,或是業務規則的檢查邏輯;這些應該是後端 Model 的責任,如此才能專心在上述兩個對 UI 最重要的關鍵議題上。
再則 UI 團隊絕對不要關注在所謂資料與邏輯的共用性議題上,每一個表單會用到的資料欄位,那是屬於表單的,卻非是資料庫的,整合性的議題,會延宕到後續 Model 的開發,那會視共用性的重要與急切性再來決定何時來整合。
所以表單會使用的資料,是歸屬於表單層級的,完全不要去考慮到資料庫的設計,這樣開發才不會耗費在不必要的共用設計問題上,開發的節奏才可能順暢。記住,UI 僅與控制層溝通而已,只要兩者能組成所需要的 DTO 資料傳輸物件即可,那是不用嚴謹的設計的。
下圖4 是企業邏輯層的主要開發活動。這一塊在以往大型 MIS 系統是最被為重視的,但對於以網站為主要的經營企業,卻普遍把它視為僅是如何取得資料庫資料的管道而已,所以對於業務邏輯的實作並沒有重視。寫在資料庫的 stored-procedure 甚或寫在 UI 表單內,還是隨便的物件,撰寫一堆的 switch、if...then...else,大部都不會作嚴格的規範。
建議一開始為了求快,是可以暫時先把業務邏輯實現在控制物件內的。至少也要從 UI 表單這邊給抽出來,若能不寫 stored-procedure 那更好 (程式碼不具物件結構性,以及資料庫獨立的議題)。
Business Model 層最需克服的即為共用性的設計議題-不僅只是考量到資料庫結構的共用性設計,甚至也要考慮到如何更有效分散業務邏輯責任的物件設計問題 (此者即考驗了 SD 關於結構設計的抽象技能與能否有效對應於 O-R mapping 的實作技術)。
共用性的設計,應該要將其視為是整合的議題,是一種持續整合的態度,而不是一開始就想求完美與精確,那是不可能的。持續整合的態度就是在開發過程甚或已提交 (release)系統的過程期間,SD 會觀察與分析共用性價值最高的結構元素,再將原來可能分散的資料結構與業務邏輯,給集中於該結構元素內。結構化元素具體化的呈現在資料庫即為表格 (邏輯層次稱為 entity),位於應用伺服器內則為企業物件 (business object,或可稱為 entity object)。
企業物件與資料庫表格最大的差別即為物件有行為能力 (behavior, 實作為 function or method),而後者僅為資料結構;但兩者均源自於問題領域的概念 (domain concept)。隨著系統規模越大,應變程度更需俱足彈性與延展性,企業物件的設計就越顯得更為重要,但抽象設計與實作的難度相對也會提昇非常多。若相對系統再利用價值並不高的情況下,企業物件的設計,是相當耗費開發成本的。
不要一開始執著於共用設計,而是在過程中再施以重構 (re-factoring)的技巧,讓系統的應變程度會更具彈性。與其說重構是技術,倒不如說重構是一種態度-軟體的系統開發不是寫完滿足當下的功能就算完成;往往那只是告一段落,是轉移到持續的整合與雕琢的另外一個階段。
重構的最基本守則就是:不能影響到系統已上線的功能。所以為何必須伴隨著測試程式碼,才能確保變更程式碼後,經由測試確保不會影響到原來系統所提供的功能。
上圖2~3 其實會隨著系統的規模與性質、組織開發者的角色與所具備的技術、技能等諸多現實因素,而會調整其開發活動與開發產出的。不過大原則是不變的:敏捷讓開發的節奏順暢。
要能達成所謂的敏捷式 (agile)開發,卻又不能讓程式碼太骯髒而無法施以後續的重構。所謂的敏捷不是只單求快,而是在於開發過程中的順暢度,降低溝通障礙。了解開發過程的焦點所在。
敏捷式平行開發最大的挑戰不在於所採用的工具與所謂的方法 (流程步驟與產出);最關鍵的核心在於要能將 I&I (Iterative & Increment)視為理所當然 。I&I 是一種習慣,它取決於心態-可以忍受不完美與不確定性。
至於普遍軟體開發人員對 I&I 的接受度是甚麼樣的情況?老實說,要能忍受不確性的人員並不多。這應該是應該是一種文化與由來已久的陋習,如果沒有有經驗的教練 (還需有管理的權力)帶著身體力行,是相當不容易達成的修煉。
「I&I」已幾近與「重構 (re-factoring)」是同義詞,兩者均是同樣的開發態度。後續個人會寫篇親身遇到的經驗談,來說明普遍軟體技術人員對於重構這一詞所抱持的設計態度為何。