鸿蒙百篇系列第 78 篇 · 专家
第 37 篇讲过 CI/CD,第 45 篇讲过测试,第 77 篇讲过设计模式。这篇聚焦一个更现实的问题:当鸿蒙团队从 3 人扩展到 10 人、20 人,怎么保证代码质量和协作效率。
小团队靠口口相传,大团队靠规范和流程。这不是形式主义——当你同时有 5 个开发者在改同一个 HSP 模块,没有规范和 Code Review,代码冲突和逻辑矛盾会让你的集成周期从一天变成一周。
一、ArkTS 代码规范:基于官方指南裁剪
华为有官方的 ArkTS 编码规范文档,覆盖命名、格式、编程实践。但官方规范有几十条,全部落地不现实。建议每个团队从中选取 15-20 条作为"红线规则",其余作为参考。
必选红线规则
以下是建议每个鸿蒙团队都纳入 Code Review 检查的规则:
.eslintrc 配置
DevEco Studio 内置 ESLint,可以在工程根目录的 .eslintrc.json5 中配置:
{
"rules": {
// 命名规范
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "class",
"format": ["PascalCase"]
},
{
"selector": "variable",
"format": ["camelCase"]
},
{
"selector": "const",
"format": ["UPPER_CASE"]
}
],
// 禁止 any
"@typescript-eslint/no-explicit-any": "error",
// 最大嵌套深度
"max-depth": ["error", 4],
// 最大行宽
"max-len": ["warn", { "code": 120, "ignoreUrls": true }],
// 大括号风格
"brace-style": ["error", "1tbs"],
// 引号
"quotes": ["warn", "single"]
}
}
ArkTS 特有的约束
ArkTS 在语言层面比 TypeScript 更严格,有些规则不是 ESLint 配置,而是编译器强制:
禁止
any类型(编译报错)对象字面量必须符合接口定义(不支持动态属性)
@Builder函数内不能有提前 return@Componentstruct 不支持继承函数参数不支持默认值的复杂表达式
这些约束是好事。它们把很多运行时错误提前到了编译期。
二、Code Review 流程
审查清单
Code Review 不是找语法错误——那是 Linter 的活。Code Review 应该聚焦在 Linter 管不到的东西:
架构层面
[ ] 新代码放在了正确的分层(服务层不放 UI 逻辑,UI 层不直接操作数据库)
[ ] 新增模块的接口是否和第 71 篇的分层架构一致
[ ] 是否引入了循环依赖
状态管理
[ ] @State / @Prop / @Link / @StorageProp 选型是否正确
[ ] 是否在不必要的地方使用了 AppStorage(应该用 @State)
[ ] @Watch 回调中有没有重计算或异步操作
性能
[ ] 长列表是否使用 LazyForEach + cachedCount
[ ] 图片是否设置 sourceSize(避免加载原图)
[ ] 条件频繁切换是否用 visibility 替代 if/else
[ ] 是否有主线程同步阻塞调用
安全
[ ] 敏感数据是否加密存储(参考第 79 篇安全审计)
[ ] 网络请求是否校验证书
[ ] 日志是否泄露敏感信息
错误处理
[ ] 异步调用是否有 catch 分支(参考第 72 篇错误体系)
[ ] BusinessError 是否正确分类处理
[ ] 是否有全局兜底错误处理
Review 粒度
一个常见误区:Review 太大。一个 PR 改 2000 行,Reviewer 根本看不过来。建议:
超过限制的 PR 必须拆分。第 71 篇的分层架构让拆分变得可行——改动集中在某一层,天然限制了影响范围。
三、模块间接口契约
大型鸿蒙应用的模块化拆分在第 71 篇和第 34 篇讲过。拆完之后,模块间怎么定义接口?靠口头约定是不行的。
接口定义文件
建议每个 HSP 模块在根目录维护一个 api.ets 文件,只导出对外暴露的接口:
// features/payment/api.ets
// 本文件是 payment 模块对外暴露的完整 API,其他模块只能通过本文件引用
// 类型导出
export { PaymentResult, PaymentConfig } from './src/main/ets/types'
export { PayErrorCode } from './src/main/ets/constants/ErrorCodes'
// 服务导出
export { PaymentService } from './src/main/ets/service/PaymentService'
// 组件导出
export { PaymentButton } from './src/main/ets/components/PaymentButton'
// 不导出内部实现:数据库操作、网络层、内部工具等
其他模块引用时:
// features/order/src/main/ets/pages/OrderConfirmPage.ets
import { PaymentService, PaymentConfig } from '@app/features/payment'
@Component
struct OrderConfirmPage {
async onPay(): Promise<void> {
const config: PaymentConfig = {
orderId: '20260903001',
amount: 99.00
}
const result = await PaymentService.getInstance().pay(config)
// ...
}
}
版本兼容
模块接口变更时,维护向后兼容:
// V1
interface PaymentConfig {
orderId: string
amount: number
}
// V2 新增字段,给默认值保证 V1 调用方不受影响
interface PaymentConfig {
orderId: string
amount: number
currency?: string // 可选,默认 CNY
sandbox?: boolean // 可选,默认 false
}
破坏性变更(删除字段、改类型)必须升大版本号,并在团队内同步迁移计划。
四、知识沉淀
组件文档
每个可复用组件应该有对应的文档。不是写 Word,是在组件目录下维护 README:
# PaymentButton
支付按钮组件,封装了支付状态、加载动画、错误提示。
## 用法
PaymentButton({
amount: 99.00,
orderId: 'ORDER_001',
onPaySuccess: (result) => { ... },
onPayFailed: (error) => { ... }
})
## Props
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| amount | number | 是 | 支付金额(元) |
| orderId | string | 是 | 订单 ID |
| disabled | boolean | 否 | 是否禁用 |
| onPaySuccess | callback | 否 | 支付成功回调 |
| onPayFailed | callback | 否 | 支付失败回调 |
## 依赖
- @app/features/payment(PaymentService)
- @app/common-ui(LoadingSpinner)
内部技术 Wiki
建议团队维护一个结构化知识库,按以下分类组织:
踩坑记录模板
## 问题:LazyForEach 在快速滚动时出现白屏
**日期**:2026-08-15
**模块**:首页信息流
**现象**:快速上滑时,列表项区域出现 200ms 白屏,然后内容才渲染出来。
**根因**:cachedCount 设置为 1,预渲染不足。滑动速度过快时,下一个 ListItem 的 build() 还没完成。
**解决**:cachedCount 调到 3,同时在 aboutToAppear 中预热数据。
**关联篇目**:第 52 篇高效列表渲染
这种记录的价值在于:下次有人遇到同样问题,不需要从零排查。
五、新人 Onboarding 路径
新人加入团队,给他们一条清晰的代码走读路径,而不是"你先看看代码":
Day 1: 环境搭建 + 跑通 Demo
→ 参考:第 1 篇 DevEco Studio 初体验
→ 目标:本地编译通过,模拟器能运行
Day 2-3: 理解架构
→ 阅读:架构文档 + 第 71 篇分层架构
→ 走读:entry/src/main/ets/entryability → pages → service → data
→ 目标:能画出模块依赖图
Day 4-5: 改一个 Bug
→ 从 Jira 认领一个低优先级 Bug
→ 参考:第 47 篇调试技巧
→ 目标:独立完成修复 + 提 PR + 通过 Review
Week 2: 开发一个小功能
→ 参考:第 3 篇 ArkUI 组件 + 第 6 篇网络请求
→ 目标:完整经历开发→测试→Review→合入流程
六、团队工具链
Git pre-commit 钩子
#!/bin/bash
# .git/hooks/pre-commit
# 只检查暂存的 .ets 文件
FILES=$(git diff --cached --name-only --diff-filter=ACM | grep "\.ets$" | tr '\n' ' ')
if [ -z "$FILES" ]; then
exit 0
fi
echo "Running ESLint on staged files..."
npx eslint $FILES --fix
if [ $? -ne 0 ]; then
echo "ESLint check failed. Please fix the errors before committing."
exit 1
fi
echo "ESLint check passed."
exit 0
小结
团队工程实践的核心不是制定多少规范,而是让规范真正落地。三条建议:
第一,规范要少而精。20 条红线规则比 200 条"建议"管用。每条规则都要能说出"不遵守会出什么问题"。
第二,Code Review 是知识传递手段,不是质量门禁。Reviewer 的重点不是挑语法错误,而是确认架构一致性和逻辑正确性。
第三,知识沉淀要及时。解决一个 Bug 花了 4 小时,花 10 分钟写个踩坑记录,下次省 4 小时。这笔账怎么算都值。