如何创建一个易维护可扩展的java工程
我们在项目中经常会遇到一个困扰,为什么写着写着,代码越来越臃肿,越来越难维护?归根结底是因为没有良好的工程规范,没有根据业务的变化,适时的进行同步调整。
 
1.问题
项目中我们经常会遇到几个误区(借口)
1.之前代码不要动,会影响稳定性。
这个是经常听到的,说到底,这么说的主要原因是项目好好的,我碰了,出了事就得自己背锅,这个是可以理解的,毕竟国内公司甩锅成风,遇到问题第一不是想着去解决问题,而是先把责任甩出去。多做多错,不做不错,也是可以理解的。
2.不要搞那么复杂,先上线再说。
如果只是做个demo,问题不大,但是,以大多土老板的尿性,他能区分的了什么是demo什么是可用级别?另外就是,大部分情况下,客户不管你怎么实现的,他只是要这个东西(你自己不要求质量,就别怪人家糊弄你了)。同等条件下,多快好省,一定是伪命题。
3.等有条件的时候,再进行重构。
别等了,基本等不到。
4.之前的团队是这么做的
很多时候,很多所谓的“CTO”,“架构师”的水平,只能用呵呵来形容了。骗一波高薪就跑路,后面的坑留给后面的人(真是死道友不死贫道)。
 
2.思路
为了尽量避免进入屎山的困境(感觉好像没法完全避免的),我们只能尽量从工程层面和设计层面多花心思。
1.设计做大,功能做小。
做业务设计的时候,把可能的场景尽量考虑进去,在实际开发的时候,先做基础的功能
2.做代码的产品经理
产品经理是对产品负责的,那么开发就要对工程负责,就要做工程的产品经理,每个package,每个函数,都要给它一个定义,都要能说的清楚,说的清楚,这样才能不迷惑。
3.基于业务领域的划分
从项目的角度来说,一个项目是可以划分成多个业务领域的,比如说,一个电商系统,其中的商品,订单,用户,是可以分为不同的业务领域的。根据业务领域进行模块的划分,把影响控制在当前的领域内,从而不会因为某一个人的胡作非为,导致整体工程规范的崩溃。而相关的问题,也可以在可控范围内尽快肃清。
4.换马不换人,换人不换规范
对工程结构的规范,最大的好处就是,当团队面临人员更替的时候,新的人员,可以快速的进入状态。只要知道工程设计规范,就可以知道自己需要的东西大概会在什么位置。避免了重复的劳动,还有五花八门的命名。
 
3.实践
这里,以平时的一些做法做一些总结,并不涉及DDD的那些玄学,单纯的就是用的清晰方便。
3.1 层级结构
根据模块的功能我们大体分为core,rest-conf,api 三大类模块
  • core 处理业务逻辑
  • rest-conf rest相关的配置,例如swagger,spring-security等
  • api 接口,主要是controller,包括一些入参,出参的处理
 
3.2 业务模块的内容部划分
这里主要的是core这个模块,90%的代码都在这边了。之前的层次结构是直接分了dao,service,controller 几层,然后一股脑的把所有的都扔进去,曾经看到过有的代码一个package下滚动条得拉半天。
我们这边调整为以业务领域为package的拆分,例如,社区项目分为article,question两个业务领域,这样的话,在core->modules下面平级的创建article,question两个package,而业务领域中,再去分层,这里我们主要分为dao,manager,service三层,另外再加一个support的package里面放业务的工具类,转换类等等。
 
3.3 跨业务领域的调用
既然是根据业务领域做了划分,那么跨业务领域的调用怎么做呢?很多时候,我们都会看到层级调用混乱的情况。简直就如同蜘蛛网一样。
 
我在A服务service层需要调用另外一个业务B的方法,但是那个方法也在service层,怎么办啊?用了就是平级调用,还可能导致循环依赖。难道要去manager层再实现一个?可是他又依赖了C的service层,真是造孽啊 我应该怎么办?大家应该上过高速公路啊,高速公路上的最右侧是一个应急车道。也就是说,这条车道一般是不让用的,只有在特数情况下,才会去使用。
那么,我们是否可以借鉴一下这个思想,专门给划分一个区域,去给他做跨业务领域的调用,我们这里是用一个provider的概念去做。通常情况下,跨业务领域的操作是比较少的,或者说,提供给其他业务领域的场景是比较少的,比如,文章领域去调用用户领域,一般来说,也就是根据ID获取用户信息,根据IDS获取用户信息列表。那么,我们的做法是所有的领域在provider中提供一个入口,如果在article领域需要调用,则引入user的provider。并且
1.provider中的实体模型应该独立定义,例如,在user领域原来的是User,那么在provider中,我们定义一个UserPDO,这样避免业务调整的时候污染其他业务领域。
2.如果在特殊情况下,发生依赖调用的情况,则可以使用懒加载。做过微服务的兄弟,其实比较容易明白,这里的业务领域,其实跟微服务的划分是很相似的。
3.跨模块可以使用事务。因为毕竟是运行在一个容器内,这个应该是允许的,当然,如果可以,尽量避免,因为如果后面拆分微服务的时候,就需要去处理这块业务了。
 
 
4.这么做的好处
1.业务边界清晰,相关负责人员只需要在对应的package内处理自己的业务即可,不必去考虑某方法是会否在某处已经存在。
2.人员更替时,只需看工程规范,就可以基本知道某个业务的某个功能大概在什么位置。
3.业务拆分简单。如果后面需要做微服务的时候,只需复制一份工程,然后,把下不需要的部分去掉(是去掉不需要的,因为做减法肯定比做加法轻松
 
5.总结
当然,这只是一些总结,不同的人会有不同的想法,归根结底,所有的规范都需要人去遵守,要有对工程质量有追求的团队成员。秦军可以在河西一战中大败天下无敌的魏武卒,靠的必然不只是秦法严苛,而是一只训练有素的新军。所以,这并不是某个人的事,而是自上而下的一个全局贯彻。

工程结构

关于作者

落雁沙
吹牛逼大王
获得点赞
文章被阅读