关于php:浅析-DDD-一个-PHP-程序员的自述

5次阅读

共计 4055 个字符,预计需要花费 11 分钟才能阅读完成。

DDD 是什么(首先它不是什么)

DDD 是 Domain Driven Design 的缩写,在中文中常被翻译为畛域驱动设计。在咱们理解 DDD 是什么之前,首先探讨下它不是什么。

  • DDD 不是一个软件框架。然而基于 DDD 思维的框架是存在的,比方 Axon,它是以 DDD 为指导思想,应用 Java 实现的一个微服务软件框架。
  • DDD 不是一种软件设计模式。它不是像工厂,单例这样子的设计模式。然而 DDD 思维中提出了诸如资源库(Repository)之类的设计模式。
  • DDD 不是一种零碎架构模式。它不是像 MVC 之类的架构模式。然而 DDD 思维中提出了诸如事件溯源(Event Souring),读写隔离(Command Query Responsibility Segregation)之类的架构模式。

那么 DDD 到底是什么

软件是服务于人类,为进步人类生产效率而产生的一种工具,每一个软件都服务于某一个特定的畛域。比方一个 CRM,它是以治理客户数据为外围,帮忙商户与客户保持联系的工具。

而软件的本质是计算机中运行的代码,如何将形象的代码更精确地映射到人类所关怀的畛域中,这是软件开发者始终在探寻的话题,不论是函数式编程(FP)还是面向对象编程(OOP)也好,都是为了帮忙开发者开发出更贴近于畛域中的软件模型。

在传统的软件开发办法中,咱们经常会遇到一系列影响软件品质的技术以及非技术问题:

  • 开发者热衷于技术,但不足设计和业务思考。开发人员在不齐全理解业务需要的状况下,闭门造车,即便性能上线也无人问津。
  • 代码输出而非业务输出。技术人员对技术实现情有独钟,呈现杀鸡焉用牛刀的状况。
  • 过于器重数据库。以数据库设计为核心,而非业务来进行开发,后果往往是,软件无奈适应始终在变动的业务逻辑。

DDD 是一种设计思维,一种以畛域(业务)为出发点,以解决软件建模复杂度为目标设计思维,咱们也能够将其了解为一种建模的方法论。

DDD 的设计思维分为策略和战术两局部。

咱们能够将策略设计了解为宏观层面的设计,它的目标包含,剖析业务的复杂程度,拆分业务的畛域领域,领导业务整合形式等等。咱们能够将战术设计了解为宏观层面(代码层面)的设计,它为咱们在实现业务逻辑提供一系列工具。

策略设计

通用语言(Ubiquitous Language)

语言本是人类沟通的根本工具,然而开发人员习惯了应用技术术语,领域专家(领域专家在此泛指精通业务的专家,比方用户,客户等等)对技术术语毫不关心,于是造成了不可避免的沟通问题,一旦沟通呈现问题,开发进去的软件便很难解决领域专家的真正痛点。

通用语言是 DDD 思维的基石,它是开发人员和领域专家独特创立一套沟通语言,一套在团队中风行的,通用的沟通语言,团队的组员之间可应用通用语言进行无障碍交换。

这要求开发人员摒弃技术味浓厚的技术术语,与领域专家单干,像领域专家一样关注业务问题,独特开掘并打磨业务中的术语,创立一套通用语言。

通用语言往往能够间接利用于代码中,它能够间接被写成一个类或者一个类的办法。

比方在开发一个购物车时,与其应用技术术语:

  • Cart::create(): 创立一个购物车。
  • Cart::updateStatus():更新购物车状态。
  • Cart::remove():移除购物车。

咱们无妨应用更贴近业务的通用语言:

  • Cart::init(): 创立一个购物车。
  • Cart::addItemToCart():增加商品。
  • Cart::removeItemFromCart():移除商品。
  • Cart::empty():清空购物车。

在应用后者时,开发人员不必解释每一个类办法的意义,领域专家能够间接看懂每一个类办法的目标。开发人员甚至能够和领域专家坐在一起应用代码来打磨业务流程。

限界上下文(Bounded Context)

在实现了通用语言自在当前,咱们须要应用限界上下文来规定每一套通用语言的应用边界。限界上下文是语义和语境的边界,在其内的每一个元素都有本人特定的含意,也就是说每一个概念在一个限界上下文中都是举世无双,不能够呈现一词多义的状况。

咱们能够用一个简略的例子来解释限界上下文。比方在一个购物车的限界上下文中,咱们能够用 User 一词来代表购买商品的客户。而在一个注册零碎中,咱们能够用 User 一词指的是带有用户名和明码的账号。尽管词汇一样,然而在不同的限界上下文中,它们的含意不同。

咱们应用限界上下文和通用语言,对业务进行语言层面的拆分。限界上下文为畛域中的每一个元素赋予清晰的概念,开发人员也就不会将不由自主的在脑海中闪现多个撑持一个元素的概念,防止写出“大泥球”(big ball of mud)代码。

子域(Subdomain)

如果说限界上下文是对业务进行语言层面拆分的话,那么子域便是对业务进行商业价值的拆分。每一个商业都有本人的关注点,即使是看起来一样的电商平台,淘宝是开放平台模式,京东是价值链整合模式,一个显著的区别是,淘宝应用第三方物流而京东自建物流体系。

那么作为一个开发人员,为何要关怀看起来仿佛与本人无关的商业模式呢?恰恰相反,只有当咱们理解一个商业的构造时,能力开发出一个主次明显的零碎来撑持一个商业的飞速发展。

子域便是这样一个帮忙咱们划分主次的工具。

有三种类型的子域:

  • 外围域(Core Domain):这是零碎中须要最大投资的畛域,它代表着整个商业的外围竞争力。咱们须要花大量资源以及资源来打磨外围域,这关乎一个企业的存亡。比方京东的自建物流零碎。
  • 撑持域(Supporting Domain):此畛域并非一个企业的外围业务,然而外围域却离不开它,它能够采纳外包定制计划实现。比方认证上下文,权限上下文。
  • 通用域(Generic Domain):如果已有成熟的解决方案,通用域能够洽购现成计划来,如果没有,也能够采纳外包,在通用域上的投资应该是最小的。比方对于淘宝而言,物流便是其通用域。

限界上下文和子域的关系七嘴八舌,有专家提倡 1:1,也有专家提倡 1:N。集体比拟提倡 1:1, 因为受实现畛域驱动设计一书作者影响比拟深。

上下文映射(Context Mapping)

在一个宏大的零碎中,限界上下文之间必然存在肯定的依赖关系。如何将一个上下文中的概念映射到另一个上下文中?咱们应用上下文映射。

以下是几种上下文映射的关系类型:

  • 单干关系 (Partnership)
  • 共享内核 (Shared Kernel)
  • 客户方 - 供应方开发 (Customer-Supplier Development)
  • 遵奉者 (Conformist)
  • 防腐层 (Anticorruption Layer)
  • 凋谢主机服务 (Open Host Service)
  • 公布语言 (Published Language)
  • 另谋他路 (SeparateWay)
  • 大泥球 (Big Ball of Mud)

以上都是比拟形象的概念,有时两个限界上下文之间也能够存在多重关系。

以上便是 DDD 策略设计的几个外围概念。

战术设计

如何为限界上下文中的概念建设模型,咱们将应用的是 DDD 所提供的战术设计。

实体(Entity)

首先咱们讲到的是,实体。

实体是畛域中独立事物的模型,每个实体都领有一个惟一的标识符,比方 ID, UUID,Username 等等。大多数状况下,实体是可变的,它的状态会随着工夫的迁徙扭转,不过,一个实体不肯定必须可变。

实体的最大的特色是它的个体性,唯一性。比方在一个简略的购物车上下文中,订单(Order) 便是一个实体,ID 是它的标识符,它的状态能够在提交(placed),确认(confirmed) 以及已退 (refunded) 之间变动。

值对象(Value Object)

值对象是畛域中用来形容,量化或者测量实体的模型。和实体不同,值对象没有惟一的标识符,两个对等的值对象是能够替换的。值对象具备不变性(Immutability),一旦创立当前,一个值对象的属性就定型了,不可更改。

了解值对象的最间接的办法是,设想咱们现实生活中的钞票,在日常生活中,甲的十块钱人民币和乙的十块钱人民币是能够对等替换的。

在上文的购物车上下文中,金额(Money)便是一个值对象,金额由货币(currency)和数目(amount):

class Money {
  public $currency;
  public $amount;

  function __construct($currency, $amount) {
    $this->currency = $currency;
    $this->amount = $amount;
  }  
}

应用值对象进行建模,能帮忙咱们用代码更准确地建设畛域模型。

聚合(Aggregate)

聚合是什么?聚合是上下文中对业务畛域更精密的划分,每一个聚合保障本人的业务一致性。

那么什么是业务不变性?业务不变性示意一个业务规定,该规定在业务畛域中不可违反,必须保障其一致性。比方,在进行订单退款时,退款金额不能够超过已付金额。

聚合的组成部分是实体和值对象,有时候也只有实体。为了爱护聚合的业务一致性,每个聚合只能够通过某一个实体对其进行操作,该实体被称为聚合根。

畛域事件(Domain Event)

畛域事件是通过通用语言剖析进去的事件,与常见的事务事件不同的是它与业务非亲非故,所以它的命名往往夹带业务名词,而不应该与数据库挂钩。比方购物车削减商品,对应的畛域事件应该是 ProductAddedToCart, 而不是 CartUpdated

总结

DDD 还提供了诸如应用服务(Application Service),畛域服务(Domain Service) 等战术设计,DDD 还提出了文章结尾就提过的事件溯源,六边形等架构模式,在此咱们将不一一介绍。

DDD 的外围是从业务的角度为软件建设模型,其目标是打造更贴近业务的代码,能更直观的从代码理清业务流程。然而实现 DDD 并非一日之举,它须要一直的实际,一直的打磨。

本文转载自【何以解耦】:https://codedecoupled.com/intro-ddd.html,如果你也对 TDD,DDD 以及简洁代码感兴趣,欢送关注公众号【何以解耦】,一起摸索软件开发之道。

正文完
 0