引言
前段时间刚看完了《面向模式的软件架构:卷一》,同时又在参与公司 EBF 框架(Extensible Business Framework,可扩展的业务框架,俗称“耳边风”)前期的相关技术探讨和框架制定。所以,借此机会一方面总结读书后的总结感悟,其次结合工作中遇到的问题做简短的知识沉淀。鉴于我做的读书笔记篇幅较长,且工作中的问题也纷乱繁杂,为了更好的聚焦问题,便于大家阅读,此博文会基于特定的场景故事来浓缩相关知识点。
—— 作为业务编码的程序员,想必在业务编码能力的提升上,不会局限于 CRUD 的胶水代码。相信会更希望运用 GoF 设计模式(四人帮,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 于 1995 年合著)来解决特定场景的代码设计问题,也有运用 DDD(领域驱动设计,由 Eric Evans 于 2003 年著)领域内聚的模式来应对可持续性交付的问题。
当然,我们也曾遇到过这些问题:一个单体服务的拆分我们应该从哪里入手?系统变的逐渐复杂且难以迭代,我们该如何让其具备可扩展能力?
简介
《面向模式的软件架构》总共有五卷,其中第一卷主要讲解模式与软件系统架构的协作,作者认为模式是在特定场景下,就经验总结得出的可复制的解决方案,在场景问题下可以套用。当然,解决方案的实现会产生新的问题/场景,由其他模式来解决。书中也将体系结构模式和 GoF 设计模式做了对比和结合。
(来源:电子版)
当具体指定一个应用的基本结构时,体系结构模式可用于粗粒度设计的开始阶段。在细化设计时,设计模式指定了详细设计阶段的方法。本书也将 GoF 设计模式进行浓缩和汇总。书中的各种模式介绍和相关变体,以及结合系统的运用,不进行详细概述了。整体来看本书的内容较务实,从场景枚举、问题罗列、方案解决到模式分析和变体模式的应用,都讲得非常详细,但是翻译质量偏差,很多语句读起来比较晦涩。其次,书本出版于 03 年(DDD 出版的年代),技术专业术语和概念上和现代人略有偏差。
此次,我们就“单体应用拆分”和“复杂系统提升可扩展性”这两个话题,以体系结构模式做相关分析讨论,解决如何在应用结构设计前,通过模式编程完成粗粒度设计的起始阶段。
单体应用拆分
“单体应用”这个词或许有些陈旧,因为当今很多公司的技术结构都以多服务的形式协作,很少会存在庞大的“单体”。但是,作为业务研发需要正视的一点是需求本身是源源不断的,且其复杂度本身也是不可改变的(我们很难通过一种模式来解决需求本身的复杂度,而是通过模式让编程语言更清楚、更友好、更可扩展的表示出需求逻辑,这是一种信息转义过程),所以在不断的需求迭代过程中,轻量级的“单体”会逐渐的变重(也有时候是因为需求倒排,在有限精力下牺牲代码质量来完成任务,加重了整体结构的负担)。
当“单体”到达一个量级需要投入更多的人员消化新的需求和系统维护时,就有了“单体”协助的问题。此时,对于它的代码边界、编程规约极其重要,这个时候沟通成本、责任边界是很高的,我曾经接触过一个由 10 多人一起维护的“单体”,因为代码都揉在一块儿,前期没有区分边界时,人人都有自己的设计原则。当区分出边界、定下规约后,我们又开始担心新人的学习成本和犯错成本,所以这个时候考虑到“单体”拆分的问题,通过物理隔离降低人为因素的影响。
上面是一套腐化的单体应用,通过事务脚本来完成编码协作,各个层的定义相对比较明确,这里不进行赘述。说明下上图表现出来的主要问题,Module A 的 Servcie 层作为服务层用于处理 A 模块特定的业务逻辑,此时可能会调用到 Module B、C 的相关业务能力,在一个没有明确约定管理的“单体”内,就很有可能出现 A 的 Service 调用了 C的Dao,这是很不可取的,将会逐步腐化整个项目工程,更有甚者会腐化到 Controller 层。
- 对于 Module C 无法控制自身的哪些能力被调用了,导致新需求迭代影响面无法评估。
- 对于 Module A 来说,Service 层是混乱的,作为一个单体应用无论是哪里的 Module Dao对它都没有特别大的影响,但是随着耦合复杂度的提升,将来拆分成 RPC 时,可能会到动到 Service 的业务逻辑。
- 也有可能,Sql Join 了不同 Module Dao 的表,这样就彻底耦合了。
- 这也引起了 Module 的边界不清晰,开展新需求时,很难辨别我应该写在哪里。
这个事件对于很多人来说可能会用自我约束来管理,但是这毕竟是一种人为约束,会有沟通和管理的成本,而且成本非常大。
解决方案
首先根据场景来看,这是一个从混沌到结构的问题。层、管道和过滤器、黑板都是这个特定场景下很好的选择。往往我们第一感触就是分层来解决。层是一种非逆向的从上往下传递的结构思路,且每个层是独立的,对该层的工作可闭环。我们经常叨叨的 “Controller”、“Service”、“Dao”,就是一种基本的层次结构。
- Controller 负责输入/输出和服务应用。
- Service 负责业务逻辑拼装,可能这里还会有 Manage 层来做 Dao 组装。
- Dao 负责数据库操作。
暂且不说领域模型和事务脚本方式孰优孰劣,我们的现状是需要解决层协调及层能力闭环的问题。
如图,系统层(System Layer)是很熟悉的“Controller Service Dao”模型,比较纯粹,需要规范好每个层
输入/输出对象,并且路径是从上往下垂直的。业务层(Business Layer)往往比较关键,也是我们拆分各个 Module需要着重思考的点,如哪些是一个 Module,多个 Module 之间如何协助等问题。有几个经验之谈:
- Module 与 Module 之间尽量少依赖,粗暴的衡量标准是相互之间的接口要尽可能少。
- 首要考虑的拆分可以沿业务流程去思考,这样比较直观,沟通起来通俗易懂,且流程要顺序尽可能不出现逆向依赖,减少模块间反复耦合问题。
- 在拆分期间,可以先不进行物理分离,优先做好代码Module的隔离及规范非常重要。
(照片:2020 年,通过领域事件风暴进行分层时,拍下的白板一角)
当然实际的业务分层还要基于业务特定的属性来思考,会更垂直。但大体要尽可能的减少耦合,让层更内聚。在拆分后,需要关注层如何闭环,如何接受上游业务来进行相关逻辑处理,这里我们需要引入业务身份的概念。因为每个层是自我闭环的,暴露出去的是接口,要确认上游业务相关的处理逻辑,需要通过业务身份识别来判断。
(业务身份在公司平台有一套丰富的身份-配置的关系逻辑,这里不深入探讨)
- 业务 A 和业务 B 分别都会流入到业务 C,业务 C 需要通过他们传递的身份来判断执行的业务逻辑。
- 定义的业务身份会非常注重,需要基于业务现状可枚举,而不是任何状态、类型都是一种身份。比如下单操作时,会根据订单的业务身份(政采/个人/企采,竞价/团购等)来识别当前场景下需要处理什么样的逻辑。
总之,我们通过分层的方式来划分边界,将混沌转向结构。分层后的每一个层级需要考虑其内聚能力和自我闭环,通过业务身份打通上下游逻辑。
复杂系统提升可扩展性
当一个系统逐渐变得丰富并逐渐复杂起来,我们更希望把复杂的逻辑能扩展出去,增强系统整体的适应性。常见的GoF 设计模式也比较多:适配器、装饰器、策略等等。从系统设计粗粒度的角度看,《面向模式的软件架构》叙述了微核体系结构模式来提供系统的适应性,这种模式把最小功能核心同扩展功能和特定客户部分分离出来,并对插件进行协调,它提供了一种“即插即用”的软件环境。
书本中描述了新型操作系统的解决方案,毕竟微核的概念来源于操作系统,但是我们想把这个模式套用到业务系统中,需要重新转换思考模式。
上图是根据书本内容简述的一个微核结构,实际内容会更加丰富。其中,系统适应性主要体现于编程接口的上下联动。编程接口侧还有一层适配器,为了解决不同操作系统应用程序可以在同一操作系统下运行的适配作用,本例没有具体展示。
- 微核提供最小且核心的能力,并协调应用程序运行。所有的扩展能力通过应用程序实现,微核只提供机制不是方针(即只提供抽象)。
- 外部服务器是通过应用领域具体分析后的方针,根据这些方针可以确定应用领域所需要的功能。外部服务器汇聚了每一条方针并使用微核的接口提供服务,让客户机实现应用的编程。(外部服务器是书本提供的名字,可能是因为将客户机视为外部系统作为 Facade 使用吧)
- 客户机通过外部服务器的编程接口实现具体功能,即“应用程序”。
结合业务系统,当我们的复杂度到达一定程度,业务场景有了一定穷举量后,我们可以分析业务领域是否适合微核这种结构模式。微核内部可以由抽象的模型和标准的定义组成,外部服务器可以是业务能力点的体现,这也是EBF 框架大体的思路,当然内部设计会非常丰富,微核只是解决适应性的一种结构模式,它产生的其他问题需要通过其他模式来解决。
其中,业务能力点是整个微核模式设计的关键,我们在分析能力点的扩展时,比如订单有创建订单的能力,与此同时该能力的动作还会在创建订单后发送消息给供应商。因为每种业务场景下,这部分消息的逻辑都有差异,我们会从领域设计模型考虑:发送消息不应该属于创建订单能力,应该由消息支持域来完成,创建订单只是调用了消息支持域的发送能力。
通过微核模式,将业务标准下沉到内核,建立不直接同应用领域相关但又是实现系统基础结构所需要的操作能力,可以增强系统整体的可适用性。目前,EBF 框架还在设计中,并有了阶段性的小成果,我们也致力于通过业务架构思维来解决复杂的企业级系统,让业务交付编程实现更简单。期待在业务编码寻找方向的小伙伴们,加入政采云技术团队。
总结
体系结构模式的设计是基于特定场景提供的解决方案,从场景问题的特性分“混沌到结构”、“分布式系统”、“交互式系统”、“适应性系统”。在解决单体应用拆分或可扩展性系统的问题时,可以通过层划分边界,实现模块的内聚;也可以通过微核模式分析应用领域的功能,下沉标准,建立基础结构所必须的操作能力。
以上文章的内容存在很多细节的缺漏(微核部分因考虑到篇幅问题没有讲述落地细节),在后续的文章中可以陆续补充,涉及个人理解上的偏差也可以评论留言一起探讨、学习。
推荐阅读
招贤纳士
政采云技术团队(Zero),一个富有激情、创造力和执行力的团队,Base 在风景如画的杭州。团队现有300多名研发小伙伴,既有来自阿里、华为、网易的“老”兵,也有来自浙大、中科大、杭电等校的新人。团队在日常业务开发之外,还分别在云原生、区块链、人工智能、低代码平台、中间件、大数据、物料体系、工程平台、性能体验、可视化等领域进行技术探索和实践,推动并落地了一系列的内部技术产品,持续探索技术的新边界。此外,团队还纷纷投身社区建设,目前已经是 google flutter、scikit-learn、Apache Dubbo、Apache Rocketmq、Apache Pulsar、CNCF Dapr、Apache DolphinScheduler、alibaba Seata 等众多优秀开源社区的贡献者。如果你想改变一直被事折腾,希望开始折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊……如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的技术团队的成长过程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 zcy-tc@cai-inc.com
微信公众号
文章同步发布,政采云技术团队公众号,欢迎关注