代码结构
截图于2017.9.22
名称 | 简介 |
---|---|
build | 用于Java部分的编译、打包、部署等 |
conf | 配置文件及SQL文件的放置;Spring Service配置存放;持久化文件配置 |
core | 核心模块。实现系统的核心功能——包括数据库、消息总线、工作流实现等等 |
coregroovy | ZStack的最新测试采用了Groovy,这里是对测试库做的支持 |
header | 消息以及Entity的定义 |
plugin | 顾名思义。其中不少组件都以插件化开发,提供较高的灵活性 |
sdk | 测试库使用的SDK |
simulator | 对于测试库支持的又一模块,主要用户simulator agent的行为 |
testlib | 测试库 |
test | 测试模块 |
工具类 | 工具包。目前仅仅支持了doc生成 |
utils | 代码中使用的工具类 |
其他 | 功能实现模块 |
通过MQ来解耦合
在ZStack
中,每个功能实现模块都会被称为服务——一个独立的服务。各个服务之间的通信由MQ来承担。这就像是传统的CSE,C和E是不耦合的,通过S来交互。同样的,一个服务需要向另一个服务发起调用,只需往消息总线发送消息,并指定这个服务ID(Service ID)即可。如果某个服务的代码需要大量重构或者做成微服务,只要提供相同的服务并注册到MQ上就可以了。这就是事件驱动架构(Event Driven Architecture)的一种典型实现。
CSE:Controller、Service、Entity。注:称作Domain或者Model都是不专业的。Domain是一个领域对象,往往我们再做传统Java软件web开发中,这些Domain都是贫血模型,是没有行为的,或是没有足够的领域模型的行为的,所以,以这个理论来讲,这些Domain都应该是一个普通的entity对象,并非领域对象,所以请把包名改为:com.xxx.entity。
使用Spring
不了解Spring的人可以看:看起来很长但还是有用的Spring学习笔记
在代码中,每当我们New出一个对象时,这个模块便对这个对象产生了依赖。当我们需要测试的时候就不得不去Mock它。当依赖的对象or Field 有成千上万个的时候,这就是一场灾难了。代码变得愈发不可测,坑就越多,开发者在扩展or维护项目的时候就会愈发的乏力。这就像是我们之前提到的MQ,服务1->MQ->服务2
,由于中间隔了一个MQ,于是服务1和服务2没有必然的关系。同样的,从对象1->调用->对象2
到对象1->调用->Spring提供的IOC容器->对象2
,这样使对象与对象之间也没有了直接调用关系,对象1只要知道它要调用的对象实现了其需要的Interface
就是可以调用的。
除了Autowired
的正确使用姿势。在ZStack中,还有一类很有意思的代码,一般称之为xxxExtensionPoint
。其本质就是定义一个接口,然后其实现类作为Bean通过XML注册到IOC中。在需要使用的时候,通过Spring获取到所有实现该接口的对象,调用其函数。这样就会使代码变得非常的灵活。
例如,ZStack
分为多个版本——开源版、企业版、混合云版等。如果一个服务在不同版本中的处理逻辑需要稍许不同,那么就可以在开源版的代码中注册一个接口,在另一个版本的服务中实现该接口。这样也不会影响到开源版的原有逻辑。从模块上看我们代码的是松耦合并且无法直接调用的,但是在内存中,却是可以调用得到的。
覆盖较为全面的测试
在ZStack
中
开发者Fix每一个Bug都是需要补充相应的Case;
每一个Feature在进去之前更会由开发工程师与QA工程师同时制定测试场景并Cover;
每一个PR(pull request)进去之前都会通过PR系统跑过所有的Case,以防止Bug的Regression;
由于ZStack
源码做到了一定的解耦合(上述提到)与无状态,使得集成测试得以进行。
其首席架构师Frank.Zhang曾说过:我们开发者在写代码的时候往往就应该考虑该怎么学测试了。
想了解ZStack的测试框架,可以看:ZStack WiKi :管理节点基于模拟器的Integration Test框架
恰当好处的使用设计模式
在ZStack
中,设计模式有较为良好的实践。笔者有机会将会在之后的文章分析其中的典型案例以及在代码中使用极其频繁的核心工具。