关注代码质量——包结构

最近想了想:在现在的项目里,我最关注什么东西?我期望它是什么样子的?实际上它是什么样子的?

第一个问题的答案,是代码质量。现有的项目中,有70%+的代码是我一手写出来的。然而现在回头看看,其中有90%+令我非常不满意。各种各样的问题充斥其中:功能上错漏百出,性能上隐患迭起;维护起来艰深晦涩,扩展起来困难重重。实在让我很不好意思承认这些垃圾是我制造的。

那么,我对代码质量的期望是什么样的呢?我想了想,有好几个方面。计划分别梳理一下。

先说说包结构。

代码的包结构应该是按模块来分。每个功能模块对应一个包。

这样做的好处在于,系统的结构会非常清晰。并且,这样处理会为后续的一些方面提供便利。

2023-02-16 补充 “按模块来分”,对应的是“按层级来分”。

举例子来说,“按模块来分”,我们可能得到这样的包结构:

com.xxx.payment.web  
com.xxx.payment.biz  
com.xxx.payment.biz.impl  
com.xxx.payment.service  
com.xxx.payment.service.impl  
com.xxx.payment.dao  
com.xxx.payment.dao.impl  

com.xxx.order.web  
com.xxx.order.biz  
com.xxx.order.biz.impl  
com.xxx.order.service  
com.xxx.order.service.impl  
com.xxx.order.dao  
com.xxx.order.dao.impl  

而“按层级来分”,上面的包结构就会变成这样:

com.xxx.web.payment  
com.xxx.web.order  

com.xxx.biz.payment  
com.xxx.biz.order  
com.xxx.biz.impl.payment  
com.xxx.biz.impl.order  

com.xxx.service.payment  
com.xxx.service.order  
com.xxx.service.impl.payment  
com.xxx.service.impl.order  

com.xxx.dao.payment  
com.xxx.dao.order  
com.xxx.dao.impl.payment  
com.xxx.dao.impl.order  

各个模块之间应该尽量相互闭包,互不引用彼此的类。

这应该是包结构上“高质量”的体现之处。包结构之间互相独立,能够将代码改动的影响范围限制在本模块之内,而且,在我们的项目中,存在这样一种情况:项目A中的某个功能A1需要以jar包的方式提供给项目B使用。在互相独立的包结构下,这个jar包很容易导出;但是在我们的项目A中,由于包结构和互相的引用非常混乱,为了导出这一个功能,常常需要把整个项目打成jar包。

但是要做到包结构的互相独立,很显然就会遇到两个问题。

第一,有一些模块的功能就是为其它模块提供基础支持服务的。这类模块可以不引用其它的包,但不可能让其它的包不引用自己。 这个问题只能特事特办。这类基础支持服务的包可以允许别的包引用它,但不应该引用到别的包;别的包仍应该坚持互相独立。

第二,如果某个包不得不引用到另一个包,那么该如何处理? 建议把被调用的服务放到基础支持服务的包里面。如果衡量之下实在不想这样做,那么就在被调用的包里放一个服务接口,为调用这个服务的包做一个适配器。

关于包的命名

这个无需太多赘述,一般都遵循类似“组织.项目.模块.子模块”的命名层次。只是对自己强调一句:各个层次的命名应该清晰、明确。另外,第二条所说到的包之间的独立性,从命名上而论,是在“模块”这一级别上的独立。

那么现在的状况呢?

这一点更加不必多费唇舌。我对包结构的期望,就是针对项目中的现状“有感而发”才产生的,由此及彼,现状不言自明。

现状中的问题,计划以小步走的重构、演进来逐步解决。后续的新的开发,应当注重遵循必要的规范才行。