如果這是第二次看到我的文章,歡迎訂閱z哥的公眾號(hào)(跨界架構(gòu)師)哦~
每周五11:45 按時(shí)送達(dá)。當(dāng)然了,也會(huì)時(shí)不時(shí)加個(gè)餐~
本書(shū)是Eric Evans對(duì)他自己寫(xiě)的《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)-軟件核心復(fù)雜性應(yīng)對(duì)之道》的一本字典式的參考書(shū),可用于快速查找《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》中的諸多概念及其簡(jiǎn)明解釋。
其它本系列其它文章地址:
[譯文]Domain Driven Design Reference(一)—— 前言
[譯文]Domain Driven Design Reference(二)—— 讓模型起作用
[譯文]Domain Driven Design Reference(三)—— 模型驅(qū)動(dòng)設(shè)計(jì)的構(gòu)建模塊
[譯文]Domain Driven Design Reference(四)——?柔性設(shè)計(jì)
Ⅲ.柔性設(shè)計(jì)
要讓一個(gè)項(xiàng)目加速發(fā)展,而不是被其自身的歷史包袱所拖累,需要一個(gè)能與之良好協(xié)作的設(shè)計(jì),它會(huì)帶來(lái)改變。一個(gè)柔性設(shè)計(jì)。
柔性設(shè)計(jì)是對(duì)深度建模的補(bǔ)充。
開(kāi)發(fā)人員扮演兩種角色,每種角色都必須通過(guò)設(shè)計(jì)來(lái)完成。同一個(gè)人可能扮演這兩個(gè)角色,甚至可以在幾分鐘內(nèi)來(lái)回切換,但與代碼的關(guān)系卻不是這樣。一個(gè)角色是客戶(hù)端的開(kāi)發(fā)人員,他們利用設(shè)計(jì)的方式將領(lǐng)域?qū)ο缶幙椀綉?yīng)用程序代碼或其他域?qū)哟a中。柔性設(shè)計(jì)揭示了一個(gè)深層次的潛在模型,使其潛在性變得清晰??蛻?hù)端開(kāi)發(fā)人員可以靈活地使用一組最小松散耦合的概念來(lái)表示域中的一系列場(chǎng)景。設(shè)計(jì)元素以自然的方式融合在一起,其結(jié)果是可預(yù)測(cè)的,清晰的特征并且是健壯的。
同樣重要的是,設(shè)計(jì)必須服從于開(kāi)發(fā)人員來(lái)改變它。要做出改變,設(shè)計(jì)必須易于理解,并能表達(dá)出客戶(hù)端開(kāi)發(fā)人員正在使用的相同底層模型。它必須遵循該領(lǐng)域深層模型的概念,所以大多數(shù)變化都會(huì)在靈活點(diǎn)上柔性設(shè)計(jì)。其代碼的影響必須透明明顯,因此更改的后果將很容易預(yù)測(cè)。
?? ?使行為特征明顯
?? ?降低變更成本
?? ?創(chuàng)建與之合作的軟件開(kāi)發(fā)人員
釋意接口
如果開(kāi)發(fā)人員必須考慮組件的實(shí)現(xiàn)才能使用它,則封裝的價(jià)值就沒(méi)有了。如果原始開(kāi)發(fā)人員以外的人必須根據(jù)其實(shí)現(xiàn)來(lái)推斷對(duì)象或操作的目的,新的開(kāi)發(fā)者可能會(huì)推斷出一個(gè)意圖——操作或類(lèi)只是偶然地執(zhí)行。如果這不是意圖的話(huà),那么代碼可能暫時(shí)有效,但設(shè)計(jì)的概念基礎(chǔ)已經(jīng)被破壞了,兩個(gè)開(kāi)發(fā)人員將在交叉目的下工作。
因此:
命名類(lèi)名和操作名來(lái)描述它們的效果和目的,而不用參考它們做出履約的方法。這減輕了客戶(hù)開(kāi)發(fā)者理解內(nèi)部的必要性。這些名字應(yīng)符合通用語(yǔ)言,以便團(tuán)隊(duì)成員可以快速推斷其含義。在創(chuàng)建它之前為行為編寫(xiě)一個(gè)測(cè)試,以強(qiáng)制您的思維進(jìn)入客戶(hù)端開(kāi)發(fā)人員模式。
無(wú)副作用方法
多個(gè)規(guī)則或計(jì)算的組合的相互作用變得非常難以預(yù)測(cè)。開(kāi)發(fā)人員調(diào)用一個(gè)操作必須理解它的實(shí)現(xiàn)以及所有委托的實(shí)現(xiàn),以便預(yù)測(cè)結(jié)果。如果開(kāi)發(fā)人員被迫刺破遮罩層,任何抽象接口的用處都是有限的。如果沒(méi)有安全可預(yù)測(cè)的抽象,開(kāi)發(fā)人員必須限制組合爆炸,對(duì)可行的豐富行為設(shè)置較低的上限。
因此:
將盡可能多的程序邏輯放入函數(shù)中,返回沒(méi)有明顯副作用的結(jié)果。嚴(yán)格地將命令(引起明顯的狀態(tài)改變的方法)分隔成不返回領(lǐng)域信息的非常簡(jiǎn)單的操作。當(dāng)發(fā)現(xiàn)了一個(gè)符合職責(zé)的概念時(shí),通過(guò)將復(fù)雜的邏輯轉(zhuǎn)化為值對(duì)象來(lái)進(jìn)一步控制副作用。
值對(duì)象的所有操作都應(yīng)該是無(wú)副作用的函數(shù)。
斷言
當(dāng)操作的副作用只是通過(guò)實(shí)現(xiàn)而隱含地定義時(shí),大量委托的設(shè)計(jì)就會(huì)成為一種混亂的因果關(guān)系。理解程序的唯一方法是通過(guò)分支路徑來(lái)跟蹤執(zhí)行。封裝的價(jià)值失去了。跟蹤具體執(zhí)行的必要性使抽象也失敗了。
因此:
狀態(tài)操作的后置條件以及類(lèi)和聚合的不變性。如果斷言不能直接用你的編程語(yǔ)言編寫(xiě),請(qǐng)為它們編寫(xiě)自動(dòng)單元測(cè)試。將它們寫(xiě)入符合項(xiàng)目開(kāi)發(fā)過(guò)程風(fēng)格的文檔或圖表中。
尋找具有相關(guān)概念集的模型,這些概念引導(dǎo)開(kāi)發(fā)人員推斷預(yù)期的斷言,加速學(xué)習(xí)曲線(xiàn)并降低矛盾代碼的風(fēng)險(xiǎn)。
斷言定義了服務(wù)和實(shí)體修飾符的契約。
斷言在聚合上定義了不變性。
孤立類(lèi)
即使在同一個(gè)模塊中,隨著依賴(lài)性的增加,解釋設(shè)計(jì)的難度也會(huì)大幅增加。這增加了理解的負(fù)擔(dān),限制了開(kāi)發(fā)人員可以處理的設(shè)計(jì)復(fù)雜性。隱式概念對(duì)此負(fù)擔(dān)的促進(jìn)作用甚至超過(guò)了顯示的引用。
低耦合是面向?qū)ο笤O(shè)計(jì)的基礎(chǔ)。如果可以,一直這樣做。消除圖中的所有其他概念。然后類(lèi)將完全獨(dú)立,可以單獨(dú)研究和理解。每個(gè)這樣的自包含類(lèi)都顯著減輕了理解一個(gè)模塊的負(fù)擔(dān)。
閉合操作
大多數(shù)有趣的對(duì)象最終都只能做一些無(wú)法用基本元素來(lái)表示的東西。
因此:
在適當(dāng)?shù)那闆r下,在定義操作時(shí)讓它返回類(lèi)型與其參數(shù)的類(lèi)型相同。如果實(shí)現(xiàn)者的狀態(tài)在計(jì)算中會(huì)被用到,那么實(shí)現(xiàn)者實(shí)際上就是操作的一個(gè)參數(shù),因此參數(shù)和返回值應(yīng)該與實(shí)現(xiàn)者有相同的類(lèi)型。這種操作就是在該類(lèi)型的實(shí)例集合中的閉合操作。閉合操作提供了一個(gè)高層接口,而不會(huì)引入對(duì)其他概念的依賴(lài)。
這種模式通常應(yīng)用于值對(duì)象的操作。因?yàn)橐粋€(gè)實(shí)體的生命周期在領(lǐng)域中具有重要意義,所以你不能創(chuàng)造一個(gè)新的實(shí)體來(lái)回答一個(gè)問(wèn)題。也有一些操作在實(shí)體類(lèi)型下閉合??梢韵蚱渲黝}對(duì)象請(qǐng)求一個(gè)屬性對(duì)象并取回另一個(gè)屬性。但總的來(lái)說(shuō),實(shí)體并不是那種適合成為計(jì)算結(jié)果的概念。所以,大多數(shù)情況下,這是一個(gè)尋找值對(duì)象的機(jī)會(huì)。
你有時(shí)會(huì)陷入這種模式的一半。參數(shù)與實(shí)現(xiàn)者匹配,但返回類(lèi)型不同,或者返回類(lèi)型與接收者匹配,參數(shù)不同。這些操作并不是閉合的,但是他們給與了思考閉合的一些優(yōu)勢(shì)的想象空間。
聲明式設(shè)計(jì)
在程序軟件中不可能有真正的保證。僅以一種逃避斷言的方式命名,代碼可能會(huì)產(chǎn)生額外的副作用而這些副作用并沒(méi)有被排除在外。無(wú)論我們的設(shè)計(jì)如何以模型為導(dǎo)向,我們?nèi)匀蛔罱K編寫(xiě)程序來(lái)產(chǎn)生概念上的交互效果。并且我們花費(fèi)大部分時(shí)間在編寫(xiě)樣板代碼上,而這些代碼并沒(méi)有實(shí)際增加任何意義或者行為。本章中的釋意接口和其它模式有所幫助,但是它們不可能給傳統(tǒng)的面向?qū)ο筇峁┬问缴系膰?yán)謹(jǐn)。
這些是聲明式設(shè)計(jì)背后的動(dòng)機(jī)。這個(gè)術(shù)語(yǔ)對(duì)很多人來(lái)說(shuō)意味著許多東西,但通常它指示一種編寫(xiě)一個(gè)程序或者程序的某個(gè)部分的方式,作為一種可執(zhí)行的規(guī)范。對(duì)屬性的非常精確的描述實(shí)際控制著軟件。在它的各種形式中,可以通過(guò)反射機(jī)制或編譯時(shí)通過(guò)代碼生成來(lái)完成(基于聲明自動(dòng)生成傳統(tǒng)代碼)。這種方法允許其他開(kāi)發(fā)人員以表面價(jià)值接受聲明。這是一個(gè)絕對(duì)的保證。
如果開(kāi)發(fā)人員有意或無(wú)意地繞過(guò)它們,很多聲明式方法可能會(huì)被破壞。當(dāng)系統(tǒng)難以使用或限制過(guò)多時(shí),這很可能發(fā)生。每個(gè)人都必須遵守框架的規(guī)則才能獲得聲明式編程的好處。
一種聲明式的設(shè)計(jì)風(fēng)格
一旦你的設(shè)計(jì)有釋意接口,無(wú)副作用函數(shù)和斷言,你就會(huì)進(jìn)入聲明式領(lǐng)域。聲明式設(shè)計(jì)的許多好處都是在您具有可交流其含義的可組合元素,并且具有特征或明顯效果,或根本沒(méi)有可觀察效果時(shí)獲得的。
柔性設(shè)計(jì)可以使客戶(hù)端代碼使用聲明式的設(shè)計(jì)風(fēng)格成為可能。為了說(shuō)明這一點(diǎn),下一節(jié)將介紹本章中的一些模式,以使規(guī)范更加靈活和聲明性。
圖上的形式主義(形式化的繪畫(huà))
從零開(kāi)始創(chuàng)建一個(gè)嚴(yán)格的概念框架是你每天都不能做的事情。有時(shí)在項(xiàng)目的生命周期中,您會(huì)發(fā)現(xiàn)并改進(jìn)其中的一個(gè)。但是你可以經(jīng)常使用和調(diào)整那些長(zhǎng)期在你的領(lǐng)域或其他領(lǐng)域建立起來(lái)的概念系統(tǒng),其中一些已經(jīng)經(jīng)過(guò)了幾個(gè)世紀(jì)的精煉和提煉。例如,許多商業(yè)應(yīng)用程序都涉及會(huì)計(jì)。會(huì)計(jì)定義了一套完善的實(shí)體和規(guī)則,可以輕松適應(yīng)深層模型和柔性設(shè)計(jì)。
有許多這樣的形式化的概念框架,但我個(gè)人最喜歡的是數(shù)學(xué)。讓人驚訝的是,在基本算法上做一些改變是多么有用。很多領(lǐng)域包括數(shù)學(xué)。尋找它。挖出來(lái)。專(zhuān)業(yè)的數(shù)學(xué)是干凈的,可以通過(guò)清晰的規(guī)則組合起來(lái),并且人們發(fā)現(xiàn)它很容易理解。
在本書(shū)的第8章討論一個(gè)真實(shí)世界的例子“Shares Math”,領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)。
概念輪廓
有時(shí)人們會(huì)為了靈活的組合而砍掉一些功能。有時(shí)候他們會(huì)把它封裝得很復(fù)雜。有時(shí)他們會(huì)尋求一致的粒度,使所有類(lèi)別和操作達(dá)到相似的程度。這些都是過(guò)于簡(jiǎn)單化的,不像一般規(guī)則那樣有效。但是他們通過(guò)基本問(wèn)題來(lái)激發(fā)。
當(dāng)模型或設(shè)計(jì)的元素被嵌入到一個(gè)整體結(jié)構(gòu)中時(shí),它們的功能會(huì)被復(fù)制。外部接口并不表示客戶(hù)端可能關(guān)心的所有內(nèi)容。他們的意思很難理解,因?yàn)椴煌母拍钍腔旌显谝黄鸬摹?/p>
相反,分解類(lèi)和方法可能會(huì)使客戶(hù)端無(wú)意識(shí)去復(fù)雜化,迫使客戶(hù)端對(duì)象了解如何將小塊組合在一起。更糟糕的是,一個(gè)概念可能完全喪失。鈾原子的一半不是鈾。當(dāng)然,重要的不是顆粒度的小大,但這只是顆粒度的來(lái)源。
因此:
將設(shè)計(jì)元素(操作、接口、類(lèi)和聚合)分解為內(nèi)聚單元,同時(shí)考慮到您對(duì)領(lǐng)域重要分支的直覺(jué)。通過(guò)連續(xù)的重構(gòu)觀察核心的變化和穩(wěn)定性,并尋找解釋這些切分方式的基本概念輪廓。對(duì)比模型與領(lǐng)域一致的方面,首先讓它成為一個(gè)可行的知識(shí)領(lǐng)域。
基于深度模型的柔性設(shè)計(jì)產(chǎn)生了一組簡(jiǎn)單的接口,這些接口邏輯上可以在通用語(yǔ)言中作出合理的聲明,并且沒(méi)有無(wú)關(guān)選項(xiàng)的干擾和維護(hù)負(fù)擔(dān)。
?作者:Zachary(個(gè)人微信號(hào):Zachary-ZF)
微信公眾號(hào)(首發(fā)):跨界架構(gòu)師。<-- 點(diǎn)擊查閱近期熱門(mén)文章
如果你是初級(jí)程序員,想提升但不知道如何下手。又或者做程序員多年,陷入了一些瓶頸想拓寬一下視野。歡迎關(guān)注我的公眾號(hào)「跨界架構(gòu)師」,回復(fù)「技術(shù)」,送你一份我長(zhǎng)期收集和整理的思維導(dǎo)圖。
如果你是運(yùn)營(yíng),面對(duì)不斷變化的市場(chǎng)束手無(wú)策。又或者想了解主流的運(yùn)營(yíng)策略,以豐富自己的“倉(cāng)庫(kù)”。歡迎關(guān)注我的公眾號(hào)「跨界架構(gòu)師」,回復(fù)「運(yùn)營(yíng)」,送你一份我長(zhǎng)期收集和整理的思維導(dǎo)圖。
定期發(fā)表原創(chuàng)內(nèi)容:架構(gòu)設(shè)計(jì)丨分布式系統(tǒng)丨產(chǎn)品丨運(yùn)營(yíng)丨一些深度思考。
掃碼加入小圈子??
