《企業應用架構模式》讀後感

martin fowler老爺子的《企業應用架構模式》一書在江湖上流傳已久,在十幾年前就企業應用中的典型場景及設計模式進行了思考和總結,能夠看到書中說起的經常使用模式在現在流行的企業應用框架中已經落地。近日拜讀,受益很多,將一些感悟和共鳴記錄下來,整理下,不全面也不深刻,只便於後續亂翻書。html

寫在前面

行文知其思惟,martin老爺子的書寫起來條理清晰,井井有條,易於理解,很是值得稱道,本文借鑑martin先生的行文模式,每一種模式均包含以下幾部分:模式概要、個人理解、項目實踐。但願經過後面兩部分的介入,嘗試將對應要點落地。web

知識概要

該書第一部分「表述」對書中說起的各類模式及知識要點作了歸納性介紹。主要從抽象層面介紹了企業應用中遇到的架構問題及常見的解決思路。涉及到:分層架構思想、領域邏輯組織、orm、web表現層、併發、會話狀態及管理、分佈式相關等。redis

企業應用

企業應用時將計算機技術這一輩子產力做用於現實世界的表現形式。一個企業應用的設計須要考慮清楚該應用的業務目標、受衆人羣等。企業應用通常有以下特色:spring

  • 須要持久化數據。採用何種持久化介質?如何持久化?
  • 涉及大量數據。數據存取的高效性?數據容量?存儲介質如何支持數據的快速增加?
  • 多人同時訪問數據。併發問題?服務可用性?用戶會話管理?
  • 大量用戶交互。交互方式?服務可用性?
  • 同其餘企業應用之間的集成。系統集成形式?如何下降耦合?快速集成?

斜線部分是我想到的一些關注點。數據庫

架構

關於「架構」的定義,衆說紛紜,martin認爲能夠統一的兩點有:後端

  1. 最高層次的系統分解;
  2. 系統中不易改變的決定。

在不一樣人看來,在不一樣的上下文下,在不一樣的系統生命週期時,對於「架構」的理解是不同的。重要的是可以因時因地地選擇合適的架構模式和設計。設計模式

分層

一般將系統分爲多層,層與層之間約定好契約,下層對上層按照契約提供服務。api

分層是最經典也是最多見的一種架構思想,在網絡協議的設計中,在應用系統的架構設計中,都使用到了分層的設計思想。緩存

分層能夠帶來以下好處能夠歸納爲:層內部內聚,層之間解耦。層內部的內聚能夠專一於本層的核心邏輯,層之間解耦,下降層與層之間的耦合,能夠替換其中某一層的實現而不對其餘層產生反作用。安全

分層一樣可能帶來反作用:人爲引入的「分層」會給開發增長必定工做量,同時可能帶來必定的性能損耗。

個人理解:「分層」及其餘架構模式都是人爲引入的,目的是爲了讓人更好地理解和維護程序和系統。對於計算機而言,它進行資源分配和調度的單位是進程,它只知道有多少個進程,每一個進程使用了哪些資源,還須要哪些資源;對於計算機來講,它並不也不須要知道即將執行的二進制流涉及到多少分層,爲何要這麼分層,對於機器來說,它只認二進制;可是因爲代碼是人寫的,系統是人搭建的,須要人來維護,所以,經過「分層」可以讓人更好地理解程序,更好地理解系統設計,提升人與人的溝通效率,提高系統可維護性。

模式

「模式」一詞你們都在用,簡單來說就是咱們經過實踐發現的一些有價值的設計或者解決方案,這些方案能複製到相似的問題域中很好地解決問題,從而提高生產效率,他是經過實踐找到的捷徑。書中給出了Chirstopher Alexander給出的定義,我以爲很好:

模式描述一個不斷重複發生的問題以及該問題解決方案的核心,這樣咱們可以使用該方案二沒必要作重複勞動。

因此,一個模式包含以下關鍵部分:問題上下文、核心解決方案。martin的書在講後續的每一個模式的時候,也據此將模式分紅了幾部分來介紹:模式名稱、意圖和概要、運行機制、使用時機、進一步閱讀。

 模式總結

事務腳本

  • 模式概要:事務腳本使用過程來組織業務邏輯,每一個過程處理來自表現層的單個請求,能夠適用於簡單的業務場景,能夠加快開發速度,去掉繁瑣的分層。
  • 個人思考:事務腳本並非指現階段不少項目中出現的「麪條式」代碼,而是根據簡單業務場景簡單處理,不引入複雜分層,一個過程走到底,對於簡單/臨時性的業務應用,能夠快速開發/測試,省去了繁瑣的框架搭建。

  •  

    項目實踐:實際項目中並無遇到能夠應用事務腳本的場景,一般意義上的企業應用,業務邏輯都不會太簡單,也不是臨時性的項目。

 領域建模

  • 模式概要:合併了行爲和數據的領域對象模型,核心在於將易變的業務邏輯內聚在領域模型中。
  • 個人思考:領域建模應當是開發人員/架構師須要增強的能力,經過領域建模對涉及的業務領域有更深刻的瞭解,同時合理的建模,確保業務邏輯內聚,使企業應用更易於維護和迭代。

  這方面的理論知識能夠參考Eric Evans的《領域驅動幹設計-軟件核心複雜性應對之道》,實踐相關的內容能夠參考Vaughn Vernon的《實現領域驅動設計》,也能夠參考個人系列博客【DDD】使用領域驅動設計思想實現業務系統

  初學者在實踐DDD的時候,首先須要改變思惟方式,業務領域的分析和建模是關鍵,經過不斷的實踐總結,造成本身的一套完整的建模戰術。

  另外,DDD對於複雜性較高的應用系統優點更加明顯,咱們團隊在用戶系統和社區系統都進行了DDD的實踐,發現相比用戶系統,DDD在社區系統的優點發揮的更充分。

  最後,DDD須要不停地實踐,不要追求一步到位,模型能夠不斷地迭代完善,DDD的實踐也是如此。

標識域

  • 模式概要:爲了在內存對象和數據庫之間維護標識而在對象內保存的一個數據庫標識域。標識域知足兩個特性:惟一性、不可變性。
  • 個人思考:在數據庫中一般存在兩種類型的惟一且不可變鍵,一個是業務主鍵,一個物理主鍵,那麼應當使用哪一個主鍵來做爲標識域呢?
    • 能夠根據DDD中介紹的實體和值對象來作區分,若是是實體,那麼建議是用業務主鍵,好比「User」和「Order」,分別可使用userNo和orderNo來標識。而對於值對象,能夠直接使用其物理主鍵做爲標識域,好比「用戶點贊信息」,可使用物理主鍵id做爲標識域,固然也可使用業務聯合主鍵(userNo和postNo)做爲標識域,可是會增長複雜度,不可取
    • 另外,一般狀況下,咱們能夠將物理主鍵命名爲以Id結尾,將業務主鍵命名爲No結尾;
    • 不少服務場景,須要將實體的標識域暴露給調用方,就要考慮安全性問題,若是你的標識域是順序遞增的long型主鍵,那麼極可能會被攻擊者遍歷,從而帶來一些安全風險,這時候能夠作以下兩種考慮:標識域再也不使用順序遞增的long型主鍵,而是使用不可遍歷的uuid等;若是無法將標識域更改成uuid,那麼考慮新建一個域,存儲專門供外部使用的uuid值。好比:咱們在用戶系統中便爲User建立了一個使用uuid值的UnionId字段。
    • 不建議先後端將標識域明文傳遞,尤爲是越權訪問會帶來數據泄露問題的場景,好比:查詢用戶信息,這時候實體的標識域應當考慮從會話中獲取,避免越權訪問帶來的數據風險
  • 項目實踐:訂單系統中,咱們使用業務主鍵orderNo做爲Order實體的標識域,且因爲orderNo形式爲:yyyyMMddHHmmssSSS+sequence,被遍歷的成本很是高,所以直接暴露在外使用。

外鍵映射

  • 模式概要:把對象間的關聯映射到表間的外鍵引用。
  • 個人思考:外鍵映射適用於:1:1及1:N的關聯關係,一般讓非root實體持有root實體的標識域,好比唱片持有做者的標識域,曲目持有唱片的標識域。
  • 項目實踐:社區系統中的「帖子」實體持有「用戶」實體的標識域,在數據庫中則表現爲Post表持有一個userNo字段。

關聯表映射 

  • 模式概要:把關聯保存爲一個表,帶有指向表的外鍵。
  • 個人思考:外鍵映射適用於:N:N的關聯關係,關聯表一般對應一個值對象。關聯表一般存在兩個方向的查詢入口,這兩個入口跟關聯表外鍵對應的實體表有關,那個在DDD中,該關聯表就能夠同時屬於兩個「聚合」中。好比用戶體系系統中「用戶帳戶關係表」(UserAccount),做爲值對象,持有userNo和accountNo;存在根據userNo查詢accounts的場景,也存在accountNo查詢UserAccount的場景;能夠看出UserAccount屬於User和Account這兩個「聚合」中。
  • 項目實踐:用戶體系系統中「用戶帳戶關係表」,做爲值對象,持有userNo和accountNo。

 單表繼承

  • 模式概要:將類的繼承層次表示爲一個單表,表中各列表明不一樣類中的全部域。
  • 個人思考:書上列出了以下優勢:只需關注一張表,對象繼承層次更改時無需更改存儲層;缺點也很明顯:數據庫空間浪費,維護成本增長,可擴展性差。實際的項目經驗代表,最好少用這種模式,好比在社區系統中,多個渠道發佈的評論屬性不同,開發人員將多個渠道的評論屬性整合放入到一張表中,且文檔註釋不全,致使後續開發人員踩坑,在寫程序時不清楚每一個字段的實際適用渠道,維護起來很是麻煩。並且後續某些渠道下線後,該大表中多餘字段仍然保留,形成了極大的空間浪費。
  • 項目實踐:社區系統中的評論表,存儲來自多個渠道的評論內容,且缺少註釋,業務代碼混亂,致使難於維護。

類表繼承

  • 模式概要:將各個子類的公共屬性放入一張父表中,子類的非公共屬性放入各自的子表中。
  • 個人思考:該模式最大的優勢在於:領域模型和數據庫結構之間關係一致,利於理解;缺點在於:讀取一個對象須要多表訪問,性能上須要注意。
  • 項目實踐:無。

具體表繼承

  • 模式概要:每一個子類對應一個具體表,多個具體表之間可能存在相同的字段。
  • 個人思考:該模式最大的優勢在於:相比「類表繼承」獲取完整對象時,無需錶鏈接查詢;每一個表都是自包含的,無不相關域;缺點在於:領域內全局主鍵較難處理;類繼承層次該表對錶結構影響較大。全局主鍵的問題能夠考慮使用:Id+type這種聯合主鍵的形式來解決,每一個子表使用獨立的seq,每一個子表定義一個類型字段,映射到模型時,使用Id+type做爲全局惟一主鍵;另一種方案是:使用全局的seq,全部子表共用一個seq,壞處在於每一個子表id的不連續性;公共seq可能成爲資源瓶頸。
  • 項目實踐:用戶體系的**帳號表和理財帳號表就是使用這種模式來建表的,固然如今是對**帳號和理財帳戶進行獨立建模,因此影響倒不是很大,可是此種模式的一個缺點較爲明顯:每次須要查詢某個用戶下的全部帳戶列表時,須要同時查詢**帳號和理財帳號表,若是使用「類表繼承」模式,則能夠避免多表查詢,由於在這個查詢場景下,僅僅須要查詢帳戶的基本信息:帳號、開戶日期,這些屬性是全部帳號共有的,所以徹底能夠從父表中獲取。

資源庫

  • 模式概要:協調領域和數據映射層,使用相似於集合的接口來訪問領域對象。
  • 個人思考:資源庫repository是一個很常見的術語,它能夠理解爲一個存儲層的gateway,也能夠理解爲一個存儲層的facade,repository提供面向對象的查詢原語,能夠參考elasticsearch等內存數據庫的api實現。在存在多個存儲介質的系統中個,可使用repository包裝多個存儲介質的實現,好比整合redis緩存和oracle主存配合使用的數據存取過程;還能夠有基礎自repository的啞實現,使用領域模型沒必要依賴於存儲層也能夠快速完成建模。
  • 項目實踐:用戶體系和社區系統中均有使用到,使用場景見上面描述。課參考:【DDD】領域驅動設計實踐 —— 一些問題及想法 中的「二、repository的實現」一節。

Web表現模式

  • 模式概要:經典的MVC模式,將‘視圖(View)’、‘模型(Model)、‘控制器(Controller)’分離。
  • 個人思考:MVC是很是經典的設計模式,從struts到springmvc,研究springmvc足矣,囊括了filter、inteceptor等基本組件。
  • 項目實踐:web類項目基本逃不掉MVC,再也不贅述。
相關文章
相關標籤/搜索