Skip to content

Latest commit

 

History

History
285 lines (226 loc) · 17.1 KB

File metadata and controls

285 lines (226 loc) · 17.1 KB

代码规范

修订记录

修订时间(CST) 修订人 修订说明
2026-08-31 whisper 明确 Prism 应用构建配置职责
2026-08-31 whisper 明确通用规范与 Aegis 文档边界
2026-08-28 whisper 接入 EditorConfig 编辑器基线
2026-08-28 whisper 明确忽略与属性文件注释编码
2026-08-27 whisper 拆分开发流程与代码规则职责
2026-08-27 whisper 明确 Aegis 标签与作者分组
2026-08-27 whisper 统一 Processor 与 Meta 参数命名
2026-08-26 whisper 补充公开注解命名规则
2026-08-26 whisper 明确私有成员与 backing property 命名
2026-08-26 whisper 补充 UI 状态与 Effect 组合命名
2026-08-26 whisper 建立 Starter 通用代码规范

本文只定义 Android Starter 的通用代码书写和命名规则. 变更决策, 任务拆分, 验证, 文档同步和 Git 提交遵守 开发规范; 模块职责, 公开契约和接入方式仍以各模块的 design.md, development.mdusage.md 为准.

1. 适用范围

本文适用于所有维护者, 自动化工具和智能体在仓库内编写的 Kotlin, XML, Gradle Kotlin DSL, TOML, ProGuard / R8 规则和测试代码.

Starter 是面向不同应用的公共基座. 规范只约束可复用的工程和编码行为, 不固化具体应用的域名, 环境, 错误码, 鉴权方式, 业务字段或 页面规则.

2. 语言和文本

  • 代码标识符使用英文, 不使用中文, 拼音, 拼音首字母或含义不明的自造缩写.
  • 注释和项目文档使用中文, 标点使用半角符号.
  • .gitignore*.properties*.prop 文件的注释使用英文 ASCII, 避免工具链默认编码差异影响解析或显示.
  • 日志, 异常信息和测试失败信息使用英文, 避免控制台编码问题.
  • 用户可见文案放入 string 资源或由业务配置提供, 不在 Kotlin 和布局 XML 中散落硬编码文案.
  • 允许通用且含义稳定的缩写, 例如 id, url, api, db, io, ui, reqresp.

3. Kotlin 基础规则

3.1 格式和文件组织

  • 遵循 Kotlin 官方编码风格和项目现有格式, 使用 4 个空格缩进.
  • 根目录 .editorconfig 是编辑器可执行的基础格式配置. 无法由 EditorConfig 表达的命名, 分层和 API 规则仍以 本文为准.
  • 一个可独立复用的 public 顶层类型默认对应一个 .kt 文件, 文件名与主类型名一致.
  • 仅服务当前文件的 private 辅助类型, 函数和常量可以与主类型放在同一文件.
  • 与主类型强绑定且体量较小的 sealed 层级, 状态或参数可以放在同一文件.
  • 不使用 Models.kt, Utils.kt, Managers.kt 等宽泛文件名聚合无关职责.
  • import 应明确且稳定, 不使用通配符 import.

类内成员建议按以下顺序组织:

  1. companion object 和常量.
  2. public / protected 属性.
  3. private 属性.
  4. 初始化和生命周期方法.
  5. public / protected 方法.
  6. private 方法.

3.2 类型和可见性

  • 常量, 成员属性, 公开参数和公开返回值应保留显式类型.
  • 局部变量的类型不明显, 参与跨层契约或显式类型有助于审查时, 写出类型.
  • 可以不可变时使用 val; 只有需要重新赋值时使用 var.
  • 使用满足职责所需的最小可见性, 不把模块实现细节暴露为 public API.
  • api(...) 只用于调用方源码或 ABI 确实需要看到的依赖, 其它依赖优先使用 implementation(...).
  • Long 字面量使用大写 L.

3.3 空安全

  • 只有调用方已经证明非空, 且失败代表编程错误时才使用 !!.
  • 可空链路优先使用安全调用, Elvis, 作用域函数或提前返回表达处理意图.
  • lateinit 只用于生命周期和初始化时机明确的对象.
  • 公开 API 使用 Kotlin 类型表达可空性, 不用注释替代类型契约.
  • 外部传输字段按真实契约声明可空性. 缺字段, 空字符串和数值 0 语义不同时必须保留区分能力.
  • 类型转换优先使用 as? 并处理失败分支.

3.4 控制流和集合

  • if, else, forwhile 默认使用大括号.
  • 处理 enum 或 sealed 类型时优先使用可穷尽的 when; 处理外部输入时提供明确兜底.
  • 不在遍历同一个可变集合时直接执行 add / remove.
  • 自定义对象作为 Set 元素或 Map key 时, equals()hashCode() 必须保持一致语义.
  • 并发读写不使用无保护的普通可变集合.

4. 命名

4.1 通用命名

  • 包名全小写, 使用点分隔自然语义英文单词, 不使用下划线.
  • 类型和泛型参数使用 UpperCamelCase.
  • 函数, 属性, 局部变量和参数使用 lowerCamelCase.
  • 常量和 enum 成员使用 UPPER_SNAKE_CASE.
  • 测试类以被测类型名开头并使用 Test 后缀.
  • 异常类型使用 Exception 后缀.
  • 只有角色稳定且能帮助理解时才使用 Factory, Adapter, Provider, Repository, Processor 等后缀.
  • XxxProcessor 类型的处理器参数统一命名为 processor, 不使用容易与 Android Handler 混淆的 handler.
  • 业务领域管线中的元信息统一命名为 meta, 不在同一契约中混用 metadata.
  • 普通私有成员使用 lowerCamelCase, 不添加 _ 前缀, 例如 repositorybindingJobbindingLifecycleOwner.
  • 只有私有可变属性作为同语义公开只读属性的 backing property 时使用 _ 前缀, 例如 _uiState / uiState_noticeUiEffectFlow / noticeUiEffectFlow.
  • _ 表示 backing property, 不用于笼统标记 private 或可变属性.
  • 不使用 Java 时代的 mNamesName 等成员前缀.
  • 选择某个策略类型的注解使用 UseXxx 命名, 避免与被选择的接口或类同名.
  • 成对的公开概念使用完整限定词, 例如 ApplicationInterceptors / NetworkInterceptors, 不用语义不对称的简写.

4.2 模型角色后缀

模型命名遵循"语义名称 + 角色后缀". 包名用于归类, 不能代替类型名中的角色后缀. 领域层模型是例外: 领域语义本身足够完整时不强制添加 技术后缀.

角色 命名形式 示例 说明
领域模型 Xxx Business 以业务或领域语义命名, 不强加技术层后缀
数据库存储模型 XxxEntity UserEntity 表示持久化结构, 不直接作为 UI 模型
网络请求模型 XxxReq LoginReq 表示外部请求契约
网络响应模型 XxxResp ProfileResp 表示外部响应契约
UI 渲染模型 XxxUiModel NoticeUiModel 表示已整理为界面消费形态的数据
UI 持续状态 XxxUiState ActiveOperationCountUiState 表示界面在当前时刻可重建, 可观察的持续状态
UI 一次性行为 XxxUiEffect LoginUiEffect 表示导航, 提示等不应通过持久状态重复消费的行为
AndroidX ViewModel XxxViewModel GettingViewModel 不使用 VM 代替公开类型后缀
异常 XxxException BusinessException 表示异常对象, 不使用错误码模型替代异常类型

补充约束:

  • UiStateUiEffect 必须按行为语义区分, 不能仅按当前承载的字段区分.
  • StateFlow<XxxUiState> 表达持续状态, 不应命名为 Effect.
  • 一次性通知可以使用 Flow<XxxUiModel> 或建模为 XxxUiEffect; 是否引入 Effect 取决于它是否是完整的行为集合.
  • XxxUiState 只表达持续状态, 可以是状态数据, 也可以是只读 StateFlow 契约, 但不能同时承载 Effect Flow.
  • XxxUiEffect 表达一次性行为契约, 可以通过不重放的 SharedFlow<XxxUiModel> 提供渲染载荷.
  • 多个窄状态 / Effect 契约经常共同使用时, 使用 Owner 组合能力; 只做接口聚合时不额外引入 Store.
  • NoticeUiModelNotice 表示语义, UiModel 表示角色, 即使它位于 model.ui 包中也不省略后缀.
  • 不使用 VO 作为统一 UI 后缀, 它容易与 Value Object, View Object 混淆.
  • 不使用 UiMessageUiModel 这类重复堆叠 UI 语义的名称. 通知语义优先使用 NoticeUiModel.
  • 避免将自定义类型直接命名为 Message, 防止与 android.os.Message 及其它框架类型产生歧义.

4.3 跨层转换命名

  • 跨边界模型使用显式转换函数, 例如 toUserEntity(), toProfileUiModel().
  • 转换函数名称应与目标类型一致, 类型重命名时同步调整函数名和调用点.
  • UI, 数据库和网络模型不通过 typealias 假装为领域模型.
  • 不在 architecture 层解释应用响应结构, 业务错误码或 Meta 内容; 具体映射与解释放入应用的 foundation 层.

5. 数据与状态边界

  • 跨网络, 数据库, 领域和 UI 边界时使用各自的明确模型, 不让外部契约直接渗透到所有层.
  • 公共 architecture 只定义技术抽象和泛型管线, 不假设响应一定包含 code, messagedata.
  • foundation 可以实现具体应用的响应拆包, Meta 建模, 错误修复和领域映射.
  • app 是环境, 域名和应用装配的组合根.architecture 与 foundation 不读取 app 的 BuildConfig 或解释 flavor.
  • 数据管线不得静默丢弃已经建模的主要载荷或 Meta, 包括失败响应中的可用数据.
  • Loading, 成功和失败属于数据加载状态; Idle 仅在调用方确实需要表达"尚未开始"时引入.

6. 协程和 Flow

  • Android 异步任务优先使用结构化协程, 不直接创建裸线程.
  • Dispatcher 由执行环境或调用方注入 / 选择, 可复用模块不硬编码无法替换的全局调度策略.
  • 不捕获并吞掉 CancellationException; 取消必须继续传播.
  • Flow 默认保持冷流和可重复收集语义. 转换操作不得隐藏额外的永久作用域.
  • UI 收集使用生命周期感知 API, 并明确持续状态与一次性事件的重放策略.
  • SharedFlow / StateFlow 的 replay, buffer 和溢出策略属于可观察契约, 修改时必须同步测试和文档.
  • 不在锁内执行网络, 数据库, 文件 IO 或可能回调外部代码的操作.

7. 注释

7.1 顶层类型

新增 class, interface, data class, enum, annotation 和公开 sealed 类型时使用中文 KDoc:

/**
 * 类型的简要说明.
 *
 * 必要时补充职责边界和容易误用的行为.
 *
 * @author whisper
 * @since 2026/08/26
 */
  • @author 优先读取根目录 local.properties 中的 author; 缺失时使用仓库 Git 作者配置; 仍无法确认时询问维护者.
  • @since 使用类型创建日期, 格式为 yyyy/MM/dd, 不因后续修改而更新.
  • 内部类型需要说明职责, 但不要求 @author@since.
  • 数据类构造属性优先在类 KDoc 中使用 @property 说明, 避免在字段上重复同一内容.
  • 方法名已完整表达行为时不强制注释; 复杂约束, 单位, 边界和异常必须通过 KDoc 说明.
  • 注释解释原因, 契约或限制, 不逐行复述代码.

7.2 Aegis 契约标记

@aegis 用于标记已经确认的公共契约或可观察行为, 主要为智能体提供修改边界. 人工维护者可将其作为兼容性审查提示; 智能体的授权和审计要求见根目录 AGENTS.md.

@aegis 与其后的全部 @aegis-audit 连续书写为一个标记组. 标记组结束后保留一行仅含 * 的 KDoc 空行, 再书写 @author@since:

 * @aegis 保护公开契约和可观察行为.
 * @aegis-audit 2026-08-27 | whisper | 简要说明本次授权修改原因.
 *
 * @author whisper
 * @since 2026/08/27

8. 异常, 日志和隐私

  • 不使用异常控制普通业务流程.
  • try-catch 只包裹可能失败的代码, 捕获后必须处理, 转换, 记录或继续抛出.
  • 底层异常文本不直接展示给用户, 应在应用边界转换为适合 UI 的通知模型.
  • 项目提供 lazy 日志 API 时优先延迟构建消息, 避免关闭日志后仍执行高成本表达式.
  • 不记录密码, 完整 token, Cookie, 身份证号, 手机号, 精确地址, 完整请求体等敏感信息.
  • 临时诊断信息也必须脱敏, 并在交付前删除临时代码, 不能仅依赖 Release 日志开关.

9. 网络和持久化模型

  • 网络模型使用 Req / Resp 后缀, 并显式声明序列化字段映射.
  • Kotlin 属性使用客户端正确命名, 服务端的历史或错误字段名只保留在序列化注解中.
  • Room 模型使用 Entity 后缀, 显式声明表名, 主键和列映射.
  • 不把真实域名, token, 证书信任策略或应用错误码写入公共 architecture 模块.
  • app 负责选择域名和安装应用级网络组件; 下层只依赖注入的抽象和配置值.
  • 禁止加入信任所有证书或主机名的占位实现.

10. Android 资源和 XML

  • library 资源使用稳定的模块前缀, 并优先通过 resourcePrefix 约束.
  • 资源名, 文件名和 View id 使用小写单词加下划线.
  • 通用资源放入公共归属模块, 页面或业务专用资源就近维护.
  • 颜色按语义命名, 不只按色值命名; 主题色, 状态色和跨页面值进入资源.
  • 简单图标优先使用 VectorDrawable, 照片和复杂插画使用合适的位图格式.
  • 图片 View 必须有明确尺寸, 比例或布局约束, 不用无约束 wrap_content 承接大图.
  • 不使用滚动容器直接嵌套同方向的列表控件.
  • Manifest 组件显式声明 android:exported; 不对外开放时设为 false.

11. Gradle 和构建配置

  • 构建脚本使用 Kotlin DSL.
  • 依赖及插件版本优先由 gradle/libs.versions.toml 统一管理.
  • 优先复用 build-logic 中已有约定插件, 但可选插件不得成为所有模块的隐式前提.
  • Prism 只负责可选的应用构建配置生成; 未接入 Prism 的项目仍应能够使用标准 Android 构建配置.
  • flavor, BuildConfig 和环境回退值由 app 或根构建配置维护, 不在下层业务 / 架构模块重复声明.
  • KSP, Aster, Habitat 等生成链路使用各自的 Gradle 配置, 不混入普通 implementation.
  • 新增 keep rule 时说明反射, 序列化, JNI, 路由或插件发现等真实原因, 并保持范围最小.
  • 构建逻辑或依赖变更至少验证受影响模块的编译; 公共插件变更应覆盖接入和未接入两种路径.

12. 测试

测试名称表达"被测行为 + 场景 + 期望结果":

@Test
fun loadProfile_whenResponseFails_preservesPayloadAndMetadata() {
    // ...
}
  • 单元测试优先覆盖纯转换, 状态流, 边界条件, 异常映射和并发契约.
  • Android Framework, Room, Manifest, 路由和生命周期行为使用 instrumented test 或对应集成测试.
  • fixture 放在测试源码集, 不污染生产代码.
  • 不为测试放宽生产 API 可见性, 暴露内部状态或增加无业务价值的构造参数.
  • 时间, 线程, 随机数, 网络和文件系统应可控, 避免不稳定测试.
  • 修复缺陷时补充能复现问题的测试; 修改公共契约时同步更新测试和模块文档.

13. Markdown 文档

  • 新增或实质修改 Markdown 文档时同步更新顶部修订记录.
  • 修订人按顶层类型的作者解析规则确定; 不追改历史记录中的作者.
  • Markdown 表格每行以 | 开头和结尾, 同列源码宽度保持一致.
  • 文档链接使用相对路径并在提交前检查目标存在.
  • 命令, 包名, 类型名和路径使用反引号.

14. 代码完成自查

以下检查聚焦代码本身. Git 暂存, 拆分和提交规则以 开发规范 为准.

检查项 要求
命名 模型角色后缀明确, 无拼音, 自造缩写或重复 UI 语义
分层 architecture 不解释业务, app 负责环境和装配
数据 跨层映射显式, 不静默丢弃主要载荷或 Meta
状态 UiStateUiEffect 行为清晰, Flow 重放策略正确
空安全 可空性准确, 不使用 !! 掩盖不确定状态
API 可见性最小, 稳定契约已完成兼容性审查
日志 无凭据, 个人信息, 请求体等敏感内容
构建 版本目录和约定插件使用合理, 未滥用 api(...)
测试 验证范围覆盖实际风险, 不为测试污染生产 API
文档 模块文档, 链接和修订记录与实现一致