☰
两个月九万行代码:我用coding agent开发macOS/iOS App的vibe coding实战
2026/10/15 9:51:05 网站建设 项目流程

1. 两个月写出一个 App,我到底经历了什么

先说结论:这个 App 从第一行代码到上架 App Store,总共九万多行,我完整读过的代码大概不超过三百行。这不是炫耀,也不是偷懒,而是我在这两个月里刻意选择的一种开发方式——把绝大部分编码工作交给 coding agent,自己只负责定义问题、验收结果、调整方向。整个过程下来,我对“写代码”这件事的理解被彻底刷新了一遍。

这个项目是一个 macOS 和 iOS 双端的效率类 App,核心功能不复杂:本地数据管理、快捷输入、跨设备同步、通知横幅提醒。听起来像是那种“一个人两周就能搞定”的东西,但真正做起来,光是 UI 适配、状态管理、数据持久化、通知权限、上架审核这几块,就足够把一个独立开发者拖进泥潭。我之所以敢在两个月内推进,是因为我把整个开发流程拆成了“我定义 → agent 实现 → 我验收 → agent 修复”的循环,而不是传统的“我写 → 我调 → 我改”。

vibe coding 这个词最近被讨论得很多,但很多人理解得比较窄,以为就是“对着 AI 说一句话,代码就出来了”。实际体验下来,它更像是一种新的协作节奏:你不再逐行控制代码,而是控制意图、边界和验收标准。coding agent 负责把意图翻译成可运行的代码,你负责判断“这是不是我想要的”。这个转变听起来简单,做起来非常反直觉,因为你会不断遇到“代码能跑但不对”“功能对了但结构烂”“结构好了但性能崩”的情况。

这篇文章我会把这九万行代码背后的完整流程拆开讲:我怎么选工具、怎么定义任务、怎么验收、怎么处理 agent 写出来的烂代码、怎么在 macOS 和 iOS 之间做适配、怎么处理通知横幅这种细节、怎么上架、以及我踩过的那些坑。适合两类人看:一类是想尝试 vibe coding 但不知道从哪下手的开发者,另一类是对 coding agent 持怀疑态度、想看看真实项目里它到底能干什么的人。

2. 为什么我选择“不读代码”这条路

2.1 传统开发流程的瓶颈在哪里

我做过不少独立项目,传统流程大概是这样的:先想清楚需求,然后搭架构,然后一个模块一个模块写,写完自己测,测完改,改完再测。这个流程的问题不在于慢,而在于上下文切换成本极高。你写 UI 的时候想着数据层,写数据层的时候想着网络层,写网络层的时候又担心 UI 状态同步。一个人做全栈,最大的敌人不是技术难度,而是脑子里同时挂着太多线程。

更现实的问题是,独立开发者最容易卡在“细节沼泽”里。比如 macOS 上做一个通知横幅,你要处理权限申请、通知样式、点击回调、前台展示策略、免打扰时段、通知分组,这些东西单独看都不难,但加起来就是几百行代码和一堆边界情况。你花两天把这些做完,回头一看,核心功能还没动。这种消耗感是很多独立项目半途而废的直接原因。

2.2 coding agent 真正改变的是什么

coding agent 改变的不是“写代码的速度”,而是你关注的对象。以前你关注的是“这行代码怎么写”,现在你关注的是“这个行为对不对”。这个转变的关键在于:agent 可以快速产出大量可运行代码,但它的产出质量高度依赖你给它的约束。你给它的约束越清晰,它产出的代码越接近可用;你给它的约束越模糊,它就越容易写出“看起来对但实际不能用”的东西。

我在这两个月里最大的体会是:agent 不是替代你思考,而是替代你打字。它不会帮你决定“这个功能要不要做”“这个交互合不合理”“这个数据结构能不能扩展”,这些仍然是你的工作。但它可以帮你把“我已经想清楚的东西”快速变成代码,而且速度远超你自己写。

2.3 为什么我敢不读代码

不读代码的前提是验收标准足够硬。我给自己定了三条规则:

  • 第一,每个功能必须有可执行的验收用例,不能靠“看起来对”来判断。
  • 第二,关键路径必须有日志和断言,出问题能定位到具体环节。
  • 第三,任何 agent 产出的代码,如果我要改,必须先让它自己解释这段代码在干什么。

这三条规则保证了我即使不逐行读代码,也能对系统行为有足够掌控。换句话说,我不是“不看代码”,而是“不逐行读代码”,我把阅读代码的精力换成了设计验收标准和排查路径。这个交换在两个月里被证明是划算的,因为它让我把时间花在了真正需要人判断的地方。

3. 工具选型:我是怎么搭这套工作流的

3.1 coding agent 的选择逻辑

市面上 coding agent 工具不少,我最终选的是一个支持多文件编辑、能跑终端命令、能读项目结构的 agent。选它的理由很实际:

  • 它能在项目级别理解上下文,而不是只处理单个文件。
  • 它能执行命令并读取输出,这意味着它可以自己跑测试、自己看报错。
  • 它支持增量修改,不会每次把整个文件重写一遍。

这三点决定了它能不能参与“实现 → 验证 → 修复”的闭环。如果一个 agent 只能生成代码但不能验证代码,那它就只是个高级自动补全,价值有限。我实测下来,能跑命令的 agent 和不能跑命令的 agent,效率差距大概在三倍以上,因为前者可以自己发现并修复大部分低级错误。

3.2 macOS 和 iOS 双端项目的特殊处理

这个项目要同时跑在 macOS 和 iOS 上,这给 agent 带来了额外挑战。两个平台的 API 差异不小,比如通知系统、文件访问、窗口管理都不一样。我的处理方式是:

  • 把平台无关的逻辑抽成独立模块,让 agent 只写一份。
  • 平台相关的部分单独建目录,明确告诉 agent “这是 macOS 专用”“这是 iOS 专用”。
  • 每次让 agent 改代码时,明确说明目标平台,避免它把两个平台的代码混在一起。

这个做法看起来笨,但非常有效。因为 agent 最容易犯的错误就是“用 iOS 的 API 写 macOS 的代码”,而一旦你把它隔离清楚,这类错误基本就消失了。

3.3 项目结构的设计原则

我让 agent 参与开发之前,先自己把项目结构定好了。这个结构不复杂,但每一条都是为了让 agent 更容易理解:

project/ core/ # 平台无关逻辑 macos/ # macOS 专用 ios/ # iOS 专用 shared/ # 共享 UI 组件 tests/ # 验收用例 scripts/ # 构建和检查脚本

这个结构的核心思想是按平台边界和职责边界切分,而不是按技术层次切分。因为 agent 对“目录名”的敏感度远高于对“架构图”的理解,你把边界写在目录名里,它就不容易越界。

提示:不要指望 agent 理解你的架构意图,它只能理解你写下来的约束。目录结构、命名规范、注释说明,这些才是它真正的“架构文档”。

4. 核心工作流:从意图到可运行代码

4.1 任务拆解:多细才算细

我一开始犯过一个错误:给 agent 的任务太粗。比如我说“做一个通知横幅功能”,它产出的代码能跑,但样式不对、点击没反应、权限没处理。后来我把任务拆到这种粒度:

  • 定义通知横幅的数据结构
  • 实现通知权限申请流程
  • 实现横幅 UI 布局
  • 实现点击回调
  • 实现前台展示策略
  • 写验收用例

拆到这个粒度之后,agent 的产出质量明显提升。原因是每个任务都有明确的输入和输出,它不需要猜“你到底想要什么”。我总结的经验是:任务粒度应该细到“你能用一句话描述验收标准”。如果你说不清楚怎么验收,说明任务还不够细。

4.2 提示词的结构化写法

我用的提示词模板大概是这样:

目标:实现 macOS 通知横幅的权限申请流程 约束: - 只在 macos/ 目录下修改 - 使用系统原生通知 API - 权限被拒绝时要有降级提示 - 不要修改 core/ 下的任何文件 验收: - 首次启动时弹出权限申请 - 拒绝后再次启动不重复弹窗 - 拒绝状态下功能可用但有提示

这个模板的关键是约束和验收分开写。约束是“你不能做什么”,验收是“我怎么判断你做对了”。这两块写清楚,agent 的产出基本不会跑偏。我试过只写目标不写约束,结果 agent 把通知逻辑写到了 core/ 目录里,导致 iOS 端编译失败。从那以后我再也没省过约束这一块。

4.3 验收用例的写法

验收用例我坚持用可执行的方式写,而不是用文字描述。比如通知权限这块,我写的是:

func testNotificationPermissionDenied() { let manager = NotificationManager() manager.mockPermissionStatus(.denied) manager.requestPermission() XCTAssertTrue(manager.shouldShowFallbackHint) XCTAssertFalse(manager.shouldRetryPermission) }

这样写的好处是 agent 可以直接跑这个用例,自己判断有没有通过。我实测下来,有可执行验收用例的任务,agent 一次通过率大概在七成左右;没有验收用例的任务,一次通过率不到三成。这个差距非常明显。

4.4 迭代节奏:一天几个循环

我一天的节奏大概是这样的:

  • 上午:定义 3 到 5 个任务,写清楚约束和验收。
  • 中午:让 agent 跑第一轮,收集失败用例。
  • 下午:针对失败用例让 agent 修复,通常两到三轮能收敛。
  • 晚上:我自己跑一遍完整流程,确认没有回归。

这个节奏下,我一天能推进的功能量大概相当于传统开发的三到四倍。但要注意,这个倍率只在“任务拆得够细”的前提下成立。任务一粗,倍率立刻掉下来,因为你要花大量时间在返工上。

5. 那些 agent 写出来的烂代码,我是怎么处理的

5.1 能跑但不对:最常见的问题

agent 最典型的产出是“能跑但不对”。比如通知横幅的样式,它写出来的代码能显示,但圆角不对、阴影太重、字体偏大。这类问题不是逻辑错误,而是审美和规范问题。我的处理方式是:

  • 把 UI 规范写成明确的数值,比如“圆角 12pt、阴影透明度 0.15、字体 15pt”。
  • 让 agent 按数值实现,而不是按“好看”实现。
  • 验收时用截图对比,而不是靠肉眼判断。

这个做法把主观问题变成了客观问题,agent 处理起来就稳定多了。

5.2 结构烂但功能对:要不要重构

agent 写出来的代码经常结构很烂,比如一个函数干五件事、变量命名随意、重复代码多。我一开始想重构,后来发现重构的成本比重新写还高。我的策略是:

  • 如果这段代码只在一个地方用,结构烂就烂,不影响功能就不管。
  • 如果这段代码要在多个地方用,就让 agent 重新写一个干净的版本,而不是改旧的。
  • 如果这段代码是核心路径,必须重构,那就拆成小任务让 agent 一步步改。

这个策略的核心是按影响范围决定是否重构,而不是按代码质量决定。因为独立项目里,代码质量的价值远低于功能交付的价值。

5.3 性能问题:什么时候该管

agent 写出来的代码在性能上经常有问题,比如列表滚动卡顿、内存占用高、启动慢。我的判断标准是:

  • 如果用户能感知到,必须管。
  • 如果用户感知不到,先记下来,等有空再管。
  • 如果是核心路径的性能问题,立刻管。

我遇到过最典型的性能问题是列表滚动卡顿,原因是 agent 在每次滚动时都重新计算布局。这个问题用户能明显感知,所以我让 agent 加了缓存,问题就解决了。整个过程大概花了半小时,比我手写缓存逻辑快得多。

5.4 安全问题:不能交给 agent 的部分

有些东西我坚决不让 agent 碰,比如密钥管理、数据加密、权限校验。这些部分我自己写,或者至少自己逐行审。原因是 agent 对安全边界的理解很弱,它容易写出“功能对但安全有漏洞”的代码。比如它可能会把密钥硬编码在代码里,或者把权限校验写在客户端。这类问题一旦出,后果比功能 bug 严重得多。

注意:agent 可以帮你写业务逻辑,但不要让它碰安全相关的代码。这不是能力问题,是责任问题。

6. macOS 和 iOS 双端适配的实操细节

6.1 通知系统的差异处理

macOS 和 iOS 的通知系统差异很大。macOS 的通知横幅支持更多自定义,iOS 的通知权限更严格。我的处理方式是:

  • 在 core/ 里定义通知的抽象接口。
  • 在 macos/ 和 ios/ 里分别实现。
  • 用条件编译隔离平台代码。

这样 agent 在改 macOS 通知时,不会影响到 iOS 的实现。我实测下来,这种隔离方式让双端适配的工作量减少了大概一半。

6.2 数据持久化的统一方案

数据持久化我选了一个跨平台的方案,让 agent 只写一份逻辑。但要注意,macOS 和 iOS 的文件访问权限不一样,所以我在 core/ 里定义了存储接口,在平台目录里实现具体的文件路径和权限处理。这样 agent 写业务逻辑时不需要关心平台差异,写平台代码时又不会污染核心逻辑。

6.3 UI 规范的统一与差异

UI 这块我没有强行统一,因为 macOS 和 iOS 的交互习惯本来就不一样。我的做法是:

  • 共享颜色、字体、间距这些基础规范。
  • 平台特有的交互各自实现。
  • 用 shared/ 目录放真正通用的组件。

这个划分让 agent 在写 UI 时有明确的边界,不会把 macOS 的交互写到 iOS 上。

6.4 构建和测试的双端流程

构建流程我写了脚本,让 agent 可以自己跑。macOS 和 iOS 的构建命令不一样,我在 scripts/ 里分别放了 build-macos.sh 和 build-ios.sh,agent 需要构建时自己选。测试也是类似,双端各跑各的。这个流程搭好之后,agent 的自我验证能力明显提升,因为它可以自己发现编译错误和测试失败。

7. 上架 App Store 的那些坑

7.1 审核被拒的常见原因

我这个 App 上架时被拒过一次,原因是隐私政策说明不完整。agent 帮我写的隐私政策模板缺少数据收集说明,审核方要求补充。后来我补了完整的说明,第二次就过了。这个经历让我意识到,上架相关的文档不能完全交给 agent,因为它对平台规则的理解不够细。

7.2 截图和描述的准备工作

截图和描述我花了大概两天准备。截图要覆盖主要功能,描述要突出核心价值。这部分 agent 帮不上太多忙,因为它不知道你的 App 到底解决什么问题。我的做法是自己写描述,让 agent 帮忙润色和检查语法。

7.3 版本管理和更新流程

版本管理我用的是语义化版本,每次更新都写清楚改了什么。agent 可以帮忙生成 changelog,但最终的版本号决策还是我自己做。更新流程我写成了脚本,让 agent 可以自己跑构建和打包,减少手动操作。

7.4 上架后的维护节奏

上架后我保持每周一次小更新,主要是修 bug 和优化体验。这个节奏下,agent 的价值主要体现在“快速修复”上。用户反馈一个问题,我定义任务,agent 实现,我验收,当天就能发版。这个速度在传统开发流程里很难做到。

8. 常见问题与排查技巧实录

8.1 agent 产出不符合预期怎么办

最常见的情况是 agent 产出的代码能跑但不符合预期。我的排查顺序是:

  1. 先看验收用例有没有覆盖这个预期。
  2. 如果没覆盖,补用例,重新让 agent 做。
  3. 如果覆盖了但没通过,看是约束没写清楚还是 agent 理解错了。
  4. 如果是约束问题,补约束;如果是理解问题,换一种说法重新描述。

这个顺序能解决九成以上的问题。剩下的一成通常是任务粒度太粗,需要重新拆。

8.2 编译错误反复出现怎么处理

编译错误反复出现通常是因为 agent 改了不该改的文件。我的处理方式是:

  • 检查最近的修改范围,看有没有越界。
  • 如果有越界,回滚,重新定义约束。
  • 如果没有越界,看是不是依赖冲突,让 agent 自己跑依赖检查。

我遇到过最麻烦的编译错误是依赖版本冲突,agent 改了依赖版本但没同步更新锁文件。后来我让 agent 每次改依赖都必须跑一次完整构建,这个问题就再没出现过。

8.3 性能问题怎么定位

性能问题我一般用两个手段定位:日志和 profiler。日志让 agent 加,profiler 我自己跑。定位到具体环节后,再让 agent 优化。这个流程比让 agent 自己找性能问题高效得多,因为它对性能瓶颈的判断经常不准。

8.4 上架审核被拒怎么应对

被拒之后先看拒因,然后针对性修改。如果是文档问题,自己改;如果是功能问题,定义任务让 agent 改。改完重新提交,通常第二次就能过。我建议第一次提交前就把隐私政策、权限说明这些文档准备好,能省不少时间。

问题类型典型表现处理方式
产出不符预期能跑但不对补验收用例,重新定义任务
编译错误反复报错检查修改范围,回滚越界改动
性能问题卡顿、内存高日志加 profiler 定位,再让 agent 优化
审核被拒隐私政策不完整自己补文档,重新提交

8.5 我踩过的三个大坑

第一个坑是任务太粗。我一开始让 agent 做“整个通知模块”,结果产出的代码结构混乱、平台代码混在一起。后来拆成六个小任务,问题就解决了。

第二个坑是没写约束。我让 agent 改一个功能,没说明不能改哪些文件,结果它把核心逻辑改了,导致其他功能崩溃。后来我每次都给明确的文件范围。

第三个坑是没跑验收。我有一次偷懒没跑验收用例,直接提交,结果上架后被用户发现一个明显 bug。从那以后我坚持每次提交前跑完整验收。

提示:这三个坑的共同点是“省了不该省的事”。vibe coding 省的是打字时间,不是思考时间。约束、验收、范围,这三样一个都不能省。

9. 两个月下来的真实体会

九万行代码,我一行都没完整看过,但我对每一行代码的行为都有判断。这不是因为我信任 agent,而是因为我信任自己设计的验收标准和排查路径。vibe coding 的核心不是“让 AI 写代码”,而是“把人的判断力集中在真正需要判断的地方”。

这两个月里,我最大的收获不是做出了一个 App,而是找到了一种新的开发节奏:定义问题、设定边界、验收结果、快速迭代。这个节奏让我一个人能推进以前需要小团队才能推进的项目。但它也有代价:你必须非常清楚自己要什么,否则 agent 会给你一堆看起来对但实际不能用的东西。

如果你也想试这条路,我的建议是从一个小功能开始,把任务拆细、约束写清、验收做硬,跑通一个完整循环之后再扩大规模。不要一上来就让它做整个项目,那样你会在返工里耗尽耐心。等你跑通几个循环,你会发现自己的关注点从“怎么写”变成了“要什么”,这个转变本身就是最大的价值。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询