1. 程式人生 > >領域驅動設計-讓程式設計師心中有碼(九)

領域驅動設計-讓程式設計師心中有碼(九)

一、易於腐化的軟體設計

猶記得剛剛參加工作時,是地圖廠商四維圖新集團旗下的一家子公司,主要從事規劃測繪相關軟體研發的公司。當時我的專案是為勘測設計院提供相對應的應用軟體,對地理資訊和規劃相關的圖紙資訊,幾乎已經專業水平。事實上,規劃設計大概和軟體設計類似,有規劃的設計、或無規劃的設計,造成的結果幾乎是天壤之別。

我們或許很容易就能設想到一個毫無規劃設計的城市,縱橫交錯的路網、雜亂無章式的建築佈局、各種凌亂的棚戶區設計,恰好象徵著軟體設計的無序性,也恰好體現了軟體企業在經費不足、組織缺乏管理、開發者能力不足、軟體隨時隨地想改就改時的行業現狀,只能說這樣的軟體是最能符合當時實際勞動生產力水平的產品。

如圖一所示,巴西棚戶區,層層疊疊、風格迥異、密密麻麻,如果作為一個外人貿然來到這樣的地方,大概很容易迷失期間、更不用說充斥在棚戶區的各類毒品和黑社會。雜亂無章的建築和街區,就像程式碼中錯綜複雜的呼叫鏈;而藉助貧民區搞事的黑社會就像是程式碼中的異味或者bug,表面上看起來如此平靜、與世無爭、但是你永遠也不知道啥時候會來一冷槍。

不要以為離我們很遠,我們其實輕易就能寫出這樣的軟體工程專案。不一定是“大泥球”系統,也有可能只是一些看似簡單的業務系統,但內部程式碼邏輯,可能會複雜到令人窒息的程度。也許那個時候有個別開發者也許會試圖靠自己的能力來改變局面,但是往往也會礙於屎山太大,難以下嚥。

大概只有最頂級的規劃設計師、耗費足夠多的資源,才能將這樣的軟體系統進行整改。然而,即便如此,如果以後沒有持續維護的手段、更好的設計、僅靠老程式設計師或個別架構師、盲目相信將單體服務拆分成微服務,幾乎不太可能實現軟體未來的可持續發展。

一個良好的軟體產品的一生、或許其實是一家企業一生的真實寫照。

在特定組織架構下,缺乏技術基因的組織有時候期待技術變革,卻會開啟新的泥坑。而那些渴望靠技術改變一切的技術專家,雖然擁有某些大廠微服務式架構、以及架構改造的經驗,他們也試圖通過自己的努力,為企業業務騰飛助力。而在他們過去的經驗中,往往相信組織遇到的問題,用微服務一定能解決問題。然後大肆擴招,一年內從幾個人的規模、擴招到數百人的規模,將原來的系統從單體服務、改良成為微服務。但是靠單槍匹馬根本無力拯救大勢,沒有更好的業務拆分策略,就只能按照資料庫的表名關係實現了最簡單的拆分。架構改造並非每次都會百試百靈,有時甚至連原來的需求都包不住,畢竟只能看到使用者介面層外觀上的表面邏輯,而隱藏在業務中的那數十萬行程式碼,哪怕包含了企業最有價值的經驗財富,也由於程式碼過於混亂,最終拋棄在原始碼管理器中,堪稱化神奇為腐朽。

二、易於腐化的面向過程開發

老系統改造也好、新系統開發也好,毫無疑問,我們最容易相信的其實是老程式設計師經驗,而程式設計師們掌控系統的方式,就是靠資料庫建模來驅動軟體開發的古老模式,而且幾乎都是面向過程式的程式碼,這些程式碼的流程幾乎一模一樣,只需簡單的按照步驟,一步步套模式,輕易就能學會。

1、檢視使用者介面,定義需要繫結到介面的模型和層級結構。

2、設計資料庫,不管什麼型別的專案,先根據客戶提供的業務表單、將其轉化成實體關係(ER圖)、然後建立對應的程式碼模型。有可能使用專業軟體設計ER圖,也有可能會使用Navicat軟體設計ER圖。

3、設計介面,然後把資料拼湊成使用者介面層所需的物件。

4、程式碼層次結構為傳統的三層架構,嚴格按照使用者介面層、業務邏輯層、資料訪問層進行設計,有時候會引入依賴注入框架,實現不同層次間的解耦。

但是有時候程式設計師不會嚴格區分需要編寫的程式碼,究竟是屬於哪個層次應該囊括的內容。於是毫無疑問,如果程式碼是為了實現使用者介面上某些資料繫結操作,程式碼就往使用者介面層寫;或者程式碼是為了實現從資料庫中抽取某些複雜資料、並構造成滿足使用者表現層邏輯的查詢物件,那麼就可以看到資料訪問層程式碼中那些臃腫的SQL語句或查詢方法。

正如“羅馬不是一天建成的”,屎山也同樣如此。這樣的寫法在程式碼剛剛編寫之初並沒有問題,只是隨著業務變化、時間的積累、程式設計師的水平、方法重構、新技術新元件的引入,程式碼將成為屎山。

這時,高階程式設計師們的價值,就在於他如何能夠在屎山中快速找到bug、並解決問題的能力,這大概是一種不能複用、不可再生的能力,因為永遠有讓人看不懂的垃圾程式碼,而且每家企業都有自己的特點,不同企業間往往不能迴圈利用。我一位朋友經常吐槽,他感覺自己的價值就是守住公司那份擁有8年曆史的古老程式碼,以便其他程式設計師在進行程式碼修改時,不會引發莫名其妙的bug讓系統無法運轉。

三、過程式開發和事務指令碼模式

在現代軟體工程學的教科書中,都會指出面向物件是解決軟體複雜性的方法,但實際上掌握這種方法的開發者並不多。由於開發者普遍缺乏抽象化思維,所以面向資料庫、面向過程式的程式設計習慣能夠成為業界主流,並非時代的倒退,而僅僅只是在短期效率和長期維護性上,被迫做出的艱難選擇。

假設我們設計出的符合三層架構的系統結構圖簡化後,如下圖所示:

我們來看看這種資料庫建模的開發流程中的輸出成果:

1、會定義兩種物件,分別是是面向UI層的模型(DTO)和資料實體(Entity)。在領域驅動設計中,將這兩種稱為所謂貧血模型,貧血模型,只有賦值器Set和取值器Get,(在Java裡面會使用POJO 這個名詞來定義)。貧血模型是為了作為儲存狀態或傳遞物件而存在,他並非按照實際用例場景對某類具體事務的抽象、也沒有與物件相關的行為。

2、定義資料訪問層來實現資料的持久化、或者從持久層實現資料的建立過程。資料訪問層存在的目的是為了構建上述貧血模型物件,這種訪問機制被成為“事務指令碼”。事務指令碼與物件行為割裂,而且容易導致異味產生。

3、與使用者行為相關的操作割裂的存放在不同層。有的可能放在使用者介面層、有的可能放在資料訪問層、有的可能放在業務邏輯層,造成了領域知識的丟失。

4、使用者介面層使用介面作為外觀或者一種行為、開發者會使用自己獨立的風格習慣來定義這種行為,就容易造成術語和規則不統一,也會為後期產品的維護迭代造成問題。

5、現在的軟體設計,往往要求輸出一份高保真的原型圖、也會按照敏捷專案管理的流程對這份原型圖建立持續更新的機制,確保原型圖是需求的具體表達,但是產品語言並非統一語言,也許產品語言具有業務含義,但是由於不能指導開發者進行介面、類、持久層的設計,造成了程式碼與需求的割裂。在張逸老師的《領域驅動戰術實踐》提到他曾經使用dimension和metric兩種不同的物件來定義一個維度物件,為程式碼造成了不必要的麻煩。我也曾經在一個專案,遇到過產品術語未能澄清,導致開發中使用style和theme兩種截然不同的定義來定義與“風格”相關術語,為程式碼引入了不必要的糾結。

四、領域驅動設計是什麼?

領域驅動設計引入了以下概念,但是我們無需在這篇文章中深刻理解這些概念的具體含義,我們只需知道,有這個東西。當我們開始按照領域驅動設計的方法設計一個系統時,按照前人整理的領域驅動的sample,往往就會將概念融匯貫通,達到更好的理解效果。

1、統一語言:定義好產品原型,需要建立統一語言。這是一種在內部和外部都能使用的規範化用語,包括UML、適當的圖、一致性的描述、以及專業術語和術語對應的英文描述。

2、實體:在領域中可以通過標識進行唯一值定位的物件。

3、值物件:在領域中,從其他領域或某個實體中分離出只包含某些特定屬性的物件。由於不具備唯一性特徵,往往無需用於資料持久化。

4、聚合、聚合根:將具有相關性的物件聚合在一起,並以聚合根的形式統一對外提供訪問方法和屬性欄位成員。

5、限界上下文:領域包含核心領域、子域和通用子域,而限界上下文則是一個具體業務的流程。每個限界上下文獨立於其他限界上下文而存在,獨立演進、功能完備。限界上下文的識別充滿技術含量。

6、領域服務:包括倉儲服務和工廠服務,前者負責實現物件與資料庫的操作過程、封裝了一系列資料庫操作的方法;後者則側重於物件的建立過程。個人認為從三層架構演進到領域驅動架構過程中,倉儲服務是最接近於資料訪問層的邏輯,也是讓大部分領域驅動架構最終又迴歸到三層架構的一種通病。從對資料訪問層中抽出物件、行為、資料訪問,是戰術設計的關鍵步驟。

領域驅動設計引入了一堆新的架構形式,包括經典的四層架構、EDA(事件驅動架構)、CQRS架構(命令查詢職責分離)。而由於Evans的原書沒有過分討論如何識別領域,後來又有許多大佬在他的基礎上進行了完善,提出了許多方法,包括名詞、形容詞、動詞建模法、事件風暴、四色建模等方法,限於篇幅,且聽下回分解。

五、思維的轉變,才是最大的困難

領域驅動設計,或許是解決這些問題的一劑良方,但也或許是開啟了暗黑世界的大門。

概念晦澀難懂、程式設計師們不願意開始思維變革、技術上可能存在不預期的坑、都可能讓新方法的實踐陷入一灘爛泥。還有許多人以為自己看懂了領域驅動設計(包括筆者),在往專案中運用時,總是有意無意的會被過程式程式碼的思維定式控制,讓架構回退到三層架構。

由於微服務架構的興起,讓複雜系統的開發維護成為大家普遍關心的問題,使得Eric Evans於十五年前提出的這套理論,在今天綻放出了新的光芒。當然領域驅動設計僅僅只是眾多面向物件程式設計的一種實踐,通過領域驅動設計將UML等方法靈活的運用其中,通過打破原有資料庫關係建模給程式碼造成的桎梏,讓開發者能夠真正的實現面向物件程式設計。

然而思維模式的轉換並非易事,從過程式程式碼中,抽離出與物件有關的行為,遠比理解這幾個概念要複雜,這需要大量經驗的積累。

毋庸置疑,資料庫建模驅動軟體開發具有速度快、學習成本低的顯著特點,在許多專案中,能在短期內可以給開發者帶來許多便利;而應用領域驅動設計,則可以在更長的維護週期內,給軟體維護帶來實質性好處。

兩種不同型別的開發模式,根據企業實際出發進行選擇,還只是開始,但能真正運用好領域驅動設計或者UML、面向物件設計這種軟體工程的美學思維來改造我們的系統,讓系統綻放出更加璀璨的光芒,這才是軟體設計的樂趣所在。

相關推薦

領域驅動設計-程式設計師心中

一、易於腐化的軟體設計 猶記得剛剛參加工作時,是地圖廠商四維圖新集團旗下的一家子公司,主要從事規劃測繪相關軟體研發的公司。當時我的專案是為勘測設計院提供相對應的應用軟體,對地理資訊和規劃相關的圖紙資訊,幾乎已經專業水平。事實上,規劃設計大概和軟體設計類似,有規劃的設計、或無規劃的設計,造成的結果幾乎是天壤之別

領域驅動設計程式設計師心中

#領域驅動設計,讓程式設計師心中有碼(四) ----------------------追憶有關分層的古老往事          我一直認為,程式設計師也是藝術家,他們撰寫的每一行程式碼,是獻給這大好世界的優美詩篇。不同的人,寫的程式碼也許風格迥

領域驅動設計程式設計師心中

領域驅動設計-聚合,一種極簡的思維模式 引言     作為IT技術產業飛速發展的產物,軟體工程學已經成為當今時代非常重要的一個學科。作為一名資深的軟體開發從業者,我們需要學習的東西實際上已經遠遠超出了原本在大學教育階段所接受的知識深度和廣度,領域驅動設計更是如此。當然必須承認

領域驅動設計程式設計師心中

 回顧   領域驅動是十五年前,由Eric Evans提出的解決軟體工程複雜性問題的方法,作者從自己多年軟體開發的角度出發,通過引入領域驅動設計的概念以及一系列戰略設計模式和戰術方法,為混沌的軟體開發領域帶來了一縷陽光。   在過去的許多年,我經歷了從技術崗位到管理崗位的變化,也深深的意識到,每

領域驅動設計程式設計師心中(三

  “正如西方古典哲學在現代社會逐漸式微,成為少數內心豐滿者們填充自己精神世界的寶貴食物,UML也這樣;網際網路技術飛速發展的今天,各類軟體設計思想層出不窮,正是站在UML和其他各種軟體基礎理論巨人的肩膀上,成就了當代軟體產業的輝煌。”     如果說軟體工程是在虛擬的世界描繪出人類對於這世界一切大千萬物的

領域驅動設計程式設計師心中

我一直認為,程式設計師也是藝術家,他們撰寫的每一行程式碼,是獻給這大好世界的優美詩篇。不同的人,寫的程式碼也許風格迥異。有的,如春風化雨潤物無聲,有的,如高山流水,曲高和寡,還有的如旱日春雷,先聲奪人。而如果說,程式碼是詩篇,那麼程式碼的分層藝術絕對是最先映入讀者眼簾的序幕了。 分層,一直以來是一

領域驅動設計程序員心中

導致 很多 集成 努力 設計模型 思考 思想 內聚 單反            引子,軟件工程沒有銀彈    上一篇博文,拋出了一個問題,領域驅動設計真的是萬能的良方嗎?對於這個問題,大家的答案無疑是一致的,作為一種非常受軟件行業歡迎的軟件思想,領域驅動設計固然有很多

領域驅動設計程序員心中

流程 處理機 解耦 驅動 容易 優點 含義 低耦合 程序 領域驅動設計- 讓程序員心中有碼(七) -設計原則和設計模式,互聯網開發者們共同的追求 前言   多年來,筆者一直從事傳統軟件企業的軟件開發和項目管理工作。筆者發現在眾多的傳統軟件企業中,評判優秀開發者的

互聯網研發設計模式之領域驅動設計程序員心中

集體 個人經驗 隨著 無法 需求調研 組織 一致性 一段 center    傳統項目管理模式,讓設計成為累贅 作為一名資深軟件行業從業者,我以前一直從事項目開發。在項目執行過程中,往往會采用快速開發模式,按照軟件工程的基本流程建立一套項目軟件管理模式。這個流程大

領域驅動設計程序員心中

需求 制造業 甚至有 model 表達 網頁程序 參與 控制系統 業務規則 我一直認為,程序員也是藝術家,他們撰寫的每一行代碼,是獻給這大好世界的優美詩篇。不同的人,寫的代碼也許風格迥異。有的,如春風化雨潤物無聲,有的,如高山流水,曲高和寡,還有的如旱日春雷,先聲奪人。而如

程式設計師愛情程式設計師適合表白的一個句子

2018年10月18日20:39:33 在我們學校表白牆發了一個找物件的帖子碰碰運氣,結果沒收穫也是意料之中。 沒想到大家評論這麼多,那以後會多寫一些這方面的東西,作為工作之餘的娛樂。 其實脫不脫單不重要,一個人也很好,現階段主要是讓自己變得更優秀吧, 最後一次發表白牆,希望大家

3年工作經驗程式設計師應有的技能面試

面試主要看幾點:專案經驗+基本技術+個人潛力(也就是值不值得培養)。 關於專案經驗,我認為併發程式設計網的創始人方騰飛老師講的一段話非常好: 介紹產品時面試官會考察應聘者的溝通能力和思考能力,我們大部分情況都是做產品的一個功能或一個模組,但是即使是這樣,自 己有沒有把整個系統架構或產

程式設計師的日常發呆

業務程式碼敲著敲者就莫名其妙走神了~ 回過神來,半個小時又過去了。 不知是年齡的日益增大導致的,還是習慣性熬夜引起的。 前幾個月學了markdown就愛上了markdown 感覺自己都好久沒開啟word了。 前幾周的公司內部技術分享會就發現了寫文件的好處。 我其實就直接把內網上wiki的

程式設計師修煉之路一個清華大學畢業生做獵頭的感受

從來沒有想過自己會加入這一行,從開始自己喜歡的專業通訊,到後來喜歡的管理,幻想過是專業高手,幻想過管理專家,卻從來沒有想過進入這一行,但真的在我剛剛離開校園的時候發生了,短短几天,對這個行業有了一個感性認識,其實最讓自己傷感的不是自己沒有幹這一行的經驗,而是代理的人,要找的人

程式設計師必備‘神器’ ——Git

須知: 1.Git與大家熟知的GitHub沒有一點關係 2.本文不會對Git進行知識點的講解,只是表達一些小編的看法 百度百科:Git是一個開源的分散式版本控制系統,可以有效、高速的處理從很小到非常大的專案版本管理。Git 是 Linus Torvalds 為

一位老實程式設計師的心魔心魔因委屈而孕育,因失望而長大

        在我現在的公司做軟體開發真心很累。我來了之後APP從無到有,從分析需求到原型設計,再到介面文件,這些其它崗位的活兒分配給我,我願意承擔,我喜歡,但是唯有一點我不認同,就是把他人的多數問題總是推脫給我,而我卻孤立無援。  我如果不澄清自己的清白的話那些問題永遠是

黑馬程式設計師——Java集合框架之迭代器、Collection層次結構等

-----------android培訓、java培訓、java學習型技術部落格、期待與您交流!------------ 集合框架概述 一、什麼是集合框架   1.什麼是集合?   集合是指把具有相同性質的一類東西匯聚成一個整體,簡單說就是指儲存資料的一個容器。集

萬里長征,始於足下——菜鳥程式設計師的學習總結

目錄: 最近一直的談論如何學習,如何做筆記,學習方法是否正確?(發現問題——創新的原動力)為什麼開始系統化學習了,反而暴露許許多多的問題?細想也並不是很多,這都是過去的遺留問題,就當磨刀不誤砍柴工吧。 學習VB的時候,我原來學習過一遍。第二次再看視訊學習VB,做筆記,畢竟是自己學過一遍的知識,沒有太

初級程式設計師面試題總結

本人將這幾天面試的題目總結一些,如果出現錯誤請指正,謝謝。 1,談一談spring。 答:spring是為java程式開發提供的綜合性的基礎java開發平臺,它提供了從表現層SpringMVC到業務層Spring再到持久層springData的一套完整的解決

黑馬程式設計師——Java IO流之流操作規律總結、File類、Properties類、序列流等

-----------android培訓、java培訓、java學習型技術部落格、期待與您交流!------------ 六、流操作規律總結  1.明確源和目的:   源:    字元流:FileReader(純文字檔案)。    位元組流:FileInputStream(