前言
在技術(shù)開發(fā)中,領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(Domain Driven Design,簡稱DDD)理念倍受推崇。最近自己也再次讀了一遍Eric Evans 的《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì) —— 軟件核心復(fù)雜性應(yīng)對(duì)之道》。本篇來談?wù)勵(lì)I(lǐng)域驅(qū)動(dòng)設(shè)計(jì)理念如何對(duì)產(chǎn)品設(shè)計(jì)的一些啟發(fā)。

什么是領(lǐng)域?
個(gè)人對(duì)領(lǐng)域的理解,可以認(rèn)為領(lǐng)域是某個(gè)行業(yè)的業(yè)務(wù)知識(shí)。軟件產(chǎn)品設(shè)計(jì)本身就是為了解決某個(gè)行業(yè)特定的業(yè)務(wù)問題,因此軟件產(chǎn)品設(shè)計(jì)者本身需要能夠充分理解相關(guān)的業(yè)務(wù)知識(shí),也就是我們經(jīng)常提到的,產(chǎn)品經(jīng)理需要成為行業(yè)專家。
統(tǒng)一領(lǐng)域模型
軟件產(chǎn)品設(shè)計(jì)者僅僅掌握領(lǐng)域知識(shí)是不夠的,還需要對(duì)領(lǐng)域知識(shí)進(jìn)行建模,形成領(lǐng)域模型。舉個(gè)例子,我們的地球儀其實(shí)就是對(duì)地球的一個(gè)建模。領(lǐng)域模型的目的其實(shí)就是在團(tuán)隊(duì)里面?zhèn)鞑ズ统恋眍I(lǐng)域知識(shí),確保設(shè)計(jì)、開發(fā)、測試人員所理解的領(lǐng)域知識(shí)是一致的,這樣才能減少類似“這個(gè)地方你又沒說清楚”的問題。在實(shí)際的產(chǎn)品開發(fā)過程中,我們很多問題其實(shí)是團(tuán)隊(duì)不同人員對(duì)領(lǐng)域知識(shí)的理解不同造成的。
然而,模型的表達(dá)會(huì)有很多種方式,比如文檔、原型、思維導(dǎo)圖、UML 圖等等,那么該采取哪種形式來表達(dá)領(lǐng)域模型呢? Eric Evans 提出了一個(gè)統(tǒng)一語言(Ubiquitous Language)的工具,這個(gè)工具有點(diǎn)類似 UML,但是并沒有那么嚴(yán)格。其實(shí),用什么工具是其次的,重要的這個(gè)工具表達(dá)出來的東西能夠讓業(yè)務(wù)人員、產(chǎn)品設(shè)計(jì)人員、開發(fā)人員和測試人員都能夠明白其實(shí)的領(lǐng)域知識(shí),同時(shí)需要有統(tǒng)一的規(guī)范。在表達(dá)具體業(yè)務(wù)對(duì)象定義、關(guān)系描述方面,個(gè)人建議可以參考 UML 的規(guī)范。
如何進(jìn)行領(lǐng)域建模?
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的關(guān)鍵是采取合理的方式對(duì)領(lǐng)域進(jìn)行建模,也就是將物理世界的業(yè)務(wù)映射到軟件產(chǎn)品中,最終使得軟件產(chǎn)品能夠承載實(shí)際的業(yè)務(wù)。個(gè)人的建議是可以從如下幾個(gè)方面來進(jìn)行領(lǐng)域建模:

名詞概念:在實(shí)際需求調(diào)研過程中,我們會(huì)聽到很多專業(yè)領(lǐng)域中的名詞。對(duì)于產(chǎn)品經(jīng)理而言,這些名稱很多是陌生的。對(duì)于產(chǎn)品設(shè)計(jì)而已,名詞意味著一個(gè)個(gè)具體的業(yè)務(wù)對(duì)象,如果一個(gè)名詞經(jīng)常在業(yè)務(wù)人員口中出現(xiàn),那么就需要特別注意。比如,我們看 CRM 系統(tǒng)中,會(huì)經(jīng)常出現(xiàn)“客戶公?!?、“線索”、“商機(jī)”、“陌拜”這類名詞,搞清楚這些名詞代表的含義會(huì)讓我們對(duì)領(lǐng)域知識(shí)有更深入的理解。因此,弄清楚名詞概念是建模的第一步。
業(yè)務(wù)對(duì)象關(guān)系:業(yè)務(wù)對(duì)象的關(guān)系是軟件設(shè)計(jì)中最為復(fù)雜的部分,一個(gè)中大型產(chǎn)品可能會(huì)存在錯(cuò)綜復(fù)雜的關(guān)系,而產(chǎn)品設(shè)計(jì)除了梳理清楚業(yè)務(wù)關(guān)系外,一個(gè)很重要的工作是簡化關(guān)系。舉個(gè)例子,一個(gè)國家在歷史上會(huì)存在多個(gè)總統(tǒng),但是在一定時(shí)間段內(nèi)只會(huì)有一個(gè)總統(tǒng),通過添加時(shí)間段的約束,我們就把一個(gè)一對(duì)多的關(guān)系簡化成了一對(duì)一的關(guān)系。
業(yè)務(wù)規(guī)則:業(yè)務(wù)規(guī)則用于對(duì)業(yè)務(wù)進(jìn)行約束,以保障業(yè)務(wù)的合理開展。有些業(yè)務(wù)規(guī)則比較簡單,例如表單的校驗(yàn)規(guī)則;有些業(yè)務(wù)規(guī)則則很復(fù)雜,例如電商平臺(tái)中的秒殺業(yè)務(wù)規(guī)則。業(yè)務(wù)規(guī)則的處理相當(dāng)考驗(yàn)產(chǎn)品經(jīng)理的能力,很多開發(fā)人員會(huì)抱怨業(yè)務(wù)邏輯老是改來改去,其實(shí)很多時(shí)候改的就是業(yè)務(wù)規(guī)則。這里,一方面是產(chǎn)品經(jīng)理在設(shè)計(jì)產(chǎn)品的時(shí)候,沒有深入與業(yè)務(wù)方溝通業(yè)務(wù)規(guī)則,另一方面則是對(duì)業(yè)務(wù)規(guī)則的處理上比較隨意 —— 比如讓開發(fā)人員直接寫死代碼。有些業(yè)務(wù)邏輯會(huì)被其他邏輯替換,或經(jīng)常發(fā)生改變,這個(gè)時(shí)候就可以參考策略(Policy)設(shè)計(jì)模式。把這部分業(yè)務(wù)邏輯提取到一個(gè)單獨(dú)的“策略”對(duì)象中,實(shí)現(xiàn)規(guī)則與它所控制的行為區(qū)分開,從而可以使得規(guī)則易于替換。典型的應(yīng)用場景就是優(yōu)惠政策。一件商品可能同時(shí)滿足多個(gè)優(yōu)惠政策,因此可以把優(yōu)惠政策單獨(dú)抽離出來用于計(jì)算最終的商品優(yōu)惠后價(jià)格。這樣,即便更換了優(yōu)惠政策,主體的計(jì)算過程只需要將優(yōu)惠政策替換即可,而無需修改其他部分。
應(yīng)用場景:應(yīng)用場景在《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》中稱之為上下文(Context)。上下文一方面是描述了某項(xiàng)功能的具體應(yīng)用條件,另一方面可以為業(yè)務(wù)劃定邊界,從而幫助我們拆分或合并業(yè)務(wù)模塊。通過上下文可以將高度相關(guān)的業(yè)務(wù)內(nèi)聚為一個(gè)模塊,而將不相關(guān)的分離到其他模塊,從而保持單個(gè)模塊的精煉。舉個(gè)例子,我們?cè)谠O(shè)計(jì)與第三方系統(tǒng)對(duì)接的模塊時(shí),就需要很清晰地將與第三方對(duì)接的部分從業(yè)務(wù)模塊中剝離形成單獨(dú)的模塊,然后通過約定的規(guī)則與業(yè)務(wù)模塊進(jìn)行交互。這樣做的原因是,第三方的對(duì)接是不受控的,如果發(fā)生變更,我們只需要更改剝離出去的模塊,而無需修改業(yè)務(wù)模塊。
責(zé)任歸屬:責(zé)任歸屬在梳理業(yè)務(wù)流程中非常重要。產(chǎn)品經(jīng)理經(jīng)常會(huì)梳理業(yè)務(wù)流程,但是業(yè)務(wù)流程的核心要義其實(shí)更多是劃分責(zé)任歸屬,而流程的推進(jìn)就是責(zé)任的轉(zhuǎn)移。書中提到了貨運(yùn)的例子,在貨物經(jīng)過不同的流程環(huán)節(jié)時(shí),實(shí)際上就是貨物在托運(yùn)人、承運(yùn)人和收貨人直接的責(zé)任轉(zhuǎn)移。對(duì)于 B 端產(chǎn)品而言,一個(gè)業(yè)務(wù)流程通常會(huì)經(jīng)過多個(gè)角色,這個(gè)時(shí)候明確每個(gè)角色承擔(dān)的責(zé)任就非常重要。一方面是有助于權(quán)限系統(tǒng)的設(shè)計(jì),另一方面則是能讓參與系統(tǒng)設(shè)計(jì)的人清楚地了解有哪些角色,以及每個(gè)角色承擔(dān)的職責(zé)。
這里需要提醒一下,對(duì)于剛做產(chǎn)品設(shè)計(jì)的人來說,會(huì)關(guān)注業(yè)務(wù)流程和功能的實(shí)現(xiàn),而會(huì)忽略最核心的領(lǐng)域知識(shí)。結(jié)果導(dǎo)致產(chǎn)品難以貼合業(yè)務(wù),擴(kuò)展性不好。領(lǐng)域知識(shí)包括了業(yè)務(wù)對(duì)象概念、對(duì)象間關(guān)系、業(yè)務(wù)規(guī)則、應(yīng)用場景等等。設(shè)計(jì)產(chǎn)品前,先把這些理清楚,再做產(chǎn)品流程梳理和功能設(shè)計(jì)會(huì)讓整個(gè)設(shè)計(jì)更加合理和易于擴(kuò)展。
怎么推進(jìn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)?
說實(shí)話,要推動(dòng)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)還是挺難的,關(guān)鍵還在于產(chǎn)品和技術(shù) Leader 的決心。我們大多數(shù)時(shí)候都是忙于需求分析、原型設(shè)計(jì)、開發(fā)交付,而很少停下來思考我們的設(shè)計(jì)和真實(shí)的業(yè)務(wù)契合度。這恰恰導(dǎo)致了一個(gè)惡性循環(huán) —— 我們陷入了不斷調(diào)整產(chǎn)品功能卻無法滿足業(yè)務(wù)需要的怪圈。
書中針對(duì)推進(jìn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì),給出了6個(gè)要點(diǎn):
決策必須傳達(dá)到整個(gè)團(tuán)隊(duì):如果不能確保團(tuán)隊(duì)中的所有人都知道策略并去遵守它,那么策略也就失去了運(yùn)用。無論開發(fā)什么系統(tǒng),都不要管理層所授予的權(quán)力來強(qiáng)制地推行戰(zhàn)略決策,而應(yīng)該更多地關(guān)注開發(fā)人員與策略之間的實(shí)際關(guān)系。
決策過程必須收集反饋意見:團(tuán)隊(duì)需要真正理解項(xiàng)目需求和領(lǐng)域概念的開發(fā)人員。單獨(dú)依靠架構(gòu)師不一定能夠設(shè)計(jì)出好的應(yīng)用架構(gòu)——畢竟應(yīng)用架構(gòu)是為業(yè)務(wù)服務(wù)的。
計(jì)劃必須允許演變:軟件開發(fā)是一個(gè)動(dòng)態(tài)的過程,如果決策過早固定下來,開發(fā)團(tuán)隊(duì)可能束手束腳,失去解決問題的靈活性。有了積極的反饋之后,當(dāng)遇到障礙或是出現(xiàn)了意想不到的機(jī)會(huì)時(shí),創(chuàng)新也就自然而然涌現(xiàn)出來了。
架構(gòu)團(tuán)隊(duì)不必把所有最好、最聰明的人員都吸收進(jìn)來:如果都把最優(yōu)秀的人員納入了架構(gòu)團(tuán)隊(duì),那么意味著業(yè)務(wù)開發(fā)團(tuán)隊(duì)的水平都是偏低的,這會(huì)導(dǎo)致業(yè)務(wù)領(lǐng)域模型設(shè)計(jì)開發(fā)水平糟糕。即便有好的架構(gòu),業(yè)務(wù)層還是很難出眾。讓業(yè)務(wù)開發(fā)人員也能夠參與架構(gòu)設(shè)計(jì)中,會(huì)讓架構(gòu)更貼合業(yè)務(wù)。
戰(zhàn)略設(shè)計(jì)需要遵循簡約和謙遜的原則:我們必須嚴(yán)格約束自己,從而使設(shè)計(jì)出來的組織原則和核心模型精簡到只包含能夠顯著提高設(shè)計(jì)清晰度的內(nèi)容。
對(duì)象的職責(zé)要專一,而開發(fā)人員應(yīng)該是多面手:讓開發(fā)人員在編寫業(yè)務(wù)代碼的時(shí)候,也能參與需求分析、架構(gòu)設(shè)計(jì),這會(huì)有助于提高整個(gè)團(tuán)隊(duì)的設(shè)計(jì)開發(fā)水平。
這里特別說一下第4點(diǎn)和第6點(diǎn)。實(shí)際開發(fā)團(tuán)隊(duì)分工上,通常會(huì)讓高水平的程序員負(fù)責(zé)技術(shù)基礎(chǔ)設(shè)施 ——比如架構(gòu)設(shè)計(jì),底層組件的構(gòu)建,而把水平一般的開發(fā)人員分配去做業(yè)務(wù)開發(fā)。很多程序員也更愿意去往架構(gòu)方向上發(fā)展,因?yàn)檎莆樟恕巴ㄓ谩钡募寄?,簡歷上更豐富。 然而,缺乏高水平的程序員去理解領(lǐng)域知識(shí)的話,對(duì)業(yè)務(wù)領(lǐng)域的建模很可能沒法反應(yīng)核心的領(lǐng)域知識(shí),結(jié)果即便有良好的底層技術(shù)支撐,業(yè)務(wù)層面可能也一團(tuán)糟——最終所謂好的架構(gòu)也沒有地方發(fā)揮價(jià)值。 因此,建議對(duì)核心領(lǐng)域的設(shè)計(jì)開發(fā),一定要高水平的產(chǎn)品、開發(fā)人員參與。并在團(tuán)隊(duì)內(nèi)部沉淀核心領(lǐng)域知識(shí),幫助整個(gè)團(tuán)隊(duì)理解核心業(yè)務(wù),提高團(tuán)隊(duì)人員對(duì)業(yè)務(wù)的理解。
總結(jié)
個(gè)人對(duì)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)最深的感觸還是在領(lǐng)域知識(shí)的理解過程上。我們的 SaaS 產(chǎn)品一開始立項(xiàng)開發(fā)的時(shí)候,獲取到的領(lǐng)域知識(shí)其實(shí)非常片面,結(jié)果是產(chǎn)品推向市場后被客戶各種吐槽。然而,隨著種子客戶的深入使用,我們與客戶的交流也變得更多,對(duì)業(yè)務(wù)領(lǐng)域知識(shí)的理解逐步清晰。這個(gè)過程中,我們會(huì)發(fā)現(xiàn)之前很多的概念、關(guān)系的理解和實(shí)際業(yè)務(wù)存在不小的偏差,于是不得不逐步調(diào)整。到客戶增長到一定量之后,發(fā)現(xiàn)很難繼續(xù)按照原有的設(shè)計(jì)繼續(xù)推進(jìn),于是重構(gòu)就提上了日程。重構(gòu),對(duì)于技術(shù)開發(fā)來說可能更關(guān)注性能瓶頸的解決,而對(duì)于產(chǎn)品設(shè)計(jì)來說則是領(lǐng)域模型的升級(jí)迭代。
從這個(gè)過程中得到的經(jīng)驗(yàn)就是,雖然我們很難做到一開始就對(duì)領(lǐng)域知識(shí)理解非常深刻,但是應(yīng)該趁早梳理業(yè)務(wù)領(lǐng)域知識(shí),建立領(lǐng)域模型。這需要我們產(chǎn)品經(jīng)理與業(yè)務(wù)人員進(jìn)行高頻次、深入的溝通交流,并且能夠?qū)㈩I(lǐng)域知識(shí)準(zhǔn)確地傳達(dá)給測試、開發(fā)人員,以保障最終開發(fā)出來的產(chǎn)品能夠高效解決行業(yè)的業(yè)務(wù)問題。