diff --git a/docs/code-style.md b/docs/code-style.md index 11026e3..2afe56a 100644 --- a/docs/code-style.md +++ b/docs/code-style.md @@ -11,6 +11,15 @@ | Middleware | ≤ 60 行 | 单一职责 | | Router | ≤ 60 行 | 只做路由映射 | +> **注意**:以上为建议上限,不是硬性指标。**是否拆分取决于职责是否内聚**,而非单纯看行数。拆分决策矩阵: + +| 该拆 | 不该拆 | +|------|--------| +| 多个独立功能塞一个文件(如 7 个 Tab 的 JS 全混居 + 5 个 IIFE) | 页面内区域共享大量样式,拆了反而碎片化(如文章详情/列表共用 `article-card`) | +| 一个文件承担了压根不同域的工作(如所有 API 路由写一个文件) | 功能高度耦合,拆了互相 import 更乱(如评论增删查+@提及+上传一体) | +| CSS 随 HTML 模板拆分自然跟随 | 公共工具函数拆成碎片没有意义 | +| 路由文件按业务域自然分割(与 admin.go 对齐) | 文件超线但职责单一、内聚良好 — 维持现状 | + ## 瘦控制器铁律 Controller 每个方法不超过三步: @@ -75,15 +84,17 @@ func (c *PostController) Create(ctx *gin.Context) { ### 响应格式 -统一使用 `common` 包的响应函数: +统一使用 `common` 包的响应函数,HTTP 状态码直接传入: ```go -common.Ok(ctx, data) // 200 成功 -common.Error(ctx, common.ErrInvalidParam, msg) // 400 参数错误 -common.Error(ctx, common.ErrUnauthorized, msg) // 401 未认证 -common.Error(ctx, common.ErrForbidden, msg) // 403 无权限 -common.Error(ctx, common.ErrNotFound, msg) // 404 未找到 -common.Error(ctx, common.ErrInternal, msg) // 500 服务器错误 +common.Ok(c, data) // 200 成功 +common.OkWithMessage(c, data, "操作成功") // 200 带消息 +common.OkMessage(c, "操作成功") // 200 纯消息 +common.Error(c, http.StatusBadRequest, "参数错误") // 400 +common.Error(c, http.StatusUnauthorized, "请先登录") // 401 +common.Error(c, http.StatusForbidden, "权限不足") // 403 +common.Error(c, http.StatusNotFound, "未找到") // 404 +common.Error(c, http.StatusInternalServerError, "服务器错误") // 500 ``` ### 模板变量 @@ -120,3 +131,40 @@ type siteSettingUseCase interface { GetAuditSettings(defaults *service.AuditDefaults) *service.AuditSettings } ``` + +各 Controller 自身的 ISP 声明放在对应的 `interfaces.go` 文件中,严禁 controller 直接 import 完整的 Service 结构体。 + +## 设计原则 + +| 原则 | 含义 | 本项目实践 | +|------|------|-----------| +| **YAGNI** | You Ain't Gonna Need It — 不为可能的需求提前实现 | 分 Phase 推进,不做预留接口/未用抽象层 | +| **DIP**(依赖倒置) | 高层模块不依赖低层,都依赖抽象 | Controller → ISP 接口 ← Service;Service → Store 接口 ← Repository | +| **SRP**(单一职责) | 一个模块只为一个角色变更 | 拆分决策:「多域混居则拆,内聚共享则留」 | +| **OCP**(开闭原则) | 对扩展开放,对修改关闭 | `config.yaml` 角色/审核配置可扩展,不改代码 | +| **ISP**(接口隔离) | 不依赖用不到的接口 | Controller 只声明自己需要的方法子集,见下方 ISP 章节 | +| **KISS** | Keep It Simple | 连续字符校验纯函数、密码强度 switch-case,不做策略模式/DI 框架 | + +### 架构风格 + +分层架构 + ISP 接口隔离,非纯六边形。Gin、GORM 等框架层不额外抽象,仅在业务边界通过接口倒置依赖方向: + +``` +Web 适配器 (Gin Controller) → ISP Ports (interfaces.go) + ↓ +Service 核心逻辑 + ↓ +Store Interfaces (repository.go) ← DB 适配器 (GORM Repo) +``` + +## 重构原则 + +### 不向后兼容 + +本项目为全新项目,尚未发布正式版。**重构时直接废弃旧实现,不做兼容层**,不保留任何向后兼容代码。遇到旧代码直接删除/覆盖,不新增 `deprecated`、`legacy` 等标记或包装函数。 + +### CMS 化 + +所有面向最终用户的硬编码文本(品牌名、标语、邮箱、空状态提示、系统消息等)应纳入 `site_settings` 表配置化,而非硬编码在模板或 Go 代码中。管理后台需提供对应输入项。 + +例外:CSS 注释、JS debug 日志、代码中的技术常量不受此规则约束。