关于阿里巴巴:如何保证同事的代码不会腐烂一文带你了解-Alibaba-COLA-架构

本文开始前,问大家一个问题,你感觉一份业务代码,尤其是互联网业务代码,都有哪些特点?

我能想到的有这几点:

  • 互联网业务迭代快,工期紧,导致代码构造凌乱,简直没有代码正文和文档
  • 互联网人员变动频繁,很容易接手他人的老我的项目,新人基本没工夫吃透代码构造,紧迫的工期又只能让屎山越堆越大。
  • 多人一起开发,每个人的编码习惯不同,工具类代码各用个的,业务命名也常常抵触,影响效率。
  • 大部分团队简直没有工夫做代码重构,任由代码腐烂。

每当咱们新启动一个代码仓库,都是信念满满,构造整洁。然而工夫越往后,代码就变得糜烂不堪,技术债权越来越宏大。

这种状况有解决方案吗?也是有的:

  1. 小组内定期做代码重构,解决技术债权。
  2. 组内设计欠缺的利用架构,让代码的腐烂来得慢一些。(当然很难做到齐全不腐烂)
  3. 设计尽量简略,让不同层级的开发都能疾速看懂并上手开发,而不是在一堆简单的没人看懂的代码上堆更多的屎山。

而COLA,咱们明天的配角,就是为了提供一个可落地的业务代码构造标准,让你的代码腐烂的尽可能慢一些,让团队的开发效率尽可能快一些。

COLA是什么

COLA是由阿里大佬张建飞所提出的一种业务代码架构的最佳实际,并且曾经在阿里云脚手架代码生成器中作为一个可选项,可见其曾经领有了肯定影响力。

COLA 是 Clean Object-Oriented and Layered Architecture的缩写,代表“整洁面向对象分层架构”。

在COLA 4.0,也就是目前最新的版本中,作者将COLA拆分为COLA架构(Archetype)和COLA组件(Components)两个局部:

  • COLA架构:COLA利用的代码模板。
  • COLA组件:提供一些十分有用的通用组件,这些组件能够帮忙咱们晋升研发效率。

两者互不烦扰,能够独立应用。

COLA整体架构

首先次要谈谈COLA架构,COLA的官网博文中是这么介绍的:

在平时咱们的业务开发中,大部分的零碎都须要:

  • 接管request,响应response;
  • 做业务逻辑解决,像校验参数,状态流转,业务计算等等;
  • 和内部零碎有联动,像数据库,微服务,搜索引擎等;

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

这些利用架构思维尽管很好,但咱们很多同学还是“不讲Co德,明确了很多情理,可还是过不好这毕生”。问题就在于不足实际和领导。COLA的意义就在于,他不仅是思维,还提供了可落地的实际。应该是为数不多的利用架构层面的开源软件。

COLA提供了一整套代码架构,拿来即用。 其中蕴含了很多架构设计思维,包含探讨度很高的畛域驱动设计DDD等。

留神:每个人对于架构设计都有着本人的了解。所以对于COLA的架构,本篇文章也仅仅只是我本人对于COLA的浅显了解,大家能够批评对待。

COLA分层架构

先来看两张官网介绍图

其次,还有一个官网的表格,介绍了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

这两张图和一个表格曾经把整个COLA架构的绝大部分内容展示给了大家,然而一下子这么多信息量可能很难消化。

既然整个示例架构我的项目是一个Maven父子构造,那咱们就从父模块一个个好好过一遍。

首先父模块的pom.xml蕴含了如下子模块:

<modules>
  <module>demo-web-client</module>
  <module>demo-web-adapter</module>
  <module>demo-web-app</module>
  <module>demo-web-domain</module>
  <module>demo-web-infrastructure</module>
  <module>start</module>
</modules>

start层

该模块作为整个利用的启动模块(通常是一个SpringBoot利用),只承当启动我的项目和全局相干配置项的寄存职责。代码目录如下:

将启动独立进去,益处是清晰简洁,也能让新人一眼就看出如何运行我的项目,以及我的项目的一些根底依赖。

adapter层

接下来咱们依照之前架构图从上到下的程序,一个个看。

首先是demo-web-adapter模块,这名字是不是很陈腐?但其实,能够了解为平时咱们用的controller层(对于Web利用来说),换汤不换药。

在COLA官网博客中,也能找到如下的形容:

Controller这个名字次要是来自于MVC,因为是MVC,所以自带了Web利用的烙印。然而,随着mobile的衰亡,当初很少有利用仅仅只反对Web端,通常的标配是Web,Mobile,WAP三端都要反对。

cilent层

有了咱们说的“controller”层,接下来有的小伙伴必定就会想,是不是service层啦。

是,也不是。

传统的Web利用中,齐全能够只有一个service层给controller层调用,然而作为一个业务利用,除非你真的只是个前端页面的有情吐数据机器,否则很大可能性你的利用会有很多其余上下游调用方,并且你须要提供接口给他们。

这时候你给他们的不应该是一个Web接口,应该是RPC调用的服务层接口,至于起因不是本文的重点,具体就不开展了。

所以在COLA中,你的adapter层,调用了client层,client层中就是你服务接口的定义。

从上图中能够看到,client包里有:

  • api文件夹:寄存服务接口定义
  • dto文件夹:寄存传输实体

留神,这里只是服务接口定义,而不是服务层的具体实现,所以在adapter层中,调用的其实是client层的接口:

@RestController
public class CustomerController {

    @Autowired
    private CustomerServiceI customerService;

    @GetMapping(value = "/customer")
    public MultiResponse<CustomerDTO> listCustomerByName(@RequestParam(required = false) String name){
        CustomerListByNameQry customerListByNameQry = new CustomerListByNameQry();
        customerListByNameQry.setName(name);
        return customerService.listByName(customerListByNameQry);
    }

}

而最终接口的具体实现逻辑放到了app层。

@Service
@CatchAndLog
public class CustomerServiceImpl implements CustomerServiceI {

    @Resource
    private CustomerListByNameQryExe customerListByNameQryExe;

    @Override
    public MultiResponse<CustomerDTO> listByName(CustomerListByNameQry customerListByNameQry) {
        return customerListByNameQryExe.execute(customerListByNameQry);
    }
}

app层

接着下面说的,咱们的app模块作为服务的实现,寄存了各个业务的实现类,并且严格依照业务分包,这里划重点,是先依照业务分包,再依照性能分包的,为何要这么做,文章前面还会多说两句,先看图:

customer和order别离对应了生产着和订单两个业务子畛域。外面是COLA定义app层上面三种性能:

App层 executor 解决request,包含command和query
App层 consumer 解决内部message
App层 scheduler 解决定时工作

能够看到,音讯队列的消费者和定时工作,这类平时咱们业务开发常常会遇到的场景,也放在app层。

domain层

接下来便是domain,也就是畛域层,先看一下畛域层整体构造:

能够看到,首先是依照不同的畛域(customer和order)分包,外面则是三种次要的文件类型:

  1. 畛域实体:实体模型能够是充血模型(请自行理解),例如官网示例里的Customer.java如下:
@Data
@Entity
public class Customer{

    private String customerId;
    private String memberId;
    private String globalId;
    private long registeredCapital;
    private String companyName;
    private SourceType sourceType;
    private CompanyType companyType;

    public Customer() {
    }

    public boolean isBigCompany() {
        return registeredCapital > 10000000; //注册资金大于1000万的是大企业
    }

    public boolean isSME() {
        return registeredCapital > 10000 && registeredCapital < 1000000; //注册资金大于10万小于100万的为中小企业
    }

    public void checkConfilict(){
        //Per different biz, the check policy could be different, if so, use ExtensionPoint
        if("ConflictCompanyName".equals(this.companyName)){
            throw new BizException(this.companyName+" has already existed, you can not add it");
        }

    }
}
  1. 畛域能力:domainservice文件夹下,是畛域对外裸露的服务能力,如上图中的CreditChecker
  2. 畛域网关:gateway文件夹下的接口定义,这里的接口你能够粗略的了解成一种SPI,也就是交给infrastructure层去实现的接口。

例如CustomerGateway里定义了接口getByById,要求infrastructure的实现类必须定义如何通过消费者Id获取消费者实体信息,而infrastructure层能够实现任何数据源逻辑,比方,从MySQL获取,从Redis获取,还是从内部API获取等等。

public interface CustomerGateway {
    public Customer getByById(String customerId);
}

在示例代码的CustomerGatewayImpl(位于infrastructure层)中,CustomerDO(数据库实体)通过MyBatis的查问,转换为了Customer畛域实体,进行返回。实现了依赖倒置。

@Component
public class CustomerGatewayImpl implements CustomerGateway {
    @Autowired
    private CustomerMapper customerMapper;

    public Customer getByById(String customerId){
      CustomerDO customerDO = customerMapper.getById(customerId);
      //Convert to Customer
      return null;
    }
}

infrastructure层

最初是咱们的infrastructure也就是基础设施层,这层有咱们方才提到的gatewayimpl网关实现,也有MyBatis的mapper等数据源的映射和config配置文件。

Infra层 gatewayimpl 网关实现
Infra层 mapper ibatis数据库映射
Infra层 config 配置信息

所有层讲完了,COLA4.0很简单明了,最初,在援用一段官网介绍博客原文来总结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层应用。

COLA架构的特色

说完了分层架构,咱们再来回顾下下面提到的COLA架构的几个特色的设计

畛域与性能的分包策略

也就是上面这张图的意思,先依照畛域分包,再依照性能分包,这样做的其中一点益处是能将腐烂管制在该业务域内。

比方消费者customer和订单order两个畛域是两个后端开发并行开发,两个人对于dto,util这些文件夹的命名习惯都不同,那么只会腐烂在各自的业务包上面,而不会将dto,util,config等文件夹放在一起,极容易引发文件抵触。

后面的包定义,都是性能维度的定义。为了兼顾畛域维度的内聚性,咱们有必要对包构造进行一下微调,即顶层包构造应该是依照畛域划分,让畛域内聚。

业务域和内部依赖解耦

后面提到的domain和infrastructure层的依赖倒置,是一个十分有用的设计,进一步解耦了取数逻辑的实现。

例如下图中,你的畛域实体是商品item,通过gateway接口,你的商品的数据源能够是数据库,也能够是内部的服务API。

如果是内部的商品服务,你通过API调用后,商品域吐出的是一个大而全的DTO(可能蕴含几十个字段),而在下单这个阶段,订单所须要的可能只是其中几个字段而已。你拿到了内部畛域DTO,转为本人畛域的Item,只留下题目价格库存等必要的数据字段。

COLA并不完满

诚然,COLA曾经做的足够清晰简洁了,然而它依然有不完满的中央,比方每个接口的出入参都会依据业务名做定义,导致了很多构造极为类似的DTO,DTO的爆炸增长是个问题。参考:ISSUE-271

然而总的来说,COLA只是给你提供了一种架构设计的思维,并不深刻到强制你应用某种标准的层面,所以对于COLA中你感觉简单,或者不了解的中央,很多时候须要你本人来做衡量,作取舍。取其精华,去其糟粕的使用到你的我的项目中。

总结

COLA架构并不简单,COLA曾经从1.0版本通过逐次精简,倒退到了现在的状态。在阿里云代码脚手架生成器中作为一个可选项,足见其曾经趋于成熟。

下一篇文章,我会和大家一起探讨下COLA组件库中的一些重要组件,比方扩大点组件(cola-component-extension-starter),状态机组件(cola-component-statemachine)等。这些组件并不强制和COLA绑定,你齐全能够不应用这些组件,只应用COLA架构来设计你的利用。然而这些组件能够晋升团队的研发效率。

咱们下期再见,我是在阿里搬砖的工程师 蛮三刀酱

继续的更新原创优质文章,离不开你的点赞,转发和分享!

我的惟一技术公众号:后端技术漫谈

欢送加我集体号:BrodyYang

参考

COLA Github

https://github.com/alibaba/COLA

COLA 4.0.0 版本

https://blog.csdn.net/signifi…

COLA 3.1.0 版本

https://blog.csdn.net/signifi…

COLA 3.0.0 版本

https://blog.csdn.net/signifi…

COLA 2.0.0 版本

https://blog.csdn.net/signifi…

COLA 1.0.0 版本

https://blog.csdn.net/signifi…

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理