文章 ·
AI 能把功能写出来以后,开发者还要做什么?
从 taobook、tbnb 和 BaoCut 的实际开发经历出发,谈 AI 加速代码生成以后,需求判断、验证、数据保护与交付为何更需要开发者投入。
在做 taobook 的过程中,有一个问题让我重新认识了“功能完成”这件事。
为了支持未加密的 MOBI 和 AZW3 电子书,应用需要先把文件转换成 EPUB,再交给阅读内核。转换程序运行结束,文件生成了,书也能打开,看起来这项功能已经完成。
但继续翻到后面的章节,才发现有些内容无法正常显示。
问题藏在生成的 XHTML 里:部分内容的序列化方式不符合要求。前面的章节能读,并不能证明整本书都能读。后来修正转换逻辑,再检查整本书生成的文档,才补上了这一层验证。
这件事很小,却让我开始反复思考:当 AI 已经能够帮我写出转换程序、阅读界面和测试代码以后,开发者还要做什么?
在自己的几个项目里,我越来越多地把时间花在明确需求、检查实际行为、处理平台差异、保护已有数据,以及判断一个结果究竟能不能交付上。
代码生成变快了,这些工作也变得更加显眼。
“做一个功能”里面,藏着许多尚未决定的事
给 AI 一个任务,最方便的表达通常是功能名:增加朗读、增加筛选、支持一种文件格式。
这些指令足以开始写代码,却往往不足以决定用户最终会得到什么。
以 taobook 的朗读工具栏为例。界面上有一个工具栏,能显示播放状态,用户可以点击展开或收起。单独看,每一项都不复杂。
但当播放状态持续变化时,谁来决定工具栏是否显示?
如果读者刚刚把它收起来,下一次播放状态更新又把它打开,程序可能没有报错,按钮也都能点击,使用起来却会不断打断阅读。
这里需要先明确一条规则:读者对界面的主动操作,应当被后续状态更新尊重。播放状态可以改变按钮上的图标和文字,但不该随意抢走读者对工具栏显隐的控制。
规则明确以后,AI 有了更清楚的实现目标,测试也有了可检查的行为。
我逐渐发现,自己需要投入精力的地方,常常就是这些没有被功能名称表达出来的决定。
取消操作意味着什么?失败以后保留哪些内容?关闭页面再回来,应该恢复到哪里?新增一个标记,会不会改变原有的未读状态?
如果这些问题悬而未决,实现代码也会替我们作出某种选择。有时符合预期,有时只是碰巧能运行。
开发者需要把这些隐含的选择找出来,明确写进产品行为里。
验证要沿着使用过程继续往下走
电子书转换的问题让我形成了一个习惯:看到“成功”,先看清楚它具体证明了什么。
转换成功,证明转换过程走完了;文件能打开,证明阅读器能够识别它;第一章正常,证明这一章的内容可以呈现。要判断整本书能否阅读,还得继续检查后面的章节、目录和文档结构。
在 tbnb 的开发里,这种区别同样重要。
tbnb 是我持续迭代的旅行应用。自动检查通过、应用编译通过、签名完成、安装到 iPhone,以及在手机上完成一段实际操作,各自回答不同的问题。
有一次真机检查,我通过手机操作进入找房页面、打开筛选,再取消返回。这能证明当时这段路径可以走通。它没有覆盖订单提交,也不能据此推断整个预订流程已经完成。
这样的表述看起来有些克制,却能帮助后续开发:我知道已经检查到了哪里,下一步还需要看什么。
如果把局部成功概括成“全部可用”,遗漏的部分就很容易从待办事项里消失。
现在,我更愿意按使用过程组织验收:从哪里进入,做了什么选择,界面如何变化,是否写入数据,取消后回到哪里,失败后怎样继续。
验证的对象需要从代码里的一个方法,延伸到用户实际走过的一段过程。
AI 也可以帮助执行检查、分析结果、补充测试。开发者仍需要判断:这次证据覆盖了什么,还有哪些结论暂时不能下。
这是从项目经历中归纳的工作流程。点击可查看大图;虚线表示验证未通过时,返回实现继续修改。
功能越容易增加,越需要控制项目的方向
AI 带来的一个直接变化,是增加功能的阻力变小了。
想到一个入口,可以很快加上;看到一个产品里有某种能力,也容易产生“我们也做一个”的想法。
但项目里多出一个页面,往往意味着多出一组状态、多一份数据关系,以及未来需要维持的行为。
做 tbnb 时,我逐渐意识到,对照成熟产品也需要有明确的问题。看见一个不同的界面,应该先判断:是已有能力缺少入口,是客户端尚未接上接口,还是背后的业务规则根本不存在?
这三种情况,需要投入的工作完全不同。
如果只是按照截图补页面,很容易先得到相似的外观,随后才遇到库存、费用、权限和重复提交的问题。界面已经在那里,底下的规则却还没有决定。
taobook 的多平台开发也让我不断作取舍。
iOS、Android 和鸿蒙各自有文件处理、阅读呈现、语音服务和生命周期方面的条件。希望用户在不同设备上顺畅阅读,并不意味着要让每一端立刻拥有相同的功能列表。
先把某一端的本地导入、阅读进度和听书做好,是一种具体的产品选择。它也意味着,有些能力需要暂时留在范围之外。
当实现速度提高以后,我需要更频繁地问自己:这项能力是否服务于最初的使用目标?它现在值得加入吗?我能不能把后面的维护也接住?
软件一旦有了数据,修改就有了历史负担
项目早期,重装应用、清空数据库、重新开始,似乎都很方便。
等到应用里有了阅读进度、收藏、会话和日常使用记录,这些操作的意义就变了。
在 tbnb 的持续迭代中,我越来越重视一个问题:新版本运行起来以后,原来的数据还在不在,归属关系是否正确,用户能不能继续原来的操作?
代码可以退回旧版本,数据库里的变化却不会因此自动消失。身份、会话以及已经发生的业务写入,都有自己的状态。
这也是我后来要求把备份、迁移检查和安装后的数据核对分别记录的原因。
安装前有备份,说明保留了恢复的可能;安装后能够启动,也不能证明每一类数据都被完整保留。需要读回并比较的数据,仍然要实际检查。
有些检查如果因为设备连接中断等原因没有完成,就应该继续列为未完成。
对持续使用的软件来说,“更新以后还能接着用”本身就是重要的产品能力。它需要进入开发计划,也需要占用真实的验证时间。
交付还要回答:谁能用,能用到哪里
参与 BaoCut 的 Intel Mac 适配时,这个问题变得很具体。
BaoCut 是一个围绕可编辑时间线组织 AI 视频处理的项目。我维护的版本基于上游 fork,Intel Mac 适配只是其中一部分工作。
源码能够编译以后,还要处理原生组件、打包、签名、公证和安装。走到这一步,用户才开始有机会在自己的电脑上打开它。
接下来还会遇到硬件和模型后端的差异。上游列出的能力,不能原样变成 Intel 版本的可用清单。有些依赖特定平台的能力需要关闭,有些路径则需要单独验证。
因此,发行说明必须交代适用的系统和架构、外部依赖、功能限制,以及实际检查过的范围。
打包与公证通过,可以支持对应的交付结论。真实模型推理、完整剪辑和导出,如果没有走过,就仍然需要验证。
这部分工作不会让功能列表显得更长,却会影响别人能否正确使用软件,也会影响他们遇到问题时如何判断。
BaoCut 还有一个让我认同的设计方向:让 AI 的修改留在可编辑的项目里,让人可以继续检查、调整和接手。
这也影响了我对 AI 开发过程的期待。我希望它留下清楚的修改记录、验证结果和未完成项,让下一轮工作有据可查。
把反复提醒,变成项目能够执行的规则
刚开始用 AI 做长时间开发时,很多要求都依赖对话提醒。
记得检查真机。不要清理日常数据。测试要覆盖相关模块。完成后说明还有什么没有验证。
这些话可以说很多遍,但对话越来越长以后,重复提醒本身也会产生负担。
在 tbnb 中,我开始把这类要求整理到开发文档、流程清单、检查脚本和变更模板里。让常用检查有统一入口,让一次变更能够留下目标、范围、结果和未验项。
这样,人与 AI 可以围绕具体记录继续工作,不必每次从头复述整个项目。
规范也需要控制成本。小范围的文字修改,不必经历与数据库迁移相同的验收;涉及身份、数据和发布的变更,则需要更充分的证据。
我希望逐渐形成的开发方式,是让重复工作能够重复执行,让重要判断有清楚的依据。
AI 可以承担其中相当多的执行工作。开发者需要根据实际问题,持续调整这些规则。
我仍然需要对“完成”作出判断
这些项目让我更愿意把 AI 看成一个能够深入参与开发的合作者。
它可以写代码、分析问题、补测试、整理文档,也可以协助构建和操作设备。很多过去需要长时间投入的工作,现在有了更快的起点。
与此同时,我对“完成”的要求也变得更具体了。
taobook 能导入一本书之后,我还要知道后面的章节能否继续读;tbnb 的页面能够打开之后,我还要知道取消、恢复和数据保存是否符合预期;BaoCut 能生成安装包之后,我还要说明这份包适合哪些机器,以及哪些工作流尚未验证。
这些判断最终要回到实际使用中。
代码会执行某种确定的行为,而用户带来的文件、设备、习惯和已有数据,始终比一次指令里写得下的内容更多。
所以,AI 能把功能写出来以后,我仍然有许多事情要做:选择值得解决的问题,把模糊的需求变成明确的行为,取得足够的验证证据,再让成果进入日常使用。
我希望自己交出去的软件,经得起这样的检查:用户把它装上,带着自己的数据走完需要的过程,第二天回来,仍然可以接着用。
评论
使用 GitHub 账号参与讨论。 前往 GitHub 评论