从核心到边界:六边形、洋葱与COLA架构的深度剖析

打印 上一主题 下一主题

主题 833|帖子 833|积分 2499

1 引言

   软件的主要技能使命:管理复杂度。
  工程师的主要技能使命就是控制复杂度。整齐面向对象分层架构(Clean Object-oriented and Layered Architecture,COLA)是阿里团队自主研发的应用架构,是复杂治理之路上的一个里程碑。
COLA不仅是一个架构头脑,还提供了一整套可以落地实行的框架和工具。我们可以利用COLA Archetype快速搭建一个符合COLA架构规范的业务应用,并在此基础上快速实现业务功能。
现在,COLA已经开源。自觉布以来,COLA得到了社区的普遍关注和认可,并已经在阿里巴巴内外部多个团队落地。从实践情况来看,COLA在应用复杂度治理上的效果显着。
2 软件架构

架构始于建筑,这是人类发展分工协作的需要。将目的系统按某个原则举行切分,切分的原则是便于不同的角色举行并行工作。
软件架构是一个系统的草图。软件架构描述的对象是直接构成系统的抽象组件。各个组件之间的连接则明确和相对过细地描述组件之间的通讯。
在实现阶段,这些抽象组件被细化为现实的组件,比如详细某个类或者对象。在面向对象范畴中,组件之间的连接通常用接口来实现。
随着互联网的发展,现在的系统要支持数亿人同时在线购物、通讯、娱乐等需要,相应的软件体系结构也变得越来越复杂。软件架构的寄义也变得更加宽泛,我们不能简单地用一个软件架构来指代所有的软件架构工作。
3 架构分类

为了更清晰地表述六边形架构、洋葱架构、COLA架构在软件架构中的位置,以及应用开发人员应该关注什么,可以将软件架构划分成业务架构、应用架构、系统架构、数据架构、物理架构和运维架构,如下图所示:

   软件架构分类图  

  • 业务架构:由业务架构师负责,也可以称为业务范畴专家、行业专家。业务架构属于顶层设计,其对业务的界说和划分会影响组织结构和技能架构。
  • 应用架构:由应用架构师负责,他需要根据业务场景的需要,设计应用的拓扑结构,订定应用规范、界说接口和数据交互协议等。并只管将应用的复杂度控制在一个可以接受的水平,从而在快速地支持业务发展的同时,确保系统的可用性和可维护性。COLA架构是一个典型的应用架构,致力于应用复杂度的治理。
  • 系统架构:根据业务情况综合思量系统的非功能属性要求(包括性能、安全性、可用性、稳固性等),然后做出技能选型。对于盛行的分布式架构系统,需要解决服务器负载、分布式服务的注册和发现、消息系统、缓存系统、分布式数据库等题目,同时解决如安在CAP(Consistency,Availability,Partition Tolerance)定理之间举行权衡的题目。
  • 数据架构:对于规模大一些的公司,数据治理是一个很告急的课题。如何对数据收集、处置处罚,提供同一的服务和标准,是数据架构需要关注的题目。其目的就是同一数据界说规范,标准化数据表达,形成有效易维护的数据资产,搭建同一的大数据处置处罚平台,形成数据利用闭环。
  • 物理架构:物理架构关注软件元件是如何放到硬件上的,包括机房搭建、网络拓扑结构、网络分流器、代理服务器、Web服务器、应用服务器、报表服务器、整合服务器、存储服务器和主机等。
  • 运维架构:负责运维系统的规划、选型、摆设上线,建立规范化的运维体系。要借助技能手段控制和优化本钱,通过工具化及流程提升运维服从,注重运营效益。订定和优化运维解决方案,包括但不限于柔性容灾、智能调治、弹性扩容与防攻击、推动及开发高效的自动化运维和管理工具、进步运维的自动化程度和服从。
4 典型的应用架构

4.1 分层架构

分层是一种常见的根据系统中的角色(职责拆分)和组织代码单元的通例实践。分层架构大概经历了以下阶段。

  • 20世纪60年代~70年代:GUI还没有出现,所有的应用程序要通过命令行利用,那时的应用程序也很简单,还不需要分层,现实上也只有一层。
  • 20世纪70年代~80年代:企业应用出现了,用户可以利用计算机通过网路访问应用,开始出现C/S两层架构模式
  • 20世纪90年代之后:互联网开始普及,随着用户的增长,以及应用复杂性和基础实行复杂性的增加,终于诞生了我们现在仍在利用的三层架构,如下图所示:

   N层应用架构图  

  • 2000年之后:2003年,Eric Evans出版了他的标志性著作《范畴驱动设计:软件核心复杂性应对之道》。从此,DDD的概念被人熟悉,以及基于DDD的一系列架构演变开始出现
可以看到,随着时间的推移,从一层到多层架构,架构的条理越来越多。不外,我们要留意另一个极度——千层面架构。这是一种分层架构的反模式,是一种过渡设计。假如在我们的系统中出现以下情况,就可能有“千层面”的嫌疑:


  • 热衷于创建完美的系统导致项目过分抽象。
  • 条理太多,增加了整个系统的复杂性。
  • 物理条理太多,不但增加了整个系统的复杂性,还降低了系统的性能。
  • 严格的分层方法导致上层必须通过中心条理访问,而不是直接访问需要的条理。
4.2 CQRS

命令查询分离(Command Query Separation,CQS)最早是Betrand Meyer(Eiffel语言之父,OCP的提出者)提出的概念,其根本头脑在于任何一个对象的方法可以分为以下两类:

  • 命令(Command):不返回任何结果(void),但会改变对象的状态。
  • 查询(Query):返回结果,但是不会改变对象的状态,对系统没有副作用。
命令查询职责分离模式(Command Query ResponsibilitySegregation,CQRS)是对CQS模式的进一步改进而成的一种简单架构模式。该模式从业务上分离修改(Command,增、删改,会对系统状态举行修改)和查询(Query,查,不会对系统状态举行修改)的举动,从而使得逻辑更加清晰,便于对不同部门举行有针对性的优化
CQRS利用分离的接口将数据查询利用(Queries)和数据修改利用(Commands)分离开来,这也意味着在查询和更新过程中利用的数据模子也是不一样的,如许读和写逻辑就隔离开了,如下图所示:

   CQRS架构  
利用了CQRS之后,我们可以或许把读模子和写模子完全分开,从而可以优化读利用和写利用。除了性能提升,CQRS还让代码库更清晰简洁,更能体现出范畴,易于维护
同样,这全部都是封装、低耦合、高内聚和单一责任原则的体现
4.3 六边形架构

六边形架构由Alistair Cockburn在2005年提出,解决了传统的分层架构所带来的题目。现实上,六边形架构也是一种分层架构,只不外不是上下,而是内部和外部,如下图所示:

   六边形架构的内外分层  六边形架构又称端口-适配器架构,这个名字更容易明白。六边形架构将系统分为内部(内部六边形)和外部,内部代表应用的业务逻辑,外部代表应用的驱动逻辑、基础设施或其他应用。内部通过端口和外部系统通讯,端口代表了一定协议,以API出现。
一个端口可能对应多个外部系统,不同的外部系统需要利用不同的适配器,适配器负责对协议举行转换。如许就使得应用程序可以或许以一致的方式被用户、程序、自动化测试、批处置处罚脚本所驱动,而且可以在与现实运行的设备和数据库相隔离的情况下举行开发和测试。
一个端口对应多个适配器,是对一类外部系统的归纳,它体现了对外部的抽象。应用通过端口为外界提供服务,这些端口需要被良好地设计和测试。内部不关心外部如何利用端口,从一开始就要假定外部利用者是可替换的
适配器的两种不同类型如图所示:

  • 左侧代表UI的适配器被称为主动适配器(Driving Adapters),因为是它们发起了对应用的一些利用。
  • 右侧表示和后端工具链接的适配器被称为被动适配器(Driven Adapters),因为它们只会对主适配器的利用做出相应。

   六边形架构的端口和适配器  两种端口-适配器的用法也有一点区别:

  • 在左侧,适配器依赖端口,该端口的详细实现会被注入适配器,这个实现包罗了用例。换句话说,端口和它的详细实现(用例)都在应用内部
  • 在右侧,适配器就是端口的详细实现,它本身将被注入我们的业务逻辑中,尽管业务逻辑只知道接口。换句话说,端口在应用内部,而它的详细实现在应用之外并包装了某个外部工具
4.4 洋葱架构

2008年,Jeffrey Palermo提出了洋葱架构(OnionArchitecture)。洋葱架构在端口和适配器架构的基础上贯彻了将范畴放在应用中心,将驱动机制(用户用例)和基础设施(ORM、搜刮引擎、第三方API等)放在外围的思绪。洋葱架构在六边形架构的基础上加入了内部条理。
洋葱架构与六边形架构有着相同的思绪,都是通过编写适配器代码将应用核心从对基础设施的关注中解放出来,避免基础设 施代码渗出到应用核心之中。如许应用利用的工具和传达机制都可以轻松地替换,在一定程度上避免技能、工具或者供应商锁定。
洋葱架构分离了基础设施和业务应用,使得我们可以方便地模拟(Mock)基础实行,对业务应用举行测试。企业应用中存在着不止两个条理,洋葱架构还在业务逻辑中加入了一些在范畴驱动设计的过程中被辨认出来的条理:


  • 应用层(Application)
  • 范畴服务(Domain Service)
  • 范畴模子(Domain Model)
  • 基础设施(Infrastructure)

   洋葱架构  在洋葱架构中,明确规定了依赖的方向。


  • 外层依赖内层
  • 内层对外层无感知
也就是说,耦合的方向是从外层指向中心的。洋葱架构提供了一个完全独立的对象模子(范畴模子),该模子位于架构的核心,不依赖其他任何条理,我们可以在不影响内层的情况下改变外层的灵活性。洋葱架构在架构层面运用了依赖倒置原则
4.5 DDD

正确地说,DDD不是架构,而是一种开发头脑。就像灵敏不是Scrum,而是一种头脑一样。之以是将DDD归类为典型架构,是因为它是我们很多架构的头脑来源。比如洋葱架构,其内层(核心业务逻辑)就应该是范畴层。固然,COLA也传承了DDD的头脑。
另外,DDD带来的最大改变是让我们得以从“数据驱动”转向“范畴驱动”,让我们知道范畴是应用的核心,其他都是技能细节,随时可以被替换。
5 COLA架构设计

复杂性治理是一个系统化工程,设计COLA的初志就是要尽统统努力在架构层面去控制软件复杂度。因此,在COLA的设计中,汲取了很多前文中先容的典型应用架构的优秀头脑。可以说,COLA是站在了巨人的肩膀上。然而又不是对前人头脑的简单结合,而是融入了很多本身的思考、判定和创新,比如扩展点设计和规范设计。
5.1 分层设计

架构分层是我们在做架构设计时主要思量的题目。架构上的不合理大多是分层不合理,没有分层或者条理太少,会导致“一锅粥”;条理太多,条理之间又有严格的限制,会导致“千层面”。因此,分层要合理,不能太少,也不能太多。
COLA的分层是一种经过改良的三层架构,主要是将传统的业务逻辑层拆分成应用层、范畴层和基础设施层。如图所示,左边是传统的分层架构,右边是COLA的分层架构。

   传统的分层架构与COLA分层架构  其中,每一层的作用范围和寄义如下:

  • 显现层(Presentation Layer):负责以Rest的格式接受Web哀求,然后将哀求路由给Application层执行,并返回视图模子(View Model),其载体通常是数据传输对象(Data Transfer Object,DTO)。
  • 应用层(Application Layer):主要负责获取输入、组装上下文、做输入校验、调用范畴层做业务处置处罚,当需要时发送消息关照。固然,条理是开放的,如有需要,应用层也可以直接访问基础实行层
  • 范畴层(Domain Layer):主要封装了核心业务逻辑,并通过范畴服务(Domain Service)和范畴对象(Entities)的函数对外部提供业务逻辑的计算和处置处罚。
  • 基础设施层(Infrastructure Layer):主要包罗数据访问通道(Tunnel)、Config和Common。这里利用Tunnel这个概念对所有的数据来源举行抽象,数据来源可以是数据库(MySQL、NoSQL)、搜刮引擎、文件系统,也可以是SOA服务等;Config负责应用的设置;Common是通用的工具类。
采用如许的分层计谋,主要是思量到“业务逻辑”是一个非常宽泛的界说,进一步分析我们会发现,“业务逻辑”可以被分层“核心业务逻辑”和“技能细节”。这正是六边形架构和洋葱架构中提倡的头脑,即只管包管内部核心范畴的独立和无依赖,而外部的技能细节可以通过接口和适配器随时更换,从而增加系统的灵活性和可测性
5.2 扩展设计

只有一个业务的简单场景对扩展性的要求并不突出,这也是扩展设计常被忽略的原因,因为我们大部门的系统都是从单一业务开始的。但是随着业务场景越来越复杂,代码中开始出现大量的if-else逻辑,此时除了通例的计谋模式以外,我们可以思量在架构层面提供同一的扩展解决方案
在扩展设计中,我们提炼出两个告急的概念,分别是业务身份扩展点
业务身份是指在系统唯一标识一个业务或者一个场景的标志。在详细实现中,我们利用BizCode来表示业务身份,采用类似Java包名命名空间的方式。例如,用“ali.tmall”表示阿里巴巴天猫业务,用“ali.tmall.car”表示阿里巴巴天猫的汽车业务,用“ali.tmall.car.aftermarket”表示阿里巴巴天猫的汽车业务的后市场场景。
扩展点的头脑源自插件模式。每个业务或者场景都可以实现一个或多个扩展点(ExtensionPoint),也就是说,一个业务身份加上一个扩展点可以唯一地确定一个扩展实现(Extension)。这个业务身份和扩展点的组合,我们称为扩展坐标(ExtensionCoordinate),如图所示。

   业务身份和扩展点  作为一个框架,COLA在此主要做了两件事情:

  • 在系统启动时,扫描注册标记有@Extension的扩展实类
  • 在系统Runtime时,根据业务身份选择对应的扩展实现举行执行
5.3 规范设计

任何事物都是规则性和随机性的组合。规范的意义在于可以将规则性的东西固化下来,只管淘汰随心所欲带来的复杂度,一致性可以降低系统复杂度。从命名到架构皆是云云,架构本身就是一种规范和约束,破坏这个约束,也就破坏了架构。
COLA订定了一系列的规范,包括组件(Module)结构、包(Package)结构、命名等。
5.3.1 组件规范

COLA规定一个应用至少要有3个组件:应用层范畴层基础实行层。假如不是严格的前后端分离,也可以加入显现层的组件,但这是可选的。组件之间的依赖关系如图所示。

   COLA的组件规范  从上面的依赖关系可以看到,范畴组件(Domain Module)是应用的核心,负责核心业务逻辑的处置处罚,不应该有任何的外部依赖
范畴组件的实现方式有两种,一种是把范畴组件设计成纯POJO,另一种是通过依赖倒置,将数据访问的接口放在范畴组件里,让基础设施组件(Infrastructure Module)去做接口实现
5.3.2 包规范

相比组件,包是更细粒度的代码组织单元。包的设计也要遵循高内聚、低耦合的原则。每个包都应该是一组功能类似的类的聚集,这种划分使得整个项目形成一个金字塔结构。这种结构化的表达在方便影象的同时,也使得整个项目结构更加清晰,有章可循。
在一个遵循COLA包规范的应用中,我们可以看到如图所示的包结构。



    COLA的包规范  5.3.3 命名规范

在COLA架构中,我们订定了一系列的命名规范,以便通过名称就能知晓该类的作用和职责范围,从而极大地提升代码的可明白性,提升代码审查(Code Review)的服从。如许假如你将不属于职责范围的代码放在某个类中,做代码审查的人很容易就能辨认出来。
规范用途解释xxxCmd.javaClient RequestCmd代表Command,表示一个用户哀求xxxCO.javaClient Object客户对象,用于传递数据,等同于DTOxxxServiceIAPI ServiceAPI接口类xxxInterceptor.javaCommand Interceptor拦截器,用于处置处罚切面逻辑xxxExtPt.javaExtension Point扩展点xxxExt.javaExtension扩展实现xxxValidator.javaValidator校验器,用于校验的类xxxConvertor.javaConvertor转化器,实现不同层级对象互转xxxAssembler.javaAssembler组装器,组装外部服务调用参数xxxE.javaEntity代表范畴实体xxxV.javaValue Object代表值对象xxxRepository.javaRepository仓储接口xxxDomainService.javaDomain Service范畴服务xxxDO.javaData Object数据对象,用于长期化xxxTunnel.javaData Tunnel数据通道,DAO是最常见的通道,也可以是其他通道xxxConstant.javaConstant class常量类xxxConfig.javaConfiguration class设置类xxxUtil.javaUtility class工具类 6 COLA架构总览

在架构头脑上,COLA主张像六边形架构那样,利用端口-适配器去解耦技能细节;主张像洋葱架构那样,以范畴为核心,并通过依赖倒置反转范畴层的依赖方向。最终形成如图所示的条理关系和依赖关系。

    COLA条理关系和依赖关系图  从COLA应用处置处罚相应一个哀求的过程来看,COLA利用了CQRS来分离命令和查询的职责,利用扩展点和元数据来提供更高应用的可扩展性,利用ColaMock来提升测试服从。我们可以得到一张如图所示的COLA纵向架构图。


    COLA架构图  7 小结

本章先容了一些典型的应用架构,如分层架构、CQRS、六边形架构、洋葱架构和DDD等。融合这些优秀的架构头脑,并对其举行建立性的改良和提升是COLA形成的基础。COLA架构是一个相对完善,比较适合解决复杂业务场景题目。因此在利用COLA时,可以根据情况选用相关功能。软件的世界里没有银弹,我们不一定要利用COLA提供的所有能力,可以根据现实情况裁剪利用COLA。
   以上内容来源于《代码精进之路:从码农到工匠》核心原理与案例分析。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

老婆出轨

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表