单一职责是微服务拆分的硬性门槛,必须以业务域为唯一依据,禁止按技术指标拆分;服务边界模糊将导致后续演进受阻,如订单服务含地址解析、支付服务掺杂库存扣减即属职责越界,判断标准是“该服务停机时是否影响非核心域业务”,go实现中须确保独立go.mod、禁用跨服务internal引用、契约先行、配置与业务逻辑物理隔离。

单一职责 是微服务拆分的硬性门槛,不是“尽量做到”,而是服务边界一旦模糊,后续演进必然卡在耦合上。
服务拆分必须以业务域为唯一依据
技术指标(如接口数量、代码行数)不能作为拆分标准。一个订单服务如果还包含用户地址解析逻辑,就违反了 单一职责;同理,支付服务里掺杂库存扣减,就是典型的职责越界。
- 判断方法:问自己“这个服务停机时,哪些其他业务会直接不可用?”——如果答案超出其核心域,说明拆分过粗或职责污染
- Go 实现提示:每个服务应有独立的
go.mod,internal/service下只放本域逻辑,绝不 import 其他服务的internal包 - 常见陷阱:为“复用”把通用函数抽到
pkg/common,结果变成隐式依赖——真正该复用的是协议(如 gRPC proto),不是实现
服务间通信必须走契约,而非直连包引用
Go 项目里最隐蔽的耦合,是 A 服务直接 import B 服务的 internal/repository 或 model。这会让部署、升级、测试全部失效。
- 正确做法:所有跨服务交互,只通过定义好的 API(HTTP JSON Schema / gRPC
.proto)或事件消息(Kafka Topic Schema) - 验证手段:构建时禁用跨服务
import—— 可在go.mod中用//go:build !production配合 linter 检查 - 性能提醒:gRPC 比 REST 更适合内部服务调用,但别为了性能绕过契约——序列化开销远小于后期维护成本
配置和启动逻辑必须与业务逻辑物理隔离
viper 读配置、etcd 做服务注册、zap 写日志——这些都不该出现在 internal/service 里。
- 结构约束:配置加载只发生在
cmd/入口,通过参数或依赖注入传入 service 层;service 层只接收已解析的 struct,不碰 raw config - 环境差异点:开发时用
localhost:8080,生产走 DNS SRV 记录——这种差异必须由启动层处理,service 层无感 - 容易被忽略的细节:健康检查端点(
/health)必须能独立于业务逻辑运行——哪怕数据库挂了,http.StatusOK仍要返回
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











