刚刚经历一个理念上的错误导致几个通宵白干了。所以呢,务实一些,我劝我自己,我把自己的架构设计,模块化的这个理念先搞懂。老李写的蛮好的,你把它完全重构了干什么你告诉我。现在几个通宵白熬了,你告诉我怎么解释?脸都不要了。
为了要脸,我决定趁着今晚芙总睡觉安稳的空闲,把这个理念先写出来搞搞明白。
采用模块化的原因是为了形成低耦合,高内聚的项目架构。但是,这种项目架构并不意味着我要使用被炒的很热的微服务。模块化和微服务我个人认为是完全不同的两个理念,甚至都不应该放到一个维度讨论,微服务是一个项目架构概念,而模块化我认为是一种开发概念,而且其内核是不断升级的。我认为现在对微服务无脑运用是一件贼搞笑的事情。有的项目的体量、人员素质等等因素完全没有必要使用微服务非要硬上,结果可想而知。当然,这篇文章是为了论述我对模块化的思考及个人浅见,微服务的就不深入探讨。
话题回归模块化。要想了解什么是模块化,首先要明确什么是模块,我个人的理解,模块应该基于其域的有界上下文建模,使用特定逻辑将组件及次级模块相关联以实现与之相关业务,具有可复用性。
模块的特性:
- 有其业务领域的边界。
- 是业务逻辑的实现载体。
- 拥有或者说可以拥有组件及次级模块(可被拆分)。
- 具有可复用性。
如果你接触过领域驱动设计 (DDD) 的话,你应该对第一个特性很好理解,在DDD理念中,任何领域模型是有其边界的。
针对这些特性,举个例子,芙总现在是我们公司的老板,她有一天告诉我,“小王,你负责一下家庭统计项目下的人员信息这个业务模块。”然后我会根据人员信息这个业务进行建模,我的所有的行为都应围绕人员信息这一具体的业务主题来进行,目的是形成一个实现芙总分配给我的家庭统计项目下的人员信息业务的载体。
当我开始设计的时候,基于我多年的工作经验,我认为我会用到一系列组件,比如鉴权组件、缓存组件等。同时我还设计了一个次级模块,人员信息上传。它拥有文件上传组件、网络通信组件等。好了,我设计完了。开开心心的向芙总汇报了。
过了没几天,芙总又告诉我,“小王,你再负责一下家族统计项目下的人员信息模块,你之前有经验了,这次就给你三天时间。”万恶的资本家,这么压榨打工人。但是完全不慌,鉴于我上一次优秀的设计,直接复用家庭统计项目下的人员信息模块,总共花费一个小时。划水三天后,又开开心心的向芙总汇报了。
通过上述例子,应该可以比较直观的了解模块的特性及设计方法。然后会发现,我又引入了组件这个概念。其实之前我对模块化和组件化也是有点混淆的,因为模块和组件的英文原单词都是Module
。后来我是这么强行分类的,业务是模块,功能是组件。人员信息业务(模块)应该有上传(组件)、获得信息(组件)、网络通信(组件)、缓存(组件)、鉴权(组件)等功能。根据业务相关性,我们又把它设计成人员信息业务(模块)应该有人员信息上传业务(模块)【上传(组件)、网络通信(组件)功能】、获得信息(组件)、缓存(组件)、鉴权(组件)等功能。
一个正常的多业务的项目,难免有组件是高度依赖且共性的。比如鉴权、缓存、对象映射、ORM等。那么,从设计人员或者架构师角度出发,我认为我们应该将此共性的组件进行抽象化或者形成固定的公用(Public)组件进而形成框架。这两种方案各有利弊,进行抽象化,这种方案更依赖于项目开发人员的技术水平,因为从技术角度你无法控制他对此抽象的实现的质量,容易出现良莠不齐的现象。但是可以提高开发人员的技术水平。形成一套固定框架,这种方案会让开发人员的精力集中在功能模块的业务实现上,解放了开发人员。但是相对而言,如果他们接触不到框架的源码或者自身没有那个意图,那么容易患上我所命名的“框架依赖症”,即脱离框架后变得茫然且无法独立较好的实现某个功能。当然,这个话题又跑题了,这是我习惯于从自身项目经理的角度分析问题所得出的利弊。
我最终所采用的方案是形成一套完整的框架搭配约定,实现开发人员的敏捷开发。
关于这一点,请格外注意,你的模块约定重要性甚至高于你的框架搭建。其实作为上古时代的程序员,我习惯了写配置文件而不是约定。但是由于约定大于配置的习惯及便利性,我在这个框架搭建的时候还是选择了约定的方式,悲剧的是我一开始忽视了模块约定的建设,导致了约定的互不统一,这直接导致了本文开篇的大失败。
最后,要感谢一下老李,因为他的模块化项目MKH: 基于.Net 6+Vue3开发的业务模块化快速开发框架和我的思路不谋而合。我在设计我的框架时也不少“参考”他的项目。
同时也推荐一篇微服务与模块化对比的文章Modules vs. microservices – O’Reilly 。我个人认为是讲的比较清楚的。
由于个人能力浅薄,认知有限。如本文中您认为有错误,欢迎指正及交流。