[工作心得]傳統程式架構到3-Layer架構的心路歷程

  • 30581
  • 0
  • 2009-03-27

[工作心得]傳統程式架構到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 LayerData 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可以用... :evil: )

不過,好處當然不只這樣。

Object Class,屬性是可以擁有NameSpaceIntelligence Sense(怎麼老是記不起來怎麼拼 :twisted: ),

而且屬性的呈現是具有可讀性的。

又會有人講,「我用列舉型別,還不是一樣可以有可讀性」。

沒錯!不過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上的需求變更頻率不高,那麼WatiNTestpartnerIEUnit就可以派上用場,

測試Presentation Layer

比較focus在驗證、回應訊息、資料呈現是否有誤,改了這隻程式,理論上跟其他程式無關,那麼UI Auto Testing的結果,就應該是一模一樣。


=========================================================================

 

Layer與Layer之間的Interface,我目前僅能體會用意,但用處有多大,沒有需求,就還看不太出來「實際」的好處。

當Present layer跟DAL程式,都是一模一樣,只是不同間企業(以銀行為例子好了),對於他們自己的服務,定義不同

舉個例子來說,可能A銀行算「信用分數」,要用a服務跟b服務回傳的分數來平均B銀行的「信用分數」,則是使用c服務

呈現層來說,呼叫的都是同一個interface,叫做「信用分數」,但不同銀行,就是根據自己的商業邏輯去呼叫不同的服務處理。

如此一來,就「只修改需要修改的部分」,甚至「只增加修改的部分」。

以後的系統,可能越來越大,就可能可以隨意切換不同DBMS、不同商業邏輯來應付不同客戶的需求,或是客戶的不同需求


PS:如果Service Layer用Web Service,那就可以搭配AJAXjQuery,在client端用javascript呼叫,讓UI上的操作效率可以更加提升...(我知道callback可以,可比較醜嘛....)

=========================================================================


以上,只是個剛跨過去3-Layer門檻的菜鳥感想...

我相信,我只掌握到3-Layer、Spring.Net、自動測試的皮毛,但是我跨過了「抗拒」的那個門檻,並且理解這樣會有什麼好處。

希望各位大大不要鞭的太用力,更希望可以發文指導一二一下,能提供自己的見解最好,

或是有相關3-Layer的資源,也很歡迎提供給小的增廣見聞一下。

畢竟我還不太會寫文章,希望看看人家如何更深入的寫這種3-Layer的架構論點。

 

(跨過門檻之後,看ASP.NET MVCSilverLight,感覺通多了…)

補充參考:

  1. Web Applications: N-Tier vs. N-Layer
  2. 程式檔案的一些配置說明 by Allen Kuo

  3. Strategy Design Pattern

 


或許您會對下列培訓課程感興趣:

  1. 2021/1/9:【針對遺留代碼加入單元測試的藝術】202101 - 台北
  2. 2021/1/10:【極速開發+】 202101 台北
  3. 2021/2/20~2021/2/21:【演化式設計】測試驅動開發與持續重構 202102

想收到第一手公開培訓課程資訊,或想詢問企業內訓、顧問、教練、諮詢服務的,請洽 Facebook 粉絲專頁:91敏捷開發之路