关于 separation-of-concerns
separation-of-concerns 是一项按职责划分模块和组件的编码技能,面向需要在项目中应用该原则的开发者。它提供实践规则、反模式、边界说明和代码审查清单,并建议结合项目技术栈应用。
主要功能
- 01职责分离规则
- 02层级边界指导
- 03常见反模式示例
- 04代码审查清单
- 05结合技术栈应用的指导
适用场景
- 01审查承担过多任务的处理函数
- 02分离业务逻辑与数据访问
- 03规划便于测试的应用模块
MCP 相关
应用该原则时,建议通过 context7 MCP 获取框架特定细节;若未覆盖,则使用网页搜索。
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ jordancoin/ codingskills --skill separation-of-concerns安装后在 Claude Code 中输入/separation-of-concerns确认已加载。
详细介绍
SoC — 关注点分离
应用前
如果 .agents/stack-context.md 存在,请先阅读。根据检测到的技术栈,使用惯用模式应用此原则。有关框架特定的细节,请使用 context7 MCP 或网络搜索——不要猜测。
原则
系统中的每个模块、层或组件都应只处理一个关注点。关注点是功能的一个独立方面,例如数据访问、业务规则、呈现、身份验证、错误处理和日志记录。
这在生产环境中为何重要
关注点彼此纠缠时,修改就会变得危险。修改数据库架构不应破坏 UI。更改日志格式不应影响业务逻辑。添加身份验证不应要求重写每个处理程序。
关注点分离意味着:
- 故障隔离。 渲染中的 bug 不会损坏数据。数据库超时不会导致 UI 崩溃。
- 独立测试。 无需数据库即可测试业务规则。无需后端即可测试 UI。
- 并行开发。 不同团队成员可以在不同层上工作,而不会产生合并冲突。
- 有针对性的调试。 出现故障时,问题会局限于某一层,而不是扩散到整个技术栈。
规则
- 将策略与机制分离。 业务规则(要做什么)应独立于基础设施(如何实现)。定价函数不应知道自己是由 HTTP 处理程序还是后台任务调用的。
- 将数据访问与业务逻辑分离。 查询和修改放在数据层。业务规则放在领域层。处理程序/控制器负责将它们连接起来。
- 将输入解析与处理分离。 在边界处验证和解析输入。内部函数应接收类型明确且经过验证的数据,而不是来自网络的原始字符串。
- 将编排与计算分离。 协调多个步骤的函数,不应同时包含这些步骤的实现。让协调器保持精简。
- 使用专用机制分离横切关注点。 身份验证、日志记录、速率限制和错误处理应由中间件、装饰器或拦截器处理,而不是散布在每个处理程序中。
反模式
- 臃肿的处理程序/控制器: 一个 HTTP 处理程序函数内同时解析输入、进行验证、查询数据库、应用业务逻辑、格式化输出并处理错误
- 数据库中的业务逻辑: 在 SQL 查询或存储过程中编写复杂的条件逻辑;这些逻辑本应位于应用代码中,以便测试和版本管理
- 领域代码中的基础设施: 业务规则函数直接导入 HTTP 客户端、数据库驱动程序或文件系统模块
- 数据模型中的呈现逻辑: 数据库模型包含 HTML 格式化、JSON 序列化偏好设置或特定于 UI 的字段
- 业务逻辑中的日志记录: 核心算法中充斥着日志语句,掩盖了实际逻辑
示例
-- Concerns entangled
def create_order(request):
# parsing
data = json.parse(request.body)
# validation
if not data.items:
return http_response(400, "No items")
# business logic
total = sum(item.price * item.qty for item in data.items)
tax = total * 0.08
# data access
db.execute("INSERT INTO orders ...")
# side effects
email_service.send(user.email, "Order confirmed")
logger.info("Order created")
# presentation
return http_response(201, {"order_id": id, "total": total + tax})
-- Concerns separated
def create_order_handler(request): # orchestration
order_input = parse_order_request(request) # parsing + validation
order = OrderService.create(order_input) # business logic
OrderRepo.save(order) # data access
notify_order_created(order) # side effects
return format_order_response(order) # presentation
边界
- 分离不意味着层数越多越好。 对于 CRUD 端点,设置 7 层还不如将逻辑内联。目标是沿着自然的故障边界进行有意义的分离,而不是官僚式分层。
- 一定程度的耦合是自然的。 编排层必须了解领域层和数据层——这是它的职责。目标是让领域层和数据层彼此互不知情。
- 微服务边界是极端形式的 SoC。 它会带来网络开销、分布式系统的复杂性和运维成本。只有在组织或扩展方面的收益足以抵消这些代价时,才应拆分为多个服务。
- 与 KISS 的张力: 过度分离简单逻辑会增加间接层,却没有带来好处。5 行脚本不需要 3 层架构。
代码审查清单
- 每个函数/模块是否只处理一个关注点?
- 是否可以在不依赖基础设施(数据库、网络、文件系统)的情况下测试业务逻辑?
- 是否通过中间件统一处理横切关注点(身份验证、日志记录、错误处理),而不是在每个处理程序中分别处理?
- 如果数据库发生变化,业务逻辑是否也需要变化?(不应该。)
- 如果 API 格式发生变化,业务逻辑是否也需要变化?(不应该。)
相关技能
- solid:用于分层结构中接口层面的设计
- kiss:当分离带来的间接层多于清晰度时使用
- law-of-demeter:用于保持层间通信清晰
评论
支持 Markdown