70% 问题是指生成通常将软件构建推进到大部分可工作状态,然后在剩余部分遇到人类难以自动化的阻力而停滞。这最后那一小部分不是更小规模的同样代码,而是质的不同工作:集成、边界情况、生产稳健化,以及最初没有人愿意明确规定的部分。前半段奖励流畅性;后半段奖励判断力,而判断力并不像样板代码那样可压缩。
- 前70%是明确规定的表层;剩余部分是未明确的内部。
- 演示证明了理想路径,并隐藏会使其失败的条件。
- 边界情况的数量增长速度比任何提示所能列举的都快。
- 集成摩擦发生在系统之间,任何单一的生成器都看不到的地方。
- 生产稳健化基本上是在防御那些没有人描述的输入。
- 该曲线随时间推移在变化,但困难的形状不会改变。
为何最后一段在本质上与第一段不同?
构建的前段密集地包含了已经被描述成千上万次的结构。表单、列表、路由、状态、一个具有可预测字段的数据形状。生成在这里之所以强,是因为模式常见且意图清晰。对于一个可排序表格或一个经过验证的表单应当做什么几乎没有歧义。
剩余部分在性质上不同。它属于一种系统的属性:在规格用尽后,现实仍在继续。两次写入竞争会发生什么?上游接口返回了它承诺永远不会返回的一个形状?用户做出合理但出乎意料的行为?这些问题并不是早期问题的更难版本。它们属于一个独立的类别,其定义不在于编写代码,而在于在原始请求从未命名的条件下,决定代码应当表示的含义。
还有一个反馈效应。早期代码生成很快,因此也积累得很快,体量本身成为需要跨越的地形。几分钟内成型的构建仍然需要在数小时内理解。读者会遇到自己没有编写、没有选择的约定的结构,理解成本恰在需要做出艰难决策的时刻落下。
这就是为什么百分比会让人觉得滑移不定。随着模型改进,边界会移动,但它沿着同一条断层线移动:显式规格结束的地方,自动化就会变慢。坡度恰恰在描述变少的地方变陡。一个看起来在进步的图形,其实是在一个不断向那些一直不太易读的部分移动的前沿上的标记。
演示隐藏了生产揭示的哪些内容?
演示是一次受控的演出。它在一个宽容的网络环境中、对输入进行选择、只跑一条路径、在希望它成功的观众面前运行。生产则是对立的相反:每条路径都要同时应对、对输入怀有敌意、存在部分失败、且没有人来引导。那两种状态之间的距离就是演示到生产之间的差距,也是大多数末端一里程努力真正发生的地方。
差距之所以宽,是因为一个可工作的演示和一个可工作的系统看起来相似,但结构并不相同。演示优化的是可见部分。系统必须考虑看不见的部分——重试、幂等、每周才触发一次的超时、在流量持续时必须运行的迁移。以上都不会在屏幕录制中出现。
一个浮现的权衡是速度与耐用性之间的权衡。生成获得一个快速、可信的产物。把该产物转化为能经受真实负载的东西往往更慢,且很少看起来像是在生成更多代码。它看起来像是阅读、追踪并约束已存在的内容。
差距还带来感知成本。一个令人信服的演示给人一种工作几乎完成的期望,这使得剩余的工作看起来像是在回退,而不是整个工作的主要部分。利益相关者亲眼看到它能工作。那个时刻与一个可靠系统之间的距离是实际的,但很难辩护,因为对只看过演示的人来说,它是不可见的。
为何最难的剩余部分出现在没有人指定的地方?
未指明的剩余部分指的是系统必须具备的、从未在任何请求中被写入的行为。它是末端成本中最大的一部分,因为它不能从一个不包含它的提示中生成。生成器只能回答所被问及的问题。难点在于那个没有人想到要问的问题。
规格在最关键的位置成本最高。没有人会去明确结账在支付界面确认但订单写入失败时应做什么,因为没有人愿意在它发生之前去考虑它。所以明确的意图与所需行为之间的差距成为要做的工作。必须有人注意到这缺失、给它命名并做出决定。
注意到这是这里被低估的技能。生成器会填充它所得到的内容,对于它未得到的内容保持沉默,这种沉默在只检查理想路径的人看来就等同于完整。剩余部分是构造上不可见的。揭示它意味着在压力到来前就设想系统在压力下的表现,这是一种注意力的习惯,而不是任何工具自带的特征。
- 理想路径
- 演示要展示的唯一事件序列,在其中每个依赖都按预期工作。
- 未指明的剩余
- 系统必须具备的、任何请求、提示或工单从未描述过的行为。
- 集成缝
- 两系统之间的边界,其中对对方的假设未被明确说明。
- 生产加固
- 使生成结构在面对未呈现的输入、故障和负载时仍然可用的工作。
人力投入将转移至何处,当生成吸收前70%?
人力并不消失;它在迁移。当一个构建的早期、明确规定的主要部分在几分钟内生成时,曾经用来敲击代码的人工时钟会转向生成在弱点处的活动。阅读不熟悉的代码成为一项主要技能。决定系统在边缘处应做什么成为稀缺的贡献。
这种迁移改变了一天的形状。用于编写初稿的时间变少,转而用于阅读、核对和决定失败行为,使判断力和对边界情形的推理成为稀缺的贡献。
它还改变了哪些经验值得。看到许多系统失败的经验对生成器没有直接转移;它存在于那种能在不熟悉的代码中辨别熟悉气味的人身上。这种识别让人只要瞥一眼生成的流程,在任何测试运行之前就能感知它会在哪些地方崩溃。早期代码被商品化;对边界的直觉并不会因此消失。
| 属性 | 前70%(生成) | 后30%(人工) |
|---|---|---|
| 规格 | 显式、常见、易读 | 隐式、罕见、存在争议 |
| 主导活动 | 生成结构 | 约束行为 |
| 故障可见性 | 在演示中明显 | 在生产前隐藏 |
| 成本驱动因素 | 代码量 | 判断深度 |
| 可压缩性 | 高 | 低 |
团队如何有意跨越最后一段?
跨越末端里程通常遵循一定的顺序,而不是因为存在一个固定的配方,而是因为失败以可预测的顺序到来。这个纪律是将生成的产物视为假设,将剩余的工作视为证伪。
- 绘出缝隙:列出构建接触到的、它不控制的系统的每一个边界。
- 枚举演示从未使用过的输入,尤其是格式错乱、空输入和重复输入。
- 将每条失败路径追溯到一个决策:重试、拒绝、降级,或暴露。
- 通过把无人明确指定的行为写下来来将隐含的显性化,然后进行选择。
- 在宣布完成之前,用真实并发和真实负载对结果施压。
每一步都把未知转化为明确的意图。生成的70%给你一个待审视的主体;这个过程就是审问。它比生成本身慢,这是有意的,因为它的产物是确定性,而不是表面的东西。
顺序比任何单独的步骤更重要。先映射缝隙可以防止常见的把内部硬化而边界仍未防守的错误。先枚举输入再追踪故障,使工作基于实际到达的内容,而不是想象中的内容。这个序列是一种把注意力花在下一次更可能出错的地方的方式,而不是花在代码最易读的地方。
随着生成能力的提升,边界将变成什么?
边界并非消解;它在向上移动。随着生成处理更多明确规定的中段,人的边界移动到那些一直最难以描述的部分——判断、故障语义,以及在系统出错时对用户应承担何种责任的决策。百分比可能上升。剩余部分的特性变得更难,而不是更容易,因为剩下的部分是所有抵抗规格的残留物。
因此,越来越稀缺的不是编码能力,而是把系统边缘牢记在心并做出正确决策的能力。这个领域倾向于奖励那些能快速阅读、富有建设性地提出怀疑并完成工作的人。生成构建的最后阶段会保持人类角色,只要系统的某个部分仍然未被指定——也就是说,较长的一段时间内。
对团队组织也有一个更静默的含义。如果生成的中段继续增长,区分一个完成的系统与一个看起来可行的系统的工作就会聚焦在更少但更密集的时间里。那往往更重视深度而非产出速度,并且使在故障情况下描述系统应有行为的能力比生产更多内容的能力更有价值。前沿在移动;它不会闭合。
F.A.Q.
