← 开发日志

所有的活,一张清单

第一回之后 · 第 2 篇 · 连载中

计划做到一半,它自己变大了,你怎么办?

我带过的每一个团队都要回答这个问题,而且往往一个月不止一次。一个谁都没想到的 bug 冒出来了;有人走过来,提了一个”很小”的要求;一件事做到一半,才发现它其实是三件事。这些东西有很多名字:功能蔓延、范围蔓延、发现的工作、冒出来的任务。可是我对它们的回答都是同一个,而且一点也不高明:全部放进同一张清单,然后跟已经承诺要做的工作放在一起排优先级。

这条规则我教了大半个职业生涯。可是直到为了写这篇文章回头去翻提交记录,我才发现,我在 MoVox 上也一直在照着它做,而这个项目从头到尾只有我一个人。

原来的计划是一到两个星期。

上一篇讲到,第一回放出去以后收到的意见,给了我一件新的活:做一个白话的版本,用现在的大白话把故事讲一遍,而不是照着文言的原文读。第一个故事定的是三顾茅庐,第三十六到三十八回。

范围是我特意定得很小的。流水线上画面这一边都已经做好了,也都能用:水墨画、写实的片段、还有把这一切拼起来的剪辑。第三十七、三十八回的画当然还得画、还得审,可是那是用现成的工具,像第一回那样跑一遍就行,而且两个版本共用同一批画面。真正新的活,全在文字和声音上:把文字重新写一遍,给新的文字配音,在同一批关键帧和片段上把每一回的两个版本都做出来,一起发布。所以我估计一个星期,最多两个星期。

结果做了四个星期。第三十七回是十月二十八号上线的,第三十八回是十月三十一号。而且最后发出去的东西,已经不是我原来计划的那个了。

然后清单就变长了。

冒出来的东西有三种,而且来的时候也不分先后。

第一种是意见:写实的片段还不够写实。这件事上一篇已经讲过了:我太太,她同时也是这个项目的美术指导,说它们看起来就像”一张像真人的照片,贴在一幅卡通画上面”,而且她说得对。所以生成照片的那一整步都重新做了。

第二种是新想法。有一天晚上,我太太和孩子们在 YouTube 上看到一些 AI 做的音乐视频,里面孙悟空、猪八戒,还有刘邦、苏轼这些人,在唱现代的摇滚和说唱。孩子们觉得很酷。于是我们就聊起来,我能不能也做出这样写实的东西,让我们的人物真的开口说他们的台词。我(在 Claude 的帮助下)做了一些调研,结果发现这是做得到的,就在我这一张显卡上,而且用到的模型全都符合 MoVox 对每一个模型的要求:宽松的开源许可证,Apache 2.0 或者 MIT。为什么要有这条规则,我在讲许可证的那一篇里讲过。对口型(lip-sync)就是这样冒出来的,没有任何人计划过它。

第三种是 bug:新的活不停地翻出老的问题,因为白话版让整条流水线走了一条它以前从来没走过的路。大约四分之一的对话没有属于自己的声音,因为以前只有比较重要的人物才配了音。有些台词算到了错的人头上。张飞的声音换一种情绪就换一个音高,后来查下来,这是声音模型生成声音的方式本身的限制,不是哪个参数没调好。电脑把白话里的助词”地”读成了 dì(土地的地),而不是 de。还有一处场景切在了不对的地方,结果把前面一个场景悄无声息地弄丢了。

这些都是真问题,单拿出来看,每一件都值得做。可是如果它们来一件你就去做一件,那你得到的就是每个团队都会得到的结果:一个两个星期的计划,两个月以后还是”快做完了”,然后大家天天加班去填这个坑。

我一直在教团队的那条规则。

如果你没跑过 Scrum,我简单讲一下冲刺(sprint)是怎么回事。冲刺开始的时候,团队承诺做一批工作,这批工作的量是按团队在这段时间里实际做得完多少来定的,这个量就叫容量(capacity)。然后冲刺开始了,外面的事情可不会停下来等你。bug、新的要求、做着做着发现的活,全部交给产品负责人(PO,也就是决定这个产品什么最重要的那个人),由 PO 拿它们跟已经承诺的工作一起排优先级。

比已经承诺的工作更不急的,就等以后的冲刺再说。比它们更急的,就拉进这个冲刺来做,可是很多人会跳过下面这一步:它不是叠加上去的。拉进来多少,就要从现有的清单上挪出去同样多的量,而且先挪出去的,是优先级最低的那一些。冲刺的大小不变,变的是里面装了什么。

整条规则就是这样。这是我尽最大努力防止范围蔓延和没完没了加班的办法,这些年我作为一个带团队的人,在不止一家公司里教过它。我并不反对变化。可是不这样做,就等于假装团队的时间比实际的要多。相信我,你不会想要一个累垮了的团队。

我自己就是那个 PO,只是没意识到。

在 MoVox 上,没有什么 PO 会议,只有我一个人。可是回头去看,每一件新冒出来的事,其实都在我脑子里过了一遍同样的流程。

对口型本来不在计划里,可是它给视频带来的价值太大了。两个人在对话,嘴巴真的跟着在动,这和一个旁白对着一幅幅画念,是完全不同的两种视频。而且它跟写实画面的要求正好凑在了一起,两件事放在一起做,比分开做值得多,因为每一个对口型的镜头都是从那张照片做出来的。如果我在旧的照片上做对口型,那等照片一换,就要全部重新渲染一遍。如果我先把照片改好,再按老办法一段一段地审片段,那很多片段审完了,马上就要被对口型替换掉。

所以十月十八号的决定是:两件都做,但是分先后。先做照片,再做对口型,而且老样子的片段审查马上停掉。这样每一个镜头都只需要审一次。

这里真正费时的是什么,我想老实交代一下。我一开始以为是 GPU 的时间,其实不是。一回在显卡上要跑好几天,光是第三十七回的对口型就用了 11.6 个 GPU 小时,可是显卡晚上可以自己跑,我睡我的觉。我自己花的时间其实也不算多,审一回的画面,我肯定没有花到 11 个小时。

真正贵的是审查和重画之间的那个循环。我需要一整块时间,能坐下来把审查做完。我标出一个问题,它就被送去重画;可是等重画好了,我可能已经不在电脑前面了。于是审查在等,重画也在等,有时候整条流水线一等就是一两天,一直等到我能回来为止。所以每省掉一次重画,省下的主要是一轮或者好几轮这样的循环,GPU 的时间倒在其次。

为了腾地方,挪出去了什么。

进来一件,就要出去一件。下面就是挪出去的东西。

第一个挪出去的,是所有文言的部分。原来的计划是第三十七、三十八回两个版本一起发,可是文言的对口型和文言版的重新制作在清单上优先级最低,所以被挪了出去,最后只发了白话版。

第三十六回也拿掉了。这是很早就定下的,三顾茅庐这个故事一定下来就定了,因为第三十六回跟三顾本身关系不大,而对口型做一回差不多就要跑一个通宵,把它去掉,省下的是实实在在的时间。所以这个故事就只有第三十七回和第三十八回。

重做第一回也往后放了。第一回本身是完整的,所以我决定把旧的视频原样留着,作为这个项目走到哪一步的记录。能回头看看那些还在半路上的版本,是很有用的。

自动审查的控制台,我已经设计好了,可是判断下来,它的优先级比不上把这两回做完,所以一直没有拉进来。

声音问题真正的修法也往后推了。张飞先用了一个临时的办法,所有台词都从他那一段平静语气的录音来克隆。这个标准比真正的修法要低,可是真正的修法需要好好规划,而临时的办法一用上,它就不那么急了。

这些都不是拒绝不做,它们全都还在清单上。我从来没有正式建过一个待办列表(backlog),可是这张清单是存在的,就在设计文档和问题记录的状态里。等时间允许、需要出现的时候,优先级就会变,某件被推迟的事就会被提上来、拉进来。敏捷开发本来就应该这样:一切都是流动的,一直在变,你要做的是欢迎这种变化,别去抵制它。这条规则不会阻止变化,它只是让每一次变化的代价都摆在明面上。

那为什么两个星期变成了四个星期?

如果你一直在算账,应该已经发现问题了。既然进来一件就出去一件,计划的大小应该不变才对,可是它变了,最多两个星期,最后做了四个星期。那这条规则是不是失灵了?

有一部分是的,而且值得说清楚是哪一部分。

第一,我的估计错了。文字和声音这部分,也就是真正新的那部分,基本是按我说的时间做完的:第三十七回的白话版一个星期之内就配好了音,大约十天的时候,剪辑已经能把白话的视频做出来了。可是这个估计里也包括了第三十七、三十八回关键帧的审查,这两回的画以前从来没画过。审查算在里面,这我是知道的,只是没想到它会花那么久。这跟范围蔓延没有关系,就是估计不准,而这恰恰是超时最常见的一种原因。

第二,进来的比出去的多。文言版、第三十六回、重做第一回,加起来并没有两个星期的工作量,而照片级写实和对口型需要更多时间。到了某个时候,清单上已经没有比新进来的东西优先级更低的了,也就没有东西可以再挪出去了。

到了这一步,你手里就只剩三个办法:再砍范围,推迟日期,或者加时间,放在团队里,加时间就是加班。在公司里,日期通常是定死的,因为团队外面有别的事情在等着它。所以当范围已经砍不动了,而优先级高的事情又必须进来,加班就是最后的手段。这种事在我的团队里发生过,而且比我希望的要多,我也不打算假装没有。这条规则从来没有承诺过零加班,它承诺的是:加班是你最后才用的办法,而且是你清清楚楚做出的决定。最怕的是从来没有人说过要挪出去什么,大家就这样一步一步滑进了加班。

在 MoVox 上,没有人在等一个日期。这是一个业余项目,什么时候发布,看的是我审得多快,没有一个非上线不可的日子。所以我用的办法是推迟日期。那我是不是也多花了时间?说实话,我也说不清。这些都是下班以后的晚上,有时候不管怎样都会做到半夜以后。我能说清楚的是:日期往后推,在对口型进来的时候我就已经决定了,没有等到最后才发现来不及。

我特意拉进来的那一件。

有一件事走的是相反的方向,也是我最喜欢的一件。

整个第三十七回做下来,我每一次手动修改,都记进了同一个问题记录里:这一帧为什么不对,我是怎么改的,按原因分好类。原来的计划是等第三十七、三十八回都审完以后,再坐下来对着它做一次复盘。可是我把这次复盘提前了,放在两回中间,因为它是在还技术债,而还了这笔债,第三十八回就能做得更快。第三十七回的审查,正好就是我估计出错的地方,同样的错,我不想犯两次。复盘做出来的是一批工具,把我原来用眼睛一项一项检查的东西,变成了流水线自己会跑的检查,审查和审查里要做的那些决定,都因此快了很多。

结果真的有用。第三十七回花了几个星期,第三十八回只花了几天。

这是我讲过的一次培训里的想法,叫”花得多,省得多”,多花一点,省下更多。简单地说:花在工具、流程和思考上的时间,看起来不像是在推进,可是它省回来的往往比花掉的多得多。每一个”接下来做什么”的决定本身就是一笔投资,所以也要像看别的投资一样,看看它的回报率(ROI)。磨刀不误砍柴工。

轻流程,不等于没有流程。

团队很小,或者只有你一个人的时候,第一反应就是把流程都去掉。很多时候这也没错。我不需要跟自己开站会,不需要冲刺看板,也不需要计划会议。这些仪式都是额外的开销,而项目越小,开销占的比例就越大。

可是这些习惯教给我的东西里,有一些即使把仪式都去掉了也值得留下来。你还是有一个容量,哪怕它只是一个人下班以后的晚上,再加一张显卡。你还是会遇到做着做着冒出来的工作,它还是要跟你已经承诺的事情放在一起掂量。你还是要决定接下来最值得做的是什么,以及为什么。如果把这些全都去掉,事情并不会变快,只会变乱,而一乱,反而更慢。

轻流程,不是没有流程。要留下来的,是让你在每一件新事情冒出来的时候都会问一句的那部分:它值不值得用它要挤掉的东西去换?

这次复盘,也是下一篇的起点。下一篇要讲的是,整整一回由我自己用手去当那道检查,我从中学到了什么,以及为什么真正的修法是把检查写出来。