最近看到有人領域模型中的客戶類別如此設計:
這個設計觀點是將個人戶與公司戶都看成客戶,因且可以把公司戶與個人戶的都有的共通屬性放到客戶類別上,然後把個別所特有的差異化屬性放到衍生類別個人與公司上。表面上,這似乎是Party〔Fowler96〕樣式的應用,然而仔細推究其設計內容,卻會發現這個設計會使系統增加沒有必要的複雜度(Unnecessary Complex)。
因為個人戶與公司戶其實有很大的差異性,衍生類別的屬性很多,也有複雜的處理邏輯,就算我們採用的永續機制框架-Hibernate可以處理類別的繼承,但繼承卻讓我們的類別之間相互牽連,卻只是為了讓公司與個人的屬性不要重覆出現而要花費如此的成本似乎太奢侈了。
其實這個設計最大的問題是只從結構面的角度來設計類別,只考慮抽取共通屬性,卻缺少了行為面的封裝,這是營養不良的領域模型,設計的本質還是採用程序導向的基本思維,造成問題的主因是設計者並未針對實際發生的問題層面來設計,而是以預期的技術層面來考量,也就是說,樣式的錯誤引用把設計問題變複雜了。
為什麼說是樣式的錯誤引用呢?Martin Fowler(1996)曾提過,Party〔Fowler96〕樣式有兩種使用場合:
- 在領域模型中看到人與組織具有共同的行為,或~
- 不需要區分人與組織,在這種狀況下,可以不提供衍生類別。
由上可知,這個設計並不適用Party[Fowler96]樣式或使用這個樣式的時機並未來到,可以預期的是,少了行為的封裝,實作大致會變成像這樣:
Customer cust = customerManagementService.getCustomer(id);
if (cust instanceof Person.class) {
Person p = (Person) cust;
// process person customer …
} else if (cust instanceof Company.class) {
Company c = (Company) cust;
// process company customer …
}
可想而知,系統設計的複雜度會從此開始衍生下去,這將是我們所不願發生的事情,我的建議是把公司與個人的is-a關係拿掉,因為目前對於一般交易而言,客戶並不需要區分他是個人或是公司,如果需要知道客戶的細節資料時,我們只要提供一個根據客戶編號查詢個人或公司資訊的操作界面,然後在領域模型中將個人或是公司的類別須關聯至客戶類別,這樣我們就可以利用查詢條件的方式就可以找出關聯此客戶的個人或是公司,就可以透過此界面取得此客戶的詳細資料。
如此設計就可以變得更單純些,等到我們需要區分出不同的客戶的共通行為再運用角色塑模(Dealing with Roles)來增加設計的彈性,這就是用面對問題的方式來設計,而不是以技術實作的觀點來設計,因為後者常常會讓我們離遠使用者需求。
在與《類別設計演化論》相關主題的討論過程中,曾針對網友GameBoy所說的「運用 “is a” 和 “has a” 要能洞察 Problem domain(初學的人容易用 real world 直觀的認知來 model,這有點危險),甚至在某些場合併用更能達到 Model 中微妙的動態平衡發揮軟體的軟性」回應:
一味地求虛其實更危險,過度設計的結果是頑空!
實務上常碰到這種人,脫離業務需求,只鑽進沒有必要的設計。
is a 或 has a 並不重要,那只是手段而已。重要的是"面對現實",也就是思考這樣設計究竟要解決什麼問題。因此,用 real world 的直觀來 modeling 沒有什麼不好。
表面上, GameBoy 與我所說的並沒有太大的差異,但我卻不認為「用 real world 直觀的認知來 model,這有點危險」。因為,如果我們不能用 real world 的語言與別人溝通的話,就不可能站在需求的觀點來看事情,我們常常看見在開發過程中,開發人員往往以為只有他們才能了解真正的需求是什麼而造成溝通上的障礙,亦即:
誠如Robert C. Martin在《敏捷軟體開發》一書中提到過的:”程式常常會誘使你遠離樣式或原則”。同樣地,在設計過程中,不適當的設計樣式也常會誘使你遠離真正地業務需求.
樣式學得愈多的人,愈容易發生這種毛病。因此,更需要自我提醒. 不要用技術眼光來看業務需求, 因為那是一種以徧概全的徧見,後面必將自惡果。
所以,站在問題概念的層次上分析問題,而不是站在技術實現的層次上。從概念層次上進行分析,也就意味著要求你從領域專家的角度來看待程式是如何表示現實世界中的概念,然後針對能夠滿足現實世界觀介面設計(註)。
總之,面對現實才能發現問題的本質,因此設計必須要面對現實。尤其應該要認清不是不能用直觀的方式去看真實世界,而卻是往往我們用錯誤的實作方式而把設計變複雜,尤其是在應用某些樣式之前,必須謹慎,不要讓樣式的錯誤引用讓問題複雜化。
您好
我用ㄧ個例子來解釋
「用 real world 直觀的認知來 model,這有點危險」。
比如以 “汽車” 為例
“汽車” 在資產系統、或進銷存系統、或在某某系統
不一定都會被 model 成汽車
可能是 Item 或 Asset 或 anything else
也就是要看清楚 Problem Domain
(其實也就是您在本文的題旨)
會講出這樣的話
「用 real world 直觀的認知來 model,這有點危險」。
是看到有些初學者容易犯這樣的問題 (汽車不見得在業務需求裡都會被視為 “交通工具\”)
但如果您就是認定敝人是以 Technical 的角度來看問題 (而非業務需求)
我想我也就是隨緣了
能在網上相遇自是有緣
如果我的文筆很容易造成您對我的誤解
That’s fine …
Have a nice year ….
GameBoy
敝人同樣也在 葉 Sir 另ㄧ篇 PO 文做了回應
http://www.lifeparty.idv.tw/blog/archives/38#comments
其實我常常拿 Agile Software Modeling 中的
Salary System 去考別人
大概十個人有九個人
會很直觀地用繼承來 Model Person 和 Role 的關係
(他們多半認為 Role is a Person 是很直觀的)
以該書該例的 reauirement 來看
這樣的繼承手法
自然會導出惡果
(但是在某些 requirement 來說
用 is-a 才符合 Business Semantic
或同時存在 is-a 和 has-a 的語意)
這是敝人提出這樣說法的起因
並非 Challenge 葉先生
葉先生提出
「用 real world 直觀的認知來 model,沒什麼不好」
在他本 PO 文來看
我個人解讀 他要強調的是
小心 Over Design
小心為 Pattern 而 Pattern
而敝人提出
「用 real world 直觀的認知來 model,這有點危險」
純粹只是從過去的經驗來提醒初學者罷了
文字有其侷限性
解讀因人而異
我個人
倒不會將
「用 real world 直觀的認知來 model,這有點危險」
和
「用 real world 直觀的認知來 model,沒什麼不好」
解讀為兩個衝突的觀點
(我個人解讀是兩人的出發點不太一樣)
因為葉 Sir 的直觀不會犯了以上過於 Technical 的問題
但往往我看到 初學 OO 的人卻常常因他們的過於直觀 而犯了這樣的問題
我到認為 葉 Sir 這篇 PO 文
對於初涉 OO 的人
是ㄧ個很好的活教材
供諸君作參考
因為我看到太多 beginner 的抽象化是
僅僅源自於他們的直觀認知
而非從 Requirement 下手
但 Real World 中直觀的名詞
不見得適合作為 Domain Model 中的 Entity
但卻往往被他們誤植於 Domain Model 中 …
有一位網友 John 提到
不妨看看 Evans 的書
我想他指的應該是這一本書
Domain Driven Design …
最近隨手翻翻
該書再提到
如何從與 User 的互動中
Iterative 地焠鍊出 Domain Model
有談及如何避免 用直觀的名詞來 Model 的 案例
初學 Modeling 的朋友
不妨做個參考
(我並非 Challenge 葉 Sir
只是我必須將敝人
「用 real world 直觀的認知來 model,這有點危險」
這句話交代清楚
)
供參考
Gameboy
想請教一下同人
敝人常用的 “結構” 一詞
在敝人的認知裡是包含語意這部份的
(也就是 model 要能呈現 problem domain 中的 Business Semantic
像 domain class 之間的 association
應該要能呈現豐富的語意
)
您對 “結構” 一詞
應該有比較嚴謹的定義
從您的 po 文看來
結構 和 Semantic 似乎是分開來的 (也許是敝人對您的文字解讀有誤)
若您有空針對此問題回 po
願聞其詳
Thx
自動引用通知: 同人的生活派對 » 探討「用 real world 的直觀來認知 model」
自動引用通知: 同人的生活派對 » 物件導向繼承與程式碼的重用
自動引用通知: 同人的生活派對 » 改變軟體開發現況的藝術
自動引用通知: 同人的生活派對 » 好的設計源自於紀律
自動引用通知: 同人的生活派對 » 永續物件查詢之設計(其二)