系列文章目录

01、GoodGuy 的诞生(一个消息推送平台)
02、GoodGuy 试图去揣摩一个好产品会如何进行消息推送管理平台的需求设计
03、GoodGuy 个人开源项目部分技术选型的初步思考
04、你想过为啥要用Maven、Git、SpringBoot吗?开始搭建GoodGuy,梦开始的地方


文章目录

  • 系列文章目录
  • 前言
  • 一、为什么要分模块?
  • 二、拆分模块的原则
  • 三、GoogGuy 如何分模块?
  • 总结

前言

大家好,我是处于 Java 行业下水道,励志重见天日的好人。

这期我们来聊一下,goodguy 是如何进行模块拆分的,主要是让大家了解各模块的职能是什么,对整个项目的有一个初步的系统了解。


一、为什么要分模块?

记得,在刚开始学 Java 的时候,总是喜欢把一些代码全部写在一个类里面,一个类里面有非常多的方法,每个方法都写得非常长。

然后学会了将方法拆分成多个子方法;也学会将一个类拆分成多个类,放在同一个包里。

再然后还学会了分包,比如 controller、service、dao 等。

上面是在传统单体应用里的拆分过程,现如今我们学到了微服务,不仅仅满足于分包了,开始分模块。

纵观整个项目拆分历程,可以发现我们的项目是一直在拆分的,颗粒度会越来越细,项目架构也越来越复杂。

搞这么复杂,主要是为了解耦高内聚低耦合无处不在,时刻都要考虑。

下面简单列举几个分模块的好处:

  1. 功能复用。项目由大变小,各子模块向外提供接口,或者供其他项目进行 Maven 引入,从而可以实现功能复用。比如 goodguy 中会划分出一个 API 模块,别的业务可以直接引入 API 模块,调用相应的 api 发送消息。
  2. 解耦。模块拆分,其实是进行了封装,模块与模块之间只能通过有限的接口互相调用,大大降低了耦合。
  3. 便于协作。对于大项目,如果所有功能的代码都揉合在一起,那么分工很难有清晰的界限。而拆分了模块之后,模块职责分明,可以以模块为单位进行分工,模块之间通过接口调用,定好接口就可以同时进行开发了,而且不必担心耦合问题。并且,对于刚接手项目的新人,只需要花费少量的时间去熟悉自己所负责的模块的代码即可,交接方便。
  4. 部署灵活。首先是编译,对于大型项目,编译需要花费很长的时间。如果不分模块,即使是一点小改动,就需要编译整个项目,一不小心半小时就过去了,完全没必要吧,太浪费时间。分了模块之后,只需要编译有改动的模块即可。部署,有些模块需要部署,有些模块不需要部署,有些模块流量比较大可以很方便地给此模块多加几台设备。

二、拆分模块的原则

对于这个标题,我的知识储备还不太够,我觉得我说不好,所以我查阅了一些大佬的资料,大佬“@书写宸子”写的一篇《微服务和模块划分原则》很不错,所以我引用一下,感谢大佬。

大家自行查看大佬的博客,我下面简单总结一下:

微服务设计四原则:

  1. AKF拆分原则
  2. 前后端分离
  3. 无状态服务
  4. Restful通信风格

微服务设计目标:

  1. 架构必须稳定;
  2. 服务必须高内聚 – 服务应该实现一小组强相关的功能;
  3. 服务必须符合开闭原则 – 将一同变更的内容打包在一起,以确保每个更改仅影响一个服务;
  4. 服务必须松耦合 – 每个服务都可以在不影响客户端的情况下更改实现;
  5. 服务应该是可测试的;
  6. 每项服务都小到足以由“两个披萨”团队开发,即一个6-10人的团队;
  7. 负责一个或多个服务的每个团队必须是自治的 – 团队能够在与其他团队尽量少的协作下,来开发和部署他们的服务。

服务划分方法:

  1. 通过领域驱动设计(DDD),设计与子域相对应的服务。DDD通过分析问题空间和业务逻辑,将应用程序定义为域。域由多个子域组成。每个子域对应于业务的不同部分。

子域可分为以下几类:

  1. 核心类:业务的关键差异化因素和应用程序中最有价值的部分;
  2. 支持类:与业务有关,但与差异化无关;这些可以在内部实施或外包;
  3. 通用类:与业务无关,理想情况下可以使用现成的软件实现。

三、GoogGuy 如何分模块?

简单用 ppt 做了个图,大家将就看一下。

下面主要说一下各模块的职责。

  1. vue:后台管理系统的前端,vue 项目,前后端分离;
  2. admin:后台管理系统的接口;
  3. job:定时任务;
  4. api:接入层的接口;
  5. apiImpl:api 接口的实现;
  6. handler:具体的消息下发业务实现;
  7. common:公共模块,主要存放一下枚举、公共类,引入一些公共依赖;
  8. stream:清洗日志(暂时还没有考虑好。预计是数据埋点、记录日志、清洗数据);
  9. support:主要用来接入一些中间件,相当于工具模块;
  10. getway:getway 网关。

api 与 apiImpl 拆分模块的主要原因是,考虑到用户接入时,用户并不需要关心接入层接口的实现,只要在项目中引入 api 包调用接口即可,并且 api 模块没有进行业务实现,其依赖是很少的,用户接入时,不用太担心依赖冲突等问题。所以将二者拆分开来,通过 rpc 调用。


总结

模块的拆分其实也挺有技术含量的。我觉得要有一定的逻辑性,跟着逻辑走,拆分会更合理。当然经验是后话了,经验要靠多实践才能得到,一时半会也很难达到这样的高度。所以可以多到网上找一下模块拆分的相关经验分享,还是能有不少收获的。比如上面提到的 DDD,我觉得就挺好的,至少能够在一定程度上弥补经验的不足,让你的拆分更容易达到及格线。

当然,我上面的模块拆分可能也不是很好,请大家批评指正。