前几天和几个饿了么的同学聊天,一听说他们还在用COLA 1.0,我二话没说,90度鞠躬,赔礼道歉,虚心聆听他们的吐槽。COLA的初衷旨在控制复杂度,救码农于水火,惭愧的是,早期的思想不成熟,设计也多有缺陷,不仅没帮到他们,反而坑了他们,实在抱歉。

实际上,我在COLA 3.0迭代的时候,已经举起奥卡姆剃刀,砍掉了很多东西。

然而还不够,主要体现在对架构的思考还不够透彻。再三考量,我觉得有必要对COLA进行一次重新梳理,回归初心,COLA真正成为应用架构的最佳实践,帮助广大的业务技术同学,脱离酱缸代码的泥潭!

应用架构的本质

什么是架构?十个人可能有十个回答,架构在技术的语境下,就和架构师一样魔幻。我曾经看过一本技术书,用了一章的篇幅讨论架构的定义,最终也没有说明白。

实际上,定义架构也没那么难,如下图所示,架构的本质,简单来说,就是要素结构。所谓的要素(Components)是指架构中的主要元素,结构是指要素之间的相互关系(Relationship

例如组织架构,其要素是什么?组成组织的要素当然是人,结构呢?结构是人与人之间的关系。因此,组织架构就是关于定义人的职责划分,以及人与人之间协作关系的一种设计方法。

同样,对于应用架构而言,代码是其核心组成要素,结构就是这些代码该如何被组织,也就是要如何处理模块(Module)、组件(Component)、包(Package)和类(Class)之间的关系。简而言之,应用架构就是要解决代码要如何被组织的问题。

 

一个没有架构的应用系统,就像一堆随意堆放、杂乱无章的玩具,只有熵值,没有熵减。而一个有良好架构的应用系统,有章法、有结构,一切都显得井井有条。

好的组织架构会遵循一定的架构模式,大部分的组织都会按职能和业务来设计自己的架构。如果你反其道而行之,硬要把销售、财务和技术人员放在一个部门,就会显得很奇怪。

同样,好的应用架构,也遵循一些共同模式,不管是六边形架构、洋葱圈架构、整洁架构、还是COLA架构,都提倡以业务为核心,解耦外部依赖,分离业务复杂度和技术复杂度

应用架构的本质,就是要从繁杂的业务系统中提炼出共性,找到解决业务问题的最佳共同模式,为开发人员提供统一的认知,治理混乱。帮助应用系统“从混乱到有序”,COLA架构就是为此而生,其核心职责就是定义良好的应用结构,提供最佳实践

COLA 架构

自从COLA诞生以来,已经被使用在很多的业务系统里面,有CRM的业务,有电商的业务,有物流的业务,有外卖业务,有排课系统…. COLA作为应用架构,有一定的普适性,是因为业务问题都有一定的共性。例如,典型的业务系统都需要:

•          接收request,响应response;

•          做业务逻辑处理,像校验参数,状态流转,业务计算等等;

•          和外部系统有联动,像数据库,微服务,搜索引擎等;

正是有这样的共性存在,才会有很多普适的架构思想出现,比如分层架构、六边形架构、洋葱圈架构、整洁架构(Clean Architecture)、DDD架构等等。

这些应用架构思想虽然很好,但我们很多同学还是“不讲Co德,明白了很多道理,可还是过不好这一生”。问题就在于缺乏实践和指导。COLA的意义就在于,他不仅是思想,还提供了可落地的实践。应该是为数不多的应用架构层面的开源软件。

分层结构

假如你是一个公司的CTO要管100号人,你怎么管?按照管理学的定义,一个人的管理幅度如果超过10个,管理就会变得很困难。因此,管100号人,你可以把他们分成10个小组,这样你管理10个小组长就好了。

所有的复杂系统都会呈现出层级结构,管理如此,软件设计也不例外,你能想象如果网络协议不是四层,而是一层,意味着,你要在应用层去处理链路层的bit数据流会是怎样的情景吗?同样,应用系统处理复杂业务逻辑也应该是分层的,下层对上层屏蔽处理细节,每一层各司其职,分离关注点,而不是一个ServiceImpl解决所有问题

对于一个典型的业务应用系统来说,COLA会做如下层次定义,每一层都有明确的职责定义:

1)适配层(Adapter Layer):负责对前端展示(web,wireless,wap)的路由和适配,对于传统B/S系统而言,adapter就相当于MVC中的controller;

2)应用层(Application Layer):主要负责获取输入,组装上下文,参数校验,调用领域层做业务处理,如果需要的话,发送消息通知等。层次是开放的,应用层也可以绕过领域层,直接访问基础实施层;

3)领域层(Domain Layer):主要是封装了核心业务逻辑,并通过领域服务(Domain Service)和领域对象(Domain Entity)的方法对App层提供业务实体和业务逻辑计算。领域是应用的核心,不依赖任何其他层次;

4)基础实施层(Infrastructure Layer):主要负责技术细节问题的处理,比如数据库的CRUD、搜索引擎、文件系统、分布式服务的RPC等。此外,领域防腐的重任也落在这里,外部依赖需要通过gateway的转义处理,才能被上面的App层和Domain层使用。

包结构

分层是属于大粒度的职责划分,太粗,我们有必要往下再down一层,细化到包结构的粒度,才能更好的指导我们的工作。

还是拿一堆玩具举例子,分层类似于拿来了一个架子,分包类似于在每一层架子上又放置了多个收纳盒。所谓的内聚,就是把功能类似的玩具放在一个盒子里,这样可以让应用结构清晰,极大的降低系统的认知成本和维护成本

那么,对于一个后端应用来说,应该需要哪些收纳盒呢?这一块的设计真可谓是费了老鼻子劲了,基本上每一次COLA的迭代都会涉及到包结构的调整,迭代到现在,才算基本稳定下来。

各个包结构的简要功能描述,如下表所示:

层次

包名

功能

必选

Adapter层

web

处理页面请求的Controller

Adapter层

wireless

处理无线端的适配

Adapter层

wap

处理wap端的适配

       

App层

executor

处理request,包括command和query

App层

consumer

处理外部message

App层

scheduler

处理定时任务

       

Domain层

model

领域模型

Domain层

ability

领域能力,包括DomainService

Domain层

gateway

领域网关,解耦利器

       

Infra层

gatewayimpl

网关实现

Infra层

mapper

ibatis数据库映射

Infra层

config

配置信息

       

Client SDK

api

服务对外透出的API

Client SDK

dto

服务对外的DTO

       

你可能会有疑问,为什么Domain的model是可选的?因为COLA是应用架构,不是DDD架构。在工作中,很多同学问我领域模型要怎么设计,我的回答通常是:无有必要勿增实体。领域模型对设计能力要求很高,没把握用好,一个错误的抽象还不如不抽象,宁可不要用,也不要滥用,不要为了DDD而DDD。

问题的关键是要看,新增的模型没有给你带来收益。比如有没有帮助系统解耦,有没有提升业务语义表达能力的提升,有没有提升系统的可维护性和可测性等等。

模型虽然可选,但DDD的思想是一定要去学习和贯彻的,特别是统一语言、边界上下文、防腐层的思想,值得深入学习,仔细体会。实际上,COLA里面的很多设计思想都来自于DDD。其中就包括领域包的设计

前面的包定义,都是功能维度的定义。为了兼顾领域维度的内聚性,我们有必要对包结构进行一下微调,即顶层包结构应该是按照领域划分,让领域内聚。

也就是说,我们要综合考虑功能和领域两个维度包结构定义。按照领域和功能两个维度分包策略,最后呈现出来的,是如下图所示的顶层包节点是领域名称,领域之下,再按功能划分包结构。

例如,在我们刚刚上线的一个云店铺(cloudstore)项目中,按照COLA的分包策略,我们在每一个module下面首先按照领域做一个顶层划分,然后在领域内,再按照功能进行分包。

解耦

“高内聚,低耦合”这句话,你工作的越久,就越会觉得其有道理。

所谓耦合就是联系的紧密程度,只要有依赖就会有耦合,不管是进程内的依赖,还是跨进程的RPC依赖,都会产生耦合。依赖不可消除,同样,耦合也不可避免。我们所能做的不是消除耦合,而是把耦合降低到可以接受的程度。在软件设计中,有大量的设计模式,设计原则都是为了解耦这一目的。

在DDD中有一个很棒的解耦设计思想——防腐层(Anti-Corruption),简单说,就是应用不要直接依赖外域的信息,要把外域的信息转换成自己领域上下文(Context)的实体再去使用,从而实现本域和外部依赖的解耦。

在COLA中,我们把AC这个概念进行了泛化,将数据库、搜索引擎等数据存储都列为外部依赖的范畴。利用依赖倒置,统一使用gateway来实现业务领域和外部依赖的解耦

其实现方式如下图所示,主要是在Domain层定义Gateway接口,然后在Infrastructure提供Gateway接口的实现。

举个例子,假如有一个电商系统,对于下单这个操作,它需要联动订单服务、商品服务、库存服务、营销服务等多个系统才能完成。

那么在订单域,该如何获取商品和库存信息呢?最直接的方式,无外乎就是RPC调用商品和库存服务,拿到DTO直接使用就完了。

然而,商品域吐出的是一个大而全的DTO(可能包含几十个字段),而在下单这个阶段,订单所需要的可能只是其中几个字段而已。更合适的做法,应该是在订单域中,使用gateway对商品域和库存域的依赖进行解耦。

这样做有两个好处,一个是降低了对外域信息依赖的耦合;另一个是通过上下文映射(Context mapping),确保本领域边界上下文(Bounded context)下领域知识的完整性,实现了统一语言(Ubiquitous language)。

COLA Archetype

以上就是COLA架构的核心内容了。然而这么多module,这么多package,如果要手动去创建的话,是非常繁琐和费时的。为了能够快速创建满足COLA架构的应用,我创建了两个Maven Archetype。

1.        一个是用来创建纯后端服务的archetype:cola-archetype-service。

2.        一个是用来创建adapter和后端服务一体的web应用archetype:cola-archetype-web。

另外,你也可以使用阿里云的应用生成器去生成一个COLA应用,只是那边的版本没有同步更新,可能会老旧一点。

COLA组件

使用过老版本COLA的同学,应该知道,COLA除了架构之外,还提供了一些框架级别的功能,比如拦截器功能,扩展点功能等。

之前,这种框架功能和架构混淆在一起,会让人以为使用COLA,就必须要使用这些功能。实际上二者是可以分开使用的,也就是说,你可以单纯的使用COLA架构,而不使用任何COLA组件提供的功能也是完全没问题的

当然,我还是强烈推荐你可以有选择的使用这些COLA组件,毕竟这些组件都是我们在实际工作中的总结沉淀,其复用性和价值是被反复验证过的。

为了方便管理,以及更清晰的把架构和框架区分开来。在此次COLA 4.0的升级中,我把这些功能组件全部收拢到了cola-components下面。到目前为止,我们已经沉淀了以下组件:

组件名称

功能

版本

依赖

cola-component-dto

定义了DTO格式,包括分页

1.0.0

cola-component-exception

定义了异常格式,主要有BizException和SysException

1.0.0

cola-component-statemachine

状态机组件

1.0.0

cola-component-domain-starter

Spring托管的领域实体组件

1.0.0

cola-component-catchlog-starter

异常处理和日志组件

1.0.0

exception,dto组件

cola-component-extension-starter

扩展点组件

1.0.0

cola-component-test-container

测试容器组件

1.0.0

这些组件是一个良好的开端,我相信,在未来会有更多有用的组件加入。当然,作为一个开源项目,如果你有好的组件idea,欢迎你随时为这个组件库添砖加瓦。

COLA 4.0

总结一下,在本次COLA升级中,我们进一步明确了架构和框架功能的定义。升级之后,如下图所示,COLA会被分成COLA架构和COLA组件两个部分:

1.        COLA架构:关注应用架构的定义和构建,提升应用质量。

2.        COLA组件:提供应用开发所需要的可复用组件,提升研发效率。

COLA 开源地址: https://github.com/alibaba/COLA

你可以按照以下步骤去使用COLA:

** 第一步:安装 cola archetype ** 下载cola-archetypes下的源码到本地,然后本地运行mvn install安装。

** 第二步:安装 cola components ** 下载cola-components下的源码到本地,然后本地运行mvn install安装。

** 第三步:创建应用 ** 执行以下命令:

mvn archetype:generate  -DgroupId=com.alibaba.demo -DartifactId=demoWeb -Dversion=1.0.0-SNAPSHOT -Dpackage=com.alibaba.demo -DarchetypeArtifactId=cola-framework-archetype-web -DarchetypeGroupId=com.alibaba.cola -DarchetypeVersion=4.0.0

命令执行成功的话,会看到如下的应用代码结构:

** 第四步:运行应用 ** 首先在demoWeb目录下运行mvn install(如果不想运行测试,可以加上-DskipTests参数)。然后进入start目录,执行mvn spring-boot:run。运行成功的话,可以看到SpringBoot启动成功的界面。

生成的应用中,已经实现了一个简单的Rest请求,可以在浏览器中输入 http://localhost:8080/helloworld 进行测试。

作者简介:

阿里巴巴高级技术专家,张建飞。著有《代码精进之路:从码农到工匠》,凭借此书,获得2020年人民邮电出版社IT类最佳作者。是开源应用架构COLA的作者,擅长应用架构和领域建模。更多技术精华内容,请关注作者的微信公众号:从码农到工匠。

阿里高级技术专家谈开源DDD框架:COLA4.0,分离架构和组件的更多相关文章

  1. 详解工作流框架Activiti的服务架构和组件

    摘要:通过这篇文章,可以对工作流有一个基本的认识,为后续工作流框架Activiti的学习打下坚实的基础. 本文分享自华为云社区<BPMN工作流的基本概念!详解工作流框架Activiti的服务架构 ...

  2. 如何打造7*24h持续交付通道?阿里高级技术专家的5点思考

    我们对于研发效能的讨论,本质上是提高整个技术生态中的协同效率.如果仅从研发角度出发,技术团队要实现的终极目标是7*24小时的灵活发布窗口,以及更快的业务迭代能力. 7*24小时发布窗口的实现其实并不简 ...

  3. (转帖)开源容器集群管理系统Kubernetes架构及组件介绍

    最近在搞Docker还有她的管理工具,选型Kuberetes后,被她的术语和概念搞得晕头转向...看了一篇文章还不错,放到这里分享出来. 地址:http://www.linuxidc.com/Linu ...

  4. 阿里封神谈hadoop学习之路

    阿里封神谈hadoop学习之路   封神 2016-04-14 16:03:51 浏览3283 评论3 发表于: 阿里云E-MapReduce >> 开源大数据周刊 hadoop 学生 s ...

  5. 进阶攻略|最全的前端开源JS框架和库

    新的 Javascript 库层出不穷,从而Web 社区愈发活跃.多样.在多方面快速发展.详细去描述每一种主流的 Javascript框架和库近乎不可能,所以在这篇文章中主要介绍一些对前端发展最具影响 ...

  6. .NET开源作业调度框架(Quartz.NET和FluentScheduler)实战项目演练

    一.课程介绍 明人不说暗话,跟着阿笨一起玩NET .本次分享课程属于<C#高级编程实战技能开发宝典课程系列>中的一部分,阿笨后续会计划将实际项目中的一些比较实用的关于C#高级编程的技巧分享 ...

  7. CDN高级技术专家周哲:深度剖析短视频分发过程中的用户体验优化技术点

    深圳云栖大会已经圆满落幕,在3月29日飞天技术汇-弹性计算.网络和CDN专场中,阿里云CDN高级技术专家周哲为我们带来了<海量短视频极速分发>的主题分享,带领我们从视频内容采集.上传.存储 ...

  8. 各大开源rpc 框架 比较

    各大开源rpc 框架 比较   1. 前言 随着现在互联网行业的发展,越来越多的框架.中间件.容器等开源技术不断地涌现,更好地来服务于业务,解决实现业务的问题.然而面对众多的技术选择,我们要如何甄别出 ...

  9. 组件化框架设计之阿里巴巴开源路由框架——ARouter原理分析(一)

    阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 背景 当项目的业务越来越复杂,业务线越来越多的时候,就需要按照业 ...

  10. .NET 5 开源工作流框架elsa技术研究

    今天假期第一天,研究了.NET 5开源工作流框架elsa,现在分享给大家. 一.框架简介 elsa是一个开源的.NET Standard 工作流框架,官方网站:https://elsa-workflo ...

随机推荐

  1. Vue <img :src=""/> 图片不显示

    场景 图片路径被原样输出,无法正确加载图片: <img :src="imgSrc"/> 原因 webpack 会将:src 动态绑定的值解析成字符串,原样输出: 解决办 ...

  2. HarmonyOS NEXT仓颉开发语言实战案例:健身App

    各位好,今日分享一个健身app的首页: 这个页面看起比之前的案例要稍微复杂一些,主要在于顶部部分,有重叠的背景,还有偏移的部分.重叠布局可以使用Stack容器实现,超出容器范围的偏移可以使用负数间距来 ...

  3. Elastic学习之旅 (11) .NET 6应用集成ES - 上

    大家好,我是Edison. 上一篇:Logstash数据采集 写在开头 有了前面10篇的基础,我们大概清楚了ES的基本概念和使用(主要是查询),这也是我们作为Developer应该了解的范畴,而至于更 ...

  4. [Ynoi2014] 人人本着正义之名

    题传 考虑 3/4/5/6 操作,发现本质上是对某段颜色相同的段向左/右拓展. 考虑 1/2 为区间推平操作,其它操作只会减少颜色段,因此总颜色段为 \(O(n+m)\) 的,直接平衡树维护即可. 然 ...

  5. 深入掌握iostat:运维必备的I/O性能分析利器

    在Linux系统运维中,磁盘I/O性能往往是系统瓶颈的关键来源.iostat作为sysstat工具包中的核心命令,能够实时监控CPU使用率和磁盘I/O统计,是性能诊断不可或缺的工具.本文将全面解析io ...

  6. react中设置短链接

    原因比如,我page要引入一个页面,那么引入起来就很麻烦.图片在src\assets\img\login\bg.jpg组件在src\pages\login\index.tsx引入代码如下: impor ...

  7. 最简单的一个 STL格式的网格文件

    简介 最简单格式的一个STL格式的文件 文件内容 solid filenamestl facet normal 1 1 1 outer loop vertex 0 0 1 vertex 0 1 0 v ...

  8. 使用Gradio快速搭建一个网站

    使用Gradio快速搭建一个网站. 提到使用gr.Interface创建UI界面,定义输入输出类型,然后通过demo.launch()启动.这应该是最基础的方法.中的示例代码也展示了类似的步骤,安装G ...

  9. Day5 备战CCF-CSP练习

    题目描述 给定 \(n\) 个不同的整数,问这些数中有多少对整数,它们的值正好相差 \(1\). 输出格式 输入的第一行包含一个整数 \(n\),表示给定整数的个数. 第二行包含所给定的$ n$ 个整 ...

  10. RestCloud ETL社区 八月精选问答