慘不忍睹的翻譯
英文原文:http://www.codeproject.com/Articles/339725/Domain-Driven-Design-Clear-Your-Concepts-Before-Yo
作者:Mahmud Hasan(我認識他,他不認識我)
翻譯這篇老外文章的兩個原因:
- 首先,這是一篇關于領域驅動設計的文章(I love DDD)。
- 其次,我想看看我英語爛到什么程度。
不可否認的是,翻譯出來的結果,確實慘不忍睹,慘到我都不想發布了,發布的原因就是讓大家看看,學不好英語,是什么樣的情況(就是我這樣)?
在閱讀下面“譯文”之前,需要明確下,我大學英語水平是3.5級B(注意上面還有個A)。
所以,英語好的,請閱讀英文原文;英語不好的,請自備詞典,閱讀英文原文,強烈建議不要閱讀下面內容。
開始一個新的應用程序
當你開始一個商業項目的時候,你應該首先設計你的對象模型,DDD(領域驅動設計)就是這樣指引你的。
當我們開始一個業務應用程序,我們通常怎么做的呢?我們閱讀其業務規則和查找相應的功能,我們分解任務,在大多數的情況下,項目出現問題的緣由是項目的估計和計劃。我們做了估計,然后給團隊成員分發任務,我們設計的數據庫架構在領導和開發者之間徘徊,然后我們開始編碼。
所以呢?這樣做有什么不對的地方嗎?我們一直都是這樣的做的啊,而且做的還不錯!難道不是嗎?答案是 YES 和 NO!是的,在我們項目的開發過程中,我們做的是不錯。但是,我們沒有做很好的維護和擴展我們的項目!
想想在這些年中,所有你用傳統開發模式開發過的項目,你有沒有遇到以下幾個問題?
- 你的項目在不同的地方用相同的方式,實現相同的功能。
- 你的同一項目有多個對象。
- 你的項目存在不屬于該對象實際屬性的對象。
- 你的相關的項目存在非常差的關系。
- 只看你的對象是不可能明白你整個應用程序的全部。
我相信你在開發的時候,經常面臨這些問題。但是,你知道為什么嗎?其原因是,傳統的開發模式沒有引導我們在設計系統中從上到下的方式。 相反,它誘惑我們來設計系統從下到上的方式。你看,當你設計一個系統,你需要知道一個整體的應用程序需要做什么?客戶端試圖達到什么目的?然后,從頂層目標,你想出了不同的小功能,最終允許用戶實現頂層目標。
但是,當你使用從下到上的設計方法,首先設計顆粒狀的功能,你并不知道這個功能滿足什么樣的需求,而且還是在實際應用中。
你有沒有聽說過,你的團隊開發人員談論,但是并不清楚整個應用的領域知識?或許是的!我覺得你可以明白其中的道理。原因是,應用程序的設計并不代表系統的領域。因此,開發人員只知道他們工作的部分。這是可悲的!是不是?
那么,傳統的開發模式-“應用程序的設計從數據庫開始”,這一概念?并不真正正確!如果你有一個復雜的應用程序,這種自下而上的設計方法,并沒有真正意義上的面向對象設計。
該如何解決呢?
解決的辦法是 DDD(領域驅動設計)。
DDD 是什么?
領域驅動設計不是一種技術或方法,DDD 提供了一種實踐理論指導,用于復雜性業務場景的設計。
本文中包含的內容
- 了解領域
- 無所不在的語言
- 上下文和界定上下文
- Entity(實體)和 Value Object(值對象)
- Aggregates(聚合)和 Aggregates root(聚合根)
- 忽略持久化
- Repository(倉儲)
- Domain Service(領域服務)
在這篇文章中,我會盡量避免使用太多技術,而我會通過 DDD 嘗試去貼近現實世界的概念。我會盡量在這里不展示任何代碼。因為我相信,如果你理解這個概念,并開始在使用這種思維方式,很容易實現。最困難的部分是調整你的思維過程!
了解領域
A sphere of knowledge, influence, or activity. The subject area to which the user applies a program is the domain of the software.
- Wikipedia
從上面的定義中,你感覺領域是什么?在這個時刻,你能談一下,你現在工作項目中的領域概念嗎?你能說下著名網站 YouTube 的領域嗎?
在這篇文章中,我想通過一個現實生活中真實的例子,來帶給你感覺,如何使用領域驅動設計,開始分析你的項目。 這個例子不能與應用程序開發相關的,但由于我們的目標是調整我們自上而下的思維方式方式,這是有益的。但同樣,我們也將使用 DDD 的技術術語!
比方說,你要設計一個建筑。 要求是:
- 你有一個明確的土地面積。
- 你的建筑將有 6 層樓。
- 每個樓層都會有 4 個公寓。
What is your domain here?
建筑是領域?這可能是。不過需要注意的是,如果你考慮建筑作為你的領域,在你的需求中,你可能會錯過一些顆粒狀的細節。你要設計的建筑必須為公寓的人生活在哪設計。因此,一個通用術語“建筑”使我們錯過一些細節。所以,我們可能要對我們的領域縮小到“住宅建筑”。
現在,當你和工程師談論你的工作,誰還要你去設計這個建筑,“住宅建筑”為大家關注,是更有意義的。在這個語言中,你有沒有標記非常小的變化?承建商告訴你,設計一個六層并且每一層有四個公寓的建筑物。 現在,如果你派工程師到現場,告訴他我們需要在這里構造一個建筑,他們可能不會考慮一個住宅建筑必須具備的很多屬性。另一方面,如果你使用“住宅建筑”的概念,最有可能,他會拿出一個有效的分析。
這就是我們如何來描述一個“通用語言”。
無所不在的語言
這個概念很簡單,開發人員和企業應該共享,理解同樣事物的一個通用語言,更重要的,那就是在商業術語,而不是技術相關的通用語言。
無所不在語言的更多示例
示例1
錯誤語言:
小床房間的長寬比例是 4:3。
正確語言:
兒童床的房間長度為20英尺,寬度為15英尺。
對于建設“小房間”的主人,需要注意的是,“比例”概念是非常技術性的術語。相反,它更容易讓他理解孩子們的房間,客房,客廳等,并明確測量是更有意義的。
示例2
從軟件角度,我們來看一個例子。
錯誤語言:
在搜索功能,我們會考慮的 SQL Server 的 inflectional and thesaurus 功能,使搜索更具相關性。此外,我們也將排除 stop word,從而使檢索更加準確。
需要注意的是,你的領域專家可能不是一個技術人員,因此他可能不明白你的“inflectional”,“thesaurus”,“Stop word”等意思。
正確語言:
在搜索功能,我們會考慮搜索短語的所有同義詞,使其不排除相關的結果。此外,我們將讓結果變得更準確由其數字(單數或復數),時態,分詞等不區分任何搜索詞。另外在任何搜索如預期般的那樣,我們將忽略所有在搜索沒有任何意義的單詞。這種干擾詞可能是“am”,“but”,“where”,“about”等。
你看到這,明白語言的區別了嗎?一個正確的語言可以使所有的參與方,思考和理解的方式相同。
回到我們的“住宅建筑”領域。 瞧,你可以繼續把建筑設計作為一個單一的任務,然后一起解決整個事情。但它確實是非常明智的方式來做到?需要注意的是,如果你只是考慮這項工作的一個簡單工作單元可能會錯過很多東西。設計一個建筑是涉及到很多的東西。例如:你需要考慮通風,公共設施,停車位,社區空間等。
現在你看,不同的其他情況下都上來了。“上下文”和“界定上下文”這是怎樣的概念?該是他們登場的時候了。
上下文和界定上下文
有界上下文可以看作是一個小型應用程序,包含它自己的領域,自己的代碼和持久性機制。在一個有界上下文中,應該有邏輯上的一致性,每一個有界上下文應該是獨立于任何其他有界上下文。
界定上下文的更多示例:
想想一個電子商務系統,最初,你可以告訴它是購物上下文的應用。但如果你更仔細,你會看到有其他情況下也是存在的,比如:庫存,交貨,賬戶等。
正確劃分不同界定上下文之間的一個大型應用程序,將使你的應用程序更加模塊化,將幫助你區分不同的關注點,并將使應用程序易于管理和擴展。這些界定上下文都有特定的職責,并可以在半自動的方式下進行操作。通過拆分這些上下文,除了使其變得更加適合自身的邏輯之外,你還可以避免 BBOM(大混球,我自己的翻譯)。
BBOM(大混球)是什么?
A Big Ball of Mud is a haphazardly structured, sprawling, sloppy, duct-tape-and-baling-wire, spaghetti-code jungle. These systems show unmistakable signs of unregulated growth, and repeated, expedient repair. Information is shared promiscuously among distant elements of the system, often to the point where nearly all the important information becomes global or duplicated. The overall structure of the system may never have been well defined.
- Brian Foote and Joseph Yoder, Big Ball of Mud. Fourth Conference on Patterns Languages of Programs (PLoP '97/EuroPLoP '97) Monticello, Illinois, September 1997
譯者注:上一段因為不知如何翻譯,所有就沒翻譯,“A Big Ball of Mud”,我翻譯為“大混球”,Mub 單詞為“泥”的意思,我想也是“混亂”的意思,泥球,是指雜亂無章、錯綜復雜、邋遢不堪、隨意拼貼的大堆代碼。作者表達的意思就是,如果沒有界定上下文,那整個應用程序就是一個 BBOM,我所理解的,也就是一個“大混球”。
我們花費所有時間的目標就是應該避免 BBOM。
再次回到“住宅建筑領域”,因此,我們可以有幾個界定上下文:
- 電力供應
- 停車場
- 公寓
- 等等
讓我們來談談公寓。該公寓的根本是不同房間的組合,房間里面都有不同的元素,如門,窗等,關于房間的窗戶,現在我有2個問題:
- 問題1:你能想象一個沒有窗戶的房間嗎?
- 問題2:如果這個房間沒有人居住,一個窗戶是有意義的嗎?(翻譯出來感覺有點奇怪,原文:Does a window have any identity without the room it is residing in?)
回答這些問題,將暴露 DDD 以下的概念。
- Entity(實體)
- Value Object(值對象)
- Aggregates(聚合)和 Aggregates root(聚合根)
Entity(實體)
“This is my Entity, there are many like it, but this one is mine.”
-“這是我的實體,有很多很像它,但是這一個才是我的。”
定義一個實體的特征,關鍵是它有一個身份(Identity)-它是系統中是唯一的,并沒有其他實體,無論多么相似,相同的實體,除非它具有相同的標識。
示例(和我們平常的表述有所不同):
- 你的床在公寓的房間里。
- 合同在 Facebook 上。
- 文章在 CodeProject 上。
Value Object(值對象)
一個值對象的定義,關鍵特征是它沒有唯一標識。好吧,也許有點簡單,但一個值對象的意圖是通過它的屬性,僅僅代表它是什么。兩個值對象可能具有相同的屬性,在這種情況下,它們是相同的。他們不不過有自己的 virtue 屬性之外的其他值。常見值對象的另一個方面是,他們或許應該是一成不變的,一旦創建就不能改變或修改。您可以創建一個新的,他們沒有身份,改變他們的方式就是再創建一個。
示例:
- 房間里的窗戶。
- 在你網站中,一些人的地址。
- 你的搜索條件。
Note:一個值對象可以成為一個實體視情況而定。你可以找到一個情況嗎?如果你應用程序的搜索功能要求說,搜索條件應保存在數據庫中,用戶可以執行來自已保存的搜索條件的相同搜索結果。在這種情況下 SearchCriteria(搜索條件)有它自己的身份,并因此它是一個實體,而不是作為一個值對象。
在 DDD 中,現在你知道什么是實體和什么值對象了吧。在領域驅動設計中,實體和值對象可以獨立存在。但在某些情況下,關系可以是這樣的,如果沒有它的上下文,一個實體或值對象沒有價值的。
示例:
- 一個窗戶只有在一個房間存在的情況下才能被定義。
- 下單了,這個訂單才能存在。
- 一個問題只有被提出,這個問題的細節才有價值。
很簡單,不是嗎?相信我,在 DDD 中,現在你將知道:什么是聚合?什么是聚合根?
Aggregates(聚合)和 Aggregates root(聚合根)
在上面給出的例子中:
- 房間、訂單和問題是我們的聚合根。
- 另一方面,訂單詳情和問題詳情是我們的聚合。
“A cluster of associated objects that are treated as a unit with regard to data changes.”
All objects of the clusters(不知怎么翻譯) 都應該被視為聚合。
所有的外部訪問聚合是通過一個單一的根實體,這根實體被定義為聚合根。
示例:
- 一個問題詳情是沒辦法保存的,除非相應的問題被保存。
- 一個問題詳情是沒有辦法進行檢索,除非相應問題被檢索。
在這邊,問題是聚合根,問題詳情是聚合。 聚集和聚合根是 DDD 的非常重要的概念。
到目前為止,我們已經講過領域、對象/實體、上下文、聚合等,那數據庫是怎樣的呢?是不是我們錯過了什么?數據庫應該在設計中?
答案是 NO!DDD 是一個忽略持久化的。
忽略持久化
在領域驅動設計中,你的目標是創建領域模型。你需要確定你的應用程序中完成功能所包含的所有對象,你需要確定不同的對象,以及他們彼此之間存在的關系。如果使用你的領域模型可以實現客戶的業務需求,那數據庫還存在嗎?在你構建領域模型時,你并不需要知道你的領域數據是在哪里或怎樣持久化的,甚至在數據確實需要持久化時,你也無須知道。
忽略持久化將使你的領域模型在應用程序中真正解耦,從你的領域模型中,領域模型的持久化和溝通機制分離開,以獲得更好的關注度。這樣你的領域模型和持久化可以很容易的進行單元測試。
但是,在實際的應用中,你確實需要有一個數據庫,但你的域模型并不關注這些,所以就有了“倉儲”的概念了。
Repository(倉儲)
Can you tell me what the meaning of the English word “Repository” is?
Repository commonly refers to a location for storage, often for safety or preservation.
- Wikipedia
正如我已經說過你的領域模型不知道任何數據庫,它只知道的是,在系統中有一個倉儲,并且這個倉儲將負責存儲數據和檢索數據,你的領域模型對數據的持久化是沒有確定方式的。因此,它可以在 SQL Server,Oracle,XML,文本文件或其他任何東西。在 DDD 中,現在我希望你對倉儲有了一些感覺。
讓我們變得更小的技術。
Repository Mediates between the domain and data mapping using a collection-like interface for accessing domain objects. It is more like a facade to your data store that pretend like a collection of your domain.(第一句理解意思,但是組織不起來語言)
倉儲不是數據訪問層。
需要注意的是,存儲庫中不關注“數據”,它關注的是聚合根。你可以使用你的倉儲添加一個聚合根到它的集合中,或者你可以要求它為特定的聚合根。如果你還記得,聚合根可包含一個或多個實體和值對象,這使得它非常不同于傳統的 DAL 層,從數據庫中返回一些行數據。
倉儲的實施策略
正如我所說的那樣,倉儲在 DDD 數據持久化中是一種設計模式,這個模式的細節部分超過了本文所涵蓋的范圍,不過,在這里用最短的時間,我想告訴你如何實現倉儲。
- 第一步,有一個 IRepository 接口。
- 定義 IRepository 接口成員。
- 有一個 INhRepository 接口提供持久化,繼承 IRepository。
- 實現 INhRepository 接口,比如 NhRepository。
- 最后,你可能有一個倉儲的泛性實現,將為這個倉儲提供所有默認的通用方法。
- 像 NhGenericRepository 繼承自 NhRepository,實現 INhGenericRepository。
- 你將為你的聚合根約束倉儲,這也將更好的擴展 NhGenericRepository。
- 你的應用程序將使用 ServiceLocator 找到應用曾許所使用的倉儲。
Domain Service(領域服務)
領域服務是 DDD 中另一個非常重要的概念,如果實體和值對象在領域中是“東西”的話?那服務就是應對行為,動作和活動的一種方式。
Shouldn’t Logic Be on the Entities Directly?(邏輯,直接,不懂)
原文:Yes, it really should. We should be modeling our Entities with the logic that relates to them and their children. But, there are occasions when we need to deal with complex operations or external responsibilities or maybe we need to expose the actions of the aggregate roots to the external world. This is why creating a domain service for different aggregate root is a good idea. You can consider the domain services as façade layer of the business logics and operations of your domain.
有點難翻譯出來,我用自己的話來表述一下,就是說實體都是內聚的,它描述了自身的業務邏輯和狀態,如果有多個實體之間相互協調,我們應該怎么處理?難道需要向外部暴露這些過程嗎?這時候就需要領域服務了,它的作用就是協調多個實體,完成一個業務功能的實現,領域服務的名稱是動詞,而且它沒有自身的狀態,更別說保存狀態了,說簡單一點,就是它是為實體服務的,實體自身完成不了的事,那就是領域服務的事,而且它事領域模型必不可少的組成部分。
結束語
在這篇文章中,我將試圖引入現實生活中的例子,來說明領域驅動設計中的基本概念,我們的目標就是讓你感覺 DDD 和現實生活如此貼切,但真正應用 DDD 是一個很大的挑戰。在你設計你的對象模型的時候,你腦袋中想著 DDD 的概念,那你的設計將更加準確。正如我之前所說的那樣,你必須考慮領域驅動設計,如果你不這樣做,如果你的應用程序是相當的復雜,你將損失更大。
DDD 參考資源
- http://www.dddcommunity.org/
- http://thinkddd.com/
- http://www.infoq.com/minibooks/domain-driven-design-quickly
- http://thinkddd.com/assets/2/Domain_Driven_Design_-_Step_by_Step.pdf
- http://www.dddcommunity.org/library/young_2010
- http://www.dddcommunity.org/library/evans_2010
- http://blog.fossmo.net/post/Command-and-Query-Responsibility-Segregation-(CQRS).aspx
- http://msdn.microsoft.com/en-us/library/ff649690.aspx
文章列表