没写一行代码,Cent iOS版是如何诞生的

在我发布的第一个介绍Cent记账的视频下面,问得最多的一个问题是,在哪里可以下载呢?没办法,Cent作为一个PWA,本来是完全不需要下载的,但是如今的应用生态中,Web天生低人一等,各家手机厂商防贼一样防着浏览器,如果不出一个详细教程,初次了解的人根本学不会怎么把一个PWA安装到桌面上。因此,我决定做一个iOS原生版Cent。

至于为什么是iOS,原因也很简单,几年前我就开通了Apple Develop Program,本来打算做一些小玩具练手,但因为懒,也一直没有动手,白白花了好几年的订阅费用。对比Android,iOS生态的好处显而易见,完善的全球上架流程,一致的硬件架构,不需要考虑各种适配问题,比起国内安卓市场那堪比规则怪谈的上架机制,不选iOS简直天理难容。

我从一开始就决定完全通过Vibe Coding来进行开发,因为如果要让我从头开始学习一门其他语言开发,了解那些犄角旮旯里的不知名API,对于如今改个样式都恨不得让AI来做的我来说,几乎是不可能的。一旦尝过了AI的甜头,要想回归手写代码的时代,那就太难了。

最难的第一步

对于Vibe Coding,最难的一步不是想做什么,而是决定做哪些,怎么做。对我而言,最大的难题是如何选型。一方面,尽管我已经决定了要做iOS端,但是也不意味着完全放弃Android端。另一方面,对AI而言,代码技术也是有熟悉程度的,JS和Python对于AI是小菜一碟,但其他领域就不一定了。为此,我跟Gemini掰扯讨论了很久。

一般我会先用网页版Gemini沟通自己的想法,我认为Gemini的最大优势在于搜集信息,背靠Google这个搜索引擎,找它问问题是十分自然的事情,关键是flash量大管饱,对于要求不高的任务,直接问Gemini比AI Agent省事得多,不然一言不合就开始“让我先了解项目结构”,白花花的token就这样扔给了文件系统,造孽啊。

这一次找Gemini问完,它推荐了我一个此前我从未听说过的开发技术,KMP(Kotlin Multiplatform),根据介绍,它可以将核心操作逻辑复用一套Kotlin代码,通过不同的UI技术适配不同的平台,在Android上用Compose,在iOS上用Swift UI,简直是我的梦中情码,精准命中了我的所有需求。于是我当即决定用KMP进行开发。

然而,我完全低估了KMP,它就像一个禁忌之海,海面上是诱人的阳光和云朵,海风吹着跨平台的美梦在你的耳边低语,但是你一旦踏入,臃肿、沉重、深不见底的Gradle/Maven平台就会像漩涡般瞬间把你的心智吸入,IDE上不计其数的按钮,讳莫如深的术语,就像克苏鲁身上不可名状的眼睛一样,让你的san值直接清空。一想到我还试图在Gemini调查员的帮助下深入这座散发着诡异黄光,飘洒着warning/loading碎屑的古神小镇,我就止不住的后怕。

当我发现,无论是Gradle古神低语般的配置语法,还是诡异的平台适配装饰器代码,以及深不见底的项目文件夹目录结构,我都完全无法理解的时候,我仅剩的理智拉住了我。Vibe Coding本身就已经很黑盒了,如果再接入一套黑盒(对我而言)的开发架构,最终开发的产物简直不敢想象。因此,即使那句大名鼎鼎的“忘掉代码,只看结果”的Vibe Coding准则一直挂在我的心里,但我还是没有勇气完全对自己“产品”的代码不管不顾,最终,我放弃了KMP。

我决定先专注于iOS一个平台,此前我了解过Swift UI,尽管不多,但我相信我能在关键时刻拉下刹车,至少不至于在plan mode时对产出的方案一头雾水,然后无脑选择Accept all。虽然这不符合纯粹Vibe Coding的定义,但事实证明后来我的选择是正确的。

渐进式开发

Cent虽然是一个纯粹的Web SPA,用的都是Web 开发中十分基础的技术,React,Zustand,没有什么黑科技,但是要想一句话让AI照着Cent原模原样复制一个iOS版出来,以现在的AI能力还做不到,因此必须拆成一系列小步骤,一步一步来。

得益于Cent Web版本身解耦做的比较充分,我拆起任务来也比较得心应手。Cent的核心同步机制,我称之为Tidal,是一个纯粹的数据操作,不绑定任何特定数据库实现,因此,我首先让Claude帮我对Tidal进行迁移,先按照Tidal的机制做一个小demo,能够成功执行增删查改即可。

当然,为了让Claude更好的理解Tidal的同步机制,我不得不为整个Tidal代码补上完整的注释和文档,详细说明每一个步骤,每一个函数抽象出来的意义,本来这部分应该在Tidal诞生时就做完的,但是因为懒一直拖着,也算是为之前的工作收尾了。对于Claude来说,有原始代码和文档,迁移到其他语言非常简单,几乎只用了一个下午,我就得到了可用的原型。

为什么不让Claude自己来拆解任务和文档?我曾经试过让Claude自己了解Tidal相关的实现,但是最终效果并不好,在代码中有一些edge case,需要特殊处理,以及部分兼容性代码,在新的代码中已经不需要了,让Claude自己分析并不能很好地识别出这些代码意义,还是需要我手动补充文档,这样下来不仅耗费了更多的token,我干的活也一点没少,后来我还是选择老老实实补全文档,把每一个场景都写清楚,最终得到的结果也不负我的期待,并且,这些文档还可以用于指导后续其他平台的移植,磨刀不误砍柴工嘛。

抽卡成功

就这样,从核心同步机制开始,我一点点地把Cent的全部功能和Claude一起搬到iOS上,记账页面,搜索页面,统计页面,设置页面,iOS的功能一点点补齐了。但是在测试过程中,我也发现了一个十分严重的问题,在账单数据较少时,App运行一切正常,但是当我用真实的账本(约1w条)测试时,App突然变得十分卡顿,使用原生的代码运行,却比Web端性能更差,令我十分意外,于是我不得不再一次违反不要看代码的“准则”,看了一眼当前的代码,两眼一黑。

我知道,Claude偷懒了,它一直在用写Demo的思路写后续的功能,所有的数据变动全往一个appState里塞,几个页面的数据变动全部耦合在一起,虽然我不太懂Swift UI的状态管理,但也能意识到出了大问题。尽管之前我有意识地让它多考虑性能,多考虑耦合度,但是积重难返,可能是某次方案里我没怎么细看,直接说了句开干,后面的代码就像脱缰野马一样,撒欢跑的谁也不认识了。

我让Claude自己分析性能问题的原因,它也老实说了,核心状态管理七八百行代码,纯纯屎山代码,各个页面直接本来没有任何关系,但是数据更新全放在一个class里,每次干点什么操作不知道哪里触发了更新,就要反序列化1w多条数据,不卡才有鬼了。这下我不放心让Claude自己改了,找来隔壁的Codex,请GPT5.5喝了杯茶,看它洋洋洒洒列出一大摞优化建议,说的有鼻子有眼的,虽然我依旧不懂这样做能不能治本,但是没关系,反正有Git回档大法,这卡先抽了再说。GPT5.5十分给力,将近50个文件几百次改动,还写了个脚本用来批量替换,吭哧吭哧干了一下午,我都觉得心疼,总算是改完了。最终测试结果不负我望,性能问题消失了,虽然没有经过严格的测试,但是同样的账单数据下,卡顿彻底消失了,我总算松了口气。

没有Harness就是最好的Harness

Harness的概念最近很火,名词一套接一套的,实际上就是试图给AI定个框架,让它在这个框架里干活,避免搞出问题来。因此我也在想,如果一开始我也能把“Harness”做好,Claude是不是就不会整出这么大的幺蛾子来呢?但马上我就放弃了,对我来说,Swift开发本来就不是我熟悉的领域,让我给Claude定规则,就像关公面前耍大刀,自不量力。

整个项目里说得上Harness的东西,就是一开始我给Claude制定的“记忆”守则,我在创建项目的时候就告诉Claude,我的目标是把整个Cent Web项目完整地移植到Swift中,这是一个十分巨大的目标,因此必须要一步一步来,Claude需要制定一个精准的README,然后每一次移植都把这次做了些什么写进memory.md中,非常古老且粗糙的做法,但对我来说足够了。每次对话前,我就把README先塞进聊天框中,Claude就会按照之前的做法完善memory,如果有比较重大且成体系的改动,例如多语言适配方案、快捷指令之类的,我就让它重新编写一份单独的指导文档。这样的好处是非常省token,很多时候一些小功能改进、UI修改等,没有必要让Claude去读完整个项目的架构文件,只需要专注于一个或者几个文件即可,塞入太多东西到claude.md中不仅昂贵,还会拖慢coding的速度,没有必要,按需读取才是兼顾效率和划算的选择。

找回乐趣

不得不说,Vibe Coding真的会让人上瘾,尤其是当成果慢慢变成你心目中的样子的时候,成就感会一点点放大,本来自己手写代码也能达到一样的效果,但是Vibe Coding把这个时间压缩了几十倍。放在两年前,要将一个Web App全部转成纯血Swift UI,让我自己来干,学习的时间不说,光敲代码就要消耗了不少时间,还要费劲心力去了解各个API的用法,各种新的“最佳实践”,我还记得之前写试手app的时候,为了实现一个UI效果,在Google、Youtube、B站上来回搜索,对着视频敲代码,现在只要说句话,说清楚一点,就能实现自己想要的效果,效率高了不止一点。一次不满意还可以重抽,只要是能够实现的,总能抽出来满意的结果,Vibe Coding像抽卡果然名不虚传。

哪怕是等待Claude编写代码的简短空隙里,我都抑制不住脑子里疯狂涌出的奇形怪状的idea,恨不得挨个让它给我实现一遍,连喝口水上个厕所的时间都在想着,怎么让Claude再多干点活,整个人已经完全变成黑心老板的形状了。

那么,代价是什么

耗时将近两个月,我终于完成了整个iOS Cent App的开发和上架,准确的说,是在Claude Opus 4.7 + Chat GPT 5.5 + Cursor Compser 2.5 的帮助下完成了开发,除了代码开发之外,我还用 Claude 帮忙编写了Cent iOS发布后的一个简易宣传视频,现在在B站搜索Cent iOS版看到的视频就是由Claude编写而成,我只负责寻找BGM和录制屏幕。

而在这场看起来光鲜亮丽,轻松写意的Vibe Coding背后,是Token在不断燃烧,我做了粗略的统计,仅仅只计算我的真实支出项目,Cursor + Claude Pro + ChatGPT Pro(全部用光每月额度,Cursor甚至连auto也用到不能再用了),合计订阅费用就已经来到了$400,还没有算各种薅羊毛、注册新用户拿免费Kiro/中转站月订阅省下来的钱,在这样的情况下,即使不算App Store开发者$99年费和抽成,按照目前的Cent iOS版定价,也需要至少卖出100份才能勉强回本。从上架后的情况来看,达成这个最低目标都算遥遥无期。

这划算吗,我觉得还行,尽管从投入产出比来看,Vibe Coding的经济效益非常低,但是它给了我一次从无到有的App上架体验,我第一次成功上架并且卖出了我的第一个作品,这对我意义重大,而且只花了两个月的时间。对于任何产品而言,难的都不是做出来,而是卖出去,在没有任何营销,单纯靠自己卖吆喝的情况下,能卖出去我就已经感到非常惊喜了。

Cent 在诞生之初就是个人特色十分强烈的作品,有很多地方刻意不去迎合市面上的主流记账软件,例如资产管理等等,因此在Github收获超千k star的时候,我都感觉十分意外,决定开发iOS版,也是为了证明Tidal的潜力,不想让这套同步机制埋没在浏览器限制之中。在决定Vibe Coding前,我也曾对AI的能力边界有过高过低的期待,一方面作为程序猿,我担心AI会抢走我的饭碗,另一方面我也好奇AI究竟能做到何种程度。但是实际体验下来,尽管我确实没有手写哪怕任何一行代码,但我开始对自己有了更多的信心。

AI绝不是万能的,如果只给一句话,让AI直接复刻一个完整的iOS版本出来,它是绝对做不到的,或者说绝无可能做到现在这样的程度,Vibe Coding,更像是 Vibe Deciding,Coding反而是最不重要的一环,重要的是挑选、验证,要做什么,不做什么,等着AI问你这样做行不行,如果有一天AI真的到了一句话就能抽出完美的结果的地步,那这绝对不是一件坏事,在这之前,至少我认为我自己,还不至于完全被取代,如果AI有一天真的消灭了工作,那才是大好事呢。