事件驱动架构设计

这是一篇译文,译文首发于 事件驱动架构设计,转载请注明出处!

这篇文章是 软件架构演进 一个有关 软件架构 系列文章中的一篇。这些文章,主要是我学习软件架构、对软件架构的思考及使用方法的记录。相比于这个系列的前几篇文章,本篇文章可能看来更有意义。

采用设计驱动开发应用程序的实践,可以追溯到 1980 年左右。我们可以在前端或者后端采用事件驱动模型。比如点击一个按钮、数据变更或者某些后端服务被执行。

但是究竟什么才是事件驱动呢?何时使用事件驱动?它有没有缺陷?

是什么、什么时候用、为什么用(What / When / Why)

就像类和组件一样我们应当在编码时实现高内聚低耦合。当需要组合使用组件时,比如 组件 A 需要触发 组件 B 中的某些逻辑,我们自然而然的会想到在 组件 A 中去直接调用 组件 B 实例中的方法。然而,如果 A 需要明确知道 B 的存在,那么它们之间是耦合的,A 依赖于 B,这使得系统难以维护和迭代。事件驱动可以 解决耦合 的问题。

此外,采用事件驱动的另外一个好处是,如果我们有一个独立的团队开发 组件 B,他们可以直接修改 组件 B 的业务逻辑而无需事先和研发 组件 A 的团队进行沟通。各个组件可以单独迭代:我们的系统更变得有组织性

甚至,在同一个组建内,有时我们的代码需要在一个 request 和 response 周期内,作为某个操作的结果被执行,但是又不需要立即被执行的类似处理。一个常见示例就是发送电子邮件。此时,我们可以直接响应用户结果,然后以异步方式延迟发送一个电子邮件给用户,这样就避免了用户等待发送邮件的时间。

不过,即使这样处理依然存在风险。如果我们胡乱使用事件驱动设计,我们就有可能要承担中断业务逻辑的风险,因为这些业务逻辑具有概念上的高度内聚,却采用了解耦机制将它们联系在一起。换句话说,就是将原本需要组织在一起的代码强行分离,并且这样难于定位处理流程(比如使用 goto 语句),来理解业务处理:这就变成了 面条式的代码[1]。

为了防止我们的代码变成一堆复杂的逻辑,我们应当在某些明确场景下使用事件驱动架构。就我的经验来讲,在以下 3 种场景下可以使用事件驱动开发:

  1. 实现组件的解耦
  2. 执行异步任务
  3. 跟踪状态的变化(审计日志(audit log))

1 实现组件的解耦(To decouple components)

当组件 A 需要执行组件 B 中的业务逻辑,相比于直接调用,我们可以向事件分发器中发送一个事件。组件 B 通过监听分发器中的特殊事件类型,然后当这类事件被触发时去执行它。

这意味着组件 A 和组件 B 都依赖于事件分发器和事件,而无需关注彼此实现:即完成它们的解耦。

理论上,分发器和事件应该处在不同的组件中:

  • 分发器应当是独立于应用的组件库,然后使用依赖管理工具安装到系统中。在 PHP 里,我们使用 Composer 将其安装到 vendor 目录。
  • 对于事件来说,它是我们应用的一部分,但需要独立于这两个组件之外,这样使得组件之间相互独立。并且事件在组件之间实现共享,它是应用核心的不可分割的一部分。事件就是 DDD(领域驱动设计) 调用 共享内核(Shared Kernel) 的一部分。这样,这些组件就依赖于共享内核,而无需知道彼此的存在。不过在单个系统中,为了方便我们也可以在组件内去触发事件。
共享内核
[...] 用明确的边界指定团队同意共享的域模型的某些子集。保持这个内核很小。[...] 这个拥有特殊状态的明确的共享机制,不得在未经团队协商情况下随意修改。
Eric Evans 2014,
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值