DDD+Javascript領域建模示例 -Alex Lawrence
這篇文章使用一個簡單的示例說明了域建模過程。第一步,確定實際問題。接下來,找到一種解決方法。接下來是建立初始域模型。之後,提供第一實施方式。然後,討論並解決了技術和邏輯上的挑戰。此外,還將解釋域模型及其實現之間的差異。該帖子最後建議即使對於小型專案,也應使用以問題為中心和模型驅動的方法。
問題識別
領域驅動設計強調解決的問題及其涉及的知識領域。在我的書中,領域模型被定義為“專注於[..]解決特定問題的知識抽象集”。這意味著,為了建立有用的模型,首先需要確定問題。作為一個具體示例,請考慮當在讀書時遇到的以下問題:我想知道文字中單個單詞的出現情況。
開始這問題提得似乎很有用,但是,它並不是真正描述問題,而是已經暗示了特定的解決方案。相關的問題是:我試圖透過計算單個單詞的出現來解決什麼問題?由於我不是英語母語,因此我通常不確定自己的詞彙多樣性。我想以某種方式衡量。因此,要解決的真正問題是確定文字的詞彙多樣性。
解決方法
發現問題後,就可以確定特定的解決方案。我的想法是,我可以透過檢視單個單詞的出現情況來確定詞彙的多樣性。但是,這種方法暗示僅軟體部分還不是完整的解決方案。相反,它將僅生成有助於推導詞彙使用指示的資料。確定實際的多樣性將由我作為使用者來完成。
初始域模型
如前所述,域模型是一組知識抽象。因此,它不必具有特定的表現形式或表示形式。更重要的是,雖然通常以某種方式表達模型,但各個工件通常只是資訊的子集。對於詞彙示例,可以透過純文字傳達知識抽象。請注意,這種方法沒有對問題或域模型的複雜性做出任何宣告。
目的是確定文字中詞彙多樣性的程度。“文字”代表單詞和標點符號的集合。“詞彙”可以定義為單個單詞的集合。術語“多樣性”包含了不同單詞的出現及其出現。表述“度”表示邊界和邊界之間的離散步驟。例如,詞彙多樣性被認為是不能透過軟體計算的主觀指標。
總而言之,可以將域模型方面總結為以下幾點:
- 給定文字,應確定詞彙多樣性
- 文字是單詞和標點符號的集合
- 詞彙是一組單個單詞
- 詞彙多樣性是手動確定的主觀指標
第一次實施
在定義域模型之後,可以開始實施。對於該示例,假定迭代軟體開發過程。結果,在域模型的完整性和正確性方面有較低的要求。相反,以上定義可以看作是進一步發展的初始草案。理解它的另一種方式是,以下迭代是實驗階段的一部分,而無需構建生產軟體。
以下程式碼是計算文字中單個單詞的出現次數的第一個實現:
const countWordOccurrences = text => { wordOccurrences = {}; text.split(' ').forEach(word => { if (wordOccurrences[word] == null) wordOccurrences[word] = 0; wordOccurrences[word]++; }); return wordOccurrences; }; const wordOccurrences = countWordOccurrences(`This is a basic example. Also, this is only one of many possible examples.`); console.log(wordOccurrences); /* output: { This: 1, is: 2, a: 1, basic: 1, 'example.\n': 1, '': 1, 'Also,': 1, this: 1, only: 1, one: 1, of: 1, many: 1, possible: 1, 'examples.': 1 } */ |
該示例用法及其輸出演示了初始解決方案的功能。
技術問題
第一次實施存在一些技術問題。這些方面不是由於模型中的缺陷所致,而是與將隱式需求正確整合到程式碼中有關:一個問題是標點符號被錯誤地視為單詞的一部分。對於換行符也是如此。另一個問題是,多個空格導致建立空單詞條目。這些方面不適合作為模型的顯式部分,因為它們應被視為常識。
以下程式碼提供了經過重做的實現,克服了上述問題:
const wordRegex = /[a-z0-9]{1}[a-z0-9-]*/gi; const countWordOccurrences = text => { wordOccurrences = {}; Array.from(text.matchAll(wordRegex), match => match[0]).forEach(word => { if (wordOccurrences[word] == null) wordOccurrences[word] = 0; wordOccurrences[word]++; }); return wordOccurrences; }; const wordOccurrences = countWordOccurrences(`This is a basic example. Also, this is only one of many possible examples.`); console.log(wordOccurrences); |
第二段程式碼透過使用正規表示式解決了上述技術問題。此表示式定義兩個規則。首先,每個單詞都必須以字母數字字元開頭。其次,第一個字元後面可以是字母數字字元和破折號的任意組合。
模型改進
重新設計的實現是一種改進,但仍然面臨問題。有一些問題提示域模型中存在Bug缺陷:
- 一個Bug是該實現是區分大小寫的,這導致具有不同大小寫的相同單詞的多個條目。
- 另外一個是:一個單詞的單數和複數形式被認為是不同的事物。
可以如下更新域模型定義:
- 給定文字,應確定詞彙多樣性
- 文字是單詞和標點符號的集合
- 詞彙集是單個單詞
- 詞彙多樣性是指示語言質量的指標
- 一個單詞的不同大小寫被認為是相同的
- 一個單詞的單數和複數被認為是相同的
最後一個示例提供了一個反映最新域模型的實現:
const wordRegex = /[a-z0-9]{1}[a-z0-9-]*/gi; const countWordOccurrences = (text, {asSingular}) => { wordOccurrences = {}; text = text.toLowerCase(); Array.from(text.matchAll(wordRegex), match => match[0]).forEach(word => { word = asSingular(word); if (wordOccurrences[word] == null) wordOccurrences[word] = 0; wordOccurrences[word]++; }); return wordOccurrences; }; const pluralize = require('pluralize'); const wordOccurrences = countWordOccurrences(`This is a basic example. Also, this is only one of many possible examples.`, {asSingular: pluralize.singular}); console.log(wordOccurrences); /* output: { this: 2, is: 2, a: 1, basic: 1, example: 2, also: 1, only: 1, one: 1, of: 1, many: 1, possible: 1 } */ |
透過使輸入文字為小寫字母來減輕大小寫敏感性。對於單數和複數形式的合併,實現中引入了dependency asSingular。此引數必須分配有一個單詞並返回單數形式的操作。例如,將pluralize載入npm模組,並將其功能singular()作為依賴關係傳入。這種方法可確保正確表達模型行為,同時又不受具體依賴。
模型與程式碼
域模型和實現所表達的知識之間存在差異。考慮一下我的書中的以下摘錄:“實際的實現可能只反映基礎抽象的一個子集,並最終處理無關的技術方面。” 詞彙多樣性示例說明了這兩種說法。一方面,該實現沒有表達完整的模型,因為它僅對每個單詞的出現次數進行計數。其次,它還處理純粹的技術問題,例如多個空格或換行符。
DDD小問題
這篇文章說明的另一方面是所謂的簡單問題可能會給他們帶來很多複雜性。對於具有豐富和複雜域的大型軟體專案,通常建議使用域驅動設計及其單獨的模式。但是,從問題空間開始並在實施之前建立有用的概念模型總是有益的。即使對於諸如確定詞彙多樣性之類的小功能,以問題為中心和模型驅動的方法也很有價值。
相關文章
- CloudNotes之領域建模篇:領域模型簡介Cloud模型
- 關於java領域建模疑惑Java
- 物件導向與領域建模物件
- 架構師之路 - 業務領域建模架構
- 用形而上學進行領域建模
- 領域驅動設計示例
- DDD學習(二)—— 領域建模重要概念
- DDD-領域驅動設計示例
- 使用Typescript實現DDD領域建模 - Matthew de NobregaTypeScript
- 請大家推薦一款適合DDD領域建模的建模工具!
- Entity Farmework領域建模方式 3種程式設計方式程式設計
- DAO模式是不是就是領域建模中的倉儲?模式
- 使用使用者故事對映實現領域建模 - pulse
- 領域驅動設計實踐:支付系統建模 - Xiao
- 非同步架構思維:使用Akka實現領域建模非同步架構
- DDD建模心得:領域概念建模是一種語文語法分析練習 - prefactordesign語法分析
- 如何進行高質量的DDD領域建模?什麼是領域模型?如何捕捉?尺寸如何? - Manning模型
- 請教四色原型與領域建模的對接技巧原型
- 使用知識圖實現領域知識建模與測試
- 關於是否在.net專案中實施領域建模的困惑!
- 資料倉儲建模思想在商務智慧領域的應用(轉)
- DDD領域驅動設計總結和C#程式碼示例C#
- 基於COLA架構建立運輸微服務應用和DDD領域建模架構微服務
- Maple—多領域系統級建模模擬和科學計算軟體
- 怎樣寫好業務程式碼——那些年領域建模教會我的東西
- 請教banq老師怎樣學習DDD領域建模和設計模式設計模式
- DDD-領域物件與領域服務物件
- DDD領域驅動設計:領域事件事件
- 關於資料建模(面向ER)和領域模型建模(面向OO)在企業應用中的作用的討論模型
- 領域建模的啟發,不同行業對模型的破壞力不同 - Mathias Verraes行業模型
- 請教大家一個支付系統領域物件建模中類提取的問題物件
- 領域驅動設計戰術模式--領域事件模式事件
- 戲說領域驅動設計(廿五)——領域事件事件
- 讀書系列-《解構領域驅動》-領域概念
- Rafy 領域實體框架示例(1) - 轉換傳統三層應用程式框架
- 領域驅動設計戰術模式--領域服務模式
- 領域服務和領域事件如何取捨?或共存?事件
- 數學建模例題2.17 匯入模組示例