go 复杂业务逻辑应采用分层契约、显式组合与状态收口:用 stepfunc+then 实现单职责函数链;状态变更须经 transitionto 受控转移;审批流返回 bool 控制终局;ai 工作流用 langgraphgo 建模为事件驱动图;所有节点透传 context 并 %w 包装错误。

Go 框架处理复杂业务逻辑流,核心不是堆砌中间件或硬编码 if-else,而是靠分层契约 + 显式组合 + 状态收口。直接用 Gin 或 Echo 写 20 层嵌套 handler,迟早线上出问题。
用函数类型 + Then 组合替代嵌套回调
常见错误是把校验、查库、调第三方、发消息全塞进一个 handler 函数里,导致无法单测、难以复用、错误处理混乱。
- 定义统一签名:
type StepFunc[T, R any] func(T) (R, error),所有环节都遵守这个契约 - 用
Then组合:比如Then(validate, fetchUser, applyDiscount, saveOrder),顺序即执行流 - 每个 step 只做一件事,失败立即返回,不吞
error;成功才传给下一步,天然短路 - 避免在组合链里做 I/O 阻塞操作(如 HTTP 调用),否则整条链卡住;超时必须由
context.Context控制
状态变更必须走 TransitionTo,禁用 state = "paid"
订单从 pending → paid → shipped,不是赋值,是一次受控的转移。硬改字段会跳过日志、漏触发钩子、并发下覆盖状态。
- 状态值用常量:
const StatePaid = "paid",不用字符串字面量 - 转移前查表:
validTransitions[StatePending][EventPay],不存在就返回ErrInvalidTransition -
TransitionTo方法内只更新内存字段 + 记日志 + 发事件,不查 DB、不发 HTTP - 耗时动作(如通知物流)放到状态变更后异步启动 goroutine,通过 channel 回传结果
事务和审批流必须显式中断,不能靠 panic
有人在审批节点里写 if amount > 10000 { panic("exceed limit") },结果 recover 不到,或者恢复后流程继续往下走,造成误审。
- 审批节点统一返回
func(ctx context.Context, req *ApprovalRequest) (bool, error) - 返回
false表示“继续流转”,true表示“已终局(通过/拒绝),不再往后传” - 错误要结构化:
ApprovalError{Code: "AMT_EXCEED", Abort: true},Abort: true就立刻终止整条链 - GORM 事务用
db.Transaction(func(tx *gorm.DB) error { ... }),别在 handler 里手动Begin/Commit
AI 工作流用 LangGraphGo 建模为图,别写 if-else 分支
当业务逻辑带循环、条件跳转、多智能体协同(比如“先意图识别 → 若是投诉则情感分析 → 再路由到人工”),线性函数链撑不住。
- 每个节点是独立函数:
func(ctx context.Context, state map[string]interface{}) (map[string]interface{}, error) - 边由事件驱动:
Edge{Source: "intent", Target: "complaint", Condition: func(state) bool { return state["intent"] == "complaint" }} - 状态存在
state map[string]interface{}里,框架负责持久化、恢复、并发安全 - 不要在节点里写
http.Post这类阻塞调用;超时、重试、降级全部交给框架配置
最易被忽略的是:所有装饰器、状态机、责任链、工作流节点,都必须透传 context.Context 并用 %w 包装错误。漏掉任意一处,超时就失效,错误链就断掉,线上排查时你会花三倍时间找源头。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











