isLayeringValid()方法的目的确定 清单 2中 DIRECTORY_TO_ANALYZE目录内所有包的传入耦合。 您可以在清单 4 底部看到,该方法遵守 isEfferentsValid()方法,如清单 5 所示。

这里,如果 isEfferentsValid()方法发现某个包不符合指定的包依赖关系(由于从一个包到另一个包的传出耦合大于 0),则使用 清单 2中的 dataLayerViolations集合将该包标记为一个架构违背。这将间接导致 testDataLayer()测试用例(如 清单 3所示)失败。

清单 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. 架构违背引起的构建失败
构建失败

这种主动监控的优势在于,你可以在发现架构分层问题后马上解决它。 问题解决得越迅速,越有助于降低风险 —— 更不用提代价了。 本质上,您的团队不会因此收到干扰,并能够继续工作,实现快速发布可用软件的目标。

针对架构的自动化
JDepend 还有哪些魔力?

存在多种方法通过 JDepend 添加主动检查。实际上,JDepend 建议使用其 DependencyConstraint类。尽管使用 DependencyConstraint 非常简单,但我还是不选择它,因为 它只具有使用 API 执行架构规则这么一种途径,而且不能可靠地根据我的需求工作。还有其他一些工具支持包依赖关系遵从性; 可参阅 参考资料以了解更多细节。

现在您能够用自己的构建过程主动发现与期望架构的设计违背了。 此外,我已向您展示了几个可能的示例之一 —— 您一定能够获得创造性的方法并分析类似 Instability包这样的度量,从而便于判定架构的整体健壮性。

我所介绍的这个方法是一种简单的方式,可以减少 为判定架构遵从性而不断反向设计代码并分析图表的需求。 如果您在使用持续集成系统(Continuous Integration system), 您可将这些测试用作一个安全网络,确保检查版本控制系统的代码传递这些架构规则 —— 每当进行了一次改动时。如果您改变了架构, 只要改变您的 JUnit 测试规则,可确保 您的团队遵守了项目标准。这是我所称的使用主动方式断言架构可靠性。