DDD 的哲學意味(下)

核心域與主要矛盾

大約公元前 800 年至前 200 年間,中國、希臘、印度和以色列的文明幾乎在同一時期興起,這被稱爲人類文明的軸心時代。不同文明展現出了不同的風貌。中國古代文化強調辯證邏輯,重視變化、聯繫和綜合的思維方式,同時又有 “子不語怪力亂神,六合之外存而不論” 的唯物主義傾向。古希臘則重視嚴格的推理和分析,孕育了形式邏輯和公理化的數學體系。印度在婆羅門和佛教哲學中,從另一個方向將辯證法、邏輯和語言學推向極致。以色列的先知則創立了一神論的猶太教和政教合一的社會體制。

直到近代,西方纔產生了系統的辯證法體系,集大成者是黑格爾。馬克思和恩格斯吸收了黑格爾的辯證法,揚棄了其中的唯心主義成分,形成了辯證唯物主義,成爲了風起雲湧的無產階級革命的理論基礎。後來唯物辯證法傳入中國,與中國傳統文化中的辯證法和唯物主義思想一拍即合。爲了將馬克思主義中國化,毛老師寫出了《實踐論》和《矛盾論》。前文提到了《矛盾論》第一部分 “兩種宇宙觀”,這一節看一下第四部分 “主要的矛盾和主要的矛盾方面”。

事物中包含着多種矛盾,其發展變化成爲事物發展的內在動力。在多種矛盾中,一般會有一種占主導地位,稱爲 “主要矛盾”。要有效地處理問題,就要抓住主要矛盾。

例如某籌備開業的保險公司要開發一個保險核心系統。在開始時,“快速開展新單業務的需要與落後的新單處理能力”的矛盾就是主要矛盾,而 “快速理賠的要求與落後的理賠能力” 之間的矛盾則是次要矛盾。這是因爲,新開業的保險公司首先面臨的是新單業務的壓力而不是理賠的壓力。

在領域驅動設計中,領域模型中包含主要矛盾的部分,稱爲 “核心域”(Core Domain)。在複雜的領域模型中,將核心域識別並有效處理的過程稱爲 “精煉”(Distillation, 《領域驅動設計》第 15 章)。領域驅動設計中還提供了 “領域願景說明”(Domain Vision Statement),“強調核心” (Highlighted Core), “分離核心”(Segregated Core)等模式用於精煉過程的具體實踐。

隨着內因和外因的變化,主要矛盾和次要矛盾會發生轉化。例如,當處理新單業務的系統成熟後,就成爲了次要矛盾,而理賠則成爲主要矛盾。當理賠也成熟後,靈活的產品和算法的定義可能變爲主要矛盾。

總之,以矛盾的觀點看問題,就可以知道識別和處理 “核心域” 的必要性,同時以發展的眼光看待覈心域的轉化。

這裏還有一個微妙的問題:目前業界不同人所說的 “核心域” 的含義是有區別的。假如我們把業務需求作爲“問題空間”,將軟件系統的分析和設計作爲“解空間”,那麼《領域驅動設計》一書中所說的核心域實際上處於解空間,而另一本《實現領域驅動設計》中的核心域說的是問題空間。

《領域驅動設計》中,核心域在 “精煉” 一章中。其邏輯在於,先有領域模型,然後在領域模型發展到一定的複雜程度時,就需要從中 “精煉” 出核心域了。由於領域模型處於解空間,因此《領域驅動設計》中的 “核心域” 談的是解空間的問題。

而《實現領域驅動設計》中的核心域則來自於對業務問題的分解,因此屬於問題空間,先於領域模型的建立。

存在兩個層面的 “核心域” 的現象具有一定的合理性。因爲矛盾是普遍存在的,既存在於問題空間,也存在於解空間,兩者都有“主要矛盾”,所以可以說兩個層面都存在覈心域。

目前多數人理解的核心域是《實現領域驅動設計》中的說法,而《領域驅動設計》原書中的模式和實踐卻沒有得到重視。領域驅動設計本來要求 “統一語言”,但“核心域” 這一概念自身已經不統一了。這是業界需要解決的一個問題。

下一節就來看看與統一語言相關的問題吧。

統一語言與哲學的 “語言轉向”

前面介紹了哲學從本體論向方法論的轉變。在方法論方面,洛克、休謨、帕斯卡等等大家宛如哲學天空中的星斗,而黑格爾和康德是其中最璀璨的兩顆。

然而新的問題來了。這些哲學家的著作中往往充斥着晦澀的詞彙,其中很多是自造的,在此基礎上又進行了複雜的推演,然後產生了更加晦澀的語言。這些莫衷一是的概念又被後人按照自己的意思做了不同的解釋。後果是,不僅普通人難以窺其門徑,即便專業的哲學工作者,也會爭論不休。儘管由此產生了大量論文和 “學術成果”,但人們也逐漸意識到,很多爭論僅僅是由於對同一名詞的理解不同,而沒有解決任何實際問題。這樣的哲學除了在象牙塔中孤芳自賞,又有多少實際意義?

到了十九世紀末,人們逐漸意識到問題很可能出在 “語言” 上,很多哲學問題來源於對語言的誤用。解決了語言問題,就解決了哲學問題。由此產生了“語言哲學”,併成爲了二十世紀上半葉英美哲學的主流。如果說認識論是“對思考的思考”,那麼語言哲學就是“對言說的言說”。儘管歷史上有很多哲學家也很重視語言,但那時語言只是研究哲學的工具;而現在,語言成了哲學本身。這種哲學關注點的轉移,稱爲“哲學的語言轉向”(the linguistic turn in philosophy)。

信息技術和語言有着不解之緣。當您初次學習編程,知道了一條條指揮計算機工作的指令被稱爲計算機 “語言” 時,是否曾像我當初那樣,有過一絲的驚訝?

在領域驅動設計中和語言直接相關的模式是 “統一語言”(Ubiquitous Language)。該模式出現在《領域驅動設計》的第二章,屬於該書第一部分“運用領域模型”,與“消化知識” 和“模型驅動設計”共同作爲全書的總綱。

“統一語言” 要求業務和開發人員要用一致的語言來溝通。例如,同一個概念應該用同一個詞彙,同一詞彙也僅表達唯一的概念。這一道理是如此 “直白”,爲什麼領域驅動設計還要專門強調呢?因爲這一實踐看似不難理解,但要在實踐中真正做好則不太容易。下面我們從語言哲學的角度看一看軟件開發中有關語言的問題。

首先,語言哲學認爲,語言的意義是在使用的過程中體現出來的。

前面提到的早期哲學家,他們的語言是爲了表達自己的觀念自造的,並沒有真正被用來解決實際問題,因而沒有 “恰當” 地使用語言,從而造成了新的哲學問題。

回到軟件開發,如果對軟件的理解只是寫在文檔中,而這些文檔很少有機會被閱讀,沒有真正起到交流的作用,那麼也可以看作對語言的誤用。這也正是敏捷軟件開發所反對的。而統一語言強調不同干係人,尤其是業務人員和開發人員間的溝通。只有在協作中,統一語言纔有意義。

近年流行的 “事件風暴” 方法,也可看作是統一語言的應用。事件風暴和經典的用例分析方法所解決的問題其實是類似的,都是爲了捕獲行爲需求,爲進一步的領域建模奠定基礎。事件風暴中的 “風暴” 來源於頭腦風暴,是常用的溝通協作方法。因此,溝通協作是事件風暴的內在組成部分,這一點是事件風暴優於傳統的用例分析的地方。

其次,語言哲學強調語言的表達能力是有的限度的。

如維特根斯坦所說,“凡可說的,皆可說清;凡不可說的,應保持緘默”。前面提到的早期哲學家的另一個問題,就是強行用語言表達無法表達的東西。 

領域驅動設計認爲,軟件開發的過程可以看作知識的學習、構建和運用的過程。而有些知識是語言難以表達的。不過,難以表達不代表不可知。比如說,我們難以向沒有喫過梨子的人描述梨子的味道,但這並不代表梨子的味道是不可知的,只要嘗一下就可以了。軟件開發中的不可言說知識同樣不是玄學,而完全可以通過持續的交流和實踐來掌握。因此,不要期望通過文檔可以表達所有知識,而要回歸到干係人之間的溝通和協作。

再次,語言哲學認爲,語言只有在特定的語境(Context)中才有意義。

前文已經提到,領域驅動設計中利用限界上下文(Bounded Context)來保證概念的一致性。而統一語言是針對限界上下文而言的,只有在其所處的上下文中才有意義。英文 Context 在中文中有兩種譯法:“語境”和 “上下文”。目前《領域驅動設計》一書中採用了“上下文” 的譯法。其實譯作 “語境” 可能更恰當,在 “語境” 中運用“語言”,意思會更協調一些。

最後,語言哲學又可分成兩大流派:較早的 “理想語言學派” 和晚一些的“日常語言學派”。

理想語言學派認爲自然語言是模糊的,哲學的出路在於利用數理邏輯創造一種形式化的語言。這種語言不僅表意明確,而且可以跨越各種自然語言。這在後來導致了計算機科學的基礎理論 “形式語言與自動機” 的產生。

這一過程可以追溯到十七至十八世紀,萊布尼茨發明的二進制以及提出的 “通用文字”(characteristica universalis)的構想。到了十九世紀,布爾利用二進制使邏輯成爲了數學演算。布爾代數至今仍然是計算機科學的基礎。稍後,現代邏輯學之父弗雷格提出了一階謂詞演算。這一理論也導致了像 Prolog 這樣的邏輯編程語言的誕生。二十世紀,羅素、哥德爾等人進一步將數理邏輯發揚光大。後來,圖靈提出的 “圖靈機”,丘奇提出的 lambda 演算,成爲了算法和編程語言的數學基礎。我們程序員所使用的各種編程語言,也可以算作形式語言。

較晚出現的一派則認爲自然語言本身就是精確的,之所以會讓人覺得模糊,是因爲沒有進入特定的語境。因此,應通過對自然語言本身的研究處理哲學問題,而無需藉助形式語言。這就是 “日常語言學派”。

對於軟件開發者來說,沒有必要陷入哲學家的爭論。我們反而可以看到兩者各自的合理性,以及互相銜接的可能。

一方面,計算機中運行的是二進制的字節流,而這又是由編程語言編譯得來的。機器語言和編程語言都是形式語言。另一方面,計算機所要解決的業務問題,卻開始於日常語言或者說自然語言的描述。因此我們必須有一種自然語言和形式語言的轉換機制。領域驅動設計中的領域建模正是這一機制的重要環節。領域模型在自然語言和編程語言之間建立起了橋樑,幫助跨越兩者之間的巨大鴻溝,成爲開發複雜軟件的重要手段。

領域驅動設計中,常用 UML(統一建模語言)進行領域建模。嚴格地說,UML 也是一種形式語言。不過比起編程語言,UML 更貼近業務概念,更容易與自然語言轉換。同時,用 UML 建立的領域模型,又可以方便地映射到編程語言和數據庫設計。UML 常用於軟件系統的分析和設計,而編程語言用於編碼。在分析、設計、編碼過程中保持語言的統一,是統一語言的另一層意思。

小結

我們用若干章節探討了領域驅動設計的哲學內涵。兩者之間的這種契合關係並非偶然。

哲學的主要目的是解決對世界進行認識(認識論)和詮釋(語言哲學)問題。前面說的本體論,從現在的觀點來看也可以理解爲一種對世界的詮釋。

計算機系統本質上是用軟硬件對現實中的事物以及邏輯進行模擬,進而解決現實中的問題。計算機軟件可以看作現實世界的模型。在計算機中最終運行的模型是二進制流,這在形式上與現實世界有巨大的差距,這是軟件開發的本質複雜性之一。

爲了跨越現實世界和二進制模型之間的鴻溝,軟件開發方法學採取了漸進的方式。首先將現實世界映射爲分析模型,然後由分析模型映射爲設計模型,再映射爲編程語言模型,最後編譯成二進制模型。通過這種逐層遞進的方式,來化解軟件開發的困難。

領域驅動設計中所說的領域模型,主要指上面說的分析模型,目的是爲了反應業務概念,也兼顧了一定的開發視角。建立領域模型的過程,就是認識現實世界中的概念及其發展變化邏輯的過程,而這正是認識論和語言哲學的應用場景。這就是哲學對領域建模以及整個軟件開發過程具有指導作用的原因。

對領域建模的強調,並非始自領域驅動設計,而是從軟件開發方法學出現的時候就已經開始了。早期的結構化方法學,採用數據流圖和 ER 圖等方式進行建模。後來發展爲面向對象方法學,採用對象建模的方式。領域驅動設計則是對面向對象方法學的歸納和發展,爲面向對象方法學建立了一套模式語言,使之更容易學習和運用。

領域驅動設計主要面向的還是傳統意義上的軟件開發,尤其是企業應用的開發。經過幾十年的發展,至少在理論上已經研究得比較透徹了,難點在於工程上的推廣和應用。而近年來,人工智能、大數據以及下一代互聯網的發展,帶來了一系列新的問題:隱私如何保護?誰擁有個人行爲數據的所有權?人工智能是否會剝奪人的自由意志?怎樣判定人工智能作惡的法律責任?機器人可以用於戰場嗎?個人怎樣面對高科技所帶來的焦慮?等等。這些則是倫理學、心靈哲學所要討論的問題。這些話題超出了領域驅動設計的範圍,我們的討論,也可告一段落了。

參考閱讀

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/CfuI-6aGn7gc6vbq2DbJVQ