前言
在技術(shù)開發(fā)中,領(lǐng)域驅(qū)動設(shè)計(jì)(Domain Driven Design,簡稱DDD)理念倍受推崇进胯。最近自己也再次讀了一遍Eric Evans 的《領(lǐng)域驅(qū)動設(shè)計(jì) —— 軟件核心復(fù)雜性應(yīng)對之道》像鸡。本篇來談?wù)勵(lì)I(lǐng)域驅(qū)動設(shè)計(jì)理念如何對產(chǎn)品設(shè)計(jì)的一些啟發(fā)。
什么是領(lǐng)域漏策?
個(gè)人對領(lǐng)域的理解派哲,可以認(rèn)為領(lǐng)域是某個(gè)行業(yè)的業(yè)務(wù)知識。軟件產(chǎn)品設(shè)計(jì)本身就是為了解決某個(gè)行業(yè)特定的業(yè)務(wù)問題掺喻,因此軟件產(chǎn)品設(shè)計(jì)者本身需要能夠充分理解相關(guān)的業(yè)務(wù)知識芭届,也就是我們經(jīng)常提到的储矩,產(chǎn)品經(jīng)理需要成為行業(yè)專家。
統(tǒng)一領(lǐng)域模型
軟件產(chǎn)品設(shè)計(jì)者僅僅掌握領(lǐng)域知識是不夠的褂乍,還需要對領(lǐng)域知識進(jìn)行建模持隧,形成領(lǐng)域模型。舉個(gè)例子逃片,我們的地球儀其實(shí)就是對地球的一個(gè)建模屡拨。領(lǐng)域模型的目的其實(shí)就是在團(tuán)隊(duì)里面?zhèn)鞑ズ统恋眍I(lǐng)域知識,確保設(shè)計(jì)褥实、開發(fā)呀狼、測試人員所理解的領(lǐng)域知識是一致的,這樣才能減少類似“這個(gè)地方你又沒說清楚”的問題损离。在實(shí)際的產(chǎn)品開發(fā)過程中赠潦,我們很多問題其實(shí)是團(tuán)隊(duì)不同人員對領(lǐng)域知識的理解不同造成的。
然而草冈,模型的表達(dá)會有很多種方式她奥,比如文檔、原型怎棱、思維導(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í)需要有統(tǒng)一的規(guī)范轰驳。在表達(dá)具體業(yè)務(wù)對象定義厚掷、關(guān)系描述方面,個(gè)人建議可以參考 UML 的規(guī)范级解。
如何進(jìn)行領(lǐng)域建模冒黑?
領(lǐng)域驅(qū)動設(shè)計(jì)的關(guān)鍵是采取合理的方式對領(lǐng)域進(jìn)行建模,也就是將物理世界的業(yè)務(wù)映射到軟件產(chǎn)品中勤哗,最終使得軟件產(chǎn)品能夠承載實(shí)際的業(yè)務(wù)抡爹。個(gè)人的建議是可以從如下幾個(gè)方面來進(jìn)行領(lǐng)域建模:
名詞概念:在實(shí)際需求調(diào)研過程中,我們會聽到很多專業(yè)領(lǐng)域中的名詞芒划。對于產(chǎn)品經(jīng)理而言冬竟,這些名稱很多是陌生的昙篙。對于產(chǎn)品設(shè)計(jì)而已,名詞意味著一個(gè)個(gè)具體的業(yè)務(wù)對象诱咏,如果一個(gè)名詞經(jīng)常在業(yè)務(wù)人員口中出現(xiàn),那么就需要特別注意缴挖。比如袋狞,我們看 CRM 系統(tǒng)中,會經(jīng)常出現(xiàn)“客戶公河澄荩”苟鸯、“線索”、“商機(jī)”棚点、“陌拜”這類名詞早处,搞清楚這些名詞代表的含義會讓我們對領(lǐng)域知識有更深入的理解。因此瘫析,弄清楚名詞概念是建模的第一步砌梆。
業(yè)務(wù)對象關(guān)系:業(yè)務(wù)對象的關(guān)系是軟件設(shè)計(jì)中最為復(fù)雜的部分,一個(gè)中大型產(chǎn)品可能會存在錯(cuò)綜復(fù)雜的關(guān)系贬循,而產(chǎn)品設(shè)計(jì)除了梳理清楚業(yè)務(wù)關(guān)系外咸包,一個(gè)很重要的工作是簡化關(guān)系。舉個(gè)例子杖虾,一個(gè)國家在歷史上會存在多個(gè)總統(tǒng)烂瘫,但是在一定時(shí)間段內(nèi)只會有一個(gè)總統(tǒng),通過添加時(shí)間段的約束奇适,我們就把一個(gè)一對多的關(guān)系簡化成了一對一的關(guān)系坟比。
業(yè)務(wù)規(guī)則:業(yè)務(wù)規(guī)則用于對業(yè)務(wù)進(jìn)行約束,以保障業(yè)務(wù)的合理開展嚷往。有些業(yè)務(wù)規(guī)則比較簡單葛账,例如表單的校驗(yàn)規(guī)則;有些業(yè)務(wù)規(guī)則則很復(fù)雜皮仁,例如電商平臺中的秒殺業(yè)務(wù)規(guī)則注竿。業(yè)務(wù)規(guī)則的處理相當(dāng)考驗(yàn)產(chǎn)品經(jīng)理的能力,很多開發(fā)人員會抱怨業(yè)務(wù)邏輯老是改來改去魂贬,其實(shí)很多時(shí)候改的就是業(yè)務(wù)規(guī)則巩割。這里,一方面是產(chǎn)品經(jīng)理在設(shè)計(jì)產(chǎn)品的時(shí)候付燥,沒有深入與業(yè)務(wù)方溝通業(yè)務(wù)規(guī)則宣谈,另一方面則是對業(yè)務(wù)規(guī)則的處理上比較隨意 —— 比如讓開發(fā)人員直接寫死代碼。有些業(yè)務(wù)邏輯會被其他邏輯替換键科,或經(jīng)常發(fā)生改變闻丑,這個(gè)時(shí)候就可以參考策略(Policy)設(shè)計(jì)模式漩怎。把這部分業(yè)務(wù)邏輯提取到一個(gè)單獨(dú)的“策略”對象中,實(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ū)動設(shè)計(jì)》中稱之為上下文(Context)胎署。上下文一方面是描述了某項(xiàng)功能的具體應(yīng)用條件吆录,另一方面可以為業(yè)務(wù)劃定邊界,從而幫助我們拆分或合并業(yè)務(wù)模塊琼牧。通過上下文可以將高度相關(guān)的業(yè)務(wù)內(nèi)聚為一個(gè)模塊恢筝,而將不相關(guān)的分離到其他模塊,從而保持單個(gè)模塊的精煉巨坊。舉個(gè)例子滋恬,我們在設(shè)計(jì)與第三方系統(tǒng)對接的模塊時(shí),就需要很清晰地將與第三方對接的部分從業(yè)務(wù)模塊中剝離形成單獨(dú)的模塊抱究,然后通過約定的規(guī)則與業(yè)務(wù)模塊進(jìn)行交互恢氯。這樣做的原因是,第三方的對接是不受控的鼓寺,如果發(fā)生變更勋拟,我們只需要更改剝離出去的模塊,而無需修改業(yè)務(wù)模塊妈候。
責(zé)任歸屬:責(zé)任歸屬在梳理業(yè)務(wù)流程中非常重要敢靡。產(chǎn)品經(jīng)理經(jīng)常會梳理業(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)移。對于 B 端產(chǎn)品而言想括,一個(gè)業(yè)務(wù)流程通常會經(jīng)過多個(gè)角色陷谱,這個(gè)時(shí)候明確每個(gè)角色承擔(dān)的責(zé)任就非常重要。一方面是有助于權(quán)限系統(tǒng)的設(shè)計(jì),另一方面則是能讓參與系統(tǒng)設(shè)計(jì)的人清楚地了解有哪些角色烟逊,以及每個(gè)角色承擔(dān)的職責(zé)渣窜。
這里需要提醒一下,對于剛做產(chǎn)品設(shè)計(jì)的人來說宪躯,會關(guān)注業(yè)務(wù)流程和功能的實(shí)現(xiàn)乔宿,而會忽略最核心的領(lǐng)域知識。結(jié)果導(dǎo)致產(chǎn)品難以貼合業(yè)務(wù)访雪,擴(kuò)展性不好详瑞。領(lǐng)域知識包括了業(yè)務(wù)對象概念、對象間關(guān)系冬阳、業(yè)務(wù)規(guī)則、應(yīng)用場景等等党饮。設(shè)計(jì)產(chǎn)品前肝陪,先把這些理清楚,再做產(chǎn)品流程梳理和功能設(shè)計(jì)會讓整個(gè)設(shè)計(jì)更加合理和易于擴(kuò)展刑顺。
怎么推進(jìn)領(lǐng)域驅(qū)動設(shè)計(jì)氯窍?
說實(shí)話,要推動領(lǐng)域驅(qū)動設(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ù)需要的怪圈朽基。
書中針對推進(jìn)領(lǐng)域驅(qū)動設(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è)動態(tài)的過程打却,如果決策過早固定下來杉适,開發(fā)團(tuán)隊(duì)可能束手束腳,失去解決問題的靈活性柳击。有了積極的反饋之后淘衙,當(dāng)遇到障礙或是出現(xiàn)了意想不到的機(jī)會時(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ì)的水平都是偏低的,這會導(dǎo)致業(yè)務(wù)領(lǐng)域模型設(shè)計(jì)開發(fā)水平糟糕具垫。即便有好的架構(gòu)侈离,業(yè)務(wù)層還是很難出眾。讓業(yè)務(wù)開發(fā)人員也能夠參與架構(gòu)設(shè)計(jì)中筝蚕,會讓架構(gòu)更貼合業(yè)務(wù)卦碾。
戰(zhàn)略設(shè)計(jì)需要遵循簡約和謙遜的原則:我們必須嚴(yán)格約束自己,從而使設(shè)計(jì)出來的組織原則和核心模型精簡到只包含能夠顯著提高設(shè)計(jì)清晰度的內(nèi)容起宽。
對象的職責(zé)要專一洲胖,而開發(fā)人員應(yīng)該是多面手:讓開發(fā)人員在編寫業(yè)務(wù)代碼的時(shí)候,也能參與需求分析坯沪、架構(gòu)設(shè)計(jì)绿映,這會有助于提高整個(gè)團(tuán)隊(duì)的設(shè)計(jì)開發(fā)水平。
這里特別說一下第4點(diǎn)和第6點(diǎn)腐晾。實(shí)際開發(fā)團(tuán)隊(duì)分工上叉弦,通常會讓高水平的程序員負(fù)責(zé)技術(shù)基礎(chǔ)設(shè)施 ——比如架構(gòu)設(shè)計(jì),底層組件的構(gòu)建藻糖,而把水平一般的開發(fā)人員分配去做業(yè)務(wù)開發(fā)淹冰。很多程序員也更愿意去往架構(gòu)方向上發(fā)展,因?yàn)檎莆樟恕巴ㄓ谩钡募寄芫奁猓啔v上更豐富樱拴。 然而,缺乏高水平的程序員去理解領(lǐng)域知識的話洋满,對業(yè)務(wù)領(lǐng)域的建模很可能沒法反應(yīng)核心的領(lǐng)域知識疹鳄,結(jié)果即便有良好的底層技術(shù)支撐,業(yè)務(wù)層面可能也一團(tuán)糟——最終所謂好的架構(gòu)也沒有地方發(fā)揮價(jià)值芦岂。 因此瘪弓,建議對核心領(lǐng)域的設(shè)計(jì)開發(fā),一定要高水平的產(chǎn)品禽最、開發(fā)人員參與腺怯。并在團(tuán)隊(duì)內(nèi)部沉淀核心領(lǐng)域知識,幫助整個(gè)團(tuán)隊(duì)理解核心業(yè)務(wù)川无,提高團(tuán)隊(duì)人員對業(yè)務(wù)的理解呛占。
總結(jié)
個(gè)人對領(lǐng)域驅(qū)動設(shè)計(jì)最深的感觸還是在領(lǐng)域知識的理解過程上。我們的 SaaS 產(chǎn)品一開始立項(xiàng)開發(fā)的時(shí)候懦趋,獲取到的領(lǐng)域知識其實(shí)非常片面晾虑,結(jié)果是產(chǎn)品推向市場后被客戶各種吐槽。然而,隨著種子客戶的深入使用帜篇,我們與客戶的交流也變得更多糙捺,對業(yè)務(wù)領(lǐng)域知識的理解逐步清晰。這個(gè)過程中笙隙,我們會發(fā)現(xiàn)之前很多的概念洪灯、關(guān)系的理解和實(shí)際業(yè)務(wù)存在不小的偏差,于是不得不逐步調(diào)整竟痰。到客戶增長到一定量之后签钩,發(fā)現(xiàn)很難繼續(xù)按照原有的設(shè)計(jì)繼續(xù)推進(jìn),于是重構(gòu)就提上了日程坏快。重構(gòu)铅檩,對于技術(shù)開發(fā)來說可能更關(guān)注性能瓶頸的解決,而對于產(chǎn)品設(shè)計(jì)來說則是領(lǐng)域模型的升級迭代莽鸿。
從這個(gè)過程中得到的經(jīng)驗(yàn)就是昧旨,雖然我們很難做到一開始就對領(lǐng)域知識理解非常深刻,但是應(yīng)該趁早梳理業(yè)務(wù)領(lǐng)域知識富拗,建立領(lǐng)域模型臼予。這需要我們產(chǎn)品經(jīng)理與業(yè)務(wù)人員進(jìn)行高頻次鸣戴、深入的溝通交流啃沪,并且能夠?qū)㈩I(lǐng)域知識準(zhǔn)確地傳達(dá)給測試、開發(fā)人員窄锅,以保障最終開發(fā)出來的產(chǎn)品能夠高效解決行業(yè)的業(yè)務(wù)問題创千。