将所有 IoT 相关的数据模型从 internal/iot/model/ 迁移到 internal/model/, 实现全局统一的模型层架构,符合项目横向分层设计原则。 变更内容: - 迁移 11 个 IoT 模型文件(carrier, iot_card, device, order, package 等) - 删除 internal/iot/model/ 目录 - 更新文档中的模型路径引用(25 处) - 创建重构总结文档 - 归档 OpenSpec 变更为 2026-01-12-refactor-iot-model-location - 创建 model-organization 规格文档 验证结果: - 编译通过(go build 成功) - 静态分析通过(go vet 无错误) - 代码格式通过(go fmt 无变更) - 无 Go 代码引用旧路径 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
8.3 KiB
8.3 KiB
设计文档:IoT 模型位置重构
问题陈述 (Problem Statement)
当前 IoT 模块的数据模型被放置在 internal/iot/model/ 目录下,这与项目的架构约定不一致。根据 openspec/project.md 的架构规范,项目采用严格的四层架构:
Handler 层 → Service 层 → Store 层 → Model 层
其中 Model 层 应该是全局统一的,所有模型都应该放在 internal/model/ 目录下。当前的 IoT 模型位置违反了这一约定。
当前架构问题分析
1. 目录结构不一致
当前状态:
internal/
├── model/ # 大部分模型在这里
│ ├── account.go
│ ├── shop.go
│ ├── enterprise.go
│ ├── personal_customer.go
│ ├── role.go
│ ├── permission.go
│ └── ...
├── iot/
│ └── model/ # IoT 模型单独在这里 ❌
│ ├── carrier.go
│ ├── commission.go
│ ├── iot_card.go
│ └── ...
存在的问题:
- 模型分散在两个位置,违反了单一数据模型层的设计原则
- 导入路径不一致:
internal/modelvsinternal/iot/model - 新开发者容易困惑,不知道应该把新模型放在哪里
2. 违反项目架构约定
根据项目架构规范,四层架构应该是 横向分层,而不是 纵向按模块分层:
正确的架构(横向分层):
internal/
├── handler/ # 所有 Handler
│ ├── user_handler.go
│ ├── shop_handler.go
│ └── iot_handler.go # IoT 的 Handler
├── service/ # 所有 Service
│ ├── user_service.go
│ ├── shop_service.go
│ └── iot_service.go # IoT 的 Service
├── store/ # 所有 Store
│ ├── user_store.go
│ ├── shop_store.go
│ └── iot_store.go # IoT 的 Store
└── model/ # 所有 Model ✅
├── user.go
├── shop.go
└── iot_card.go # IoT 的 Model
错误的架构(纵向按模块分层):
internal/
├── user/ # 用户模块(纵向)
│ ├── handler.go
│ ├── service.go
│ ├── store.go
│ └── model.go
├── shop/ # 店铺模块(纵向)
│ ├── handler.go
│ ├── service.go
│ ├── store.go
│ └── model.go
└── iot/ # IoT 模块(纵向)❌
├── handler.go
├── service.go
├── store.go
└── model/ # 违反横向分层原则
└── iot_card.go
3. Go 语言惯用设计原则
根据 Go 语言的包组织最佳实践:
- 包应该扁平化:避免深层嵌套(最多 2-3 层)
- 包应该按功能组织:
model包应该包含所有数据模型,不是按业务模块分散 - 包名应该描述功能:
model表示数据模型,而不是iot/model(冗余)
当前 internal/iot/model 的包名虽然是 package model,但实际导入路径是 internal/iot/model,这是不必要的复杂性。
设计决策 (Design Decision)
决策: 将所有 IoT 模型迁移到 internal/model/ 目录,与项目的其他模型保持一致。
为什么选择统一的 Model 层?
- 符合项目架构约定:遵循严格的横向四层架构(Handler → Service → Store → Model)
- 简化导入路径:所有模型统一使用
internal/model导入 - 提高代码可维护性:开发者只需要在一个地方查找所有数据模型
- 符合 Go 语言惯用设计:扁平化包结构,按功能组织
- 降低认知负担:新开发者不需要猜测模型应该放在哪里
为什么不保留 internal/iot/model?
反驳方案 1:按业务模块组织(纵向分层)
internal/
├── iot/
│ ├── model/ # IoT 模型
│ ├── service/ # IoT 服务
│ └── store/ # IoT 存储
缺点:
- 违反项目架构约定(横向分层)
- 导致模型分散,难以统一管理
- 跨模块调用时需要引用不同的 model 包(如
iot/model和internal/model) - 不符合当前项目已有的架构实践
反驳方案 2:IoT 模型使用子包(internal/model/iot)
internal/
├── model/
│ ├── user.go
│ ├── shop.go
│ └── iot/ # IoT 子包
│ └── iot_card.go
缺点:
- 引入不必要的层级嵌套
- 导入路径变为
internal/model/iot,不符合项目惯例 - 其他模型(User、Shop)没有子包,为什么 IoT 要特殊对待?
- 增加认知负担:需要记住哪些模型有子包,哪些没有
最终方案:扁平化模型目录
internal/
└── model/
├── account.go
├── shop.go
├── enterprise.go
├── personal_customer.go
├── role.go
├── permission.go
├── carrier.go # IoT 相关模型
├── commission.go # IoT 相关模型
├── data_usage.go # IoT 相关模型
├── device.go # IoT 相关模型
├── financial.go # IoT 相关模型
├── iot_card.go # IoT 相关模型
├── number_card.go # IoT 相关模型
├── order.go # IoT 相关模型
├── package.go # IoT 相关模型
├── polling.go # IoT 相关模型
└── system.go # IoT 相关模型
优点:
- 符合项目架构约定(横向分层)
- 所有模型统一管理,易于查找和维护
- 导入路径统一(
internal/model) - 符合 Go 语言扁平化包结构的最佳实践
- 与项目现有架构保持一致
实施风险评估
风险等级:低
理由:
- 无代码引用:经过搜索,当前项目中没有任何代码引用
internal/iot/model(因为 IoT 模块尚未完全实现) - 纯文件移动:只需要移动文件,不需要修改文件内容(包名已经是
package model) - 无数据库影响:模型位置变更不影响数据库表结构或迁移脚本
- 无 API 影响:模型位置变更不影响 API 接口定义
潜在风险
风险 1:并发开发冲突
- 描述:如果在重构期间有其他开发者新增了对
internal/iot/model的引用 - 缓解措施:在重构前和重构后都执行全局搜索,确保无遗漏引用
- 恢复方案:如果发现遗漏引用,只需要更新导入路径即可(从
internal/iot/model改为internal/model)
风险 2:Git 历史追踪
- 描述:Git 的
git log或git blame可能无法自动追踪文件移动历史 - 缓解措施:使用
git mv命令移动文件(或确保提交信息清晰说明文件移动) - 影响评估:低(可以通过
git log --follow追踪文件历史)
验收标准 (Acceptance Criteria)
-
目录结构正确:
internal/iot/model/目录不存在- 所有 11 个 IoT 模型文件都在
internal/model/目录下
-
包名一致性:
- 所有模型文件的包名都是
package model
- 所有模型文件的包名都是
-
无遗漏引用:
- 项目中不存在
internal/iot/model的引用
- 项目中不存在
-
编译成功:
- 执行
go build成功,无错误
- 执行
-
测试通过:
- 执行
go test ./...成功(如果存在测试)
- 执行
后续改进建议
虽然本次重构只涉及模型位置,但建议后续也考虑其他架构一致性改进:
- 完善 IoT Handler 层:创建
internal/handler/iot/或internal/handler/iot_handler.go - 完善 IoT Service 层:创建
internal/service/iot/或internal/service/iot_service.go - 完善 IoT Store 层:创建
internal/store/postgres/iot_store.go - 删除空的
internal/iot/目录(如果迁移后为空)
参考资料
- 项目架构规范:
openspec/project.md - Go 包组织最佳实践:Effective Go - Package names
- Go Code Review Comments:Go Wiki - Package names
- 现有模型目录:
internal/model/ - IoT 规格文档:
openspec/specs/iot-card/spec.md