談談軟件項目的dependency

說到軟件項目的依賴管理,能夠從三個方面來考慮:java

1、由build system控制的dependencyui

如今的build system,都支持必定程度上的dependency management, 好比make支持target之間的dependency,ant也支持其每一個target之間的dependency(區別是make的每一個非PHONY的target是個文件,make會檢查輸入與輸出之間的timestamp來達到incremental build的效果,而ant則是對上一次build沒有任何記憶,除了javac task支持incremental compile)spa

上面的dependency講的主要是如何肯定build的順序,但dependency管理的另外一個很是重要的目標,是自動獲取dependency,並設置好:component

  • 對於C++來說:includedir(-I), libdir(-L)
  • 對於Java來說:classpath

手工的維護這些path,很是麻煩並且容易出錯,由於咱們在一個太低的level管理這些信息 - 事實上,正確的作法應該是:用戶只需聲明我依賴這個component或者我依賴這個library,dependency manager自動幫我設置好這些path。server

總的來說,dependency manager有這麼幾個做用:xml

  • 讓用戶在合適的邏輯層次聲明dependency,自動設置好須要的path
  • Resolve transitive dependency
  • Conflict manage (diamond dependency)

這些功能都不是手工可以解決的。接口

2、不禁build system控制的dependencyip

若是有兩個或者多個不一樣的project,由不一樣的team開發,甚至使用了不一樣的build system,那麼基本上是不可能把他們放在同一個build pipeline中編譯的。可是他們之間又有dependency,該怎麼處理?資源

這裏其實就是一個升級的問題, 好比:開發

B -> A/1.0

而A仍是不斷的開發,可能會改變已有的實現(引發B的運行時錯誤),也可能改變已有的接口(引發B的編譯時錯誤),若是B在一段時間以後升級到A的新版本A/1.1,B可能須要很長時間作migration - 或者說integration。其實從continuous integration的角度來理解這個問題,正確的作法應該是:

A要儘量快的推出一個新的release,而B要立馬跟上,這樣每次B的改動都很是小,不容易出錯,出了錯也容易解決。

但推出一個新的release畢竟不是件小事,不少team會有本身的擔憂:資源不夠,risk過高等等 - 因此上述是一個比較理想的狀況。在達到那個狀況以前,能夠另外有個方案:

B繼續使用A/1.0, 可是同時B新開出一個branch:B/edge,依賴於最新的A的代碼,A的每次build,都會trigger B/edge的build (edge build),這樣保證B老是build against最新的A,任何問題均可以在第一時間發現,並fix

關於edge build,值得另外寫一篇文章討論一下。

這裏,這種不禁build system控制的dependency,就須要由其餘系統來控制,好比各類CI server中的job,一個job會trigger另一個job,也是一種dependency關係,恰好對應起來。

 

3、dependency graph的顯示

軟件項目之間的dependency graph,很好的反映了各個項目之間的關係,注意這個dependency的單位不是project,而是release,這更動態的反映出了依賴關係,同時,因爲你知道每一個項目的dependency,根據這個信息就能建出一張完整的dependency graph,從而能得出全部consumer的信息,因而,我就有了關於這個項目的全部dependency和consumer的信息:

  • 我用了那些項目,用的版本會不會太老?
  • 我被哪些項目用了?受不受歡迎?是否是能夠中止支持某個release了(若是沒有太多consumer的話)

顯示一個項目的dependency時,能夠有如下幾部分:

  • 直接dependency
  • 間接dependency
  • 直接consumer
  • 間接consumer
  • dependency graph

關於dependency graph,要注意的是:首先它是一張完整的圖,正確的顯示了全部直接dependency和間接dependency,可是這樣的圖,對於一個大的項目來說的話,會比較亂 - 考慮某個項目便是直接dependency,又是間接dependency的狀況,就會有多個箭頭指向它。因此通常顯示的時候,會將其的transitive reduction顯示出來(tred,dot自動作reduction),在保證其reachbility的同時,減小邊的數量,使圖看起來比較簡練:

 

還有要注意的一點是,咱們須要提供額外的metadata,來保證這個圖的正確性。以ivy爲列,ivy.xml提供了比較完整的dependency信息(沒有相似機制的build system至少要產生這種metadata),但其問題是對於有dependency conflict的狀況(diamond dependency),如上面第二張圖,若是b和c依賴於不一樣版本的d,單憑ivy.xml沒法確認到底選d的那個版本,這是ant/ivy在build過程當時選擇必定的conflict manager方式肯定下來的,而這個信息,必須以某種方式告訴dependency graph - 通常的方式就是在build過程當中產生metadata並予以保存。

對於沒有ivy.xml這種機制的build system,須要產生metadata一保存:

  • 全部直接的dependency
  • 有conflict的間接dependency

而後能夠根據全部項目的這個信息產生正確的dependency graph

相關文章
相關標籤/搜索