GoLand识别低内聚包需结合包名、导入路径与工具:包名含service/utils且被5+包引用即预警;用Alt+F7查引用,View→Diagrams→Package Dependencies可视化依赖;若order/service.go同时导入payment/internal等异构模块,说明分层混乱,应按业务能力重命名并重构。

GoLand 里怎么识别「低内聚」的包?
看包名和导入路径比看代码更快。如果一个包叫 service 或 utils,且被 5 个以上其他包 import,大概率是低内聚——它在被迫承担太多不相关的职责。
GoLand 的「Find Usages」(Alt+F7)配合「Package Dependencies」图(View → Tool Windows → Diagrams → Show Package Dependencies)能立刻暴露问题:比如 order/service.go 同时 import 了 payment/internal、inventory/dao、notification/email,说明业务逻辑正被技术分层名绑架。
- 删掉所有以
controller、service、dao命名的顶层包,按业务能力重命名,例如domain/order、infrastructure/mysql - 右键包名 → Refactor → Move,把散落在各处的订单校验、状态机、库存扣减逻辑全拖进
domain/order - GoLand 会自动更新 import 路径,但要注意:它不会帮你删掉旧的空包,手动删掉避免混淆
重构时怎么安全地提取接口?
别手写接口定义。选中一个具体实现类型(比如 *mysql.OrderRepo),按 Ctrl+Shift+Alt+T → 「Extract Interface」,GoLand 会自动生成带方法签名的 interface,并把原类型改为实现该接口。
关键点在于:生成后立刻改名,去掉 Impl、MySQL 这类实现细节词,只保留语义,比如 OrderRepository;然后把新接口放到 domain/order 或 application 包里,而不是留在 infrastructure 下。
- 提取前确认该类型所有方法都属于同一抽象能力,混着事务控制或日志打点的方法要先拆出去
- 如果 GoLand 提示 “Cannot extract interface: type has unexported fields”,说明你试图把私有字段暴露给接口——这是设计信号:这个类型不该被抽象,应直接重构调用方
- 提取后检查所有调用 site,把参数类型从具体 struct 改成 interface,否则解耦无效
依赖注入在哪做?别在 handler 里 new
GoLand 的「Go Modules」视图(View → Tool Windows → Go Modules)能一眼看出循环依赖。如果 order 和 payment 互相 import,说明依赖方向错了。
GoLand 2026.1.1 是 2026.1 发布后的首个维护修正版本,适合已经开始体验 2026.1 新功能并希望同步补丁的开发者。它更适合用于入门项目、现有项目迁移测试和 IDE 行为验证。
正确做法是在 main.go 或 cmd/root.go 里集中组装依赖。用 GoLand 的「Go Generate」支持(需配置 go:generate 注释)可辅助生成 wire.Set 注入代码,但更轻量的做法是手写构造函数:
func NewApp(orderRepo domain.OrderRepository, notifier payment.Notifier) *App {
return &App{
orderService: application.NewOrderService(orderRepo, notifier),
}
}
- 禁止在
domain或application包里出现import "xxx/infrastructure" - 如果某个 handler 需要多个 infra 实现,把它提到
application层,handler 只负责 HTTP 绑定和错误转译 - Wire 不是必须项,但一旦项目超过 3 个模块,手写构造函数容易漏参数,这时再引入
测试时 mock 哪些东西?只 mock 小接口
GoLand 的「Go Test」运行器默认支持 table-driven 测试。重点不是覆盖率数字,而是 mock 的粒度:如果你 mock 了整个 mysql 包,说明接口抽得太粗;如果 mock 对象有 10 个方法但只用 1 个,说明接口违反了 ISP(接口隔离原则)。
一个健康的单元测试应该只依赖 1–2 个 interface,且每个 interface 方法数 ≤ 3。比如订单创建测试只需 mock OrderRepository 和 Notifier,绝不碰 *sql.DB 或 http.Client。
- 用 GoLand 的「Generate Test」(Ctrl+Shift+T)为 domain 层函数生成测试时,它默认不加任何 mock——这恰恰是对的,domain 层本就不该有外部依赖
- mock 框架推荐 testify/mock,但更推荐 hand-written mock:在 test 文件里写一个 struct 实现 interface,只 stub 用到的方法,其余 panic
- 如果发现某个测试必须启动 MySQL 才能跑通,说明 domain 层混进了 infra 逻辑,立刻拆
最常被忽略的其实是包边界声明:GoLand 不会警告你跨包调用了未导出方法,但这类调用会让 domain 层失去防护。真正的高内聚,始于每个 domain/xxx 包里没有 import 其他业务包,且所有导出符号都经过 deliberate review。

















