三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

Harness Engineering:AI辅助Android开发的质量保障与工程实践

Harness Engineering:AI辅助Android开发的质量保障与工程实践

1. 项目概述:从 Harness Engineering 到 AI 驱动的 Android 开发

最近在和一些资深架构师交流时,频繁听到一个词:Harness Engineering。这个词乍一听有点陌生,但拆解其内核,你会发现它直指现代软件工程,尤其是我们这些在移动端、AI 领域摸爬滚打的开发者,每天都在面对的核心痛点——如何系统化地“驾驭”复杂性,确保项目不“翻车”。Harness,意为“驾驭”、“控制”,在工程语境下,它强调的是一套完整的、可重复的、自动化的工具链和流程,用以管理和控制从代码提交到最终交付的每一个环节,确保质量、效率和可预测性。这让我立刻联想到了当前最火热也最让人又爱又恨的组合:用 AI 辅助 Android 应用开发

我们正处在一个奇妙的拐点。一方面,AI 代码助手(如 GitHub Copilot、Cursor、以及各种大模型驱动的 IDE 插件)已经能显著提升编码效率,从生成样板代码、补全函数到解释复杂逻辑,无所不能。另一方面,Android 开发本身的复杂性并未减少,甚至因为多设备、多形态(手机、折叠屏、车载、电视)而加剧。当我们将这两者结合,梦想着“AI 帮我写 App”时,一个巨大的问号随之而来:效率提升的背后,质量如何保障?项目会不会在看似智能的辅助下,悄无声息地滑向混乱、不可维护甚至崩溃的深渊?

这正是 Harness Engineering 理念给我的核心启发。它告诉我们,不能只盯着 AI 生成的单行代码是否“正确”,而必须构建一个系统性的“驾驭”框架。这个框架要能容纳 AI 的创造力,同时用工程化的缰绳约束其可能带来的不确定性。本文将结合我过去在多个中大型 Android 项目中的实战经验,深入探讨如何将 Harness Engineering 的原则落地,构建一套让“AI + Android”开发既高效又稳健的最佳实践。无论你是独立开发者,还是团队的技术负责人,这些思路都能帮助你避免常见的陷阱,真正让 AI 成为你可靠的副驾,而非导致项目偏离航向的“幽灵司机”。

2. 核心理念拆解:什么是“驾驭工程学”?

在深入技术细节之前,我们必须先统一思想。Harness Engineering 不是一个具体的工具,而是一种方法论和思维模式。它的核心目标是通过自动化、标准化和持续反馈,来“驾驭”软件开发过程中的各种变数和风险。对于“AI + Android”这个场景,我们可以将其分解为三个需要被“驾驭”的核心维度:

2.1 驾驭“不确定性”:AI 生成代码的固有风险

AI 模型是基于概率的,它生成的代码在语法上可能完美,但在逻辑、架构、性能甚至安全性上存在隐蔽缺陷。这种不确定性是固有的,无法完全消除,但可以被管理和控制。

  • 逻辑正确性风险:AI 可能生成一段能编译运行的代码,但其业务逻辑与你的需求存在微妙偏差。例如,你让它“实现一个 RecyclerView 的适配器,并支持点击事件”,它可能生成了代码,但却把点击监听器错误地绑定在了onCreateViewHolder而不是onBindViewHolder中,或者在多选场景下状态管理混乱。
  • 架构一致性风险:一个健康的 Android 项目有其约定的架构模式(如 MVVM、MVI)、包结构、命名规范。AI 在缺乏完整上下文时,生成的代码可能破坏这种一致性。比如,它可能把网络请求逻辑直接写在Activity里,而不是按照项目规范放在Repository层。
  • 性能与资源风险:AI 可能写出低效的代码。例如,在RecyclerView适配器中频繁创建对象、在主线程进行耗时操作、或生成存在内存泄漏风险的代码(如未正确解注册监听器)。
  • 安全与合规风险:这是最危险的一点。AI 可能引入不安全的 API 使用(如硬编码密钥)、或者使用了已被废弃且有安全漏洞的库版本。

Harness Engineering 的应对策略是“假设生成物不可信,必须验证”。我们需要建立强大的自动化验证屏障,让每一行 AI 参与生成的代码,都必须通过和人工编写代码同等甚至更严格的检验。

2.2 驾驭“复杂性”:Android 生态与 AI 工具的整合

Android 开发本身就是一个复杂的生态系统:Gradle 构建系统、Kotlin/Java 语言特性、Jetpack 组件、第三方 SDK、厂商适配……引入 AI 工具后,复杂性是指数级增加的。你需要管理 AI 工具的配置、上下文提示(Prompt)的优化、不同模型(本地 vs. 云端)的切换等。

Harness Engineering 的应对策略是“标准化与抽象”。我们需要为 AI 的使用制定团队规范,创建可复用的、高质量的上下文模板(比如针对“生成一个使用 Room 的 DAO”、“生成一个 ViewModel 单元测试”的专用 Prompt),并将 AI 工具链无缝集成到现有的开发工作流(如 Git、CI/CD)中,减少开发者的认知负担和操作成本。

2.3 驾驭“演进性”:AI 与项目的共同成长

项目和 AI 模型都在不断演进。Android 框架会更新,项目的业务逻辑会变化,AI 模型的能力也在迭代。如何确保今天用 AI 生成的代码,在三个月后依然可维护、可理解,并且能与新引入的 AI 能力协同工作?

Harness Engineering 的应对策略是“持续反馈与知识沉淀”。这不仅仅是收集数据,更是要建立一个闭环:将 AI 生成代码在实际项目中暴露出的问题(通过 Code Review、测试失败、生产故障)反馈回来,用于优化我们的使用规范、验证规则和 Prompt 策略。同时,将成功的 AI 应用模式沉淀为团队的知识库或内部工具。

理解了这三个需要驾驭的维度,我们就可以开始构建具体的防御体系了。接下来的内容,将围绕一个核心闭环展开:如何为“AI + Android”开发打造一个从代码生成、到验证、再到集成的“安全驾驶系统”

3. 构建防御体系:AI 辅助开发的四大核心实践

空谈理念不如实战。下面我将结合具体场景,分享四个关键的工程实践,它们共同构成了驾驭 AI 风险的防御体系。

3.1 实践一:制定精准的 AI 交互契约(Prompt Engineering as Code)

把向 AI 提问(Prompt)看作是与一个能力超强但经验不足的实习生沟通。模糊的指令必然得到模糊甚至错误的结果。我们需要将 Prompt 工程化、代码化。

1. 创建上下文丰富的“角色卡片”不要每次从头开始描述。为你的 AI 助手定义一个明确的“角色”和“上下文”。例如,创建一个名为android_senior_dev.prompt的模板文件保存在项目根目录或团队知识库中:

你是一位经验丰富的 Android 高级开发工程师,精通 Kotlin、Jetpack Compose、MVVM 架构和 Clean Architecture。你熟悉最新的 Android 开发最佳实践,注重代码性能、可读性和可测试性。 **当前项目上下文:** - 项目名称:MyProductApp - 主要架构:MVVM + Repository 模式 - 网络层:Retrofit + Kotlin Coroutines - 本地数据库:Room - 依赖注入:Hilt - 代码规范:遵循 Kotlin 官方编码约定,使用 ktlint 进行格式化。 - 关键包结构: com.myproduct.data // 数据层(Repository, DataSource) com.myproduct.domain // 领域层(UseCase, Model) com.myproduct.presentation // 表现层(ViewModel, UI) **你的任务准则:** 1. 生成的代码必须符合上述架构,将代码放在正确的包层级中。 2. 优先使用 Kotlin 协程处理异步,避免回调地狱。 3. 所有公开的 ViewModel 状态必须使用 `StateFlow` 或 `SharedFlow` 暴露。 4. 为所有非 trivial 的公共函数编写 KDoc 注释。 5. 避免使用已弃用(Deprecated)的 API。 6. 考虑内存泄漏,确保在生命周期结束时清理资源。 现在,请根据以下具体任务生成代码:

当需要 AI 协助时,先加载这个基础上下文,再附加具体任务描述。这能极大提高生成代码的准确性和一致性。

2. 任务描述结构化、场景化坏例子:“写一个登录功能。” 好例子:“在com.myproduct.presentation.auth包下,创建一个名为LoginViewModel的类。它需要依赖一个AuthRepository(通过 Hilt 注入)。功能要求:1. 包含两个StateFlow,分别表示用户名和密码的输入状态(String类型)。2. 包含一个login方法,该方法会调用AuthRepository.login(这是一个 suspend 函数,返回Result<AuthToken>)。3. 在登录过程中,需要一个_isLoadingMutableStateFlow来驱动 UI 显示加载状态。4. 登录成功或失败后,需要用SharedFlow发射相应的事件(LoginSuccessLoginError)供 UI 层消费。请生成该 ViewModel 的完整 Kotlin 代码。”

实操心得:我发现,将 Prompt 保存在项目下的.prompt/目录中,并纳入版本控制,是非常有效的做法。团队新成员可以快速了解如何与 AI 协作,保证了协作的一致性。

3.2 实践二:建立自动化的代码质量关卡

生成代码只是第一步,立即投入使用的风险极高。必须设立多道自动化检查关卡,这是 Harness Engineering 的精髓。

1. 静态代码分析(SAST)强化在 CI/CD 流水线中,在 AI 生成代码合并前,必须运行比平时更严格的静态检查。

  • 基础工具ktlintdetekt确保代码风格统一。将规则配置得严格一些,例如强制要求显式返回类型、禁止使用!!非空断言。
  • 架构守护:使用ArchUnit编写架构规则测试。这是对抗 AI 破坏架构一致性的利器。例如,你可以写一个测试:“ViewModel类不能直接依赖android.*包下的类(如Context)”,或者“data层包下的类不能被presentation层直接导入”。当 AI 生成了不符合架构的代码时,这些测试会在合并前失败。
  • 安全扫描:集成工具如MobSF(Mobile Security Framework) 或DependencyCheck,对引入的依赖和代码模式进行安全扫描,防止 AI 引入已知的安全漏洞代码模式。

2. 针对性单元测试生成与验证让 AI 生成代码的同时,也让它为这段代码生成单元测试。然后,必须运行这些测试

  • Prompt示例:“为我刚才生成的LoginViewModel编写相应的单元测试。使用kotlinx-coroutines-test进行协程测试,使用MockKMockito进行依赖模拟。请覆盖以下场景:1. 初始状态验证。2. 输入用户名密码后状态更新。3. 登录成功用例。4. 登录失败用例。5. 加载状态切换。”
  • 关键动作:生成测试后,立即在 CI 中运行它们。如果测试失败,首先检查是测试用例写得不对,还是生成的业务代码本身有逻辑缺陷。这个过程能发现大量隐蔽的边界条件错误。

3. 依赖与许可证审查AI 可能会在代码中建议引入新的第三方库。必须有一个自动化流程来审查这些依赖。

  • 版本冲突检查:Gradle 的dependencyUpdates插件可以帮助检查是否有新版本,但更重要的是检查 AI 建议的依赖版本是否与项目现有依赖冲突。
  • 许可证合规性扫描:使用如FOSSABlack Duck等工具,自动扫描新引入依赖的许可证(如 GPL、AGPL 等),确保符合公司合规要求。AI 可不会替你考虑法律风险。

注意:千万不要因为代码是 AI 生成的,就绕过或简化 Code Review 环节。相反,应该进行更聚焦的 Review。Reviewer 的重点应从“语法细节”转向“架构符合度”、“业务逻辑正确性”和“AI 引入的特定风险点”。

3.3 实践三:AI 集成开发环境(IDE)的标准化配置

开发者的主要战场是 IDE。混乱的 AI 工具配置会导致效率低下和结果不一致。

1. 统一团队 AI 助手插件团队应约定使用同一款或同一类 AI 代码助手插件(如 GitHub Copilot、Amazon CodeWhisperer、或基于特定大模型定制的 IDE 插件)。并共享配置模板。

  • 上下文配置:在插件设置中,明确哪些文件应该被纳入上下文(如build.gradle.kts,项目架构说明.md),哪些不应该(如*.log, 大型二进制文件)。
  • 快捷键统一:定义团队内接受建议、触发生成的统一快捷键,减少操作摩擦。

2. 创建项目级的“智能上下文”文件在项目根目录创建.cursor/rules.copilot/instructions.md文件(取决于你的工具)。这些文件会被 AI 插件自动读取,作为项目级的固定上下文。内容可以包括: * 项目技术栈摘要。 * 重要的架构决策记录(ADR)。 * 团队约定的代码风格(如“我们使用sealed class而不是枚举来处理状态”)。 * 常见任务的代码片段示例。

3. 本地模型与云端模型的策略对于涉及敏感代码或网络不便的场景,可以考虑配置本地运行的大模型(如通过ollama运行 CodeLlama 等)。在 IDE 中配置备用模型源,并制定清晰的使用策略:普通代码补全用云端模型以保证速度和质量;涉及核心业务逻辑或敏感信息时,切换到本地模型进行辅助。

实操心得:我们团队曾因为未统一配置,导致有的成员用 Copilot 生成了 Java 代码,而项目主体是 Kotlin,造成了不必要的格式转换成本。一个简单的、版本化管理的 IDE 配置文件(如.vscode/settings.json.idea/codeStyles/)能避免很多此类问题。

3.4 实践四:度量、反馈与持续改进闭环

没有度量,就无法改进。我们需要数据来回答:AI 到底帮了我们多少?又带来了多少麻烦?

1. 定义关键度量指标

  • AI 代码采纳率:在 Code Review 中,标记出由 AI 生成的代码块。统计最终被合并的代码中,AI 生成代码的行数占比。这能衡量 AI 的实际贡献度。
  • AI 引入缺陷率:在测试阶段(单元测试、集成测试)和线上故障中,追踪那些根本原因可追溯到 AI 生成代码的缺陷数量。与总缺陷数对比,评估其风险。
  • 任务完成时间:抽样记录特定类型开发任务(如“创建一个新的带列表的页面”)在使用 AI 辅助前后的平均耗时。
  • 开发者满意度:定期进行匿名调研,了解开发者对 AI 工具在准确性、流畅度、对工作流干扰度等方面的感受。

2. 建立反馈收集机制

  • 在 Code Review 中嵌入反馈:在 Review AI 生成代码时,除了评论代码本身,可以增加标签如#ai-logic-error,#ai-arch-issue,便于后续分类分析。
  • 创建“AI 模式库”:建立一个内部 Wiki 或共享文档,记录两种内容:
    • 成功模式:记录那些高质量的、可复用的 Prompt 和生成的优秀代码案例。例如,“如何用 Prompt 生成一个完美的 Paging 3 DataSource”。
    • 失败模式与修复方案:记录常见的 AI 生成错误及其人工修正方法。例如,“AI 生成的 Room@Query方法漏掉了suspend关键字,需手动添加”。

3. 定期复盘与策略调优每季度或每两个迭代,团队应进行一次复盘。基于收集的度量数据和反馈,讨论并调整:

  • 我们的 Prompt 模板需要更新吗?
  • 静态分析规则是否需要针对新的 AI 错误模式进行加强?
  • 是否需要调整 AI 工具的使用场景(例如,规定业务核心逻辑模块暂时禁用全自动生成,只使用补全)?

通过这个“实践-度量-反馈-优化”的闭环,你就能像驾驭一辆高性能赛车一样,驾驭 AI 的开发潜力,让它始终在安全的赛道上为你加速。

4. 典型场景实战:一个需求从 Prompt 到 Merge 的全流程

让我们通过一个虚构但非常典型的 Android 需求,将上述所有实践串联起来,看一个完整的、“不翻车”的工作流是怎样的。

需求描述:在“我的”页面,新增一个“消息中心”入口,点击后进入一个列表页,展示用户的消息(包括系统通知和私信),支持下拉刷新和上拉加载更多。

4.1 第一步:需求分析与 Prompt 准备

开发者(或产品经理)首先需要将模糊的需求转化为精确的技术任务描述。这本身就是一个重要的分解过程。

  1. 任务拆解

    • A. 在“我的”页面 (ProfileFragment) 的 UI 上添加一个入口项。
    • B. 创建新的消息列表页 (MessageListFragmentActivity)。
    • C. 实现对应的MessageListViewModel
    • D. 实现数据层:MessageRepository,MessageRemoteDataSource,MessageLocalDataSource(如果需要缓存)。
    • E. 定义数据模型Message
    • F. 实现分页逻辑(使用 Paging 3)。
  2. 编写结构化 Prompt: 打开之前定义的android_senior_dev.prompt基础模板,在后面附加具体的任务描述。我们以创建MessageListViewModel和 Paging 相关逻辑为例:

    具体任务:实现消息列表的 ViewModel 和分页逻辑。

    • 请创建MessageListViewModel
    • 使用 Paging 3 库进行分页。
    • 定义一个MessagePagingSource,它需要依赖一个MessageRepository来获取数据。假设MessageRepository有一个suspend fun getMessages(page: Int, pageSize: Int): List<Message>方法。
    • MessageListViewModel需要暴露一个Flow<PagingData<Message>>给 UI 层。
    • 同时,ViewModel 需要处理下拉刷新和重试逻辑。请提供刷新和重试的方法。
    • 考虑到消息可能有已读/未读状态,ViewModel 还应提供一个markAsRead(messageId: String)的方法。
    • 请为以上所有内容生成完整的 Kotlin 代码,并包含必要的导入语句。”

4.2 第二步:在受控环境中生成与初步审查

  1. 生成代码:在 IDE 中,将上述 Prompt 提交给 AI 助手。
  2. 本地运行静态检查:生成代码后,不要立即复制粘贴。先在 IDE 或本地命令行运行./gradlew ktlintCheck detekt,检查生成代码的风格和基础问题。
  3. 运行架构单元测试:运行项目中已有的 ArchUnit 测试,确保新生成的ViewModel没有破坏架构约束(比如错误地引入了 Android 依赖)。
  4. 人工逻辑初审:开发者快速浏览生成的代码,重点关注:
    • 分页逻辑是否正确(PagingSourceload方法实现)。
    • 状态管理是否合理(刷新状态是否用MutableStateFlow管理)。
    • 协程作用域 (viewModelScope) 的使用是否正确。
    • 生成的markAsRead方法是否合理(是否调用了 Repository 的相应方法)。

4.3 第三步:生成并运行配套单元测试

针对生成的MessageListViewModelMessagePagingSource,再让 AI 生成单元测试。

Prompt:“请为上面生成的MessageListViewModelMessagePagingSource编写单元测试。使用MockK模拟MessageRepository。测试用例需覆盖:1.PagingSourceload方法在成功、失败、无更多数据时的行为。2.ViewModel刷新操作是否能触发新的PagingData。3.markAsRead方法是否能正确调用 Repository。”

生成测试后,立即在本地运行./gradlew test --tests "*MessageList*"。如果测试失败,分析原因:是测试写得不对,还是 ViewModel 逻辑有问题?这个过程能发现大量边界情况 Bug。

4.4 第四步:集成与提交前检查

  1. 将生成的代码和测试放入项目正确位置。
  2. 运行完整的本地构建./gradlew clean build。确保编译通过,所有现有测试(包括刚生成的)都通过。
  3. 提交代码:提交时,在 Commit Message 中明确标记[AI-Assisted],并简要说明 AI 协助的部分(如“MessageListViewModel及分页逻辑由 AI 生成,已通过单元测试”)。
  4. 触发 CI/CD 流水线:流水线应自动执行:
    • 更全面的静态代码分析。
    • 所有单元测试和集成测试。
    • 依赖安全扫描。
    • 如果有 UI 测试,也应运行。

4.5 第五步:聚焦的 Code Review

Reviewer 收到 Pull Request 后,其审查重点非常明确:

  1. 架构符合度:代码是否放对了包?依赖方向是否正确?
  2. 业务逻辑正确性:分页、刷新、标记已读的逻辑是否符合产品需求?有无遗漏或过度设计?
  3. AI 特定风险点
    • 生成的代码中是否有“幻觉”引入的不存在的 API 或方法?
    • 错误处理是否完备(网络错误、空状态)?
    • 性能是否有隐患(如内存泄漏、主线程操作)?
  4. 测试充分性:AI 生成的测试是否覆盖了核心场景?是否需要补充?

只有通过所有这些关卡,代码才能被合并。至此,一段由 AI 深度参与的功能代码,才算是被“驾驭”着安全落地。

5. 常见“翻车”点与避坑指南

在实际操作中,即使遵循了上述流程,依然会遇到一些典型问题。下面是我和团队在实践中总结出的“翻车”重灾区及应对策略。

问题现象根本原因避坑策略与解决方案
生成的代码编译通过,但运行时崩溃或逻辑错误AI 基于过时或错误的上下文生成,或对 Android 生命周期理解有偏差。1. 强化上下文:在 Prompt 中明确指定使用的库版本和最小 SDK 版本。
2. 即时验证:生成后立即写一个最简单的集成测试或运行到模拟器上验证核心流程。
3. 代码审查聚焦逻辑:Review 时,让作者口头复述一遍关键算法或数据流,常能发现理解偏差。
AI 破坏了项目的统一架构风格Prompt 中架构描述不够具体,或 AI 未充分理解项目现有代码。1. 架构守护测试:如前所述,用 ArchUnit 编写硬性规则,CI 失败则无法合并。
2. 提供“参考样本”:在 Prompt 中链接或粘贴一段项目中公认的、符合架构的典型代码(如一个现有的ViewModel),让 AI “依葫芦画瓢”。
3. 创建项目脚手架工具:对于常见页面(如列表页、详情页),开发内部代码生成模板或脚本,比依赖 AI 更可靠。
AI 引入了有安全漏洞的依赖或代码模式AI 的训练数据中包含大量旧代码或存在漏洞的示例。1. 依赖白名单/黑名单:在项目build.gradle或 CI 脚本中配置规则,禁止引入特定已知不安全的库。
2. 自动化安全扫描:将DependencyCheck等工具集成到 CI,任何引入新依赖或版本变更的 PR 都必须通过扫描。
3. 代码模式审查清单:在 Review 清单中加入安全项,如“检查是否有硬编码密钥”、“检查网络请求是否使用 HTTPS”等。
过度依赖 AI,导致开发者自身能力退化或代码“黑盒化”开发者将 AI 当作“黑箱”代码生成器,不思考其输出。1. 设立“无 AI 区”:规定核心业务模块、算法模块必须由人工主导编写,AI 仅作辅助。
2. 强制注释与解释:要求对 AI 生成的关键代码段,开发者必须添加注释,说明其工作原理和设计考量。
3. 定期代码重构:安排专门时间,对早期 AI 生成的大量代码进行重构和梳理,确保团队对其有集体所有权和深刻理解。
Prompt 效果不稳定,时好时坏Prompt 描述模糊,或 AI 模型本身存在波动。1. 沉淀 Prompt 模板库:将针对不同任务(CRUD 操作、网络层、UI 组件)验证有效的 Prompt 保存下来,形成团队资产。
2. 迭代优化 Prompt:将生成效果不佳的案例记录下来,分析是描述不清、缺少上下文还是任务本身过于复杂,然后针对性优化 Prompt。
3. 结合使用多种模型:对于关键任务,可以尝试用不同的 AI 模型(如 Claude、GPT)生成,对比结果,取最优或综合。

我个人最深刻的一个教训是:曾经让 AI 生成一个复杂的图像处理管道,它生成了一段大量使用GlobalScope.launch的代码。在简单测试中运行良好,但上线后不久就收到了关于内存泄漏和 ANR 的崩溃报告。根本原因是 AI 对 Android 生命周期和结构化并发的理解是割裂的。自那以后,我们在所有涉及协程的 Prompt 开头都加上了铁律:“严禁使用GlobalScope,所有协程必须基于viewModelScopelifecycleScope启动,并确保在生命周期结束时取消。” 这个具体的、强制的约束,彻底解决了这一类问题。

6. 工具链推荐与配置片段

工欲善其事,必先利其器。一套好的工具链配置是实践 Harness Engineering 的基础。以下是一些经过验证的推荐和配置示例。

1. 静态分析与架构守护配置 (build.gradle.kts模块)

// 在模块级的 build.gradle.kts 中 plugins { id("org.jlleitschuh.gradle.ktlint") version "11.6.1" id("io.gitlab.arturbosch.detekt") version "1.23.5" } ktlint { // 启用实验性规则,更严格 enableExperimentalRules.set(true) // 输出彩色报告 coloredOutput.set(true) // 自定义规则(例如禁用 !! 操作符) disabledRules.set(setOf("no-unused-imports")) // 示例,可根据需要调整 } detekt { config = files("$projectDir/config/detekt/detekt.yml") buildUponDefaultConfig = true } dependencies { // ArchUnit for Android 测试 testImplementation("com.tngtech.archunit:archunit-junit5:1.2.1") }

2. ArchUnit 测试示例 (src/test/kotlin/arch/ArchitectureTest.kt)

import com.tngtech.archunit.core.importer.ImportOption import com.tngtech.archunit.junit.AnalyzeClasses import com.tngtech.archunit.junit.ArchTest import com.tngtech.archunit.lang.ArchRule import com.tngtech.archunit.lang.syntax.ArchRuleDefinition.* @AnalyzeClasses( packages = ["com.yourcompany.yourapp"], importOptions = [ImportOption.DoNotIncludeTests::class] ) class ArchitectureTest { @ArchTest val viewModelsShouldResideInPresentationPackage: ArchRule = classes().that().haveSimpleNameEndingWith("ViewModel") .should().resideInAPackage("..presentation..") .`as`("ViewModels 应放在 presentation 包下") @ArchTest val repositoriesShouldOnlyBeAccessedByUseCasesOrViewModels: ArchRule = noClasses().that().resideInAPackage("..data..") .should().beAccessedByClassesThat().resideInAPackage("..ui..") // UI层(如Fragment)不应直接访问Repository .`as`("Data层(如Repository)不应被UI层直接访问") @ArchTest val useCasesShouldNotDependOnAndroidFramework: ArchRule = noClasses().that().resideInAPackage("..domain..") .should().dependOnClassesThat().resideInAPackage("android..") .`as`("Domain层(UseCase)不应依赖Android框架") }

3. CI/CD 流水线关键步骤示例 (GitHub Actions.github/workflows/ci.yml)

name: Android CI on: [push, pull_request] jobs: build-and-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up JDK uses: actions/setup-java@v4 with: { distribution: 'temurin', java-version: '17' } - name: Cache Gradle uses: actions/cache@v4 with: { path: ~/.gradle/caches, key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} } - name: Run ktlint run: ./gradlew ktlintCheck - name: Run detekt run: ./gradlew detekt - name: Run ArchUnit Tests run: ./gradlew testDebugUnitTest --tests "*ArchitectureTest*" - name: Run All Unit Tests run: ./gradlew testDebugUnitTest - name: Dependency Security Check run: ./gradlew dependencyCheckAnalyze # 需要配置 org.owasp.dependencycheck 插件 - name: Build APK run: ./gradlew assembleDebug

4. 项目级 AI 上下文文件示例 (.cursor/rules.mdc)

# 项目:MyProductApp - Android 开发规范 ## 技术栈 - 语言:Kotlin - 最小 SDK:API 24 - 架构:MVVM + Clean Architecture (Data, Domain, Presentation) - 异步:Kotlin Coroutines + Flow - 依赖注入:Hilt - 网络:Retrofit + Moshi - 本地数据库:Room - 分页:Paging 3 ## 代码风格 - 使用 `StateFlow`/`SharedFlow` 暴露 UI 状态和事件。 - ViewModel 中使用 `viewModelScope` 启动协程。 - Repository 返回 `Result<T>` 密封类包装成功/失败。 - UI 层使用 Jetpack Compose(如项目使用)或 ViewBinding(如使用 XML)。 - 禁止使用 `!!` 非空断言,优先使用空安全调用或 Elvis 操作符。 - 所有 `Activity`/`Fragment` 的导航使用 Navigation Component。 ## 生成要求 - 生成的代码必须包含合适的 KDoc 注释。 - 优先使用不可变数据(`val`, `data class`)。 - 对于可能为空的集合,返回空集合而非 `null`。

配置好这些工具和规范,就如同为你的项目安装了“自动驾驶”的基础传感器和交通规则,让 AI 这辆快车能在既定的轨道上安全驰骋。

7. 总结:从“试用”到“驾驭”的心态转变

回顾整个过程,从 Harness Engineering 中汲取的最大智慧,是完成了一次关键的心态转变:从把 AI 当作一个偶尔“试用”的新奇玩具,转变为将其视为一个需要被系统化“驾驭”的核心生产力组件。

这意味着,我们不再纠结于“AI 能不能写出这段代码”,而是专注于“我们如何建立一套流程,确保 AI 写出的任何代码都能符合我们的质量标准”。前者关注单点能力,后者关注系统工程。前者可能导致惊喜与惊吓并存,后者则追求稳定的、可预期的产出提升。

这套方法的最终目标,不是取代开发者,而是增强开发者。它将开发者从重复性、模式化的编码劳动中解放出来,让我们能更专注于架构设计、复杂问题拆解、核心算法实现和创造性的产品思考。同时,它通过自动化的质量关卡,将我们从低级的 Bug 排查中拯救出来,提升了整个团队的交付信心和代码健康度。

开始行动吧。不妨从为一个现有项目配置一套严格的ktlintdetekt规则开始,然后尝试为一个简单的功能编写一个详细的 Prompt,并运行生成的代码通过你新设立的 CI 关卡。你会立刻感受到,那种代码既快速产出又稳稳落地的可控感,正是高效、稳健的现代 Android 开发应有的样子。

← 返回列表