转载

少年,休想破坏朕的架构

讲一讲ArchUnit的应用。

架构需要保护但难以落地

不只是在软件开发的领域,几乎所有的领域,架构之重要性,不用多说,万丈高楼,若是根基不牢,则摇摇欲坠,崩塌也是不可避免的事情,只是很难预料崩塌的时间点而已。

软件又和建筑和硬件等这些成熟行业非常不同,摩天大厦虽然复杂,电子器件虽然精密,但一旦造就,就很少再被改变,但软件产品不一样,即使是已经在生产环境中使用的软件,其功能的变化也极其频繁,尤其是在快速变化的互联网时代,其变化往往是以天计。通过不断的变更快速响应变化,具有柔韧性,这也是软件之所以冠名以"软"的原因。

然而,变化对根基会带来很大的冲击。

一个系统的架构设计在一开始可能是清晰的,但演化过程中,会逐渐被侵蚀,逐渐腐化掉。日积月累,以致最终积重难返。

少年,休想破坏朕的架构

热力学第二定律告诉我们,如果不为秩序维护付出努力,最终一切都会归于混乱。

对很多开发团队来说真没有精力做这种"额外"的努力,毕竟需求交付是第一位的。每个开发团队都是值得尊敬的阿基米德——在被执行死刑前,还在忙于题目的计算。所以要保护架构设计不被破坏重要但不紧急,以致于被一直搁置。

最近我研究了ArchUnit,用它来维护已有架构秩序所耗无几,但收益颇多。让这种"额外"努力变得廉价而有效,是的自动对架构质量保障在开发团队落地成为可能。

ArchUnit简介

ArchUnit巧妙地利用自动化单元测试来执行架构规则的校验。

举个例子,模块化是保证我们系统架构清晰合理的最基本的方法,这种模块化通常在技术架构层面通过诸如分层架构这样的架构模式来实现。可以用下面这样的JUnit/ArchUnit测试来保障分层依赖原则不被破坏:

上面的代码几乎是不言自明的——Contrller层不能被任何层访问,Service层只能被Controller和自己访问,Dao层只能被Service访问。这条规则保证了层间依赖的正确性。如果Controller调用了Dao,这个JUnit测试就会运行失败,如果你使用Maven或Gradle,这个失败会让整个构建失败,结合CI,就可以阻止破坏分层架构的代码被提交到代码库中,对架构起到了应有的保护作用。

并不只能用ArchUnit才能做这件事。很多产品和类库都比ArchUnit更早地区尝试做这件事,比如 structure101,JDepend, jqassistant等,也可以自己写maven或sonar的插件来做这件事儿,但用ArchUnit的优点是:

  • 轻量级且开源,巧妙利用自动化单元测试,无缝和CI集成

  • 规则和正式代码在一起,编写和修改随时都可以,且容易为每个工程的规则按需定制

  • 简单且灵活的DSL,容易读懂,它看上去更像是配置而不是代码,但你需要灵活扩展的时候,可以实现很多的钩子,这时候它作为代码的优势又能体现出来了

下面会展示一些高级的示例。

ArchUnit高级示例

我们展现一些更高级的规则,看看ArchUnit还能做什么。

上面这个规则可以保证,model层要足够的技术无关,比如不能依赖Spring里的Utils等。

上面这个规则保障服务只能通过接口访问,不能之间访问实现类,这可以保障面向接口编程。

上面这个规则可以保障Controller之间不互相访问,一般来说,Dao也符合这个规则。

slices是一个很强大的功能,它把类分成多个组,可以用它保障组之间没有环装依赖:

这种分组规则可以自定义,比如:

这个规则在检查DDD的聚合根之间不能相互引用上非常有用。

还可以检查命名规则:

总之,利用ArchUnit你可以将你的工程中的很多规范落实成可执行的规则检查。规范越多,它的价值越大。本文使用了一个的Controller/Servcie/Dao的结构的代码工程为例,是因为熟悉这种结构的人多,方便读者理解。实际上,在一个用DDD的思想实现的项目中,约束会更多,那么ArchUnit起得作用会更大。

少年,休想破坏朕的架构

2

原文  http://mp.weixin.qq.com/s?__biz=MzU1Njc5MTEwOA==&mid=2247483726&idx=1&sn=95e4d193281d6fe49263fc27d0f15323
正文到此结束
Loading...