学习
实践
活动
工具
TVP
写文章
专栏首页斑斓事件风暴过程全体验-下篇

事件风暴过程全体验-下篇

ThoughtWorks 钱平

作为TW技术咨询师,为多家企业进行架构和 Fintech 创新相关技术咨询,如架构设计、遗留系统上云迁移及规划、各种技术赋能、企业技术相关平台的生态规划及落地建设,创新实验室的技术部分筹建等等。此前,10多年的投行研发经验,包括外汇交易等核心系统,涉猎从架构、开发、Scrum Master、运维等多个角色。个人创业经验经历涉及互联网、金融和教育行业,并在广州多所重点大中院校担任创客导师。

在上一篇文章中,以英雄联盟自动预警系统为例子,展开了事件风暴获得了上下文,这里就继续延伸,看看事件风暴的产物还可以怎么进一步落到开发代码上面。

这里我们聚焦案件记录上下文,假设它独立为一个服务存在。然后我们可以把它对应的决策/命令搬过来一起看:

Step1. 设计API

结合命令风暴的结果我们发现有一部分的决策是外部触发的(框起来的部分),那这部分我们就应该为它们设计对应的API

在api/rest/CaseController.java:

@RestController
@RequestMapping("/case")
public class CaseController {
    @PostMapping
    public void createCase(@RequestBody String caseBrief) {}

    @PostMapping("/{caseId}/close")
    public void closeCase(@PathVariable int caseId) {}

    @PostMapping("/{caseId}/esculate")
    public void esculateCase(@PathVariable int caseId) {}

    @PostMapping("/{caseId}/thief")
    public void updateThiefInfo(@PathVariable int caseId,
                                @RequestBody String thiefInfo) {}

    @PostMapping("/{caseId}/fight-plan")
    public void addFlightPlan(@PathVariable int caseId,
                              @RequestBody FightPlanDTO fightPlanDTO) {}

    @PostMapping("/{caseId}/fight-plan/{planId}/success")
    public void markSuccessFightPlan(@PathVariable int caseId,
                                     @PathVariable int planId) {}

    @PostMapping("/{caseId}/fight-plan/{planId}/fail")
    public void markFailFightPlan(@PathVariable int caseId,
                                  @PathVariable int planId) {}
}

这里大体上遵循了REST的规则,充分使用URL指定所需的资源。当然,比如像“关闭”案件记录“应该用POST还是DELETE这些细节地方也是可以进一步斟酌的。

Step2. 构建领域对象

把聚合根对应的实体和值对象,以及后面补充的一些关键属性补充起来,暂时它还是一个贫血的POJO:

public class CaseReport {
    int id;
    Timestamp startTime;
    Timestamp closeTime;
    String caseBrief;
    String thief;
    List<FightPlan> fightPlanList;
}

public class FightPlan {
    int id;
    String status;
    String planDetail;
    int meetingId;
}

Step3. 构建应用服务和领域服务

这里以系统收到升级预警通知的步骤为例子:

场景与步骤:收到升级预警通知 -> 触发升级预警

  • 校验所升级预警的案件存在
  • 创建线上会议
  • 把会议登陆URL发送通知给其他英雄

如果按我自己原来的写法,我会把这个逻辑写在应用服务层ApplService里面。但是刚巧在DDD跟张逸老师协作了他的一个场景驱动工作坊,所以这里尝试用他的方式去规划一下。

场景放在App Service:

@Service
public class CaseReportService {
    @Autowired
    CaseReportService caseReportService;

    @Transactional
    public void esculate(int caseId) {
        caseReportService.esculate(caseId);
    }
}

步骤放在DomainService:

@Service
public class CaseReportService {
    @Autowired
    CaseReportRepository caseReportRepository;

    @Autowired
    FightPlanRepository fightPlanRepository;

    @Autowired
    MeetingGateway meetingGateway;

    @Autowired
    NotificationGateway notificationGateway;

     public void esculate(int caseId) {
        final CaseReport caseReport = caseReportRepository.getCaseReportById(caseId);

        if (caseReport != null) {
            final MeetingInfo meeting = meetingGateway.createMeeting(caseReport);
            notificationGateway.sendEsculationMsg(meeting);
        } else {
            throw new BizException(INVALID_CASEREPORT_ID);
        }
    }
}

碰巧这里三个步骤都是调用底层服务,所以都是调用了gateway/repository去进行,如果当中有一些是不依赖与底层的动作,则应该充血地放到DomainObject(CaseReport)里面去。

至此,一个分层架构大概出来了,并且已经完成了业务domain的开发以及API的入口:

分层架构

最后,聚合细化的信息其实也是可以对应给DB设计指引的:

  • 1-1的场景下,可以合在一个表,可以两个表
  • 1-n的场景下,通常两个表,也可以三个表
  • n-n的场景下,通常三个表

对应我们的例子,可以这样来设计表结构:

CREATE TABLE case_report_tbl (
  id int NOT NULL AUTO_INCREMENT,
  case_brief varchar(255) NOT NULL,
  start_time TIMESTAMP NOT NULL,
  close_time TIMESTAMP NOT NULL,
  thief varchar(255),
  PRIMARY KEY (ID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE fight_plan_tbl (
  id int NOT NULL AUTO_INCREMENT,
  status varchar(10) NOT NULL,
  plan_detail varchar(255) DEFAULT NULL,
  meeting_id int NOT NULL,
  case_id int NOT NULL,
  PRIMARY KEY (ID),
  FOREIGN KEY (case_id) REFERENCES case_report_tbl(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

当然,现在也有很多是推荐不用FOREIGN KEY的设计手法,开放式无约束地建表,并把校验的逻辑都回归到代码里面并使用自动化测试去保证这个必须的逻辑校验,所以这里也只是一个指引,大家可以按需谋划。

到此,事件风暴对应下来,唯一还未补的缺应该就剩下底层所需的技术支撑了。比如Rest调用三方服务,或者是DB相关的SQL。这个应该是easy job就不继续写了哈 ^_^

文章分享自微信公众号:
逸言

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!

作者:钱平
原始发表时间:2019-12-13
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • 事件风暴过程全体验-上篇

    作为TW技术咨询师,为多家企业进行架构和 Fintech 创新相关技术咨询,如架构设计、遗留系统上云迁移及规划、各种技术赋能、企业技术相关平台的生态规划及落地建...

    张逸
  • 事件风暴的设计要素与驱动力

    个人认为,相比较传统领域分析方法,事件风暴的革命意义在于它建立了以“领域事件”为核心的建模思路,这相当于改变了我们观察业务领域的世界观。

    张逸
  • 运用事件风暴进行领域分析建模

    本文是事件风暴方法的第二部分,从获得的业务全景开始进行领域分析建模,通过事件识别出决策命令,进而驱动出读模型和聚合。获得领域分析模型还将是领域驱动设计过程的重要...

    张逸
  • 全栈设计+编程的方法论,以“猜对联”小程序为例

    趁着快过年,花了 2 天晚上从设计到开发,做了一款小程序 “ 猜对联 ” ,可以用于公众号吸粉,也可以朋友间拜年,也可以作为聚会的真心话大冒险游戏,玩法多样,全...

    mixlab
  • 领域驱动实践总结(基本理论总结与分析+架构分析与代码设计+具体应用设计分析V)[通俗易懂]

    领域驱动设计DDD是一种设计思想,它可以同时指导中台业务建模和微服务设计(中台本质是业务模型,微服务是业务模型的系统落地),领域驱动设计强调领域模型和微服务设计...

    全栈程序员站长
  • 识别领域事件 | 洞见

    随着微服务架构的兴起,微服务设计与拆分的的最佳实践DDD已然成为大家讨论与实践的热点,整个行业都在探索如何用DDD建模来实现微服务设计。事件风暴作为最接地气的实...

    ThoughtWorks
  • 【2019领域驱动设计峰会】领域场景驱动设计实战工作坊

    领域场景驱动设计实战工作坊将以事件风暴为纵贯线,以领域场景为横切面,引入场景驱动设计与测试驱动开发完成从领域建模到编码实现的全过程实战。内容涵盖事件风暴、场景驱...

    ThoughtWorks
  • DDD中的建模方法有哪些[通俗易懂]

    在之前的文章中已经介绍了DDD相关的概念模式,DDD相关的业务技术架构,但是我们还没有找到一个核心的抓手去实践DDD。DDD的一个核心本质就是对业务建模,或者领...

    全栈程序员站长
  • 域名劫持事件频发 网站安全形势不容忽视

      6月26日消息,近日,安恒信息风暴中心在日常监测中发现了多起国内网站域名解析地址跳转至美国或加拿大等国外IP的情况。安恒信息风暴中心对此异常行为进行深入分析...

    安恒信息
  • 「领域驱动设计DDD」事件风暴简介:实现域驱动设计的简便方法

    事件风暴是一种快速,轻量级且未得到充分认可的群体建模技术,它对于加速开发团队而言非常强大,有趣且有用。作为Alberto Brandolini的心血结晶,它是G...

    首席架构师智库
  • 基于领域驱动设计的业务中台架构设计

    软件设计首要面对的挑战是如何应对复杂多变的业务问题。而对于业务中台来说,这个问题变得尤为突出。一方面,数字化时代,高度不确定并且快速变化的商业环境必然要求企业的...

    爱撸猫的杰
  • 鼠标框选(上篇)

      好久没有更新博客了,感觉有些手生了,最近换了工作,有传统软件公司跳槽到互联网公司,由原来主做后端,兼职前端变成了全职前端;第一次进入互联网公司,感觉和传统软...

    Jerremy
  • NASA和亚马逊正在合作开发可以预测太阳超级风暴的应用程序

    我们已经看到这些超级风暴过去曾造成破坏。1859年,据称发生了卡灵顿事件,这中断了电报通信。1989年冬天,加拿大魁北克省的数千名居民在水电中断时陷入了黑暗。这...

    AiTechYun
  • DDD实战课--学习笔记

    我认为,要想应用 DDD,首要任务就是要吃透 DDD 的核心设计思想,搞清楚 DDD、微服务和中台之间的关系。中台本质是业务模型,微服务是业务模型的系统落地,D...

    郑子铭
  • 限界上下文是什么鬼?DDD 最抽象的概念详解

    通用语言, 最主要的目的就是减少交流中信息丢失, 在实际开发中, 可能关联很多人, 例如有业务层面的业务细节制定者、领域专家、产品经理、项目经理 、架构师、开发...

    孙玄@奈学教育
  • DDD领域驱动实战(二) - 限界上下文(bounded context)

    限界上下文定义领域边界,以确保每个上下文含义在它特定的边界内都具有唯一的含义,领域模型则存在于这个边界之内。

    JavaEdge

扫码关注腾讯云开发者

领取腾讯云代金券