企业架构设计实战4 应用架构设计

Posted 禅与计算机程序设计艺术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了企业架构设计实战4 应用架构设计相关的知识,希望对你有一定的参考价值。

前言

企业IT架构包括应用架构、数据架构和技术架构,企业IT架构与业务架构共同构成了企业架构的核心内容。接下来重点介绍IT架构中的应用架构。

应用架构是对企业所有应用系统、服务及它们之间交互关系的整体描述,反映应用系统如何支撑业务运行及未来业务发展,同时需要体现应用与技术、数据之间的关系。其中我们会看看应用架构的本质、价值、设计框架、常用模式、核心策略、设计原则,并重点讨论应用架构的利器——领域驱动设计(DDD),并给出一些参考设计。

企业IT架构概述

企业IT架构承载着业务架构,并指导企业IT和具体项目的开展。业务的开展依赖IT,而IT的需求来自业务

业务架构向IT架构转化的过程

在企业IT架构设计过程中,我们需要关注IT与业务的关系,理解并转化业务方向,并进行正确的技术选型,提供IT的投资依据,结合数字化转型项目,提高企业业务和技术的核心竞争力

图例:业务架构向IT架构转化的过程

在业务架构向IT架构转化的过程中,业务架构为IT架构提供了企业业务的输入,通过对战略技术的转化,业务架构把企业的业务通过业务能力、业务流程及更细粒度的业务活动等业务需求具象化地展示出来。进而,IT架构中的应用架构承接这些需求,通过领域驱动设计等设计方法,使用领域服务构建服务化能力,并通过服务化的功能接口等,逐步构建应用系统,同时结合业务发展,构建企业的产品和解决方案。在整个过程中,数据是核心,应用架构中构建的领域模型对数据架构中的数据模型进行输入,指导数据实体等数据分布和分析,并通过技术架构的数据存储进行具体的数据管理。而应用架构产生的应用、产品、服务等内容通过技术架构提供的开发能力实施落地,比如使用微服务、云计算、云原生等应用服务开发方法,并通过技术架构中的基础设施、系统集成等完成整体技术底座的支撑和保障。

企业IT架构总体框架

企业IT架构主要包括应用架构、数据架构、技术架构,具体如下所示。

图例: 基于云原生体系的企业IT架构总体框架

  • 应用架构:涵盖应用、服务、应用组件、功能组件、服务接口等。核心是将业务架构的业务流程和服务翻译成人们可以看得懂的应用服务和服务流程,过程中涉及领域驱动设计、服务化、微服务等相关架构设计能力。此外,应用架构还包括系统、共享中心、产品、解决方案等层面的系统级抽象,这是整个IT架构的关键阶段,决定着企业为客户提供的具体的应用服务功能。

  • 数据架构:描述企业架构的数据模型、数据分布、数据资产之间的结构和关系,是IT架构的核心。数据架构与应用架构的领域模型密切相关,并与技术架构的数据存储紧密相连。数据架构通过数据标准、数据治理、管控流程和技术工具等方面进行制定,并协同业务架构、应用架构、技术架构层面的数据形成统一、完整的数据标准

  • 云原生技术架构:通过构建企业开发平台、运维平台来协助系统统一管理,并结合敏捷交付、精益管理等管理开发和运维一体化的平台,协助应用和数据等数字化项目落地。云原生体系主要涉及云原生基础设施、云原生应用平台、低代码开发平台、云原生技术组件,以及一些集成平台和安全平台的构建。


应用架构概述

应用架构是对企业所有应用系统、服务及它们之间交互关系的整体描述,反映应用系统如何支撑业务运行及未来业务发展,同时需要体现应用与技术、数据之间的关系

应用架构是业务架构、技术架构、数据架构,以及企业业务、文化、组织等的成果体现方式,核心是通过建模将业务流程和服务转化成应用系统层面的应用与服务等概念,决定了企业为客户提供的具体的应用服务功能

应用架构的本质

应用架构的本质其实是建模的过程

从现实世界到软件应用世界,是一个不断抽象、不断建模的过程,即从业务架构中抽象出业务能力和业务流程,进而对系统和应用建立模型,通过不同层面的模型设计,层层抽象,最终得到用户可以使用的系统,这个过程的本质就是建模

什么是模型(Model)?

模型指用一个较为简单的东西来代表另一个东西

比如,科学模型中的数学公式极其简单并准确地表达了某种理论的计算原理。

在架构设计中,模型本身是业务需求的映射,以需求场景为输入,需要根据业务场景来进行验证和完善;同时模型是连接业务和应用系统的桥梁,基于业务的理解,逐步展开,并产出应用中需要完成的服务、功能、接口等。另外,从落地层面,代码是模型的印证,最终模型在项目中通过具体的程序代码,把复杂的业务诉求构建成简单的模型,最终形成应用系统供用户使用。

什么是建模(Modeling)?

百度百科是这样定义的:建模就是建立模型,就是为了理解事物而对事物做出的一种抽象,是对事物的一种无歧义的书面描述

《大象:Thinking in UML》中是这样定义的:建模是指通过对客观事物建立一种抽象的方法,用以表征事物并获得对事物本身的理解,同时把这种理解概念化,并将这些逻辑概念组织起来,构成一种对所观察的对象的内部结构和工作原理便于理解的表达

建模的整个过程可大致分为业务建模和应用建模。

  • 业务建模的本质就是我们前文所讲的业务架构,通过把业务的各种信息作为输入,建立企业业务的顶层视图,核心是识别企业的业务能力和业务流程,以及各个业务活动的组成部分,思考从用户使用的业务场景视角,企业该提供什么样的业务,大致的业务分类和业务逻辑是怎样的,应如何提供这些能力等,逐步通过业务能力和业务流程将业务抽象为“一张图”。

  • 应用建模是在业务建模的基础上,完成业务需求到应用系统模型之间的映射,最终设计出可以供用户使用并能具体解决用户问题的系统。应用建模更强调职责、依赖、约束关系,用于指导研发的落地实现,所以这个过程的核心是如何抽取核心概念,合理地划分这些模型层次,模型之间的边界是怎样的,如何控制模型之间的粒度等。应用建模可以使用不同的方法,如面向对象方法、面向数据方法、面向领域设计方法等,目前领域驱动设计是最受欢迎的设计方法之一。

我们再从业务架构和应用架构之间的关系来看这个建模过程,在从业务架构中识别出业务能力和业务流程后,将基本组成部分抽象成业务活动,而这些业务活动通过应用架构中的模型和服务进行映射,在此过程中,应用架构通过领域模型和领域服务,对业务能力和业务流程进行了翻译和关联,最终设计出相关的功能,并逐步抽象成产品和解决方案。

应用架构的价值

应用架构的价值主要体现在以下几点。

  • 应用架构作为企业IT架构的核心,连接业务架构中业务能力、业务流程和业务需求,也能够连接数据架构的数据管理和使用,同时提出对技术架构和IT基础设施的要求

  • 应用架构向业务部门提供整体IT应用系统的服务和功能,确保将来的应用与业务需求一致,并保持整体架构的连贯性,对企业系统孤立、功能重复建设、灵活度差、难以共享等问题进行整合和优化。

  • 应用架构对应用系统和服务的整体功能进行统一规划,建立企业应用系统的总体视图。同时,万物皆服务,以服务为中心的应用架构可以解决企业在开发、部署、运维、集成等过程中面临的问题。

  • 应用架构区分企业共享部分与定制化部分,经过应用架构的分层设计,将通用、成熟的功能进行共享下沉,将个性化、特殊的功能开放到更前端的业务部门,便于功能的灵活扩展和业务的快速应变。

  • 应用架构为企业产品化提供支持。经过应用的能力设计和服务识别,为企业进一步优化产品和相应的解决方案提供基于架构视角的主要参考。

  • 应用架构协助团队沟通。通过维护统一、便于理解的应用视图,各业务和技术团队可以保持同频和一致,防止各部门进行重复建设。

应用架构的设计原则

应用架构有比较多的参考设计原则,包括应用设计原则、服务设计原则、服务分层原则、微服务设计原则、接口设计原则、开发设计原则等。在实践过程中,我们可以选择性地加以参考。

应用设计原则

应用设计的总体原则可以借鉴第1章中介绍的架构设计原则,即正交性、高内聚、低耦合、简单适用等。此外,在应用设计过程中,还有如下参考。

  • 边界清晰:每个应用的范围和边界要清晰,没有重叠,无重复定义的应用功能,同时应对应合理的组织。

  • 拆分和分层:在满足业务需求的情况下,多考虑应用和系统如何拆分和分层,控制粒度,将核心、稳定、可复用的业务能力进行抽象和沉淀。

  • 线性扩展:企业需要采用去中心化架构,服务尽量无状态,便于水平扩展。在设计时,还需要考虑应用和服务的扩展能力,如流程扩展、服务扩展、编排扩展、界面配置,以及开放能力和对外集成能力等。

  • 数据化运营:应用功能内部数据共享最大化,应用功能之间共享最小化。通过运营指标驱动,增强数字化运维、监控告警、限流降级、性能分析和诊断等方面的能力。

  • 异步化:互联网应用一般不苛求强一致性,而使用最终一致来平衡。在业务允许范围内,尽可能采用异步解耦,比如不同域之间异步调用,核心业务异步调用非核心业务,而同步调用的,需设置超时时间及重试机制等。

  • 自动化管控:提升自动化运维能力,如自动部署、自动弹性扩容、自动升降级、自动限流降级等,降低运营成本,提高系统的稳定性和业务连续性。

服务设计原则

应用架构是以服务为中心的,在进行服务设计时需要遵循以下原则。

  • 稳定性原则:一切以系统稳定为核心,不允许过度设计,应用架构应尽可能清晰、简单。

  • 松耦合原则:各个应用确保稳定部分与易变部分,核心业务与非核心业务、服务提供者与服务消费者、核心服务与非核心服务、应用与数据、服务与实现细节等分离。

  • 抽象化原则:确保应用抽象化、数据存储抽象化、服务计算抽象化。

  • 容错原则:通过自治、冗余、延缓等手段提高服务的容错能力,通过服务自治、服务隔离、限流降级等避免出现连锁反应,通过集群容错、避免单点、服务中心容灾等提高系统容错能力。

  • 安全性原则:采用多层安全防火设计,提高系统的故障恢复、应急响应能力,阻止来自外部的非法访问,预防黑客攻击,服务数据等安全合规,系统应具备数据备份和恢复能力等。

  • 规范统一原则:通过统一接口方式和管控手段,统一规划建设、统一标准管理,信息共享,协同合作。

  • 开放扩展原则:服务的数据交换符合行业标准,提供服务的扩展能力,包括服务流程、服务接口、应用等多层次定制化扩展能力。

  • 服务无状态原则:服务设计为可以伸缩的,并且可以部署到高可用性基础结构中,尽可能减少服务的状态,或者通过分布式存储方式来保存。

服务分层原则

服务分层对于服务设计非常重要。对服务进行分层后可以使我们讨论问题聚焦在某一层上,降低问题的复杂度。一些服务分层原则如下。

  • 高内聚、低耦合:服务分层的首要原则是高内聚、低耦合,即服务内部高度内聚,服务外部降低耦合度。在分层时,我们可以每次从不同的角度进行,通过多次优化,减少服务与服务之间的依赖。

  • 基于通用性进行分层:稳定、通用的服务向下沉淀,个性、定制化的服务向上沉淀,同时可以设计一些变化的分层来隔离变化。另外,还有其他考虑维度,如是否是非功能性服务、是否是平台类型服务、是否是重要服务等。

  • 团队规模参考:以垂直业务划分开发维护团队,澄清跨团队服务消费需求,并订立服务契约,3~8人的开发维护团队为理想规模。同时,需要架构委员会处理跨域冲突,处理有冲突的服务能力归属等跨组织的协调问题。

  • 数据访问原则:数据归属应该单一化,跨域数据读写需要尽量减少,并且严格遵循依赖原则及接口访问原则。

  • 服务依赖原则:服务分层访问,上层可调用同层或下层服务,禁止下层调用上层服务,同时要对跨层访问次数加以限制,为后续限流降级打好基础。

  • 共享服务划分原则:是否足够通用、普适,是否高度抽象,可以被不同业务进行定制和扩展;是否有业务价值,可以解决某种通用的业务问题;是否有业务数据的持续输入,架构运营的核心是数据,如果一个服务数据输入不足,则可以先不考虑共享;是否能力相对稳定,共享服务会迭代变化,但不应该变化过于频繁。

微服务设计原则

这里从应用服务设计角度介绍一些微服务设计原则。

  • 业务优先原则:当有冲突时,以业务需求为核心。

  • 顶层架构设计原则:以业务架构为设计基础,遵循顶层业务架构的设计。

  • 稳定性原则:以稳定为中心,设计得尽可能简单和清晰,不过度设计。

  • 依赖和分离原则:需要把稳定的服务部分与易变的服务部分进行分离,把核心业务微服务与非核心业务微服务分离,应用与数据分离,服务接口与实现细节分离。

  • 异步松耦合原则:不同业务域间尽量异步解耦;核心业务与非核心业务间尽量异步解耦。

  • 垂直划分优先原则:尽可能根据业务领域进行服务的垂直划分,这样更加关注业务实现,端到端负责,便于持续改进,减少调用次数。水平划分需要充分从总体考虑。

  • 持续演进原则:应逐步划分、持续演进,避免服务数量的“爆炸性”增长。当服务数量增加时,需要考虑持续交付、微服务监控与治理等环节。

  • 服务自治原则:服务需要提供SLA,保持稳定性,可以独立开发、测试、部署和运行,避免发生连锁反应。

  • 自动化驱动原则:可以结合DevOps和CI/CD等自动化工具,以及成熟的微服务治理框架,提高微服务生命周期的自动化效率。

  • 微服务拆分原则:优先拆分比较独立的服务、通用服务、边界明显的服务、核心服务。

接口设计原则

服务之间交流的契约是API,一个好的接口应该是无状态、标准且兼容的,技术上目前采用比较多的是RESTful API。下面介绍一些通用的接口设计原则。

  • 合适粒度原则:平衡可维护性与易用性。可提供普适的粗粒度业务逻辑片段,根据需求增加精细化的服务接口。

  • 强描述性原则:服务名和方法的意义明确,表意精准,服务模式明确,比如是同步还是异步。

  • 内聚完整原则:从服务消费者的角度,考察提供服务的完整性、功能的自洽性。

  • 语义接口原则:接口信息使用语义化封装,内外隔离,接口信息对象独立于服务内部的实现信息对象定义。

  • 接口普适原则:接口信息基本属性尽量使用跨语言的基本类型(字符串、日期、数值等)。

  • 扩展兼容原则:在保证易用性的前提下,尽可能考虑扩展性,避免未来频繁更改接口,同时做好版本管理。

  • 服务命名原则:自描述,易于理解,并且有意义。

  • 契约先行原则:当与其他团队交流时,双方的交流基础就是接口,要形成契约意识,对双方形成强有力的约束,并为双方提供保障。

开发设计原则

在开发过程中,一些关于设计阶段的通用参考如下所示。

  • 定义相关的技术规范:包括服务设计规范、接口设计规范、Java开发规范、产品使用规范、数据库使用规范、部署升级规范、运维规范、编程规范、日志规范、工程规范、安全规范等。

  • 应用开发原则:边界清晰、应用内数据共享;应用间依赖最小化,不存在循环依赖;应用可管理、可监控、可开发、可扩展。

  • 服务开发规范:考虑如下设计,如超时重试、快速失败、结果可预期、服务无状态、幂等性、乱序可容忍、无循环依赖。

应用架构设计框架

应用架构构建业务架构、数据架构、技术架构之间的关联关系。应用架构以企业业务架构为基础,规划整个企业所有应用系统的蓝图,将业务架构中业务流程、业务能力等落实到应用系统的具体功能和服务,并对数据架构的数据分析和管理提供诉求,对技术架构中涉及的开发平台、技术选型、基础设施、集成、安全等提出要求,指导后续架构的部署与构建。

图例:应用架构的设计框架

应用架构的设计框架主要包括以下部分。

  • 应用核心设计:对应用架构的核心内容进行设计,包括应用、领域服务、功能接口及对应的产品与解决方案等。

  • 应用系统设计:应用对应的系统能力设计,确定系统的边界、定义、接口,包括系统对应的表现层、应用层、领域层、基础设施层。

  • 应用架构管理:应用涉及的相关协同管理,包括应用共享、应用开发、应用集成等,也涉及一些技术组件。

  • 应用架构原则规范:包括服务设计原则、服务分层原则、系统集成原则等,以及相关的开发规范、设计规范、设计工具等。

  • 应用架构行业参考:包括通用的一些行业参考模型,提供企业参考、资产沉淀和复用。从以上可以看出,应用架构设计的核心是应用核心设计,而实际过程中领域驱动设计是非常重要的理论参考。

应用架构常用模式

应用架构常用模式主要有以下几种。

集中式架构

集中式架构又称单体架构,传统企业根据各个业务部门的需求,开发了多个“烟囱式”系统,这种架构模式有很多弊端,在一些传统企业中还存在。

SOA(面向服务架构)

企业采用企业服务总线(ESB)来解决多系统之间复杂的接口交互模式,也就是传统的SOA模式。而随着互联网企业的发展,采用去中心化、去IOE的分布式服务架构,不需要ESB作为中心节点,而是进行直接发现和调用,以解决中心化服务扩展难、不适合互联网大流量要求快速响应的痛点。

The Open Group的面向服务架构 (SOA) 工作组提出了一个SOA架构的参考模型,主要包括:

图例:SOA参考应用架构

SOA参考应用架构,具体包括以下几个层面。

  • 基础设施服务:由操作系统和后台的应用系统组成,能够被系统组件调用,实现IT系统服务功能,并确保服务的质量,为各层次的系统提供数据支持。

  • 服务总线::通常由ESB系统提供路由、多协议、转换等,服务在这里注册和发现,也可以通过组合形成组合服务,并且通过对服务的服务组合和编排实现业务流程。

  • 关键服务组件:由服务使用者组成,构建前台的访问应用。

  • 开发工具:提供SOA的相关开工具,如WSDL等

  • 管理工具:提供服务质量(QoS)服务,包括安全、管理和基础设施监控等。

SOA并不是推倒重建企业的系统,而是在现有的系统之上进行包装服务,建立标准结构,方便互通和调用。SOA也使得架构设计的过程从面向对象、面向组件的设计方法过渡到面向服务的设计方法,其强调以服务为中心的设计理念,接口和实现分离、服务提供和服务使用分层的设计思想。

事件驱动架构

事件驱动架构(Event Driven Architecture,EDA)以SOA为基础,以事件为单位进行各种处理。事件驱动的核心是事件,事件是历史,是事实,是已经发生的事。

图例:事件驱动架构示意

事件由事件源生成,并通过事件管理器进行发布,各种事件的订阅方根据需要进行订阅消费,可以直接处理该事件,或者即时转给其他订阅方,同时事件作为一种业务数据的载体,可以进行存储,从而在以后进行处理。

图例:事件驱动概念示意

事件驱动系统通常是异步的,事件生产者向事件管理器发布事件,如果事件消费者不可用,事件管理器将保留这个事件,之后再次转给事件消费者。

事件生产者与事件消费者相对独立且解耦,事件生产者不需要知道哪个消费者会接收消息。事件消费者彼此之间也互相解耦,每个消费者都可以接收全部或者部分消息。因此,事件驱动架构的系统更适用于包含较多未知因素的环境或者异步的环境,通过构建分布式高可用架构,提供事件生产者和事件消费者相对灵活解耦的能力。事件驱动架构适用于多种场景,比如有多个子应用且处理相同事件,需要实时处理大量数据,有复杂的事件处理等。

图例: EDA领域事件

从领域设计角度,事件驱动架构也有广泛应用,比如基于事件风暴的分析方法。其中,事件源和订阅者都是具体的领域实体,事件管理器可以作为基础设施的一部分技术组件,这个过程会借助消息中间件来进行能力提供。

微服务架构

随着互联网技术的发展,SOA技术进一步进化为以微服务为主流的分布式服务架构。微服务是一种分布式架构模式,微服务架构凭借其简单清晰、灵活可扩展、独立部署等优势,逐渐成为分布式架构的主流。微服务将大型复杂软件应用拆分成多个微小的服务,服务之间是松耦合的,每个服务描述一个小业务,可以独立地进行升级、部署、扩展和重新启动等流程,并通过接口契约、标准协议等保持彼此互通。

微服务架构由SOA演化而来,是SOA的一种特殊实现方式,突出将服务划分为更细粒度的微服务,按照业务领域划分,强调服务编排、服务治理、自动化运维,并具备高可用、性能要求、分布式事务一致等特点。

关于微服务是什么,转述Martin Flower 大神的系统阐述:

  • 微服务是一种架构风格,也是一种服务

  • 微服务的颗粒比较小,一个大型复杂软件应用由多个微服务组成,比如Netflix目前由500多个的微服务组成

  • 微服务采用UNIX设计的哲学,每种服务只做一件事,是一种松耦合的能够被独立开发和部署的无状态化服务(独立扩展、升级和可替换)。

图例:微服务架构示例

与集中式架构相比,微服务有降低系统复杂度、提高迭代效率、促进团队沟通、弹性扩展、容错能力、独立部署、可扩展性、跨语言编程等很多优点,这里挑选几个进行说明。

  • 提高迭代效率:支持细粒度的独立迭代和发布,速度快。由于微服务架构中的每个小型服务是独立部署的,可以单个服务进行缺陷修复或者特性变更,无须重新部署整个应用程序,一旦发现缺陷,就立刻回滚服务。

  • 促进团队沟通:单个小型服务仅需要一个小的开发团队就可以完成开发、测试和部署工作。相比之下,更大的团队通常意味着更低的沟通效率、更高的管理开销。

  • 容错能力:当系统出现问题时,将仅影响单个小型服务,不一定导致整个应用程序中断;同时对应的数据也将会进行隔离,风险明显降低。

  • 可扩展性:每个小型服务都支持独立水平扩展,无须扩展整个应用程序,资源的利用率高,扩展快速。每个小型服务都可以独立进行服务升级,并且结合持续集成工具可以进行持续发布,快速完成服务升级和发布流程。

微服务架构有很多好处,不过也存在以下一些挑战。

  • 设计的复杂性:与传统架构的应用程序相比,微服务架构的组件更多。服务数量多意味着部署和管理的工作量更大,还需要考虑分布式系统的复杂性和分布式事务的处理难度。

  • 开发、测试、部署难度:当服务拆分后,几乎所有功能都会涉及多个服务,所依赖的其他独立服务增多,此时处理好服务间的依赖关系成为关键。原本单个程序的测试会变为服务间调用的测试。测试变得更加复杂。

  • 运维难度:由于可能采用不同的语言和框架,应用程序可能变得难以维护。整个应用分散成多个小型服务,这导致问题定位更加困难,同时可能增加服务间的通信量。

  • 数据一致性:每个小型服务都仅负责各自相关的数据持久性,因此不同服务间的数据一致性很难达到。

云原生架构

分布式架构的出现是为了解决应用难以开发和维护的问题。

  • 垂直拆分:把按业务领域拆分为多个松耦合的独立应用,各自独立部署和维护。

  • 水平拆分:把通用的、共性的应用进行分层沉淀,形成共享的服务能力,这样可以对性能稳定性等问题进行统一处理和优化,防止重复开发。

如今,架构朝着越来越轻量化、能力越来越下沉、应用越来越灵活的方向发展,到云原生时代达到了新的高度。

云原生将云应用中的非业务代码进行最大化的剥离,关注点分离,让云来负责原有的大量非功能特性需求,如可靠性、扩展性、可观测性、弹性、轻量、敏捷、自动化等

同时,有很多企业也在尝试“双IT架构”,即以云原生架构来应对敏态业务的快速变化,以及传统的基于ESB方式的架构应对稳态内部系统的管理,二者相互结合并互补。

应用架构核心策略

应用架构的核心是将应用的领域和服务进行分层划分,其中主要应解决的问题是如何制定边界,划分的粒度怎样定义,怎样对应用架构进行分层。这里我们先讨论一些核心策略。

应用架构边界策略

针对应用架构的边界问题,有以下策略参考。

  • 高内聚:采取统一的概念和定义,在内部的修改不会影响到其他应用,内部功能在总体上保持一致,有助于隔离和管理。

  • 单一职责:各应用服务的功能单一,有助于控制范围边界,保证职责的一致和完整;各应用服务可自治,如可独立部署、升级、自我恢复等。

  • 制定限界上下文:各部分相关行为控制在一个显示边界的范围内,深刻理解业务场景,挖掘业务知识,识别合理的上下文,才能合理定义服务边界。

  • 避免循环依赖及双向依赖:业务组件之间的依赖是分层和单项的,循环或者双向会导致职责不清晰。

  • 避免采用技术边界来划分应用服务边界:比如通过UI层、逻辑层、存储层等,这是技术角度的划分方法,不适合以业务为核心的应用划分。

  • 避免与微服务、云原生技术体系的技术细节相关联:这样容易把简单业务问题复杂化。此外,避免引入过多的IT概念,如云计算平台、技术组件、编程语言、软件框架等。

  • 避免与数据共享和通信模式相结合:数据共享涉及单一数据和分布式数据,而与通信模式相结合会涉及传输过程状态、网络状态等。

  • 跳出“部门墙”思考:避免受限于组织结构,如系统、需求、分析、开发、运维团队等。

应用架构粒度策略

应用架构的粒度粗细需要适度,不宜过粗或过细,应该在满足业务需要、应用场景、管理幅度、扩展方式等多个因素要求的基础上,保持应用和服务的规模。针对应用架构的粒度问题,有以下策略参考。

  • 确定粒度的依据:比如功能、职责、组织、需要的资源等,以及可独立部署性、灵活性和可扩展性。

  • 粒度确认规则:按照职责划分大小,如果是微服务角度,有时也可以以代码量工程为参考,提高开发效率,降低代码风险。

  • 组织跨越原则:建立一个不需要频繁跨越服务和组织边界就可进行修改的应用服务。

  • 功能单一且完整原则:功能的原子性,有回滚或重试能力;同时是完整的,如果再继续细分,就会失去业务意义。

  • 粒度复杂性可控:可以演化、版本化的接口契约,并尽可能使用异步方式来解耦业务。

应用架构分层参考

结合边界和粒度的思考,应用架构可以从多种角度进行分层,下面给出一些通用的参考。从企业要服务对象的粒度角度,可以有如下分层。

  • 企业级服务:企业对外(如与合作伙伴、供应商或者开放平台)提供的服务能力,通过标准协议进行对接。

  • 应用级服务:将业务通过应用服务的形式对外暴露,将企业核心的业务逻辑封装在应用、产品、解决方案中,对外提供能力。

  • 流程服务:把多个服务聚合成一个服务流程并对外提供,可以通过流程引擎或者更友好的流程编排界面来提供。

  • 数据服务:基于数据相关的服务,比如多系统的服务集成、多数据源的数据聚合,实现数据的共享。

  • 服务:提供有价值的、可重复运行的、规范标准的服务活动组件,尽量无状态、可复用、松耦合、可治理。

  • 微服务:更细粒度的服务形态,通过微服务构建的服务,可独立开发、部署和维护,并通过标准接口进行交互。

从应用中服务用途角度,可以有如下分层。

  • 应用层:应用系统,由应用组件组成。

  • 应用组件服务层:应用级别的组件服务。

  • 共享服务层:应用级别共享服务内容。

  • 基础服务层:核心共用的底层服务内容。

  • 规则服务层:用于流程规则配置的服务。

  • 资源服务层:基础资源,如主数据服务模型。

从用户访问层次角度,可以有如下分层。

  • 表现层:对外展示,包括前台页面和各种用户端触点。

  • 应用层:应用系统,由服务层服务组成。

  • 服务层:服务组件,服务化的基本单元。

  • 基础设施层:包括基础设施资源配置,如数据库连接等。

  • 集成层:与外界集成,如企业服务总线。

领域驱动设计

在应用架构的设计中,领域驱动设计(Domain Driven DesignDDD)占据着非常重要的位置,可以说DDD是应用架构设计的核心。

DDD为我们提供了一种架构设计方法,既面向业务,又面向技术,从业务需求到领域建模,从领域服务到技术转化,强调开发人员与领域专家协同。DDD是埃里克·埃文斯(Eric Evans)在2003年出版的《领域驱动设计:软件核心复杂性应对之道》(Domain Driven Design: Tackling Complexity in the Heart of Software)一书中提出的具有划时代意义的重要概念,不过这种领域建模和设计的思想其实早在20世纪就有很多设计人员重视起来。DDD通过统一语言、领域模型、领域划分和服务划分等一系列手段来降低软件复杂度。

DDD的核心思想是业务与技术相结合的一种过程,既强调业务的理解,又强调应用领域建模方法的使用。DDD本质上是面向对象分析的扩展和延伸,它基于面向对象分析技术进行了分层规划,同时对其中的核心概念和划分做了详细的指引。

DDD的价值

DDD对应用架构设计有非常大的指导作用,具体如下所示。

  • 统一语言:团队成员会在有界的上下文中有意识地形成统一语言,便于沟通,减少分歧,以一种所有干系人都能理解的通用语言为相互交流的工具,在交流的过程中形成领域概念,然后将这些概念设计成领域模型。

  • 业务知识沉淀:DDD不以人为中心,而以业务为中心,通过承接业务架构的业务流程和业务能力,并且通过领域知识进行转化,进而反哺业务架构和应用架构。

  • 边界清晰的应用服务划分:用领域模型划分边界来界定哪些需求是合理的,一些需求应该在什么地方实现,不断拉齐团队成员对需求的认知,让设计更加清晰和规范,分而治之,控制规模。

  • 关注点分离领域模型与数据模型分离,业务复杂度与技术复杂度分离,保持结构清晰,以应对不可预测性挑战。

  • 团队协同业务人员和设计人员共同参与,这样有助于创建大家都能理解的通用模型,并用该模型来沟通业务需求、数据实体和过程模型。

  • 模型可扩展:很好地对业务需求进行了到领域服务的转化,同时是微服务及项目落地开发的纽带,领域模型是可扩展且易维护的,也提高了相应的可重用性和可测试性。

当然DDD也不是万能的,在采用DDD之前,我们需要考虑是否真正需要,思考以下几个问题可以帮助我们做出判断。

  • 是否以数据为中心,所有操作都是数据库CRUD?

  • 业务逻辑是否只是少量的业务场景和用例?

  • 应用功能是否稳定?

  • 是否已经对业务领域足够了解?

如果以上问题的答案基本都是“”,说明系统并没有复杂的业务逻辑,则可以用一般的面向数据的架构或者事务脚本等模式。但如果业务逻辑复杂、变化频繁、团队对该领域还缺乏一定的认知,需要进行领域模型和服务的梳理,那么DDD会帮助我们抽象和解决问题。

DDD的设计理念

DDD大体的分析过程中,其中比较关键的几个切入点是通用语言、领域、限界上下文。

图例:DDD分析过程

通用语言(Ubiquitous Language)

业务人员和技术人员在协作过程中,如何讲同一种语言?在DDD中用通用语言来解决。通用语言是理解业务需求和梳理领域知识的过程,也是团队中各个角色就系统目标、范围与具体功能达成一致的过程。通用语言可以定义公共术语,减少概念混淆,消除歧义和理解偏差,提升需求和知识消化的效率,达到概念和代码的统一,使得虚拟概念和具体实现一致。

通用语言可能由团队所有相关角色参加,如业务代表、产品经理、业务架构师、技术架构师、开发人员。同时,领域专家也非常关键,领域专家需要对业务领域非常了解,或者能够跟领域专业人员学习到足够的领域知识。

通用语言建立的过程并不容易,因为技术人员和领域专家在沟通过程中存在“天然屏障”:

  • 技术人员考虑的是类、方法、算法、继承、封装、代码等

  • 领域专家考虑的是订单流程、库存状态、商品类目等

因此,在建立领域知识的时候,双方必须交换知识,彼此深度参与,才可能得出领域模型。知识的范围涉及领域模型的各个元素,如果一方感到困惑,那么应该立刻换一种方式,直到双方能够理解一致。

领域(Domain)

领域是用于确定范围和边界的,DDD将业务上的问题限定归属在特定的边界内,而这些边界就可以叫作领域。为了降低业务理解和系统实现的复杂度,DDD会将领域进一步划分为更细粒度,也就是子域。子域根据自身的重要程度和功能属性又可以划分为三类子域。

  • 核心域决定应用和系统核心竞争力,它是决定业务是否成功的主要因素,比如电商系统中关注的会员、商品、订单、交易、库存、营销等。

  • 通用域没有太多个性化的诉求,同时被多个子域使用的通用功能子域是通用域,比如统一的认证和权限管理系统。

  • 支撑域既不包含核心竞争力的功能,又不包含通用功能的子域,但该功能子域又是必需的,也就是支撑域,比如某个特定领域的数据字典。

图例:DDD子域结构示例

领域中的核心是领域模型(Domain Model),领域模型具备自己的属性行为状态,并与现实世界的业务对象相映射,领域模型之间具备明确的职责划分,领域对象元素之间通过聚合和引用来关联相应的业务规则,同时反映通用语言中的领域知识

领域模型通过提炼领域对象,定义领域对象之间的关系、属性和行为,属于DDD的核心产物

限界上下文(Bounded Context)

领域帮助我们对系统进行拆分,而限界上下文帮助回答各领域之间的边界及它们如何交互。

DDD中有一个形象的比喻,“细胞之所以会存在,是因为细胞膜定义了什么在细胞内、什么在细胞外,并且确定了什么物质可以通过细胞膜”。

这个“细胞膜”就是对限界上下文很形象的举例。

再举个例子,我们在平时的人际沟通中,为了避免同样的词语产生歧义,我们会把这个词语带入语言上下文中去理解其语义。比如,当谈到“苹果”时,有的人可能想到平时吃的水果,而有的人可能想到苹果手机。 图例:DDD领域与限界上下文

限界上下文是一个显式的边界,领域模型便存在于这个边界之内,通用语言必须限制在这个限界上下文之中。在微服务设计中,一般一个限界上下文理论上就可以设计为一个微服务。限界上下文对应用的边界交互有重要作用,可以帮助我们保持模型的一致性,避免边界之外问题的混淆。这一点很重要,因为在大多数组织中,某些术语在不同的业务领域或团队中有不同的含义。

在限界上下文中,通过上下文映射图(Context Map)确立上下文之间的关系,通过上下游来表达依赖,最后形成限界上下文如何在应用程序中相互配合的全局视图。上下文的交互方法有多种,在实际工作中,目前使用比较广的是防腐层和统一协议。

  • 已发布的语言(Published Language):两个上下文使用共同的语言,比如SOA服务总线定义了一堆XML模型,或者基于共享的文件或数据库,上下文可以基于此进行直接交互。

  • 开放主机服务(Open Host):又叫统一协议,为上下文之间的服务定义一套包含标准化数据结构在内的协议,比如基于HTTP风格的RESTful接口协议。

  • 共享内核(Shared Kernel):两个上下文使用一个共同的代码内核作为通用语言,比如两个工程使用同一个Bean基础模型库。

  • 客户/供应商(Customer/Supplier):一个上下文使用另一个上下文的服务,有显著的上下游依赖关系,比如基于RPC的服务交互方式。

  • 顺从者(Conformist):一个上下文使用另一个上下文的服务,但彼此之间的关系并不紧密,比如基于消息传递机制的交互模式。

  • 防腐层(Anti-Corruption Layer,ACL):使用一层适配层来协助上下文的交互,隔离业务逻辑,比如在商品子域和采购子域之间提供防腐层,将商品的变更进行收口,隔离子域内的后端业务实现。

这里先就领域和限界上下文举一个简单的例子,此处举一个关于购物车订单支付下单的例子。

图例:DDD领域与界限上下文示例

购物车进行在线的支付授权,订单处理下单过程,并触发支付域的付款结算。

这里我们简化整个建模的过程,假设已经抽象出购物车域、支付域、订单域(通常购物车域也可以被包含在订单域内),核心的CartPaymentOrder

领域之间通过限界上下文进行交互,因为购物车域和支付域密切相关,需要等待支付授权,我们通过ACL进行关联;而订单下单和付款动作相对解耦,通过领域事件在订单已下单后,触发支付域的付款动作。

DDD的核心概念

DDD在构建领域模型的过程中,涉及比较多的概念。这里着重解读一下以下几个。 

图例:DDD的核心概念

实体(Entity)

实体是一个具有唯一身份标识的对象,并且可以在相当长的一段时间内持续变化

我们可以对实体进行多次修改,一个实体对象可能和它先前的对象大不相同,但拥有相同的身份标识,即依然是同一个实体

对实体而言,重要的不是其属性,而是其延续性和身份标识。一般实体的唯一标识有两种生成方式。

  1. 应用可以自动为实体生成唯一标识,比如JDK自带的UUID、数据库的自增序列

  2. 有时也需要综合业务语义来考虑,比如通过业务属性、时间、IP等因素生成

另外,实体具有可变性,这里需要引出两个概念:

  • 贫血模型:贫血模型与Bean或者DO对象类似,一般只有Getter和Setter方法,只作为保存状态或者传递状态,不包含业务逻辑,这种只有数据没有行为的对象不是真正的领域对象

  • 充血模型DDD中的实体属于充血模型,会封装包含这个实体相关的所有业务逻辑,它既是多个业务属性的载体,又是操作或行为的载体。

以订单(Order)为例,Order有下单、发货和退单等行为而面向数据设计方式是将这些行为放到另一个服务OrderService中,而不是Order对象中

值对象(Value Object)

值对象是只关心属性的对象,并且是一个没有标识符的对象

值对象本质上是一个集合,这个集合中包含若干用于描述目的、具有整体概念和不可修改的属性。它可以避免属性零碎,使属性归类更加清晰,从概念理解上也更加完整。

值对象在领域模型中是可以被共享的,它们应该是不可变的,当有其他地方需要用到值对象时,可以将它的副本作为参数传递。

值对象与实体的区别在于:

  • 值对象一般依附于实体而存在,是实体属性的一部分

  • 值对象没有唯一标识,当任何属性发生变化时,都意味着新的值对象产生。

  • 值对象功能单一,一般是贫血模型。

以Order为例,订单下的送货地址(Address)就是典型的值对象。Address并不随着Order的产生而产生,它相对不变,也不需要单独标识

领域服务(Domain Service)

领域中的一些概念不太适合建模为对象,它们本质上是一些操作、一些动作,代表领域中一个重要的行为。这些操作或动作往往涉及多个领域对象,并且需要协调这些领域对象共同完成这个操作或动作,这就是领域服务。

领域服务有一个重要的功能就是可以避免领域逻辑泄露到应用层。如果没有领域服务,那么应用层会直接调用领域对象完成本该领域服务执行的操作。

领域服务体现的行为一定是不属于任何实体和值对象的,但它属于领域模型的范畴,同时领域服务应该是无状态的,应确保领域服务和通用语言是一致的

  • 领域服务是无状态

  • 领域对象是有状态

虽然服务本身也是对象,但它没有属性,只有行为,因此说它是无状态的。

以订单发货(OrderDelivery)为例,需要Order和履约两种实体之间通过一定的业务逻辑,确保事务可以作为领域服务

聚合(Aggregate)

聚合的核心思想是将关联减至最少,这样有助于简化对象之间的遍历,使用一个抽象来封装模型中的引用

聚合由两部分组成:

  • 一部分称为根实体,是聚合中的特定实体。根实体是聚合中所包含的一个特定实体,是唯一允许外部对象保持对它的引用的元素。

  • 另一部分描述一个边界,定义聚合内部有什么。边界内部的对象之间可以互相引用。

除根实体外的其他对象都有本地标识,但这些标识只有在聚合内部才需要加以区分,因为外部对象除根实体外看不到其他对象

聚合行为被视为一个整体,在每个行为完成时,必须满足聚合内部所应用的固定规则的要求,即保证数据变化的一致性

根实体最终检查固定规则,如删除操作必须一次删除聚合边界之内的所有对象

过程中有一些最佳实践,比如可以设计一些小的聚合,通过唯一标识引用其他聚合,并且在边界之外考虑最终的一致性。

比如,订单域可能有很多实体,如Order、子订单、订单明细、地址、物流信息、支付信息等,而在我们将它们聚合为订单域后,这些实体都聚焦在一起,并由Order这个实体作为聚合根对外交互

工厂(Factory)

当创建一个对象或创建整个聚合时,如果创建工作很复杂,或者暴露了过多的内部结构,则可以使用工厂来进行封装。也就是说,将创建复杂对象的实例和聚合的职责转移到一个单独的对象,这个对象本身在领域模型中可能没有职责,但它也是领域设计中的一部分

设计模式中的工厂类和工厂方法与领域模型中的工厂概念是相似的,其可以帮助我们封装复杂的对象创建过程。

我们可以把工厂作为一种创建复杂对象和聚合的实现方式。工厂用来封装对象创建所必需的知识,它们对创建聚合很有帮助。当聚合的根建立时,所有聚合包含的对象将随之建立。

资源库(Repository)

在DDD中,资源库作为对象的提供方,能够实现对象的持久化,解耦领域内业务逻辑与底层持久化

每个聚合类型可以对应一个资源库,过程中需要避免实体和值对象成为单纯的充血模型,我们需要资源库把ORM框架与领域模型隔离,以屏蔽数据访问的技术复杂度。资源库可以获取持久化对象,使应用程序和领域设计与持久化技术解耦,让我们始终聚焦于模型,并且将所有对象的存储和访问操作交给资源库来完成。在面向接口和依赖注入机制支持下,资源库也容易通过Mock等方式进行测试。

图例:DDD中资源库模式

工厂和资源库之间存在一定的关系,它们都能帮助我们管理领域对象的生命周期。然而,工厂关注的是对象的创建,而资源库关心的是已经存在的对象

当一个新对象被添加到资源库时,它应该是先由工厂创建过的,再被传递到资源库,以便更好地保存它。

另外,资源库和数据访问对象(Data Access ObjectDAO)的作用类似,但也有所不同,资源库以“领域”为中心,所描述的是“领域语言”,不涉及数据库实现的细节;而DAO是比资源库更低的一层,其包含如何从数据库中提取数据的代码

领域事件(Domain Event)

领域事件表示领域中所发生的重要事件,在事件发生后通常会导致进一步的业务操作,或者在系统其他地方引起反应

领域事件非常重要,我们在系统设计过程中经常需要解耦,技术人员一般通过MQ方式进行;架构人员可能采用事件驱动架构(Event Driven ArchitectureEDA)的方式。Serverless架构中核心的就是基于事件编程,这一切的核心就是对领域事件的设计,不过当前大部分系统事件(Event)设计比较随性,从而导致Event滥用和无用情况发生,而领域事件是对我们很好的指引。

比如,在订单的例子中,在订单下单后,会进行库存冻结、支付状态更新、物流同步等,这些都是对系统事件良好的解耦设计。

  • Event命名Domain Name + 动词的过去式 + Event,如OrderCreatedEvent

  • Event内容EnrichmentPayload中放Data),Query-Back(通过回调拿到更多的Data)。

  • Event管理:通过MQ等保存所有的Events,并提供良好的Event查询和回溯。

  • Event处理:事件构建和发布、事件数据持久化、事件总线、消息中间件、事件接收和处理等。

小结

图例:DDD核心概念总结

图例:DDD核心概念职责与关系

DDD常用的分析方法

DDD常用的分析方法主要有用例分析法四色建模法事件风暴法

用例分析法

用例分析是比较通用的领域建模方法,可以在比较传统的需求调研过程中结合领域模型的设计思路进行,核心是通过业务需求、场景流程等梳理用例,进而规划领域模型

用例分析的前提是业务架构的需求输入,其中核心是业务能力与业务流程

比如电商领域的

以上是关于企业架构设计实战4 应用架构设计的主要内容,如果未能解决你的问题,请参考以下文章

5.业务架构·应用架构·数据架构实战 --- 业务驱动的数据架构设计

3.业务架构·应用架构·数据架构实战 --- 战略驱动的业务架构设计

大数据项目之电商数仓数据仓库概念项目需求及架构设计

java架构师(实战篇)

企业架构设计实战0 企业数字化转型和升级:架构设计方法与实践

大数据实战精英+架构师班 ④ 期