目录
EventStorming:揭开领域的面纱
战略领域驱动设计
定义边界(有界上下文
无处不在的语言
战术领域驱动设计
实体和值对象
实体
值对象
服务
域名服务
申请服务
基础设施服务
服务分类
组建团队:塔克曼的阶段
成型
风雨飘摇
规范
表演
文档:Diátaxis 模型
首页 后端开发 php教程 了解领域并建设团队:变革的基础(II)

了解领域并建设团队:变革的基础(II)

Jan 19, 2025 pm 06:05 PM

着手一个复杂的项目需要全面的背景收集,同时利用领域专家的见解从全新的角度接近领域知识。这种方法使技术团队与业务目标保持一致,并为整个产品生命周期中的明智决策建立了基础路线图。

与之前的团队和当前应用程序用户进行的初步知识收集会议被证明没有成效。 尽管存在固有风险,我们还是短暂考虑过独立进行。

EventStorming:揭开领域的面纱

作为技术主管,考虑到项目的复杂性和团队对所有权的需求,我从一开始就倡导领域驱动的方法。这以领域为中心,促进了共同的理解(无处不在的语言),从而简化了沟通并促进了应用程序当前状态的映射。

我们使用 Miro 模板启动了 EventStorming 会议,提供了有效聚焦的结构和图例。 通过会前准备或初步解释提前熟悉 EventStorming 概念是非常有益的。

Understanding the Domain and Building the Team: The Foundations of Change (II)

我们的结构化 EventStorming 流程包括:

  1. 探索领域事件(大局):与领域专家一起识别、按时间顺序排列和验证关键系统事件,突出显示差距和依赖性。
  2. 细化和分析:添加解释性注释,记录问题,深入分析每个事件,并查明关键决策点。
  3. 域建模:识别聚合和边界,定义参与者和角色,建立触发命令,记录策略和业务规则,以及识别内部/外部事件触发器。
  4. 文档和验证:组织和清理收集的信息,建立清晰的关系,与利益相关者验证模型,并创建参考文档。

EventStorming 不仅提供了领域理解,还为战略和战术上应用领域驱动设计 (DDD) 原则奠定了基础。

战略领域驱动设计

关键的第一步涉及战略性地构建领域。 系统的复杂性和技术/业务协调的需要导致采用 DDD 原则。 上下文映射被证明是无价的,即使在我们等待重构的整体中也是如此。 我们确定了限界上下文,在具有共享内核的单一技术上下文中运行。 这种分析虽然没有深入探讨,但指导项目走向面向领域的架构,改善了技术开发和跨团队协作。

定义边界(有界上下文

识别有界上下文澄清了系统间和外部系统的关系,简化了复杂性,为未来的模块化奠定了基础。 这些初始决策将指导整体结构分解为与定义的上下文一致的可管理组件。 这也有助于确定优先级并确定需要简化、解耦或消除的领域。 我们专注于实施用于外部系统交互的反腐败层 (ACL),以保持系统完整性。

确定了五个关键背景:

  • 订单分配
  • 标签生成
  • 订单准备
  • 电子商务整合
  • 批量订单准备

这些决策促进了可持续架构的发展,并使开发与业务需求保持一致。

Understanding the Domain and Building the Team: The Foundations of Change (II)

无处不在的语言

事实证明,建立一种强大的通用语言至关重要。 通过领域专家和开发人员之间的协作创建的共享语言的好处远远超过翻译工作或误解。 这种活跃的资源将技术团队与领域专家联系起来,改善了沟通,减少了误解,并确保代码中准确的领域表示。 这促进了高效、符合业务的技术解决方案。

战术领域驱动设计

按照战略框架,我们实施了战术 DDD 原则来构建代码,反映领域现实并确保长期可持续性。

实体和值对象

理解实体和值对象之间的区别至关重要。

实体

实体拥有唯一、持久的身份,即使属性发生变化也是如此。 示例包括:

  • 订单
  • 产品
  • 承运人
  • 商店
  • 顾客

值对象

值对象缺乏个体身份;他们的价值定义了他们。 相同的属性意味着等同。 它们是不可变的,非常适合封装跨领域出现的概念。示例包括:

  • 产品参考
  • 产品Ean13
  • 订单参考
  • 价格
  • 体重
  • 送货号码

这种方法创建了更易于理解和模块化的代码,并具有明确定义的职责。

示例值对象:

<?php
readonly class ProductEan13
{
    public string $value;

    public function __construct(string $value)
    {
        $pattern = '/^\d{13}$/';
        if (!preg_match($pattern, $value)) {
            throw new \Exception('Invalid product Ean13');
        }
        $this->value = $value;
    }
}
登录后复制
登录后复制

服务

服务按目的和实施模式进行分类。

域名服务

域服务封装了不适合实体或值的业务逻辑,严格在域规则内运行,无需基础设施依赖。

<?php
readonly class ProductEan13
{
    public string $value;

    public function __construct(string $value)
    {
        $pattern = '/^\d{13}$/';
        if (!preg_match($pattern, $value)) {
            throw new \Exception('Invalid product Ean13');
        }
        $this->value = $value;
    }
}
登录后复制
登录后复制
申请服务

应用服务协调域操作与外部交互,集中复杂的操作并将域和基础设施分开。 其中包括用例、命令处理程序和事件处理程序。

Understanding the Domain and Building the Team: The Foundations of Change (II)

基础设施服务

基础设施服务处理外部组件交互(数据库、文件系统等),充当适配器来维护领域不可知论。

<?php
class CheapestCarrierGetter
{
    public function get(
        DeliveryOptionCarrierCollection $deliveryOptionCarriers,
        Weight $orderWeight,
        Country $country,
        PostalCode $postalCode,
        bool $isCashOnDelivery = false,
    ): Carrier {
        // Logic to get the cheapest carrier
    }
}
登录后复制
服务分类

服务按功能和相关设计模式进行分类:Transformers、Builders、Factories、Presenters、Notifiers、Validators 和 Clients。

这个最初的领域建模虽然不完整且迭代,但促进了团队的参与和承诺。 预计将进一步完善和重组。

推荐的 DDD 资源:

  • “领域驱动设计:解决软件核心的复杂性”作者:Eric Evans
  • Vaughn Vernon 的“实现领域驱动设计”
  • “PHP 领域驱动设计”,作者:Carlos Buenosvinos、Christian Soronellas 和 Keyvan Akbary

组建团队:塔克曼的阶段

采用 DDD 与团队组建并行,遵循塔克曼的阶段(形成、风暴、规范、执行)。

成型

初始团队成员审查了项目,记录了操作,并建立了技术和组织基础(流程、标准、工具)。

风雨飘摇

微小的分歧导致了工作方式、沟通方法和决策过程的定义。

规范

建立了团队协议、编码标准、开发流程、WIP 限制、部署规则、技术债务管理和 ADR。

表演

建立的框架实现了高效的产品开发,优先考虑有价值的举措,并培育持续改进的文化。

文档:Diátaxis 模型

使用 GitLab Pages 和 Jekyll 以及 Just the Docs 主题来管理文档,遵循 Diátaxis 模型:教程、指南、解释和参考。 使用事件目录和 AsyncAPI 自动化文档已计划但尚未完全实施。

以上是了解领域并建设团队:变革的基础(II)的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

在PHP API中说明JSON Web令牌(JWT)及其用例。 在PHP API中说明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

PHP 8.1中的枚举(枚举)是什么? PHP 8.1中的枚举(枚举)是什么? Apr 03, 2025 am 12:05 AM

PHP8.1中的枚举功能通过定义命名常量增强了代码的清晰度和类型安全性。1)枚举可以是整数、字符串或对象,提高了代码可读性和类型安全性。2)枚举基于类,支持面向对象特性,如遍历和反射。3)枚举可用于比较和赋值,确保类型安全。4)枚举支持添加方法,实现复杂逻辑。5)严格类型检查和错误处理可避免常见错误。6)枚举减少魔法值,提升可维护性,但需注意性能优化。

会话如何劫持工作,如何在PHP中减轻它? 会话如何劫持工作,如何在PHP中减轻它? Apr 06, 2025 am 12:02 AM

会话劫持可以通过以下步骤实现:1.获取会话ID,2.使用会话ID,3.保持会话活跃。在PHP中防范会话劫持的方法包括:1.使用session_regenerate_id()函数重新生成会话ID,2.通过数据库存储会话数据,3.确保所有会话数据通过HTTPS传输。

描述扎实的原则及其如何应用于PHP的开发。 描述扎实的原则及其如何应用于PHP的开发。 Apr 03, 2025 am 12:04 AM

SOLID原则在PHP开发中的应用包括:1.单一职责原则(SRP):每个类只负责一个功能。2.开闭原则(OCP):通过扩展而非修改实现变化。3.里氏替换原则(LSP):子类可替换基类而不影响程序正确性。4.接口隔离原则(ISP):使用细粒度接口避免依赖不使用的方法。5.依赖倒置原则(DIP):高低层次模块都依赖于抽象,通过依赖注入实现。

解释PHP中的晚期静态绑定(静态::)。 解释PHP中的晚期静态绑定(静态::)。 Apr 03, 2025 am 12:04 AM

静态绑定(static::)在PHP中实现晚期静态绑定(LSB),允许在静态上下文中引用调用类而非定义类。1)解析过程在运行时进行,2)在继承关系中向上查找调用类,3)可能带来性能开销。

什么是REST API设计原理? 什么是REST API设计原理? Apr 04, 2025 am 12:01 AM

RESTAPI设计原则包括资源定义、URI设计、HTTP方法使用、状态码使用、版本控制和HATEOAS。1.资源应使用名词表示并保持层次结构。2.HTTP方法应符合其语义,如GET用于获取资源。3.状态码应正确使用,如404表示资源不存在。4.版本控制可通过URI或头部实现。5.HATEOAS通过响应中的链接引导客户端操作。

您如何在PHP中有效处理异常(尝试,捕捉,最后,投掷)? 您如何在PHP中有效处理异常(尝试,捕捉,最后,投掷)? Apr 05, 2025 am 12:03 AM

在PHP中,异常处理通过try,catch,finally,和throw关键字实现。1)try块包围可能抛出异常的代码;2)catch块处理异常;3)finally块确保代码始终执行;4)throw用于手动抛出异常。这些机制帮助提升代码的健壮性和可维护性。

PHP中的匿名类是什么?您何时可以使用它们? PHP中的匿名类是什么?您何时可以使用它们? Apr 04, 2025 am 12:02 AM

匿名类在PHP中的主要作用是创建一次性使用的对象。1.匿名类允许在代码中直接定义没有名字的类,适用于临时需求。2.它们可以继承类或实现接口,增加灵活性。3.使用时需注意性能和代码可读性,避免重复定义相同的匿名类。

See all articles