用 AI 通过 275 次提交更新 side project
前段时间我所在的公司放了年中假,大家都在差不多同一时间休两周。作为管理者,之前我用 AI 工具多半是做代码审查和技术探索,没怎么真正用来写代码,这次想改变一下。
于是我假期里一直在捣鼓自己的 side project——Gifty Weddings。之前我在 2016 年把它重构成 Go 后端,2019 年换成了 Elm 前端。这次我有两个目标:
- 把它从单纯的婚礼礼物登记册,升级为婚礼网站构建工具。
- 学会如何用 AI 工具写出高质量的代码。
在同事的推荐下,写代码的主力我用的是 Claude Code 搭配 Opus 5。一些小任务则用 Pi加开源权重模型 GLM 5.2 来完成。当然,也用了我自己的脑子。
开个玩笑,但我确实觉得,动脑子正是区分“批量生产垃圾”和“做出能让自己骄傲的产品”的关键。我们终究还是工程师。
这篇文章里,我会聊聊我对 AI 的怀疑,也会说说我觉得这个项目能成功的原因,以及为什么我做得很开心。
我的怀疑
我对 AI 怀疑很久了,最早是那个 AI 聊天机器人爱上《纽约时报》记者的时候,后来更是要应付大量由所谓“贡献者”投喂的 AI 垃圾,怀疑就更深了。
2024 年我曾试过用它写代码,效果并不好。当时我花在修补它生成代码上的时间,比自己从头写还要多。
最近我又试了两次:一次是几乎一口气为我妻子搭建了室内设计网站,另一次是用它修复 GoAWK里的各种 bug(其中一次 Opus 4.6 表现得相当犹豫不决)。
这两次都让我印象不错:做网站那次是因为我本来就不太喜欢写 CSS,修 bug 那次则是因为它确实加快了进度,还给了我不少好点子。
我的做法
首先,我是一名经验还算丰富的 Web 开发者。这意味着我能有效地引导整个过程,也能有效地审查 agent 的输出。顺带一提,我对 AI 最大的担忧之一,就是新人会想走捷径,跳过这些来之不易的经验积累。
其次,我是在已有基础之上构建。我用了旧站的 CSS 样式表(它本身又是基于 Skeleton的)、大部分 SQL 数据库结构,以及一份清晰的构建计划。此外,我还亲手写了初始的 Go 服务和几个 package,很大程度上复用了旧版 Gifty 的代码。我先给项目定下了我想要的代码风格。
在此基础上,我采用的是迭代开发,而不是想一次性搞定:每一步我都保持技术和创意上的主导权。每次改动,我通常用几句话的 prompt 提出功能需求,然后审查生成的代码,并在浏览器里实际测试功能。
我做了适度的代码审查。在代码工艺上不得不做些让步——它写的代码风格并不完美,至少很多地方不是我会选择的方式。当然,遇到 bug 我会指出,结构上的问题也会提出质疑,但总体来说,我对它写的代码还是挺满意的。
不过,我没有仔细审查测试。AI agent 似乎会写大量测试——有时多得离谱,我删掉了不少我觉得得不偿失的。起初我还会看一些细节,到后来基本就是粗略扫一眼了。
过程中我也学到了不少:
- LLM 写的注释特别啰嗦。我得不断提醒它要简洁、只写一行概括。在一次“精简注释”的提交里,我把大约 2500 行注释缩减到了 1500 行。
- 当我让 Claude 装上无头浏览器、自己截图后,它写 HTML 和 CSS 的能力明显变强了。在那之前我得自己截图再手动上传。现在它有了超能力:它会启动服务,用应用真实的表单添加假数据,然后用 Chromium 保存 PNG 截图并“查看”效果。
- 不过,每次改动都截图并处理会消耗大量 token。最后我只在做较重大的前端改动时才让它这么做。
- 即使被关在容器里(我用的是 Canonical 的 Workshop),Claude 还是会干些烦人的事。好几次它执行了类似
rm -rf $SOMEVAR/*.png的命令,但SOMEVAR根本没赋值,结果把我用来测试的照片全删了。我在它的记忆里加了些规则想让它别再这样——总之,一定要在容器或虚拟机里运行 LLM。 - 别把所有工作都放在同一个会话里。我一开始就是这么做的,但上下文很快变得非常长,没多久就触到了 Claude Pro 的各种限制。于是我了解了压缩上下文,并开始定期开启新会话。
接下来看看我做的功能。
功能
Gifty 能让一对新人创建一个包含照片、文字和礼物登记册的简单多页婚礼网站。(旧版 Gifty 只支持登记册功能。)

新人可以用 Markdown 区块编写文字、上传照片(照片会被压缩并存储在 Tigris 上)、添加和调整页面顺序等等。当然,我也会收一点费用,支付通过 Stripe 处理。
宾客可以浏览新人的网站,并在礼物登记册上勾选已送的礼物。
不过我最喜欢的功能是从旧版 Gifty 延续下来的:新人可以一键试用。
技术栈
我喜欢保持简单,所以用了以下技术:
- Go 后端,尽可能少用非标准库的依赖:用于上传的 AWS SDK、Stripe SDK、一个图片缩放库、一个 Markdown 渲染器、
modernc.org/sqlite模块,以及“近乎标准库”的golang.org/x/crypto模块。 - 出色的 SQLite 数据库。
- Htmx负责更具动态性的部分:礼物登记册和页面编辑功能。
- 以及在合适的地方加的几行原生 JavaScript。
网站托管在 Fly.io上,我非常推荐它来做这类项目:fly deploy非常方便,价格也不贵。
心怀感激
完成新网站大概花了 10 个整天。我非常感谢 AI 工具,尤其是这次的 Claude。我跟妻子说,如果不用 AI,恐怕要花三倍的时间。
最让我印象深刻的一点是 Claude 移植旧礼物登记册系统的表现——原来是 Go JSON API 加 Elm 前端的架构,要移植到新版本 Go HTML 接口加截然不同的 htmx 前端。它几乎一次性就完美完成了,这让我喜出望外,也省了大量时间。
另一件几乎一次搞定的事(后续只有几个 bug 修复)是生成了一个迁移工具,用来把旧版 Gifty 的数据库迁移到新版。这算不上什么高深技术,毕竟两个数据库结构相似,只是有些结构上的差异,但我原本以为这会需要更多轮迭代。
但话说回来,既然我总体上对 AI 持怀疑态度,为什么这次会这么享受呢?我想有两个原因:
第一,我喜欢创造东西。大约 10 天就完成了一个实用又好看的网站。
第二,我喜欢编程这门手艺,而我依然感受到了这一点。我会构思下一个功能,让 AI 去实现,然后审查代码、修复 bug、提交。如此反复 275 次。小功能花 10 到 15 分钟,大功能花一两个小时,但朝着目标持续前进的感觉真的很棒。
我依然有不少担忧,也希望我们不会用这些工具去建造一座通天之塔,以至于上帝不得不再来给我们一点教训。不过,我还是很感激这些新工具。
最后一件事:如果你近期要结婚,或者认识要结婚的人,欢迎把新的 GiftyWeddings.com推荐给他们。如果你想结婚但还没找到对象——抱歉,这就是另外一个网站的事了!
随机一篇博客
评论
登录后参与讨论