代碼整潔之道-第11章-系統-讀書筆記

第 11 章 系統

  要將注意力放到代碼組織的更高層面,才能獲得整潔的代碼。java

11.1 如何建造一個城市

  城市在沒有一我的管理時,也能正常運轉,是由於它能演化出恰當的抽象等級和模塊。
  本章將討論如何在較高的抽象層級—系統層級—上保持整潔。web

11.2 將系統的構造與使用分開

  首先,構造與使用是很是不同的過程。
  軟件系統應將啓始過程和啓始過程以後的運行時邏輯分離開,在啓始過程當中構建應用對象,也會存在相互纏結的依賴關係。
  每一個應用程序都該留意啓始過程。將關注的方面分離開,是軟件技藝中最古老也最重要的設計技巧。
  延遲化初始化/賦值(獲取對象時,若是對象爲空則建立對象,反之則直接返回對象)的好處是在真正用到對象以前,無需操心這種架空構造,啓始時間也會更短,並且還能保證永遠不會返回 null 值。壞處是獲得了對象及其構造器所需一切的硬編碼,不分解這些依賴關係就沒法編譯,即使在運行時永不使用這種類型的對象;在測試中,因爲構造邏輯與運行過程相混雜,就必須測試全部的執行路徑,在全局中也沒法確保初始化的值是正確的。有了這些權責,說明方法作了不止一件事,這樣就略微違反了單一權責原則。
  僅出現一次的延遲初始化不算是嚴重問題。不過,在應用程序中每每有許多種相似的狀況出現。因而,全局設置策略(若是有的話)在應用程序中四散分佈,缺少模塊組織性,一般也會有許多重複代碼。
  若是咱們勤於打造有着良好格式而且強固的系統,就不應讓這類就手小技巧破壞模塊組織性。對象構造的啓始和設置過程也不例外。應當將這個過程從正常的運行時邏輯中分離出來,確保擁有解決主要依賴問題的全局性一向策略。編程

11.2.1 分解 main

  將構造與使用分開的方法之一始將所有構造過程搬遷到 main 或被稱之爲 main 的模塊中,設計系統的其餘部分時,假設全部對象都已正確構造和設置。
  控制流程很容易理解。 main 函數建立系統所需的對象,再傳遞給應用程序,應用程序只管使用。注意看橫貫 main 與應用程序之間隔離的依賴箭頭的方向。它們都從 main 函數向外走。這表示應用程序對 main 或者構造過程一無所知。它只是簡單地期望一切已齊備。
設計模式

11.2.2 工廠

  有時應用程序也要負責什麼時候建立對象。
  可使用抽象工廠模式讓應用自行控制什麼時候建立對象,但構造的細節卻隔離於應用程序代碼以外。
緩存

11.2.3 依賴注入

  有一種強大的機制能夠實現分離構造與使用,那就是依賴注入(Dependency Injection DI),控制反轉(Inversion of Control,IoC)在依賴管理中的一種應用手段。控制反轉將第二權責從對象中拿出來,轉移到另外一個專一於此的對象中,從而遵循了單一權責原則。在依賴管理情景中,對象不該負責實體化對自身的依賴。反之,它應當將這份權責移交給其餘「有權利」的機制,從而實現控制的反轉。由於初始設置是一種全局問題,這種受權機制一般要麼是 main 例程,要麼是有特定目的的容器。
  調用對象並不控制真正返回對象的類別(固然前提是它實現了恰當的接口),但調用對象仍然主動分解了依賴。
  真正的依賴注入還要更進一步。類並不直接分解其依賴,而是徹底被動的。它提供可用於注入依賴的賦值器方法或構造器參數(或兩者皆有)。在構造過程當中, DI 容器(構造器容器)實體化須要的對象(一般按需建立),並使用構造器參數或賦值器方法將依賴鏈接到一塊兒。至於哪一個依賴對象真正獲得使用,是經過配置文件或在一個有特殊目的的構造模塊中編程決定。
  但延後初始化的好處是什麼呢?首先,多數 DI 容器在須要對象以前並不構造對象。其次,許多這類容器提供調用工廠或構造代理的機制,而這種機制可爲延遲賦值或相似的優化處理所用。安全

11.3 擴容

  與物理系統相比軟件系統比較獨特。它們的架構均可以遞增式地增加,只要咱們持續將關注面恰當地切分。
  沒有恰當的切分關注面,業務邏輯與容器緊密耦合,隔離單元測試很困難,也會致使冗餘類型的出現。
橫貫式關注面
  持久化之類關注面傾向於橫貫某個領域的自然對象邊界。會想用一樣的策略來持久化全部對象(例如,命名約定採用一致的語義)。
  原則上,能夠從模塊、封裝的角度推理持久化策略。但在實踐上,卻不得不將實現了持久化策略的代碼鋪展到許多對象中。用術語「橫貫式關注面」來形容這類狀況。一樣,持久化框架和領域邏輯,孤立地看也能夠是模塊化的。問題在於橫貫這些領域的情形。
  實際上,EJB(Enterprise Java Bean,JavaEE 中面向服務的體系架構的解決方案)架構處理持久化、安全和事務的方法要早於面向方面編程(aspect-oriented propramming,AOP),而 AOP 是一種恢復橫貫式關注面模塊化的普適手段。
  在 AOP 中,被稱爲方面(aspect)的模塊構造指明瞭系統中哪些點的行爲會以某種一致的方式被修改,從而支持某種特定的場景。這種說明是用某種簡潔的聲明或編程機制來實現的。
  以持久化爲例,能夠聲明哪些對象和屬性(或其模式)應當被持久化,而後將持久化任務委託給持久化框架。行爲的修改由 AOP 框架以無損方式在目標代碼中進行。架構

11.4 Java 代理

  Java 代理適用於簡單的狀況,例如在單獨的對象或類中包裝方法調用。然而,JDK 提供的動態代理僅能與接口協同工做。對於代理類,你得使用字節碼操做庫,好比 CGLIB、ASM 或 Javassist。
  代碼量和複雜度是代理的兩大弱點,建立整潔代碼變得很難!另外,代理也沒有提供在系統範圍內指定執行點的機制,而那正是真正的 AOP (面向方面編程)解決方案所必須的。   框架

11.5 純 Java AOP 框架

  幸運的是,編程工具能自動處理大多數代理模版代碼。在數個 Java 框架中,代理都是內嵌的,如 Spring AOP 和 JBoss AOP 等,從而可以從純 Java 代碼實現面向方面編程。在 Spring 中,你將業務邏輯編碼成舊式 Java AOP 對象。POJO (Plain Ordinary Java Object,簡單的 Java 對象,實際就是普通 JavaBean。)自掃門前雪,並不依賴於企業框架(或其餘域)。所以,它在概念上更簡單、更易於測試驅動。相對簡單性也較易於保證正確地實現相應的用戶故事,併爲將來的用戶故事維護和改進代碼。
  使用描述性配置文件或 API ,你把須要的應用程序構架組合起來,包括持久化、事務、安全、緩存、恢復等橫貫性問題。在許多狀況下,你實際上只是指定 Sprint 或 Jboss 類庫,框架以對用戶透明的方式處理使用 Java 代理或字節代碼庫的機制。這些聲明驅動了依賴注入(DI)容器,DI 容器再實體化主要對象,並按需將對象鏈接起來。模塊化

11.6 AspectJ 的方面

  經過方面來實現關注面切分的功能最全的工具是 AspectJ 語言,一種提供 「一流的」 將方面做爲模塊構造處理支持的 Java 擴展。在 80% ~ 90% 用到方面特性的狀況下,Spring AOP 和 JBoss AOP 提供的純 Java 實現手段足夠使用。然而,AspectJ 的弱勢在於,須要採用幾種新工具,學習新語言構造和使用方式。函數

11.7 測試驅動系統架構

  先作大設計能夠理解爲一開始就設計好一切實現的方式,先作大設計(Big Design Up Front,BDUF)在必定程序上會阻礙改進,由於心理上會抵制丟棄既成之事,也由於架構上的方案選擇影響到後續的設計思路。
  固然,這不是說要毫無準備地進入一個項目。對於總的覆蓋範圍、目標、項目進度和最終系統的整體架構,咱們會有所預期。不過,咱們必須有能力隨機應變。
  最佳的系統架構由模塊化的關注面領域組成,,每一個關注面均用純 Java (或其餘語言)對象實現。不一樣的領域之間用最不具備侵害性的方面或類方面工具整合起來,這種架構能測試驅動,就像代碼同樣。

11.8 優化決策

  模塊化和關注面切分紅就了分散化管理和決策。
  延遲決策至最後一刻也是好手段。它讓那個咱們可以基於最有可能的信息作出選擇。提早決策是一種預備只是不足的決策。若是決策太早,就會絕少太多客戶反饋、關於項目的思考和實施經驗。
  擁有模塊化關注面的 POJO 系統提供的敏捷能力,容許咱們基於最新的知識作出優化的、時機恰好的決策。決策的複雜性也下降了。

11.9 明智使用添加了可論證價值的標準

  有了標準,就更易複用想法和組件、僱用擁有相關經驗的人才、封裝好點子,以及將組件鏈接起來。不過,創立標準的過程有時卻漫長到行業等不及的程度,有些標準沒能與它要服務的採用者的真實需求相結合。

11.10 系統須要領域特定語言

  DSL(領域特定語言)是一種單獨的小型腳本語言或以標準語言寫就的 API ,領域專家能夠用它編寫讀起來像是組織嚴謹的散文通常的代碼。
  優秀的 DSL 填平了領域概念和實現領域概念的代碼之間的「壕溝」,若是你用與領域專家使用同一種語言來實現領域邏輯,就會下降不正確地將領域翻譯爲實現的風險。
  DSL 在有效使用時能提高代碼慣用法和設計模式之上的抽象層次。它容許開發者在恰當的抽象層級上直指代碼的初衷。
  領域特定語言容許全部抽象層級和應用程序中的全部領域,從高級策略到底層細節,使用 POJO 來表達。

11.11 總結

  系統也應該時整潔的。侵害性架構會湮滅領域邏輯,衝擊敏捷能力。當領域邏輯受到困擾,質量也就堪憂,由於缺陷更易隱藏,用戶故事更難實現。當敏捷能力受到損害時,生產力也會下降,TDD(Test-Driven Development 測試驅動開發,是敏捷開發中的一項核心實踐和技術,也是一種設計方法倫)的好處遺失殆盡。  在全部的抽象層級上,意圖都應該清晰可辨。只有在編寫 POJO 並使用類方面的機制來無損地組合其餘關注面時,這種事情纔會發生。  不管是設計系統或單獨的模塊,別忘了使用大概可工做的最簡單方案。

相關文章
相關標籤/搜索