DDD的函数式编程实现

简介: 【8月更文挑战第16天】

DDD是一种成熟的软件设计方法,旨在确保领域专家和开发人员能够有效合作,创造出高质量的软件。

本文介绍咋将FP(函数式编程)应用于DDD的实现,使其既优雅又简洁。C4模型中,软件架构图分为四个层次:“系统上下文”、“容器”、“组件”和“代码”。

“组件”是构成容器的基本单位,也是本文描述的层次。

1 代码组织结构

随应用程序复杂性增加,管理这种复杂性的一种方法是根据应用程序的职责或关注点将其拆分。分层架构是一种遵循这一原则的方法,它有助于保持不断增长的代码库的组织性,使开发人员能够轻松找到某个功能的实现位置。

分层架构中,代码被水平拆分为不同的层次,每一层通过面向对象(OO)设计进行封装。请求从顶层进入,代码从上到下执行,输出从顶层产生。

这种设计的一个问题是,多个层次不仅分离了关注点,还将同一业务功能的上下文分离到不同的位置,这意味着在修改同一业务功能时,可能需要同时修改多个层次。

另一个问题是,表示层和应用层通常被设计为外观模式,这易导致上帝对象的出现,而上帝对象被认为是一种反模式

FP本质是组合。FP更倾向于垂直组织代码,而不是水平拆分代码。多个函数通过Monad)组合成一个函数流水线来实现一个业务功能(通常是一个API)。

基于函数式编程的垂直代码结构:

2 信任边界

现实世界中,问题域之间的边界是模糊的。限界上下文是计算机系统中对现实世界问题的人工投影:

  • 边界之外的世界不可信,因为它包括来自用户的各种输入
  • 边界之内的世界则是可信的、合法的、共享的领域模型

这要求我们在限界上下文的边界处引入验证和转换,从而防止外部输入并验证输出的合法性。

常见的验证和转换包括:

  • 将输入数据转换为领域模型
  • 验证输入数据的有效性,例如确保用户名和电子邮件不为空
  • 输出检查器,防止如用户密码等敏感信息被包含在输出数据中

在FP中,Applicative通常用于验证和转换输入数据为领域模型。一旦输入数据突破信任边界,你就无需担心用户名是否为空或电子邮件格式是否正确。你应专注于使用ADT进行领域建模,并通过纯函数处理业务规则。

3 使用状态机进行领域建模

业务模型可以通过不同状态的转换来建模。你总是可以通过联合类型(和类型)将领域建模为状态机。另一个好处是,在FP中,模式匹配迫使你处理联合类型的每个分支,以避免遗漏情况。

状态之间的转换

以用户注册为例:注册可以分为三个步骤:

  • 输入用户名和密码
  • 验证电子邮件
  • 支付会员费

这三个步骤可以通过联合类型记录为三个明确的状态。诸如注册、添加电子邮件、验证电子邮件等行为可以通过对这个领域模型进行模式匹配设计为函数。

4 保持领域纯粹

遵循依赖倒置原则的应用程序倾向于实现洋葱架构或整洁架构。其核心思想是将业务逻辑和领域模型置于应用程序的中心,而不是让业务逻辑依赖于数据访问或其他基础设施。依赖关系被倒置:基础设施和实现细节依赖于应用程序核心。

同样,在FP中,我们倾向于在每个API请求中将函数组合为流水线。与洋葱架构类似,我们尽可能将副作用置于领域之外,以保持领域的纯粹性。纯函数遵循持久性无知原则,它们专注于实现业务规则。

洋葱架构:

5 总结

通常,面向对象编程语言是实现DDD的首选,函数式编程则被认为适合数据科学的管道处理。实际上,DDD只是一个强调应专注于领域的思想,它并不依附于任何特定的编程范式。你可以利用FP的特性,如可组合性、Monad、Applicative和模式匹配,在“组件”架构层级上实现DDD。

目录
相关文章
真下饭!字节技术官DDD(领域驱动设计)手册,拆解业务代码首选
至少20年前,一些顶尖的软件设计人员就已经认识到领域建模和设计的重要性,但令人惊讶的是,这么长时间以来几乎没有人写出点儿什么,告诉大家应该做哪些工作或如何去做。尽管这些工作还没有被清楚地表述出来,但一种新的思潮已经形成,它像一股暗流一样在对象社区中涌动,我把这种思潮称为领域驱动设计(domain-driven design)。
|
前端开发 测试技术 人机交互
DDD - 理论到落地从统一语言开始
DDD - 理论到落地从统一语言开始
1425 0
软件体系结构 - 系统工程【切克兰德方法】
软件体系结构 - 系统工程【切克兰德方法】
981 0
|
5月前
|
存储 人工智能 算法
告别模糊检索:深度拆解向量数据库,手把手教你选对AI底座
本文深入解析向量数据库在大模型时代的关键作用,揭示其作为AI“外挂大脑”的原理与价值。从技术原理、选型维度到RAG全链路实践,结合Elasticsearch与LLaMA-Factory等工具,手把手教你构建专属AI系统,助力迈向场景化智能。
342 1
|
2月前
|
人工智能 安全 中间件
Harness 架构 与 LangChain、LangGraph 三者联动 的底层逻辑 。<Harness 学习圣经> 之二
Harness 架构 与 LangChain、LangGraph 三者联动 的底层逻辑 。<Harness 学习圣经> 之二
Harness 架构 与 LangChain、LangGraph 三者联动 的底层逻辑 。<Harness 学习圣经> 之二
|
传感器 监控 数据挖掘
Flink 四大基石之 Time (时间语义) 的使用详解
Flink 中的时间分为三类:Event Time(事件发生时间)、Ingestion Time(数据进入系统时间)和 Processing Time(数据处理时间)。Event Time 通过嵌入事件中的时间戳准确反映数据顺序,支持复杂窗口操作。Watermark 机制用于处理 Event Time,确保数据完整性并触发窗口计算。Flink 还提供了多种迟到数据处理方式,如默认丢弃、侧输出流和允许延迟处理,以应对不同场景需求。掌握这些时间语义对编写高效、准确的 Flink 应用至关重要。
999 21
|
存储 缓存 NoSQL
Redis Quicklist 竟让内存占用狂降50%?
【10月更文挑战第11天】
485 2
|
缓存 NoSQL 安全
|
开发工具 git
GIT:如何合并已commit的信息并进行push操作
通过上述步骤,您可以有效地合并已提交的信息,并保持项目的提交历史整洁。记得在执行这些操作之前备份当前工作状态,以防万一。这样的做法不仅有助于项目维护,也能提升团队协作的效率。
1040 3
|
前端开发 数据挖掘
字节面试:领域、子域、核心域、通用域和支撑域怎么划分?
领域驱动设计(DDD)通过划分业务领域和子域简化复杂性。领域是业务问题的范围,子域是更小的专业部分。核心域代表业务的核心竞争力,如电商中的商品、订单和支付;通用域提供跨领域服务,如用户管理;支撑域支持核心功能,如物流、客服和数据分析。这种划分帮助团队专注关键业务,提高开发效率和软件对业务需求的契合度。
1232 0

热门文章

最新文章