Code Linter + HarmonyOS 开发助手:静态检查与 HiLog 定位闭环【共创稿事节】
改完一段 ArkTS 代码,编辑器里没有红线,就可以说“问题已经解决”了吗?未必。静态检查擅长发现特定规则能表达的代码问题,运行日志则回答程序在某次操作中走到了哪一步。两者各有盲区:一个只能分析写在代码里的结构与约束,另一个只有在对应执行路径真正被触发时才会留下线索。把它们当成两个互不相关的按钮,排障时就容易出现“修了格式,却还在崩溃”或“日志很多,却找不到应修的代码”的情况。
这里以一款完全独立的 HarmonyOS 离线备忘小工具为例:页面输入标题,点击保存,调用本地仓储写入。本文不依赖其他连载的工单、巡检或动效模块,也不把某个 AI 开发助手的回答当作编译和测试证据。我们要建立的是从规则扫描—可复现操作—分层日志—修复复核的诊断闭环,并明确哪些结论必须在工程环境中验证。

一、先定义缺陷,别把所有警告混为一个等级
一个简单保存按钮至少有三种不同的问题。第一类是确定的代码风格违规,例如分号前留有不合规范的空格,适合让 Code Linter 直接给出文件与位置。第二类是可能影响运行性能或可维护性的实现方式,例如不必要的稀疏数组,需要结合上下文决定是否修改。第三类是业务失败,例如标题为空、仓储抛出异常、用户连续点击造成重复写入,这些行为无法只靠格式检查证明正确。
实验的最小变量应该是“只改一处代码”,观察诊断类别是否变化,而不是同时改规则、换 SDK、重构保存流程。可以在 DevEco Studio 中给一个独立工程启用 Code Linter,并把需要关注的规则写进工程的 code-linter.json5。华为官方的规则说明明确列出 @hw-stylistic/semi-spacing 用于检查 .ets 文件中分号前的空格,@performance/sparse-array-check 则针对稀疏数组提供性能建议。前者设置为 error,后者设置为 suggestion,有助于把必须修正和需要评审的事项区分开。
// code-linter.json5 中的规则片段
{
"rules": {
"@hw-stylistic/semi-spacing": "error",
"@performance/sparse-array-check": "suggestion"
}
}
这段配置只列出本文用到的两条规则。实际工程若还有其他规则集、扫描范围或团队预设,应与现有配置合并,不应删除原来的项目策略。具体的扫描入口和适用文件类型依赖所安装的 DevEco Studio 版本,按官方“代码检查”指引设置即可。对误报的处理也不应简单降低全局规则等级;应先定位为什么触发,再决定代码是否值得重写。

二、写一个既能定位又不过度输出的日志边界
备忘工具的保存流程不复杂,但恰好能说明日志设计的关键:记录的是操作阶段与结果,而不是把用户输入的备忘正文全部打印出来。页面可以在点击保存时产生一个非个人信息的操作编号,并在参数校验、写入开始、写入结束、错误分支中保留同一个编号。这样一条链路即使穿过页面和仓储,也能沿编号还原出先后顺序。
HiLog 是 HarmonyOS 的系统日志能力,示例采用官方文档中公开的 hilog.info 与 hilog.error,通过 @kit.PerformanceAnalysisKit 导入。使用项目内固定 tag 和小范围的动作名称,而不是拼接完整用户输入、账户信息、原始设备标识或令牌。日志中所谓“保存成功”只表示仓储 Promise 按定义返回;数据是否满足持久化与重启恢复要求,要由真实仓储的契约另行保证。
// entry/src/main/ets/debug/SaveTrace.ets
import { hilog } from '@kit.PerformanceAnalysisKit';
const DOMAIN: number = 0x0000;
const TAG: string = 'MemoSave';
export type SavePhase = 'validate' | 'write' | 'finish';
export class SaveTrace {
private sequence: number = 0;
newId(): string {
this.sequence += 1;
return `save-${this.sequence}`;
}
step(id: string, phase: SavePhase): void {
hilog.info(DOMAIN, TAG, 'id=%{public}s phase=%{public}s', id, phase);
}
failed(id: string, phase: SavePhase): void {
hilog.error(DOMAIN, TAG,
'id=%{public}s phase=%{public}s result=failed', id, phase);
}
}
这里的 save-1 是应用进程内的临时诊断键,进程重启后可能重复,不能拿它作数据库主键,也不能把它解释成全局唯一的事务 ID。使用公开格式占位符时,建议只放非敏感的阶段、固定错误分类与内部操作键。如果系统日志要供线上收集,仍需按应用隐私政策、设备日志级别和保留周期做审查。开发阶段便于定位,不等于生产环境可以无限输出。
三、用依赖注入把“日志”和“保存行为”分开
让页面直接在每个条件分支里拼 hilog.error(),短期看很快,后来却会发现每个页面对失败的命名都不同。更清楚的边界是:仓储实现真正的写入;服务负责业务校验与错误传播;SaveTrace 只负责记录事件。下面用一个足够小的业务契约展示调用关系。MemoRepository 是项目自己的接口,可以接 RDB,也可以在单元测试中接内存替身,不依赖任何不存在的 SDK 方法。
// entry/src/main/ets/model/MemoService.ets
import { SaveTrace } from '../debug/SaveTrace';
export interface MemoRepository {
save(title: string): Promise<void>;
}
export class MemoService {
private repo: MemoRepository;
private trace: SaveTrace;
constructor(repo: MemoRepository, trace: SaveTrace) {
this.repo = repo;
this.trace = trace;
}
async submit(rawTitle: string): Promise<boolean> {
const id: string = this.trace.newId();
this.trace.step(id, 'validate');
const title: string = rawTitle.trim();
if (title.length === 0) {
this.trace.failed(id, 'validate');
return false;
}
this.trace.step(id, 'write');
try {
await this.repo.save(title);
this.trace.step(id, 'finish');
return true;
} catch (error) {
this.trace.failed(id, 'write');
return false;
}
}
}
这段调用链可以展开为三个可以明确判断的分支:标题空白时止于 validate,不会调用 repo.save();写入接口拒绝时显示 write 失败,不会错误地记录 finish;接口完成后才出现 finish。它没有把任何时间、内存或“100% 通过率”写成结果。实际观察应在目标工程中触发对应输入,过滤 MemoSave 标签,检查记录顺序是否满足这些预期。若只看到 validate 而没有 write,先查入参;若看到 write 但没有 finish,再看仓储错误和异步链,而不是先去修改界面颜色。

还有一个容易忽视的安全差别:上面的 catch 不直接输出 error.message,是有意减少误把文件路径、服务响应或业务内容带进日志的风险。实际项目可在仓储适配层将异常归类为“校验失败、写入失败、容量不足”等稳定错误代码,再由页面展示清楚的提示,同时保留内部不含敏感数据的关联键。UI 是否给出“重试”按钮,应由错误是否可恢复决定,不能看到所有 failed 都自动循环提交。
四、把诊断流程设计成可复核的对照实验
排查不是把所有开关点亮,而是让每一步能回答一个独立问题。先执行静态扫描,记录触发规则的文件和位置;修正一个错误后再次扫描,比较同一规则的诊断变化。此时不启动应用也可以完成代码风格层面的对照,但不能推断保存流程已经正确。接着通过正常标题、空白标题、仓储拒绝三种输入触发 MemoService,查看 HiLog 中的阶段路径与业务接口调用是否一致。
可以再加一个“慢速写入”情境,不过要小心把测试替身当成真实性能结果:让测试仓储返回可控 Promise,在 Promise 尚未完成时重复点击,检查业务是否需要按钮禁用、请求合并或持久幂等保护。时间长短不是本实验要比较的指标;重点是当尚未完成的保存请求存在时,系统是否允许用户无意制造第二次写入。这个问题属于业务契约,不属于 Code Linter 规则可以自动保证的范围。

建议将问题分类为四档:扫描就能定位的确定规则错误、只有运行路径能触发的业务异常、需要目标设备和 SDK 验证的平台适配问题,以及只能通过持续测量判定的性能问题。各类问题应保留各自证据;尤其不要把编辑器红线消失、日志出现某个阶段或一次页面可交互当作全部质量门槛都通过的证明。
如果团队引入 DevEco Code 等开发助手,可以让工具先解释某条诊断、归纳相关接口调用链、提出小范围修复方案,再由开发者对照官方 API 文档审查代码。不要把自动生成的“已修复”描述当作现场证据,更不要让助手在没有真实构建与设备输出时补写日志截图。助手提高的是排查效率,最终质量仍由可核验的构建输出、测试条件与业务状态决定。
五、让每次改动都留下可追溯的结论
一次好的修复记录至少能回答:触发条件是什么,哪个规则或运行阶段提供了直接线索,改动只影响哪些文件,修复前后的判断条件如何变化,是否引入新的依赖或权限,以及哪些条件仍需要真实设备验证。比起“把报错都修好了”,这种记录更便于下一位维护者继续工作。
这套流程的适用边界很清楚。Code Linter 负责可静态表达的规则,HiLog 负责实际调用路径中的事件顺序,业务替身负责隔离错误分支,正式 SDK 与设备测试负责环境兼容性。它们相互补充而不互相取代。对于 HarmonyOS 项目,能区分诊断的来源,往往比堆积更多日志行更重要。
官方资料:DevEco Studio 代码检查、分号空格规则、稀疏数组规则、HiLog API、DevEco Studio 官方入口。
更多推荐

所有评论(0)