掌中生活——β冲刺代码规范
掌中生活——代码规范 v2.0(β冲刺)
| 这个作业属于哪个课程 | 202601福大-软件工程实践-W班 |
|---|---|
| 这个作业要求在哪里 | 团队作业—Beta冲刺+事后诸葛亮 |
| 这个作业的目标 | 在 α 规范 v1.0 基础上,补上安全、附件、通知、数据库迁移、测试和 Git 协作的强制条款,作为 β 冲刺的开发规范 |
| 其他参考文献 | 阿里巴巴 Java 开发手册 v1.3.0;Kotlin 官方编码规范;Android Developers 官方文档;团队《代码规范与冲刺计划 v1.0》;《04-接口契约文档 v1.1》;《掌中生活_系统设计说明书 v1.0》 |
目录
- 掌中生活——代码规范 v2.0(β冲刺)
- 一、为什么升到 v2.0
- 二、适用范围和分层约束
- 三、命名、格式和 Kotlin 写法
- 3.1 命名
- 3.2 格式
- 3.3 Kotlin 和 Android
- 四、错误码和日志
- 4.1 错误码
- 4.2 日志
- 五、安全编码(β 的重点)
- 5.1 单一加密边界
- 5.2 明文出口唯一
- 5.3 账号和密码
- 5.4 数据库和备份
- 六、数据库和迁移
- 七、附件
- 八、通知
- 九、界面
- 十、测试和缺陷
- 10.1 测试
- 10.2 缺陷
- 十一、Git 和协作
- 11.1 分支
- 11.2 提交
- 11.3 MR 和 review
- 十二、AI 生成代码
- 十三、提交前检查清单
- 十四、v2.0 和 v1.0 的差异
- 十五、执行
一、为什么升到 v2.0
α 的 v1.0 主要解决命名、格式、注释、异常和 Git 提交,够用,但不够覆盖 β 要做的事。α 期间暴露了几个具体问题:
- D-02 口令长度,SRS 写 8
20,契约写 20,代码常量 32,测试按 820 写,三处口径并存了五天; - 受保护记录的凭据字段在数据库里是密文,但代码里没有加密服务,只能把编辑入口锁掉;
- 个别日志把字段值打了出来;
- 远端 40 多个分支,合并后大多没删;
- 缺陷"修了没合",测试在 dev 上跑还是红。
所以 v2.0 在原来的基础上加了六块:分层的硬约束、安全编码、数据库迁移、附件、通知、测试与缺陷管理。原来的命名、格式、注释、Git 提交规范继续有效,这里不重复全文,只写新增和变化的部分。
三条原则不变:
- 可读性优先。代码首先是给人读的,其次才是给机器跑的。
- 安全约束优先于写法自由。加密边界、掩码、日志脱敏是强制项,违反就是缺陷,不是风格问题。
- 约束尽量下沉到工具。能写进脚本、CHECK、触发器的,不靠自觉。
再加一条:可验证。做完的功能要能指出用什么命令、什么用例、什么截图证明它做完了。
二、适用范围和分层约束
规范适用于 app/src/main/java/com/lifemap/lifemap/ 下的 Kotlin 代码、res/ 资源、tools/ 脚本、数据库脚本、测试代码和提交说明。
项目是 Android 原生、完全离线、Room + SQLite,不申请网络权限。分层和依赖方向如下:
ui(Activity/Fragment/Adapter/ViewModel)
↓ 只能依赖
service(业务服务接口与实现)
↓
domain(纯模型、规则、状态机、掩码投影)
↑
data(Room 实体/DAO/Repository 实现)
↓
core(Result、错误码、时间、安全、定位器)
硬约束:
| 层 | 可以做 | 不可以做 |
|---|---|---|
| ui | 绑定 ViewModel、渲染 UiState、发事件、跳转 | 写 SQL、直接调 CryptoBox、直接 new Repository、手写掩码 |
| service | 编排用例、校验、事务、错误码转换 | 持有 View/Context(Application 除外)、直接拼 SQL |
| domain | 纯函数、模型、规则、状态机、MaskProjector | 依赖 Android 框架、Room、Keystore |
| data | Room 实体/DAO、Repository 实现、加解密字段读写 | 做业务判断、抛裸异常给上层、直接弹 UI |
| core | Result、ErrorCode、时间、CryptoBox、ServiceLocator | 依赖 ui/service.impl(α 出现过 core 反向 import service.impl,属于违规) |
ServiceLocator 是唯一的装配入口。新增服务时在这里加 by lazy,不要在 Activity/Fragment 里自己 new。装配顺序和依赖关系写进契约,不靠猜。
模块边界按 A~I:A 账号、B 记录、C 分类标签、D 附件、F 状态、G 日期、H 提醒、I 检索、Z 安全。跨模块调用走 service 接口,不直接调对方的 impl。
三、命名、格式和 Kotlin 写法
3.1 命名
| 元素 | 规则 | 例子 |
|---|---|---|
| 类/接口 | UpperCamelCase | RecordRepository、SensitivityPolicy |
| 方法/变量 | lowerCamelCase | getRecordById(userId, id) |
| 常量 | UPPER_SNAKE | MAX_FAIL_COUNT = 5 |
| 资源文件 | 全小写下划线 | activity_record_detail.xml |
| 数据库对象 | 小写下划线,主键 {表名}_id | reminder_task、record_id |
| 测试方法 | should_行为_when_条件 | should_lock_when_fail_five_times |
| 布尔变量 | is/has/can/should 开头 | isProtected、hasAttachment |
类别(category)和敏感级别(sensitivity)是两个正交维度,字段名不能混用。这是作业 3 就澄清过的口径。
3.2 格式
- 缩进 4 空格,行宽 ≤120,import 按「平台 → 第三方 → 项目」分组,不用通配符;
- 一个方法 ≤40 行,超了拆私有方法;一个文件一个公开类;
- 公开 API 写 KDoc,说明职责、参数、返回和可能抛的错误码;
- 注释解释为什么,不解释是什么。复杂取舍要写清楚,比如"
reminder_task.user_id冗余是为了避免三层 join,这是有意的反范式"; - TODO 必须带 Issue:
// TODO(#71192049): 接入 H 模块提醒生成; - 不提交被注释掉的代码,用 git 历史找回。
3.3 Kotlin 和 Android
- 能不用可空类型就不用;必须可空时,调用处要处理,不滥
!!; - 数据类用
data class,状态用sealed interface/class,不要用一堆布尔标志; - 异步统一
suspend+Dispatchers.IO;UI 层用StateFlow暴露状态,SharedFlow发一次性事件; - ViewModel 不持有 View、Fragment、Activity 引用;Fragment 在
onDestroyView里清 binding; - 资源字符串放
strings.xml,不硬编码中文;颜色、间距、圆角走设计令牌,不在布局里写魔法值; - 不在主线程做数据库、文件、加解密操作;
- 广播、通知、WorkManager 的入口要判空、判权限,不能假设一定拿得到。
四、错误码和日志
4.1 错误码
统一用 LmResult<T> 返回,成功 Success(data),失败 Failure(ErrorCode)。错误码分两类:
- 数据库侧沿用
DBAC-xx,由触发器RAISE(ABORT)携带; - 业务侧用
BIZ-xx,在契约的错误码表里登记,新增必须先改契约。
规则:
- Repository 不把
LmResult往上抛,也不把 SQLException 直接抛给 service;在边界处转成业务错误码; - service 层负责把底层错误翻译成用户能看懂的错误码,UI 只负责展示文案;
- 不用异常做正常流程控制;
- 捕获异常不允许静默吞掉。解密失败按"数据不可用"处理,不降级返回空串,防止用户覆盖真实数据。
4.2 日志
强制条款:
- 日志只记错误码、时间戳、字段名,不记字段值;
- 不打印密码、凭据、金额、证件号、手机号,也不打印密文和密钥;
- 不打印完整 SQL 参数;
Log.d只在BuildConfig.DEBUG下用,release 不留调试日志;- 崩溃日志如果接了第三方,要先脱敏。
反面例子:Log.d("Auth", "login password=$pwd"),这条在 α 出现过,v2.0 起按缺陷处理。
五、安全编码(β 的重点)
5.1 单一加密边界
所有敏感字段和附件只能经过 CryptoBox 读写,明文不能出现在 SQL、日志、异常消息里。加密算法用 Android Keystore 托管密钥的 AES-256-GCM:
- 密钥别名
lifemap_dek,由 Keystore 生成和保管,应用不持久化密钥明文; - 每次加密随机 12 字节 IV,和密文一起存;密文格式
v1:{iv}:{cipher},带版本号,方便以后换算法; - 解密失败返回"数据不可用"的错误码,不返回空串;
- 安全区不可用时走显式降级,必须让用户确认,不能静默降级为明文。
敏感字段清单:record.amount、record.remark、credential.account_name、credential.password、credential.service_name、credential.expire_date,以及受保护记录的附件文件。
5.2 明文出口唯一
- 所有展示统一走
MaskProjector,禁止在 View、Adapter、XML 里手写掩码; - 受保护内容默认掩码,验证通过后才显示明文;验证有效期默认 2 分钟,切后台、超时、点"隐藏"都立即恢复掩码;
- 受保护页面设置
FLAG_SECURE,最近任务缩略图不能出现明文; - 剪贴板 30 秒自动清空,敏感字段不进入剪贴板历史;
- 通知文案只允许出现记录名称、节点类型、剩余天数,金额、账号、密码、证件号一律不进通知;
- 验证失败 5 次锁定 5 分钟,锁定期间正确凭据也不放行;验证和查看行为写
access_log,日志本身不含明文。
5.3 账号和密码
- 口令 8~20 位,必须含字母和数字;上限、下限、正则三处口径必须一致(SRS、契约、代码常量、测试期望);
- 密码只存 PBKDF2-HMAC-SHA256 哈希,20 万次迭代,16 字节随机 salt;不存明文,不存可逆加密;
- "账号不存在"和"密码错误"统一返回
E_LOGIN_FAILED,防止枚举; - 登录失败计数和锁定时间以数据库为准,SharedPreferences 只做缓存,不能再出现两份真相;
- 修改密码成功后旧会话立即失效;密码找回走密保问题或恢复码,重置后同样失效旧会话。
5.4 数据库和备份
- 数据库文件、WAL、备份文件里都不能出现明文敏感值;提交前用
strings或 Database Inspector 抽查; - 受保护记录改为明文、或反过来,要在同一个事务里完成,失败回滚,不允许出现"标记明文但数据还是密文";
- 备份用口令派生密钥(PBKDF2)加 AES-GCM,备份文件不自动上传任何云端位置;
- 恢复前校验完整性、版本和口令,失败回滚,不能破坏本机原有数据。
六、数据库和迁移
- 表结构以
001_init.sql和迁移脚本为准,Room 的@Entity只是映射,不替代 CHECK、触发器和外键; - Room 的
onCreate要先 DROP 由脚本管理的表,再执行脚本重建,避免CREATE TABLE IF NOT EXISTS整条跳过导致 CHECK 丢失(α 踩过); - 数据库版本升级必须写迁移脚本和迁移测试,禁止在 release 用
fallbackToDestructiveMigration; - 迁移脚本要能在旧库上跑通,升级后记录、节点、状态日志、附件关联都在;
- 查询按
user_id隔离,所有列表、详情、搜索、统计都要带账号条件; - 多表写操作放同一个事务;状态变更先改
record.status再插status_log,顺序反了会被触发器 ABORT; - 常用查询字段建索引,新增索引要说明服务的查询场景,不为了保险给所有字段建索引;
- 测试数据用合成数据,不把真实证件、手机号、凭据写进 SQL 夹具。
七、附件
- 来源支持拍照、相册、文件;类型支持 JPG/JPEG/PNG/HEIC/PDF;单文件 ≤10MB,单记录 ≤9 个;
- 文件存应用私有目录
files/attachments/{recordId}/,文件名用 UUID,不用用户原始文件名; - 受保护记录的附件必须加密后落盘,缩略图在未验证时用遮挡块覆盖,预览前先验证;
- 删除记录或替换附件时,要同时删文件和数据库记录,避免孤儿文件;
- 文件被外部清理或损坏时,提示"文件已不可用",应用不能崩;
- 图片预览支持缩放和翻页,PDF 支持翻页;打开大文件不能阻塞主线程;
- 测试附件用自制样例,不用真实证件照片。
八、通知
- 通知渠道 id、名称、重要性在代码里固定,渠道名称用中文;
- Android 13+ 先申请
POST_NOTIFICATIONS,拒绝时保留待办,并在首页显示提示条,点击能跳系统设置; - 每日扫描用 WorkManager,触发时间默认 09:00,启动时补扫一次;同节点同一天只推一次;
- 通知标题统一"掌中生活 · 到期提醒",正文模板"{记录名称} 还有 {剩余天数} 天到达{节点类型},请及时处理。";
- 正文只允许名称、节点类型、剩余天数,不能出现金额、账号、密码、证件号;
- 点击通知进对应记录详情;受保护记录仍要先验证;
- 提供"锁屏时隐藏通知详情"开关。
九、界面
- 用 Material 3 主题,颜色、字体、圆角、间距走设计令牌,不在布局里写死;
- 间距用 4/8 的倍数,常用 8、12、16、24;触控目标不小于 48dp;
- 每个页面都要有加载、空数据、错误三种状态,不能只画有数据的样子;
- 受保护字段显示掩码,记录列表带锁标记;验证弹层说明验证方式、剩余次数、锁定倒计时;
- 文案用简体中文,不出现占位文字、调试信息、英文按钮;
- 320dp 小屏要能正常显示,不横向溢出;
- 图片和图标给
contentDescription,纯装饰图设为null; - 不做深色模式(P2),但颜色不要写死到只在浅色下能看。
十、测试和缺陷
10.1 测试
- 单元测试覆盖正常路径、边界、空数据、异常、权限五类;命名
should_..._when_...,结构按 Arrange-Act-Assert; - 优先用 Fake,不滥用 Mockito;数据库测试尽量在真实 SQLite 上跑;
- 新增业务方法必须有单测或明确的验收记录;UI 关键路径用 Robolectric,至少覆盖登录、掩码、验证弹层、附件遮挡;
- 测试用例对应 FR/AC 编号,AC-38 一条一行,结果只填通过/不通过/阻塞;
- 每个缺陷先写复现用例,修复后用例转绿进基线;D-01
D-06 的探针转成 B-01B-06,每次回归先跑; - 测试数据用合成数据,不写真实个人信息。
10.2 缺陷
- 缺陷 ID 从 B-01 起全局唯一,不再按天编号;
- 状态只有打开、修复中、待验证、关闭;
- "修了没合"不算关闭,必须合入 dev 并回归通过;
- 缺陷清单单一来源
docs/测试/缺陷清单-beta.md,群里说的结论当天入库; - P0/P1 缺陷 48 小时内关闭,P2 可以带到总结里说明。
十一、Git 和协作
11.1 分支
- 只保留
dev(日常集成)、master(发布)和短期feature/{模块}-{Issue号}; - 功能分支活不过 3 天,MR 合并后当天删除;
- 文档、博客、脚本直接提交
dev,不建分支; - 不 force push 到
dev和master;发布打 tag(v0.8.0-beta); - 远端已有的历史分支不再新增,β 结束前统一清理一次。
11.2 提交
格式:feat/fix/docs/test/refactor/chore(scope): 描述 (#Issue)。例子:
feat(crypto): 接入 Keystore AES-GCM 字段加密 (#71234567)
fix(record): 受保护记录编辑保存后回滚 (#71234568)
test(ac): 补 AC-14 掩码验证用例 (#71234569)
一次提交只做一件事,粒度控制在半天内能 review。提交前检查改动范围,不把 IDE 配置、构建产物、临时截图、本地数据库提交上去。
11.3 MR 和 review
合并前必须:
- 本地
assembleDebug通过; - 相关单测通过;
git diff --check没有空白错误;- 至少一人 review;
- 入口可达,附一张运行截图;
- 接口、字段、错误码变更同步了契约和测试期望。
review 三查:规范符合度、缺陷密度(对照错误码)、文档同步。AI 生成的代码和人工代码同一套标准,不因为"AI 写的"就放宽。
十二、AI 生成代码
- 提示词写清五件事:角色、输入材料、任务、约束、输出格式;
- 喂给 AI 的材料要脱敏,真实手机号、证件号、凭据、密钥一律替换;
- AI 只出初稿,不直接合入;合并前人工逐行读,标出采纳、修改、拒绝;
- AI 不得修改契约外的接口、字段、依赖;不得生成真实密钥、绕过权限、关掉校验;
- 生成代码要附规范自查表,说明对应哪条规范、怎么验证;
- 每个任务记三个数:生成条数、人工采纳条数、发现缺陷数,写进每日随笔。
十三、提交前检查清单
- 能编译,
assembleDebug通过; - 相关单测通过,新增方法有用例;
- 没有明文敏感字段进数据库、日志、通知、异常消息;
- 受保护内容展示走
MaskProjector,没有手写掩码; - 新页面有加载、空数据、错误三态;
- 320dp 小屏不溢出;
- 新增/修改的接口、字段、错误码同步了契约和测试;
- 没有提交密钥、Token、真实个人信息、本地数据库、构建产物;
- 提交说明关联 Issue,分支名合规;
- 文档、截图、测试记录已归档。
十四、v2.0 和 v1.0 的差异
| 章节 | v1.0 | v2.0 |
|---|---|---|
| 分层约束 | 有原则,没列表 | 每层能做/不能做,core 反向依赖算违规 |
| 安全 | 提了 CryptoService 和掩码 | 补 Keystore、密文格式、明文出口、验证有效期、锁定、日志、通知、备份 |
| 数据库 | 建表规范 | 补 Room 与脚本顺序、迁移测试、禁止 destructive migration、事务和索引 |
| 附件 | 无 | 补来源、类型、大小、私有目录、加密、缩略图、清理 |
| 通知 | 无 | 补渠道、权限、文案、去重、点击跳转 |
| 测试 | 有单测要求 | 补 Robolectric、AC 映射、探针、缺陷 ID 和关闭口径 |
| Git | 有分支和提交格式 | 补分支收敛、合并即删、MR 六项检查 |
| AI | 有三道关 | 补提示词五要素、脱敏、禁止改契约、度量 |
十五、执行
- 规范从 Day1 起执行,代码 review 按本规范检查;
- 违反强制项(安全、明文、日志、迁移、分支)按缺陷登记,不按风格问题放过;
- 规范条款有异议,站会提,改规范要记 CR,不在代码里各写各的;
- 工具层面目前是
scripts/ci-check.sh(单测 + 数据库验收)加人工 review。ktlint/detekt 没有接入,Day1 有余力再补,不阻塞冲刺; - 本规范的解释权在团队,最后由组长确认。
附:相关文档
- 接口契约 v1.1:仓库
docs/接口契约/ - 系统设计说明书 v1.0:仓库
docs/系统设计说明书/ - 测试计划与报告:仓库
docs/测试/ - 代码仓库:https://codehub.devcloud.cn-north-4.huaweicloud.com/10668555b4754395b09a3ce886e8a3d8/software-schoolwork-lifemap
相关推荐
中级财务管理冲刺试卷二.doc
中级财务管理冲刺试卷二.doc
2021年全国高考物理冲刺信息卷(新课标Ⅲ卷)(一)(原卷版) .pdf
2021年全国高考物理冲刺信息卷(新课标Ⅲ卷)(一)(原卷版)
广东省仲元中学七校联合体2018届高三物理考前冲刺交流考试试题201808210241
广东省仲元中学七校联合体2018届高三物理考前冲刺交流考试试题201808210241
高考理科数学三轮冲刺热点题型 12+4专项练习18精选.doc
高考理科数学三轮冲刺热点题型 12+4专项练习18精选.doc
2013高考理综百天仿真冲刺卷(九)(生物部分)
2013高考理综百天仿真冲刺卷(九)(生物部分)



