[工作心得]傳統程式架構到3-Layer架構的心路歷程
採3-Layer 系統架構跟傳統一支Class寫到底,差異在哪呢?
要講好處之前,要先來聲明一下壞處,
寫程式上面變得比以前麻煩,因為你要多很多class,
如果原本只要一支vb或cs處理所有UI跟邏輯上的東西,還包括資料上的處理,
現在至少Service Layer要多寫一支,對應到Data Access Layer要多寫一支。
通常還會有OR-Mapping的RowMapper,所以RowMapper還要一支。
再來是Layer與Layer之間傳遞的資料,我們通常不會單純使用參數,這樣會比較沒彈性,所以會設計成一個DTO(Data Transfer Object),通常也是至少一個。
一開始的話,可能在三層之間,還要加上至少兩個Interface,未來維護才會有彈性,不過Interface畢竟不是每次都要加一整個檔案,就暫且不算進去檔案數。
看到這邊,原本一支Class可以搞定的東西,「基本上」會至少變成5支(當然BLL跟DAL的檔案,及DTO的Class,都是很有可能重複使用的。這邊指的是從沒有到有的差別)
覺得很麻煩嗎?
當你一支程式寫到上萬行,一個Function寫了10頁,你會不會覺得不好維護,牽一髮動全身?
切Layer,程式支數變多,其實有點像把一個太冗長、處理太多東西的Function,再額外分出來。
分出來的規則,就類似根據商業邏輯來抽共用Function,Layer切出來,就會有高內聚、低耦合的特點(這是我覺得Layer一個很重要的目的)。
用這個角度,去看一支程式變成五支程式,就會覺得理所當然。
如果一個Class寫了一萬行,出了問題,要看的是一萬行。
倘若簡單切成3 Layer,三層個別都是四千行好了,通常可以快速定義到,是哪一個四千行出錯。
以我自己的感覺,我認為維護上在追哪個部分出錯,是可以更快定義到問題點。(可能需要配套措施,也就是程式與Log之間,可能透過註解要能快速找到對應的Class)
==================================================================
再來,透過3-Layer,可以讓寫程式的邏輯更清楚。
舉個例子,畫面上某個值的單位是"千元",DB單位當然是"元",這個UI與DB之間乘除一千的動作,該在那邊做?
在三個Layer都可以做,出來結果都會一樣,但是意義整個大不同。
在之前專案的例子裡面,我們是在Present Layer做,因為搞不好我下次UI的單位是萬元,百元,甚至是不同幣別,
但對DB存放的資料,對商業邏輯服務來說,都管不著你要怎麼樣去「呈現」資料結果。
要在Present Layer乘除一千的緣由,是因為UI上給user看的單位是千元。
這種概念,在原本一支Class打死的設計裡面,是很難體會的。
倘若下個系統要調整單位,就又是要去找一萬行裡面的程式修改。
在3-Layer的程式裡面,修改的觀念簡單得多,UI上呈現的單位修改就是Present Layer的事,我不必去看Service Layer跟Data Access Layer的八千行。
===================================================================
還有,DTO跟參數的差異,當只為了傳不到三個的參數,要額外定義一個Class去傳遞,這對我來說一開始也是抗拒超大的。
今天我從兩個參數,改成三個參數,原本是有用到的Function都要修改,可能兩支,也可能一萬支程式有用到,否則建置會錯。
我用Object Class去存放參數,我也是要改程式啊,好在哪裡?!
好處在「擴充」,假設我要多撈一個欄位,或多加一個條件,我只需要在Object Class裡面,新增一個屬性,
多的屬性,沒用到的,不會錯。但要用到的,就可以直接拿來用。
假設原本DB撈的資料叫做篩選個人資料,SQL是Select * from Joey where A=@param1,有50支程式用的到。
Function的接受參數叫做個人資料條件A=@param1。
現在有25支程式要多一個條件是B=@param2,
以舊的方式寫的程式,就是去找是哪25支程式要多這個參數,然後深怕沒改到或改錯。
3-Layer以Object Class傳遞的話,就只需要在SQL上加上B=@param2。
Function的接受參數仍為「個人資料條件DTO」,建置不會有問題。
當然這個例子,只是有一點點像Optional 參數的味道(C#裡面沒有Optional可以用... )
不過,好處當然不只這樣。
Object Class,屬性是可以擁有NameSpace的Intelligence Sense(怎麼老是記不起來怎麼拼 ),
而且屬性的呈現是具有可讀性的。
又會有人講,「我用列舉型別,還不是一樣可以有可讀性」。
沒錯!不過Object class可以有自己的行為、Method,可以繼承.....可以有NameSpace的多層式結構。
==============================================================================
Service Layer,就像具有Business Logic的Function,
可以幫助撰寫程式的人,瞭解這個功能在Domain know-how上的意義。
一萬支程式用的到商業服務,放到Service Layer來,就是同一個服務,不管你畫面上長的如何,不管你是什麼人登入的,
該服務只care,你把什麼樣的Domain Object 丟過來,要用什麼樣的商業邏輯來判斷,該服務要做什麼事。
是要呼叫其他的服務,還是要根據Domain Object來呼叫存取Data Access Layer的Function。
是否還要根據Data Access Layer回傳(經過RowMapper後)的Domain Object,來判斷要做其他事情。這個,Present Layer都不管。
UI 跟使用者只care,我已經給了商業服務需要的資訊,我只要結果,
中間Service Layer要呼叫Web Service,要連接外部系統,DB是Oracle、SQL Server、MySQL,甚至分散式的DB,網路DB,
UI跟使用者都不管,也不需要管,那不干他們的事。
Present Layer只要處理好,回來的資料要如何呈現。
這邊有個弔詭的地方,也就是程式錯了,我要追哪個Layer的程式?
如果是呈現方式的錯誤,單位錯誤,該隱藏打開的沒有作用,那當然就是Present Layer的問題,這相當明確。
可是,如果是資料的問題呢?資料出來有問題,這超常發生的!
絕大部分,一定是BLL或DAL的問題,怎麼樣降低這樣的問題呢?
沒錯,就是自動化測試。(切Layer另外一個最大目的)
由於3-Layer的架構,BLL跟DAL這兩層,與UI跟runtime上的資訊一點關係都沒有了。
跟UI沒關係,就代表靜態(static),就可以黑箱測試,只要知道input、output,透過test case就可以知道BLL跟DAL的Function是否有設計錯誤。(test-drvien)
BLL跟DAL,都是很單純的在做該Layer應該做的事情,可以很獨立的去測試每一個Function是否有問題。(低耦合特性...)
今天當整個程式,出現資料面的問題,
第一件事,就是把input的資訊,當作test case,去跑自動化測試,倘若結果都跟預期的一樣,
那就代表BLL跟DAL錯誤的機率很小,應該是Presentation Layer的問題。
這也是我前面說的,要定義問題發生的地方變得很明確、很容易。
有了自動化測試的機制,就可以避免掉維護上「未知」的風險,不再有以往牽一髮動全身的擔心..
PS:如果,UI上的需求變更頻率不高,那麼WatiN、Testpartner與IEUnit就可以派上用場,
測試Presentation Layer,
比較focus在驗證、回應訊息、資料呈現是否有誤,改了這隻程式,理論上跟其他程式無關,那麼UI Auto Testing的結果,就應該是一模一樣。
=========================================================================
Layer與Layer之間的Interface,我目前僅能體會用意,但用處有多大,沒有需求,就還看不太出來「實際」的好處。
當Present layer跟DAL程式,都是一模一樣,只是不同間企業(以銀行為例子好了),對於他們自己的服務,定義不同。
舉個例子來說,可能A銀行算「信用分數」,要用a服務跟b服務回傳的分數來平均,B銀行的「信用分數」,則是使用c服務。
對呈現層來說,呼叫的都是同一個interface,叫做「信用分數」,但不同銀行,就是根據自己的商業邏輯去呼叫不同的服務處理。
如此一來,就「只修改需要修改的部分」,甚至「只增加修改的部分」。
以後的系統,可能越來越大,就可能可以隨意切換不同DBMS、不同商業邏輯來應付不同客戶的需求,或是客戶的不同需求。
PS:如果Service Layer用Web Service,那就可以搭配AJAX或jQuery,在client端用javascript呼叫,讓UI上的操作效率可以更加提升...(我知道callback可以,可比較醜嘛....)
=========================================================================
以上,只是個剛跨過去3-Layer門檻的菜鳥感想...
我相信,我只掌握到3-Layer、Spring.Net、自動測試的皮毛,但是我跨過了「抗拒」的那個門檻,並且理解這樣會有什麼好處。
希望各位大大不要鞭的太用力,更希望可以發文指導一二一下,能提供自己的見解最好,
或是有相關3-Layer的資源,也很歡迎提供給小的增廣見聞一下。
畢竟我還不太會寫文章,希望看看人家如何更深入的寫這種3-Layer的架構論點。
(跨過門檻之後,看ASP.NET MVC跟SilverLight,感覺通多了…)
補充參考:
blog 與課程更新內容,請前往新站位置:http://tdd.best/