<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 讓開發自動化: 斷言架構可靠性 _通過主動構建過程掌控架構_ 您的軟件架構和您所期望的一樣嗎?當架構落實到代碼時,它并不總是 我們曾經互相討論并預想的那個。在本期的 [_讓開發自動化_](http://www.ibm.com/developerworks/cn/java/j-ap/)中,Paul Duvall 將演示如何通過使用 JUnit、JDepend 和 Ant 編寫 有關測試來發現架構偏差,從而做到在發生問題之前主動發現問題。 我在曾經從事的很多軟件開發項目中觀察到,軟件開發中一直存在這樣一種現象:_您實際擁有的架構往往與想象中的不同。_ 通過分析代碼的度量報告,比如由 JDepend (參閱 [Resources](#resources))工具生成的報告, 您可以有效地判定代碼是否實現了確定的架構。有些團隊對代碼做反向設計,得到對應的 UML 圖表,也能夠達到上述效果, 還有一些團隊甚至在編程時使用 IDE 生成相同的工件 —— 即實時反向設計。可是, 所有的這些方法都還是 _反應式(reactive)_的。 您必須手工審視并分析報告或圖表,確定架構是否存在偏離,而有時這種 偏離可能很久之后才被發現。 設想每當某部分代碼與 _期望的_架構有所違背時,您就得到一個提示 —— 比如一個 Ant 構建腳本失敗 —— 如清單 1 所示: ##### 清單 1\. 違背架構導致構建失敗 ``` ... BUILD FAILED ... build.xml:35 Test ArchitecturalRulesTest failed Total time: 20 seconds ``` ## 關于本系列 作為開發人員,我們的工作就是為終端用戶實現過程自動化; 然而,很多開發人員卻忽略了將自己的開發過程自動化的機會。 為此,我編寫了 [_讓開發自動化_](http://www.ibm.com/developerworks/cn/java/j-ap/)這個系列的文章,專門探討軟件開發過程自動化的實際應用,并教您 _何時_以及 _如何_成功地應用自動化。 本文所提及的技術能夠使您通過實現構建自動化主動分析軟件架構。 除此之外,本文的示例還演示了如何基于規則觸發構建過程失敗,您可以使用 JDepend 的 API 和 JUnit 定義這些規則。 當然,最重要的是,通過構建自動化,您和您的團隊能夠在開發周期的 _前期_發現 源代碼與確定架構之間的偏離。 這就是我所說的掌控架構! ## 反應式地設置開發階段 圖 1 說明了在構建 Web 應用時一種常見的架構模式。 `presentation`層(代表一組相關的包)依賴于 `controller`層,`controller`層依賴于 `domain`和 `business`層,最后,`business`層依賴于 `data`和 `domain`層。 ##### 圖 1\. 典型 web 應用的一個架構分層圖 ![](https://box.kancloud.cn/2016-05-11_573331602b842.gif) 至此,一切都很好,是嗎?但是,我很確定您以前遇到類似的情形,那些常見的最佳實踐規則會在日常的軟件開發中被遺忘。事實上,這一點很容易(也很快)就會發生。 舉例而言,圖 2 闡明了對該示例架構的一個微小違背;在這個例子里, `data`層至少調用一次 `business`層: ##### 圖 2\. Data 層正在調用 Business 層的一個對象,由此產生了架構違背 ![](https://box.kancloud.cn/2016-05-11_573331603b49b.gif) 架構的微小變化產生的意外影響使代碼的修改變得更加困難。實際上,現在對一個代碼區域的修改 會要求其他很多區域的變動。舉例而言, 如果您清除或改變 business 層中類的一些方法, 則可能需要從 data 層中清除某些引用。當更多的違背發生時, 修改代碼就會更加困難。 若使用傳統的監控技術,比如查看 JDepend 或 Macker 報告(參閱 [參考資料](#resources)), 您能夠多快地發現對期望設計的偏離呢? 如果您和我一樣,想快速地生產出能夠工作的軟件, 那么越快發現影響交付速度的問題越好, 難道您不這么認為嗎? * * * ## 使用簡單的 JDepend JDepend 是最方便的幫助評定架構違背的工具之一。經過幾年的發展, 該開源工具能夠很好地與 Ant 和 Maven 集成; 此外,它對大量的 Java?API 提供支持,具有更細化的交互性。但是, 如同我已經指出的,它生成的報告本質上是被動的。根據您實際運行(并查看)它們的頻率, 架構違背可能直到很難矯正的時候才會被發覺。 ## 傳入耦合(Afferent coupling)與傳出耦合(Efferent coupling) JDepend 中,傳入耦合表示一些包的數量,這些包依賴某個經過分析的包。比如說,如果您正在使用日志框架或一個象 Struts 一樣的 Web 框架, 您會希望這些包具有高的傳入耦合, 因為整個代碼庫的很多包都依靠這些框架。 某包的傳出耦合與傳入耦合相反,是指某個經過分析的包所依賴的其他包的數量,也就是說,它具有的依賴包的數量。 ### 斷言架構 要主動判定架構變動是否恰當,實際上就是研究某特定包的耦合。事實上,通過對軟件架構內關鍵包的傳入和傳出耦合進行監控, 以及觀察預期值的偏離,您能輕松地發現錯誤的修改。 舉例而言,在圖 2 所示的修改中, `data`層的新傳出耦合現在大于 0,因為該層目前要 直接與 business 層通信。當然,這種耦合是通過 `data`層中一個簡單的 `import`(及對引用類的使用)而引入的。幸運的是,很容易通過 JUnit、JDepend 的優秀 API 發現此類問題,還有,構建時需要一些技巧。 事實證明,在構建(如 Ant 或 Maven)上下文中,您能夠運行使用 JDepend API 的 JUnit 測試主動辨別耦合值的變化; 此外,如果這些變化不正確,您就可以使構建失敗。 這就實現了主動性,不是嗎? 第一步是創建一個 JUnit 測試并且對 JDepend 做相應配置,如清單 2 所示: ##### 清單 2\. 在 JUnit 中設置 JDepend ``` import junit.framework.TestCase; import jdepend.framework.JavaPackage; import jdepend.framework.JDepend; public class ArchitecturalRulesTest extends TestCase { private static final String DIRECTORY_TO_ANALYZE = "C:/dev/project-sandbox/brewery/classes"; private JDepend jdepend; private String dataLayer = "com.beer.business.data"; private String businessLayer = "com.beer.business.service"; private Collection dataLayerViolations = new ArrayList<String>(); public ArchitecturalRulesTest(String name) { super(name); } protected void setUp()throws IOException { jdepend = new JDepend(); jdepend.addDirectory(DIRECTORY_TO_ANALYZE); // Calling the businessLayer from the dataLayer is a violation dataLayerViolations.add(businessLayer); } ``` 清單 2 很長,我們總結以下幾個要點: * 需要兩個 JDepend 類:`jdepend.framework.JavaPackage`和 `jdepend.framework.JDepend`。 * 待分析的源類位置由 `DIRECTORY_TO_ANALYZE`常量定義。JDepend 通過 調用 `JDepend.addDirectory`掃描該目錄,該操作通過一個 fixture 完成(即 `setUp()`方法)。 * 要分析的包由 “Layer” `String`定義。 * `dataLayerViolations``Collection`添加了 `businessLayer``String`(表示一個包)來指明 這是對期望架構的違背。 按照這四個要點,我已經有效地設置了 JDepend,以針對特定代碼庫發揮其魔力。 現在,我要設定一些精確的邏輯以說明耦合值的變化。 清單 3 中的 `testDataLayer()`測試用例是架構斷言的核心。 該方法可判定是否存在對 `dataLayer`的任何違背 —— 如果 `isLayeringValid()`方法(在下面的 [清單 4](#listing4)中定義)返回 `false`,測試用例 就被認為失敗,也意味著必然存在一處架構違背。 ##### 清單 3\. 使用 JDepend 測試架構違背 ``` public void testDataLayer() { if (!isLayeringValid(dataLayer, dataLayerViolations)) { fail("Dependency Constraint failed in Data Layer"); } } ``` 清單 3 中測試用例所調用的方法如清單 4 所示: ##### 清單 4\. 循環查找每個包的傳入耦合 `isLayeringValid()`方法的目的確定 [清單 2](#listing2)中 `DIRECTORY_TO_ANALYZE`目錄內所有包的傳入耦合。 您可以在清單 4 底部看到,該方法遵守 `isEfferentsValid()`方法,如清單 5 所示。 這里,如果 `isEfferentsValid()`方法發現某個包不符合指定的包依賴關系(由于從一個包到另一個包的傳出耦合大于 0),則使用 [清單 2](#listing2)中的 `dataLayerViolations`集合將該包標記為一個架構違背。這將間接導致 `testDataLayer()`測試用例(如 [清單 3](#listing3)所示)失敗。 ##### 清單 5\. 判定包依賴關系違背 ``` private boolean isLayeringValid(String layer, Collection rules) { boolean rulesCorrect = true; Collection packages = jdepend.analyze(); Iterator itor = packages.iterator(); JavaPackage jPackage = null; String analyzedPackageName = null; while (itor.hasNext()) { jPackage = (JavaPackage) itor.next(); analyzedPackageName = jPackage.getName(); Iterator afferentItor = jPackage.getAfferents().iterator(); String afferentPackageName = null; while (afferentItor.hasNext()) { JavaPackage afferentPackage = (JavaPackage) afferentItor.next(); afferentPackageName = afferentPackage.getName(); } rulesCorrect = isEfferentsValid (layer, rules, rulesCorrect, jPackage, analyzedPackageName); } return rulesCorrect; } ``` 正如您所看到的,清單 2 到 5 實際上都是掃描一系列包以確定耦合變化; 如果耦合發生了變化,失敗條件被觸發,因此 JUnit 報告測試失敗。 要讓我說的話,這真是令人印象深刻! ### 別忘了自動運行測試 一旦您結合使用 JUnit 和 JDepend 編寫好基于約束的測試后, 您就能夠用諸如 Ant 或 Maven 這樣的工具把它作為構建過程的一部分運行。 舉例而言,清單 6 闡述了用 Ant 運行一系列此類測試。 `test.dependency.dir`屬性 映射到 root/src/test/java/dependency 目錄,其中包含了一些神奇的架構驗證程序。 ##### 清單 6\. 運行依賴性約束測試的 Ant 腳本 ``` <target name="run-tests" depends="compile-tests"> <mkdir dir="${logs.junit.dir}" /> <junit fork="yes" haltonfailure="true"dir="${basedir}" printsummary="yes"> <classpath refid="test.class.path" /> <classpath refid="project.class.path"/> <formatter type="plain" usefile="true" /> <formatter type="xml" usefile="true" /> <batchtest fork="yes" todir="${logs.junit.dir}"> <fileset dir="${test.dependency.dir}"> <patternset refid="test.sources.pattern"/> </fileset> </batchtest> </junit> </target> ``` 要使 JUnit 測試成功執行,JDepend JAR 必須出現在 Ant 的類路徑中。 `haltonfailure` 屬性被設為 true,以便讓構建過程在測試失敗時停止。 * * * ## 閾值驅動的架構 我已經指出,使用被動的方法維持架構需要付出大量的努力, 另外,我希望我已經使您相信,開發過程中很容易發生架構違背。 通過將架構測試作為構建過程的一部分執行, 您能夠使這種檢查自動化并且能夠重復執行。圖 3 顯示了在運行 Ant 后顯示構建失敗,這樣不是很好嗎?我甚至根本不需要再去看 JDepend 報告了。 ##### 圖 3\. 架構違背引起的構建失敗 ![](img/build-failure.jpg) 這種主動監控的優勢在于,你可以在發現架構分層問題后馬上解決它。 問題解決得越迅速,越有助于降低風險 —— 更不用提代價了。 本質上,您的團隊不會因此收到干擾,并能夠繼續工作,實現快速發布可用軟件的目標。 * * * ## 針對架構的自動化 ## JDepend 還有哪些魔力? 存在多種方法通過 JDepend 添加主動檢查。實際上,JDepend 建議使用其 `DependencyConstraint`類。盡管使用 DependencyConstraint 非常簡單,但我還是不選擇它,因為 它只具有使用 API 執行架構規則這么一種途徑,而且不能可靠地根據我的需求工作。還有其他一些工具支持包依賴關系遵從性; 可參閱 [參考資料](#resources)以了解更多細節。 現在您能夠用自己的構建過程主動發現與期望架構的設計違背了。 此外,我已向您展示了幾個可能的示例之一 —— 您一定能夠獲得創造性的方法并分析類似 _Instability_包這樣的度量,從而便于判定架構的整體健壯性。 我所介紹的這個方法是一種簡單的方式,可以減少 為判定架構遵從性而不斷反向設計代碼并分析圖表的需求。 如果您在使用持續集成系統(Continuous Integration system), 您可將這些測試用作一個安全網絡,確保檢查版本控制系統的代碼傳遞這些架構規則 —— _每當進行了一次改動時_。如果您改變了架構, 只要改變您的 JUnit 測試規則,就可確保 您的團隊遵守了項目標準。這就是我所稱的使用主動方式斷言架構可靠性。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看