做菠菜网站有没有被骗的,dede网站改成自适应,智慧团建登录网站入口,儿童 html网站模板领域驱动设计(Domain-Driven-Design)是一种针对大型复杂系统的领域建模与分析方法论。2003 年#xff0c;Eric Evans 发布《Domain-Driven Design: Tackling Complexity in the Heart of Software》(领域驱动设计#xff1a;软件核心复杂性应对之道)#xff0c;其中定义了DD…领域驱动设计(Domain-Driven-Design)是一种针对大型复杂系统的领域建模与分析方法论。2003 年Eric Evans 发布《Domain-Driven Design: Tackling Complexity in the Heart of Software》(领域驱动设计软件核心复杂性应对之道)其中定义了DDD。DDD改变了传统软件开发针对数据库进行的建模方法DDD先对业务领域进行分析建立领域模型根据领域模型驱动代码设计。合理运用面向对象的高内聚低耦合设计要素降低整个系统的业务复杂性并使得系统具有更好的扩展性更好的应对多变的业务需求。领域 Domain一个领域就是一个问题域只要是同一个领域那问题域就相同。只要确定了系统所属的领域那么这个系统的核心业务即要解决的问题以及问题的边界就基本确定了。举例陌生人社交领域包含有聊天用户推荐朋友圈等核心环节。 只要是这个领域一般都会有这些相同的核心业务因为他们要解决问题的本质是一样的就是交友。每一个领域都有一个对应的领域模型领域模型能够很好的帮我们解决复杂的业务问题。驱动设计在DDD中以领域(domain)为边界分析领域的核心问题再设计对应的领域模型最后通过领域模型驱动代码设计的实现。这样设计的系统才有合理的分层与解耦对以后业务的迭代开发代码的维护才更加容易。然而很多互联网公司为了追求快速的上线都是模型都没有想清楚就开始写代码这就导致了后续代码维护困难无法扩展。修改bug同时又引入新的bug反反复复进入恶性循环。当然这跟梳理清楚领域模型需要一定时间这与初创型的互联网公司需求快速上线有点相悖但是这点时间的投入是非常值得的。因为可以避免了系统上线后不久又得重构的问题。概念总结领域就是问题域模型驱动的思想通过建立领域模型来解决领域中的核心问题领域建模的目标针对我们在领域中核心问题而不是整个领域中的所有问题领域模型设计设计时应考虑一定的抽象性、通用性以及复用价值代码实现通过领域模型驱动代码的实现确保代码让领域模型落地代码最终能解决问题为什么需要DDD系统复杂性耦合随着产品不断的迭代业务逻辑变得越来越复杂系统也越来越庞大。模块彼此互相关联、耦合。导致增加或修改一个功能变得异常艰难同时功能间的界限也变得模糊职责不再清晰。这个时候就需要进行重构拆分。虽然架构本身是随着业务进行不断演进的但是如果架构初始设计不体现出业务的模型那么新需求就无法体现在现有架构上导致不断腐化不断重构。内聚贫血模型 Anemic Domain Objectdomain object仅用作数据载体而没有行为和动作的领域对象。指领域对象里只有get和set方法没有相关领域对象的业务逻辑。业务逻辑放在业务层。充血模型 Rich Domain Object将业务逻辑和对象存储放在domain object里面业务层只是简单进行小部分业务的封装及其他domain的编排。面向对象设计符合单一职责设计。贫血 vs 充血贫血模型的domain object很轻量这导致业务层的复杂domain object相关的业务逻辑散布在各个业务层造成业务逻辑的冗余以及原本domain object的定义就变得相对模糊这就是贫血症引起的失忆症。而采用领域开发的方式将数据和行为封装在一起与业务对象相映射领域对象职责清晰将相关业务聚合到领域对象内部。微服务DDD 的本质是一种软件设计方法论而微服务架构是具体的实现方式。微服务架构并没有定义对复杂系统进行分解的具体方法论而 DDD 正好就是解决方案。微服务架构强调从业务维度来分治系统的复杂度而DDD也是同样的着重业务视角。DDD能带来什么建立通用语言 围绕领域模型建立的一种语言团队所有成员都使用这种语言进行沟通和活动驱动代码设计领域建立模型模型指导设计设计产出代码解决核心问题模型的设计中心就是核心域就是解决核心的问题DDD建模战略设计战略设计就是从宏观角度对领域进行建模。划分出业务的边界组织架构系统架构。DDD中对系统的划分是基于领域的也是基于业务的。通用语言Ubiquitous Language通用语言是指确定统一的领域术语提高开发人员与领域专家之间的沟通效率。一旦确定了统一语言无论是与领域专家的讨论还是最终的实现代码都可以通过使用相同的术语清晰准确地定义领域知识。当确认整个团队统一的语言后就可以开始进行领域建模。领域和子域领域Domain一个领域本质上可以理解为就是一个问题域。只要我们确定了系统所属的领域那这个系统的核心业务即要解决的关键问题、问题的范围边界就基本确定了。举例社交领域关键问题是用户推荐聊天电商领域关键问题是购物订单物流子域Subdomain如果一个领域过于复杂涉及到的领域概念、业务规则、交互流程太多导致没办法直接针对这个大的领域进行领域建模。这时就需要将领域进行拆分本质上就是把大问题拆分为小问题把一个大的领域划分为了多个小的领域(子域)那最关键的就是要理清每个子域的边界子域可以根据自身重要性和功能属性划分为三类子域核心域公司核心产品和业务的领域支撑子域不包含决定产品和公司核心竞争力的功能也不包含通用功能的子域通用子域被多个子域使用的通用功能子域每个领域的划分都不一样。对相同领域公司而言其核心支撑通用的子域也可能有不一样的地方但大体上基本都是一样的。举例社交领域的划分核心域用户推荐聊天支撑子域客服反垃圾通用子域消息推送限界上下文Bounded Context限界上下文限界指划分边界上下文对应一个聚合限界上下文可以理解为业务的边界。一个子域对应一个或多个限界上下文。如果对应多个上下文则可以考虑子域是否要再进行细粒度的拆分。限界上下文的目的是为了更加明确领域模型的职责和范围划分限界上下文三个原则概念相同含义不同(通用语言)如果一个模型在一个上下文里面有歧义那有歧义的地方就是边界所在应该把它们拆到不同的限界上下文中。外部系统有时候系统需要同外部系统交互这时可以把与外部系统交互的那部分拆分出去以实现更好的扩展性。这样一旦外部系统发生了变化就不会影响到我们的核心业务逻辑。组织扩展尽量不要两个团队一起在一个限界上下文里面开发因为这样可能会存在沟通不顺畅、集成困难等问题。组织架构康威定律任何组织在设计一套系统时所交付的设计方案在结构上都与该组织的沟通结构保持一致。团队结构就是组织结构限界上下文就是系统的业务结构。所以团队结构应该尽量和限界上下文保持一致。举例社交领域中订单子域对应订单上下文上下文映射从宏观上看每个上下文之间的关系可以更好理解各个上下文之间的依赖关系。梳理清楚上下文之间的关系是为了任务更好拆分一个开发人员可以全身心的投入到相关的一个单独的上下文中沟通更加顺畅一个上下文可以明确自己对其他上下文的依赖关系从而使得团队内开发直接更好的对接每个团队在它的上下文中能够更加明确自己领域内的概念因为上下文是领域的解系统举例聊天上下文依赖消息推送推广上下文也依赖消息推送战术建模战术建模是从微观角度对上下文进行建模。梳理清楚聚合根实体值对象领域服务领域事件资源库等。实体Entity当一个对象可以由标识进行区分时这种对象称为实体和数据库中的实体是不同的这里的实体是从业务角度进行划分的。实体具有唯一标识持久化可变举例社交中的用户即为实体可以通过用户唯一的id进行区分。值对象value object当一个对象用于对事物进行描述而没有唯一标识时它被称作值对象。在实践中需要保证值对象创建后就不能被修改即不允许外部再修改其属性。例如年龄聊天表情符号( :stuck_out_tongue:: 吐舌 (U1F61B))习惯了使用数据库的数据建模后很容易将所有对象看作实体聚合根Aggregate Root聚合是一组相关对象的集合作为一个整体被外界访问聚合根是这个聚合的根节点。聚合由根实体值对象和实体组成。(聚合根里面有多少个实体由领域建模决定)外部对象需要访问聚合内的实体时只能通过聚合根进行访问而不能直接访问举例一个订单是一个聚合根订单购买的商品是实体收货地址是值对象。领域服务Domain Service领域服务一些既不是实体也不是值对象的范畴的领域行为或操作可以放到领域服务中。用来处理业务逻辑协调领域对象来完成相关业务。例如有些业务逻辑不适合放到领域对象中或实体之间的业务协调这些业务逻辑都可以放到领域服务中。特征与领域相关的操作如执行一个业务操作过程但它又并不适合放入实体与值对象中操作是无状态的对领域对象进行转换或以多个领域对象作为输入进行计算结果产生一个值对象当采用微服务架构风格一切领域逻辑的对外暴露均需要通过领域服务来进行。如原本由聚合根暴露的业务逻辑也需要依托于领域服务。举例必须通过订单领域服务来创建和访问订单领域事件领域事件是对领域内发生的活动进行的建模。捕获一些有价值的领域活动事件。作用解耦可以通过发布订阅模式发布领域事件一致性通过领域事件来达到最终一致性事件溯源举例发送聊天消息这属于一个领域事件撤回消息也属于一个领域事件。推送服务订阅消息事件然后将消息推送给用户端。这样就解耦了消息服务与推送服务之间的强依赖关系。资源库Repository资源库用于保存和获取聚合对象。领域模型 vs 数据模型资源库介于领域模型(业务模型)和数据模型(数据库)之间主要用于聚合对象的持久化和检索。资源库隔离了领域模型和数据模型以便上层只需要关注于领域模型而不需要考虑如何进行持久化。分层架构把一系列相同的对象进行分类放在同一层然后根据他们之间的依赖关系再确定上下层次关系。在实际决策时我们需要知道各层的职责、意义以及相应的场景落实到代码层面时我们还需要知道各层所包含的具体内容、各层的一些常见的具体策略/模式、层次之间的交互/依赖关系。DDD经典分层架构用户接口层(interfaces)处理显示和用户请求以及一些基本的参数检查不包括业务逻辑应用层(application)主要协调领域对象的操作处理持久化事务、发送消息、安全认证等领域层(domain)处理核心业务逻辑不包括技术实现细节。领域层是业务软件的核心基础设施层(infrastructure)处理纯技术细节为其他层提供技术支撑也可用于封装调用的外部系统细节。例如持久化的实现消息中间件的实现工具类rpc等个人理解这种分层既可以在一个单体应用中也可以是微服务的形式。DDD分层并不一定要按微服务的服务粒度进行分层。如果一个业务逻辑非常简单的子域则可以将几层都放进一个单体应用中在应用中进行分层。如果业务较为复杂则可以按服务进行拆分每层都有自己对应的服务。其他架构对称性架构洋葱架构整洁架构CQRS架构DDD工程实践以一个简化的社交领域的例子来实践DDD。核心概念用户(User) 一个账户并以用户id识别关系(Relationship)用户之间的关系动态(Feed) 用户发布文字图片视频评论等内容会话(Conversation)用户之间的聊天会话领域设计战略建模领域就是社交领域核心问题和绝大部分社交系统一样。子域核心域聊天动态支撑子域反作弊推广通用子域用户关系消息推送上下文消息上下文会话上下文动态上下文推送上下文用户上下文战术建模以会话上下文为例子来进行战术建模会话上下文会话聚合根用户实体用户实体消息列表实体发送人实体接收人实体消息内容值对象消息在会话上下文属于实体在消息上下文属于聚合根。结构以会话子域为例架构分层interfaces 接口层RESTfulRPCapplication 应用层ConversationMessagedomain_service 领域服务层modelConversationMessagerepositoryConversationMessageinfrastructure 基础设施层storeConversationRepositoryMessageRepositorymessageSendMessageutils领域package domain// 聚合根type Conversation struct { ID int User1 User User2 User Messages list.List}// 实体type Message struct { ID int From User // 实体 To User Body Content // 值对象}用户接口层type ChatInferface struct { // 应用层 app app.ChatApplication}func (c *ChatInferface) Route() { c.route(POST, /api/message, c.SendMessage) c.route(PATCH, /api/message, c.RecallMessage)}// POST /api/messagefunc (c *ChatInferface) SendMessage(ctx *Context) { if !c.validateRequest(ctx) { return } message : c.parseMessage(ctx) app.SendMessage(message)}func (c *ChatInferface) RecallMessage(ctx *Context) { if !c.validateRequest(ctx) { return } messageID : c.parseMessage(ctx) app.RecallMessage(messageID)}应用层type ChatApplication struct { user service.UserService chat service.ChatService // 这里领域事件由应用层发布 // publisher EventPublisher lbs LBSFacade}func (c *ChatApplication) SendMessage(msg *Message) { if !c.user.CheckUser(msg.UserID) { return } c.chat.SendMessage(msg)}领域服务层type ChatService struct { // 领域事件 publisher MessageEventPublisher repo MessageRepository}func (c *ChatService SendMessage(msg *Message) { // 业务逻辑 ... // 领域资源持久化 c.repo.Save(msg) // 发布领域事件 c.publisher.Publish(msg)}基础设施层package infrastructuretype MessageRepository struct { db MessageDatabase cache MessageCache}func (m *MessageRepository) Save(msg *Message) { db.Save(m.ToPO(msg))}func (m MessageRepository) Get(msgID int) *Message { msg : m.cache.Get(msgID) if msg ! nil { return m.FromPO(msg) } return m.FromPO(m.db.Get(msgID))}总结在设计和实现一个系统的时候这个系统所要处理问题的领域专家和开发人员以一套统一语言进行协作共同完成该领域模型的构建在这个过程中业务架构和系统架构等问题都得到了解决之后将领域模型中关于系统架构的主体映射为实现代码完成系统的实现落地。