我为什么不喜欢子项目或者子模块的概念
王福强
发现大部分人愿意使用Maven的modules来管理多个项目的组织结构, 这或许是Maven的最佳实践提倡的,也或许是开发人员为了开发阶段可以集中管理这些项目相关的关注点, 当然,大范围出现这种现象,可能更多是不加思考的copy(比如原来有人用jredis的时候使用了Jedis而不是JedisPool,那么, 后面的人再参考代码的时候也会复制这种不恰当的API理解和实践), 从我个人来讲, 我其实更愿意让每个项目都是独立的, 那么为什么那?
个体独立性
项目应该是一个可以独立发布的粒度, 它应该是独立的实体:
- 如果某些功能只是最终发布实体的一个组合部分,那么,使用package粒度就可以了,设置modules反而是多此一举;
- 如果某些功能是可以独立发布,供别人依赖或者可独立运行的,那么, 这些功能就应该是一个顶层的project粒度,而不应该设置为modules;类似于,你就算有多个孩子,但他们依然是独立的实体, 如果要组织成一个家庭的概念,那么, 这种概念不应该作为你孩子的强制属性,而应该是外部化的概念;
但你会讲,很多时候, 就算设置为多个项目,可这些项目会因某种因素有所关联,我想集中管理, 所以我才会设置一个parent的project,然后把子的modules或者project包含在这个parent的project下面, 原则上, parent project的概念其实对你我来说一个目录就足够了,最常见的就是你的workspace目录, 下面包含和管理了project这个概念的一批实体。
所以, 即使是使用parent + modules的结构来管理一批项目, 我更倾向于parent和modules的项目目录是并列的,而不是包含的关系。
但parent + modules的结构其实还有其它不合适的地方…
版本个异性
使用parent+modules的一个好处是, 我们只要在parent项目设置一个版本号,然后让modules继承就好了, 所谓版本一致性是也。 可是,这种版本一致性的考虑很多时候在实践的过程中却是一种pains in the neck,比如, 针对一个服务的项目设置,我们可以有两种项目设置结构的选择:
(d) xxservice - (d) api - (d) impl
或者
(d) xxservice.api (d) xxservice.impl
在开发阶段,显然第一种更便于集中管理,也很契合maven的parent+modules的实践, 但是, 服务接口很多时候是没有那么频繁更新的,因为它是某种契约,也是屏蔽服务实现复杂度的入口, 不管impl如何频繁变化(修复bug也好, 更新实现策略也罢), api应该是尽量稳定的,而且第三方系统需要的也应该仅仅是api而已, 你的impl不管多么频繁的更新和变更, 对使用服务的系统来说应该尽量没有太大的冲击,甚至服务使用方根本就不会感知那些变化。 但是, 使用parent+modules的结构一个很自然地步骤就是, 每次发布,parent关联的所有项目都以同一版本发布, 这就造成一种很蛋疼的局面, 即使api没变,所有使用了该服务的系统原则上都需要更新api依赖(当然,你可以说老子就不升,只要没出问题,可那你还搞鸡毛版本化啊?), 想想这是多么“脱裤子放屁”的举措啊!
当然啦, 使用parent+modules的实践不一定非要都以同一个版本号发布所有的modules,可这就又回来到第一个概念了,你到底是把modules当成独立的实体还是某种功能关注点的组织形式? 如果是独立的实体,那么, 使用clean folder来组织独立的project就可以了, parent+modules则没有什么太大意义。
那么,是不是使用workspace下管理多个并行的project的方式就一定比parent + modules的形式更好那? 也不尽然,起码开发期间你可能要同时在多个project之间切换,但从整个开发-测试-部署-运行的pipeline来说, 我更倾向于采用第二种项目设置结构: api和impl独立开发和发布, 依赖关系通过maven(或者sbt等工具进行版本化关联管理), impl的更新对api的依赖者来说尽量透明,模块化的治理粒度从各个层面都有清晰的区分。
嗯,就先扯这么些吧!
「福强私学」来一个?
「福强私学」, 一部沉淀了个人成长、技术与架构、组织与管理以及商业上的方法与心法的百科全书。
开天窗,拉认知,订阅「福报」,即刻拥有自己的全模态人工智能。