真正的防腐层必须切断外部api的数据结构、错误类型和行为语义对核心域的渗透,需通过自定义struct解析、统一错误转换、接口隔离、最小依赖封装及装饰器模式实现彻底解耦。

防腐层不是加个中间结构就叫防腐
Go 里写个 adapter 包、套一层函数,不等于实现了防腐层。真正的防腐层必须切断外部 API 的数据结构、错误类型、行为语义对核心域的渗透。否则改个第三方 SDK 版本,json.Unmarshal 失败、http.StatusTooManyRequests 被当成业务错误透传进来,核心逻辑就崩了。
实操建议:
- 所有外部响应(HTTP body、gRPC message、数据库 row)必须在进入 domain 层前完成「彻底解耦」:用自定义 struct 解析,不复用外部 SDK 的 model
- 外部错误必须被
errors.As捕获后转成你定义的 error 类型,比如ErrPaymentTimeout,而不是直接返回context.DeadlineExceeded - 避免在 adapter 层做业务判断(比如“如果 status == 404 就返回空订单”),这类逻辑属于 domain,该由 usecase 控制流决定
用 interface + struct 实现可测试的适配器
Go 的接口不是为了炫技,而是让 PaymentService 这类依赖能被轻松 mock。关键不是定义多“优雅”的 interface,而是它是否覆盖了真实调用路径上的全部行为分支(含重试、超时、幂等头、签名逻辑)。
常见错误现象:
立即学习“go语言免费学习笔记(深入)”;
- interface 只定义了
Charge(ctx, req),但没暴露Cancel(ctx, id),导致取消支付逻辑只能直连外部 SDK - struct 字段直接嵌套第三方 struct(如
type StripeAdapter struct { client *stripe.Client }),测试时无法替换底层 HTTP transport - 忘记把 context.WithTimeout 包裹进 adapter 方法内部,结果 timeout 控制权被上层 usecase 错误地分散管理
正确做法:每个 adapter struct 持有最小必要依赖(比如 *http.Client 而非 *stripe.Client),所有外部交互通过封装后的 doRequest 统一出口,便于打桩和日志注入。
别在防腐层里处理重试和熔断
重试策略(指数退避?固定次数?)、熔断开关(失败率阈值、半开状态)、降级逻辑(返回缓存值 or 默认值)——这些属于 cross-cutting concern,不属于防腐层职责。混在一起会导致 adapter 变重、难以复用、测试爆炸。
使用场景:
- 你有一个
OrderRepo依赖外部订单查询 API,需要自动重试 3 次;但另一个InventoryClient同样调这个 API,却要求失败立即报错 - 某个下游服务突然抖动,你只想临时熔断它,而不影响其他 adapter
解决方案:用装饰器模式,在 adapter 外包一层 RetryableOrderRepo 或 CircuitBreakerInventoryClient。它们接收原始 adapter 接口作为参数,只负责控制流,不碰数据映射逻辑。
时间字段、ID 格式、分页参数最容易漏掉转换
外部 API 返回的 "created_at": "2024-05-21T08:30:45Z",别直接赋给 domain struct 的 CreatedAt time.Time 字段——Go 的 time.UnmarshalJSON 会静默失败或解析出零值。同理,Stripe 的 payment_intent_1Qx... ID 如果直接塞进你的 PaymentID string,后续做一致性哈希或 DB 分片时就踩坑了。
容易被忽略的点:
- 分页参数名不统一:
limit/offsetvssize/fromvsper_page/page,必须在 adapter 入参时就标准化为内部约定(比如始终用PageRequest{Limit, Offset}) - 时间精度丢失:外部返回毫秒级 Unix 时间戳,但 Go
time.Unix()默认是秒级,少传三个零就会偏移数小时 - 布尔值序列化差异:有些 API 用
"is_active": "true"(字符串),有些用"active": true(原生 bool),解析时没做类型检查就 panic
复杂点在于:这些转换不能只靠一次性的 DTO 映射,得贯穿整个请求生命周期——从 HTTP header 解析、query 参数绑定、到 response body 解析,每一步都得有明确的边界校验。漏掉任意一环,腐烂就从缝隙里长出来。










