← [ BACK_TO_NOTES ]

DDD 领域服务与应用服务

什么时候服务需要放到领域层,又什么时候需要放到应用层?

#synthesis #growing #architecture #ddd

[!info] related notes

DDD 领域服务与应用服务

领域服务表达不自然属于某个实体或值对象的业务规则;应用服务编排一个用例的执行。不能仅凭“注册、登录、销户”这些动作名称,或是否写数据库,决定整段流程属于哪一层。

判断职责

问题常见归属
单个聚合能否进行某次状态变化聚合自身的领域行为
一条业务规则无法自然归属实体/值对象领域服务或领域策略
加载模型、调用规则、提交事务、协调外部能力应用服务
数据库访问、密码哈希、邮件传输的具体实现基础设施适配器

应用服务可以执行用例级权限与流程控制,但不应复制领域不变量。领域服务可以依赖必要的抽象接口,不表示应直接耦合 ORM、Redis 或邮件 SDK。跨多个聚合不是自动建立一个“大领域服务”的理由,还要明确事务与一致性边界。

注册、登录、登出与销户

  • 注册:应用服务组织输入、哈希和持久化;身份创建、邀请码规则等按模型归属实体或领域策略。邮箱是否已存在的查询只是预检查,并发唯一性还需数据库约束及冲突映射。
  • 登录:应用服务协调凭证验证与会话签发;锁定条件等规则可在领域模型中表达,哈希比对由适配器实现。不能因为它重要就把完整用例都称为领域服务。
  • 登出:可能包含会话撤销、令牌失效与在线状态变化。写了登出时间不自动意味着领域服务;是否有领域规则取决于业务模型。仅删除客户端 Token 不证明服务端会话已撤销。
  • 销户:应用层编排资格检查、身份状态转换与跨上下文协作。欠款、未完成订单等规则由其所属上下文提供可靠结果,不能让账号领域模型任意直读其他模块内部表。

注册用例如何协作

应用入口认证/校验请求
→ 创建领域身份,执行注册规则
→ 通过适配器计算密码哈希
→ 在事务中保存身份与必要 outbox 事件
→ 唯一约束冲突映射为可处理的注册冲突
→ 提交后返回注册结果
→ 后台可靠发送欢迎邮件,失败按任务协议恢复

这只是职责示意,顺序按实际业务前置条件调整。密码应哈希而非可逆加密;示例不构成完整认证方案。欢迎邮件若不决定注册是否成立,不应在身份已提交后因邮件异常把请求伪装成“注册未发生”,也不能靠普通 fire-and-forget 保证邮件必达。

原笔记中的 libs/modules/auth/domain/services 与 commands/register.handler.ts 是一种目录示例,不是 DDD 强制布局。文件名和 service 后缀不能代替职责判断。

易混淆点

  • 领域服务不等于所有核心业务代码:实体和值对象也承载规则。
  • 应用服务不等于 HTTP Controller:同一用例可由 HTTP、CLI 或作业入口调用。
  • 持久化在哪里调用与事务由谁控制需要明确约定,没有“写数据库就属于领域层”的规则。
  • 跨上下文不等于跨网络;模型边界与部署边界分别设计。
创建于 2026/2/3 更新于 2026/10/7
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本