《程序員修煉之道》——第二章 注重實效的途徑(二)

8、正交性算法

  在計算技術中,該術語表示某種不相依賴性或是解耦性。若是兩個或更多事物中的一個發生變化,不會影響其餘事物,這些事物就是正交的。在設計良好的系統中,數據庫代碼與用戶界面是正交的;你能夠改動界面,而不影響數據庫;更換數據庫,而不用改動界面。數據庫

  當任何系統高度依賴時,就再也不有局部修正(local fix)這樣的事情。設計模式

  消除無關事物之間的影響。咱們想要設計自足的組件:獨立、具備單1、良好定義的目的。若是組件是相互隔離的,你就知道你可以改變其中之一,而不用擔憂其他組件。只要你不改變組件的外部接口,你就能夠放心:你不會形成波及整個系統的問題。多線程

  若是你編寫正交系統,你獲得兩個主要好處:提升生產率與下降風險。模塊化

  

  提升生產率函數

  • 改動得以局局部化,因此開發時間和測試時間得以下降。與編寫單個的大塊代碼相比,編寫多個相對較小的、自足的組件更爲容易。你能夠設計、編寫簡單的組件,對其進行單元測試,而後把它們忘掉——當你增長新代碼時,無須不斷改動已有的代碼。
  • 正交的途徑還可以促進複用。若是組件具又明確而具體的、良好定義的責任,就能夠用其最初的實現者不曾想象過的方式,把它們與新組件組合在一塊兒。
  • 若是你對正交的組件進行組合,生產率會有至關微妙的提升。假定某個組件作M件事情,而另外一個組件作N件事情。若是它們是正交的,而你把它們組合在一塊兒,結果就能作N×N件事情。可是,若是這兩個組件是非正交的,它們就會重疊,結果能作的事情就更少。經過組合正交的組件,你的每一份努力都可以獲得更多的功能。

 

  下降風險工具

  • 正交的途徑能下降任何開發中固有的風險。
  • 有問題的代碼區域被隔離開來。若是某個模塊有毛病,它不大可能把病症擴散到系統的其他部分。要把它切掉,換成健康的新模塊也更容易。
  • 所得系統更健壯。對特定區域作出小的改動與修正,你所致使的任何問題都將侷限在該區域中。
  • 正交系統極可能獲得最好的測試,由於設計測試、並針對其組件進行測試更容易。
  • 你不會與特定的供應商、產品、或是平臺緊綁在一塊兒,由於與這些第三方組件的接口將被隔離在所有開發的較小部分中。

 

工做中應用正交的幾種方式單元測試

  項目團隊測試

  你是否注意到,有些項目團隊頗有效率,每一個人都知道要作什麼,並全力作出貢獻,而另外一些團隊成員卻總是在爭吵,並且好像沒法避免互相妨礙?編碼

  這經常是一個正交性問題。若是團隊的組織有許多重疊,各個成員就會對責任感到困惑。每次改動都須要整個團隊開一次會,由於他們中的任何一我的均可能受到影響。

  怎樣把團隊劃分爲責任獲得良好定義的小組,並使重疊度降至最低呢?沒有簡單的答案。這部分地取決於項目自己,以及你對可能變更的區域的分析。這還取決於你能夠獲得的人員。咱們的偏好是從使基礎設施與應用分離開始。每一個主要的基礎設施組件(數據庫、通訊接口、中間件層等等)有本身的子團隊。若是應用功能的劃分顯而易見,那就按此劃分。而後咱們考察咱們現有的(或計劃有的)人員,並對分組進行相應的調整。

  你能夠對項目團隊的正交性進行非正式的衡量。只要看一看,在討論每一個改動時須要設計多少人。人數越多,團隊的正交性就越差。顯然,正交的團隊效率也更高(儘管如此,咱們仍是鼓勵子團隊不斷地相互交流)。

 

  設計

  大多數開發者都熟知須要設計正交的系統,儘管他們可能會使用像模塊化、基於組件、或是分層這樣的數據描述該過程。系統應該由一組相互協做的模塊組成,每一個模塊都實現不依賴於其餘模塊的功能。有時,這些組件被組織爲多個層次,每層提供以及抽象。這種分層的途徑是設計正交系統的強大方式。由於每層系統都只使用在其下面的層次提供的抽象,在改動底層實現,而又不影響其餘代碼方面,它擁有極大的靈活性。分層也下降了模塊間依賴關係失控的風險。

  對於正交設計,有一種簡單的測試方法。一旦設計好組件,問問你本身:若是我顯著地改變某個特定功能背後的需求,有多少模塊會受影響?正交系統中,答案是「一個」。移動GUI面板上的按鈕,不該該要求改動數據庫schema。增長語境敏感的幫助,也不該該改動記帳子系統。

  讓咱們考慮一個用於監視和控制供暖設備的複雜系統。原來的需求要求提供圖形用戶界面,但後來需求被改成增長語音應答系統,讓按鍵電話控制設備。在正交地設計的系統中,你只須要改變那些與用戶界面有關聯的模塊,讓它們對此加以處理:控制設備的底層邏輯保持不變。事實上,若是你仔細設計你的系統結構,你應該可以用同一個底層代碼支持庫支持這種界面。

  還要問問你本身,你的設計多大程度上解除了與現實世界中的變化的耦合?你在把電話號碼看成顧客標識嗎?若是電話公司從新分配了區號,會怎麼樣?不要依賴你沒法控制的事物屬性。

 

  工具箱與庫

  在你引入第三方工具箱和庫時,要注意保持系統的正交性。要明智地選擇技術。

  在引入某個工具箱時(甚至是來自大家團隊其餘成員的庫),問問你本身,它是否會迫使你對代碼進行沒必要要的改動。若是對象持久模型(object persistence schema)是透明的,那麼它就是正交的。若是它要求你以一種特殊的方式建立或訪問對象,那麼它就不是正交的。讓這樣的細節與代碼隔離具備額外的好處;它使得你在之後更容易更換供應商。

 

  編碼

  每次你編寫代碼,都下降應用正交風險性的風險。除非你不只時刻監視你正在作的事情,也時刻監視應用的更大語境,不然,你就有可能無心中重複其餘模塊的功能,或是兩次表示已有的知識。

  你能夠將若干技術用於維持正交性:

  • 讓你的代碼保持解耦。編寫「羞怯」的代碼——也就是不會沒有必要地向其餘模塊暴露任何事情、也不依賴其餘模塊的實現的代碼。若是你須要改變對象的狀態,讓這個對象替你去作。這樣,你的代碼就會保持與其餘代碼的實現的隔離,並增長你保持正義的機會。
  • 避免使用全局數據。每當你的代碼引用全局數據時,它都把本身與共享該數據的其餘組件綁在一塊兒了。即便你只想對全局數據進行讀取,也可能會帶來麻煩(例如,若是你忽然須要把代碼改成多線程)。通常而言,若是你把所需的任何語境(context)顯式地傳入模塊,你的代碼就會更易於理解和維護。在面向對象應用中,語境經常做爲參數傳給對象的構造器。換句話說,你能夠建立含有語境的結構,並傳遞指向這些結構的引用。
      《設計模式》一書中的Singleton(單例)模式是確保特定類的對象只有一個實例的一種途徑。許多人把這些Singleton對象用做某種全局變量(特別是在除此而外不支持全局概念的語言中,好比Java)。使用Singleton要當心——它們可能形成沒必要要的關聯。
  • 避免編寫類似的函數。你經常會遇到看起來全都很像的一組函數——它們也許在開始或結束處共享共享公共的代碼,中間的算法卻各有不一樣。重複的代碼時結構問題的一種症狀。要了解更好的實現,參見《設計模式》一書中的Strategy(策略)模式。

  養成不斷批判對待本身的代碼的習慣。尋找任何從新進行組織、以改善其結構和正交性的機會。

 

  測試

  正交系統和實現的系統也更易於測試。由於系統的各組件間的交互式形式化的和有限的,更多的系統測試能夠再單個的模塊級進行。這是好消息,由於與集成測試(integration testing)相比,模塊級(或單元)測試要更容易規定和進行得多。事實上,咱們建議讓每一個模塊都擁有本身的、內建在代碼中的單元測試,並讓這些測試做爲常規構建過程的一部分自動運行。

  構建單元測試自己就是對正交性的一項有趣測試。要構建和連接某個單元測試,都須要什麼?只是爲了編譯或連接某個測試,你是否就必須把系統其他的很大一部分拽進來?若是是這樣,你已經發現了一個沒有很好地解除與系統其他部分耦合的模塊。

  修正Bug也是評估整個系統的正交性的好時候。當你遇到問題時,評估修正的局部化程度。

  你是否只動了一個模塊,或者改動分散在整個系統的各個地方?當你作出改動時,它修正了全部問題,仍是又神祕地出現了其餘問題?這是開始運用自動化的好機會。若是你使用了源碼控制系統,當你在測試以後,把代碼籤回時,標記所作的bug修正。隨後你能夠運行月報,分析每一個bug修正所影響的源文件數目的變化趨勢。

 

  文檔 

  也許會讓你驚訝,正交性也適用於文檔。其座標軸是內容和形式表示。對於真正正交的文檔,你應該能顯著地改變外觀,而不用改變內容。

   

  認同正交性  

  運用DRY原則,你是在尋求使系統中的重複降至最小;運用正交性原則,你可下降系統的各組件間的相互依賴。這樣說7也許有點笨拙,但若是你緊密結合DRY原則、運用正交性原則,你將會發現擬開發的系統會變得更爲靈活、更易於理解、而且更易於調試、測試和維護。、

  若是你參加了一個項目,你們都在不顧一切地作出活動,而每一處改動彷佛都會形成別的東西出錯。項目極可能沒有進行正交的設計和編碼,是時候重構了。

相關文章
相關標籤/搜索