基本规则
- •只能改必要的代码 也就是在更改最少代码的情况下实现用户的目标
- •尽可能使单个文件中的代码功能单一 只执行某个特定功能 减少单个文件行数
- •请勿在任何代码中添加任何注释
- •请注意代码的可读性 有合理换行和缩进
- •在每个块之间有一个空行
核心原则
核心原则: 系统性设计优先
禁止就近解决 每一个实现都必须从系统层面思考 而非只解决眼前的单点问题
当用户提出需求时 思考顺序是:
- •这个需求属于哪个系统/子系统?
- •该系统是否已存在? 是否有可复用的基础设施?
- •如果不存在 应该设计怎样的通用系统来支撑这个需求及其同类需求?
- •最后才是具体实现
1. 唯一真相源
- •常量/配置/共享参数只允许定义在一个地方
- •多个模块需要的值 → 创建统一的 constants/config 模块 所有消费方从中导入
- •实现前搜索已有定义 禁止重复定义
- •添加参数前检查是否已有同类参数存在
反面案例: entity/world/celestial 中各自定义了 time_scale 正确做法: 唯一的 time 模块导出 time_scale 所有系统引用它
2. 分层架构
- •严格依赖方向: Core/Logic 层绝不依赖 Rendering/UI/Platform 层
- •Rendering/UI 层通过明确定义的接口依赖 Core/Logic 层
- •Logic 层必须平台无关 — 不允许出现任何平台特定的 API 调用
- •实现逻辑时 为外部依赖定义抽象接口 不直接调用具体实现
- •跨层需求拆分为: (1) 核心逻辑模块 (2) 抽象接口 (3) 平台/框架特定适配器
反面案例: 系统中直接调用渲染API来绘制调试线 正确做法: 系统输出调试数据 渲染层读取并绘制
3. 泛化优先
- •被要求"添加X"或"创建Y"时 通过通用系统(工厂/注册表/组件组合/配置驱动)实现 禁止硬编码
- •所有实体/对象必须可通过数据/配置构建 — 不允许存在特定实例的专属代码路径
- •测试/调试用的实体使用与正式环境相同的构建管线
- •如果实现只对一个特定案例有效 则实现有误 — 在继续之前先向用户确认泛化范围
- •编写实体/对象创建代码前 确认工厂/构建器/注册系统是否存在并使用它
反面案例: 用硬编码坐标和属性创建一个测试球体 正确做法: 通过通用 entity spawner 从配置数据创建任意实体
4. 去重 (Deduplication)
- •实现任何功能前 搜索已有的同类实现
- •如果相似代码已存在于 2+ 个位置 先重构为共享模块 再添加新功能
- •禁止创建"平行系统" — 扩展已有系统 或提出重构方案
反面案例: 为新模块单独写一套事件系统 而项目中已有一个 正确做法: 复用/扩展已有的事件系统
5. 模块边界 (Module Boundaries)
- •每个模块有明确的单一职责
- •模块间通过接口/trait/protocol通信 不直接访问内部实现
- •共享数据通过明确定义的数据通道传递 不通过全局可变状态
- •跨模块的功能需求通过组合而非继承解决
6. 数据驱动 (Data-Driven Design)
- •行为由数据/配置决定 而非由代码分支决定
- •场景/关卡/预设等内容是数据文件 不是代码
- •新增一个变体应该只需要添加一条数据 而不是写新代码
- •如果添加一个新类型需要修改多处 switch/match 说明架构需要重构
7. 实现前检查清单
每次写代码前 按顺序检查:
- • 搜索已有的同类功能/常量/系统
- • 确认所属系统/模块的边界
- • 确认依赖方向是否合规(不向上依赖)
- • 确认实现是否泛用(不止适用于一个案例)
- • 如果不确定泛化范围 先询问用户
子规范
Go/JS/TS/Rust/PHP/Java等代码风格书写规范 用户界面设计规范 CSS代码风格书写规范 纯原生HTML代码风格书写规范 Vue代码风格书写规范