今天读了《系列文章整理 - “听”乔梁讲述持续集成的故事》,其中一些观点非常赞同,其中提到一个Java领域中一个很有名气的项目管理工具:Maven,特别想对此多说几句,于是形成此文~~
先说个题外话,老的Java程序员一看到Maven就想起Ant,而实际本站的代码构建也是用的Ant,不过Maven和Ant的关注点真的不是很一样,Ant帮你执行很多脚本目标,仅此而已,是个很好的工具,可以用它做很多你想做的事情,但是Maven远不止此,Maven更像是一个项目管理工具,它传达出了一些很好的思路和最佳实践~~
OK,现在开始侃一侃~~
1、测试代码与功能代码同源
用Maven创建的项目普遍都有两个源码目录,一个叫src,另一个叫test,src下是存放的业务逻辑相关的代码,test下是存放的测试用例。有些人可能并没有意识到这点有啥了不起的,他们可能使用自己的平台来管理测试用例代码脚本云云。不过在敏捷实战中,测试用例,特别是单测,是为所有人服务的,包括开发人员,在TDD实战中甚至主张测试先行。当然,如果你还在使用传统的瀑布开发方法,可能这么做的意义的确不大。对于测试代码和功能代码分开管理的弊端,比如测试代码更新不及时,为了让保证上线时间,直接注释掉一些过时的测试用例,开发人员不方便在开发过程中写单测,以至于直接放弃单测等等。所以,感觉Maven的这种做法,很值得推荐
1.1、延伸一下,其他脚本也要放到源码库中
比如服务的启停脚本,部署脚本,都应该有版本控制,保证可追溯,便于审计,同时功能代码变了,部署方式和服务启停脚本也很可能同步修改,放到svn、git中吧,乔帮主都说了:Everything is code,还犹豫个啥捏?呵呵
2、配置文件要单独抽取出来
一般来讲Maven会在src和test目录下创建一个resources目录来管理一些配置文件,具体什么配置呢?比如数据库连接配置,缓存配置,程序的业务逻辑配置,功能开关,log配置等等。还有程序在运行过程中需要的比较大的数据,如果不方便打包进来的话也可以转化为配置,只是在配置文件中描述一下这些大数据的下载地址即可。另外,对于服务的关联关系,比如所依赖的上游服务的IP地址之类的,不建议放到配置里,这应该是Naming Service应该解决的问题,不过关联关系的name本身倒是可以放在配置中。对于Maven本身而言,它会把配置和代码的编译产物打到一个包里,这点值得商榷,在某些场景下,配置单独出来会更方便。举个例子:代码关着开关上线,此时服务不需要停摆,然后再单独发起一次开开关的动作,因为只是对配置本身做了修改,此时对于部署脚本应该可以判断二进制bin文件没有修改不用重新下载并更新,只是下载conf更新一下即可,如果发现开开关的这个版本有问题,可以很快再上一个关开关的版本用于回滚,但是对于conf和bin打包在一起的情况,部署脚本就很难做出这样的判断,每次都下载bin文件比较不值得
3、对于不同的环境,单独准备conf文件
因为有了第二步的做法,即把配置文件单独抽取出来了,这样还有另外一个好处,比如:现在有多套环境的情况,开发人员有个CI单测环境,测试人员有个自动化集成测试环境,再来个沙盒环境,验收测试环境,线上环境,这样会有多套环境,而各个环境可能配置文件不同,这个问题也是我现在工作中遇到的一个很麻烦的问题,Maven的解决方案是:对不同的环境准备不同的conf,然后再打包的时候根据传入的环境ID来获取相应的配置文件,这样做,实际是为每个环境单独编译打包了一份,我只能说是一种方案,好不好,还是比较难以评论,因为我现在也没想明白,呵呵,有相关经验的朋友期望能赐教一二。
4、模块的依赖管理
依赖可以分为三种,编译时依赖,测试时依赖,运行时依赖,Maven的scope就是描述这几种类别的
不过这不是关键,依赖管理里很关键的做法是通过描述一个lib库的identity来让Maven找到这个jar,这个identity包含了一个可寻址的名称和version,这样一来maven在编译打包的时候就可以找到这个jar并下载到本地,并且在最终打包的时候一起打到发布包里,这么做很赞,好在哪里?从部署的角度来考虑,这个包对外的依赖很少,要想服务run起来只要在本地准备一个JDK(如果是WEB服务还需要有个WEB容器)就可以,换句话说叫容易部署,呵呵,当然,如果把JDK和WEB容器一起打包进去就更好了,不管是服务扩容还是搭建环境都很容易。从这个角度来看C模块的动态链接库就会比较麻烦,因为依赖问题是部署不友好的,于是~~~Google的C模块统统用的静态链接库,于是~~~Canonical要开发自己的包管理工具,O(∩_∩)O~
今天先扯到这吧,北京这天气。。。从冬天一下子到了夏天,好热。。。