Skip to content

Matt Pocock 演讲:AI 时代,软件基本功反而更重要 | AI Engineer Europe

字数
4632 字
阅读时间
18 分钟

逐字稿(中文配音(p=2,中配中字版))。由 faster-whisper (medium, CPU int8) 自动转写,可能存在个别识别误差(专有名词、人名、书名等),请以原视频字幕为准。


[00:15] 会议开到现在还顺利吗? [00:18] 大家这个会开得还开心吗? [00:20] 很好,太棒了! [00:22] 我今天带来一个消息 [00:24] 希望它能让那些觉得自己的技能 [00:26] 在新时代一文不值的人感到安慰 [00:29] 我认为软件基本功在今天的分量 [00:32] 比以往任何时候都重 [00:38] 我是个老师 [00:39] 最近在教一门课 [00:41] 叫 Claude Code for Real Engineers [00:45] 这名字起得挺挑衅的 [00:47] 做这门课的过程中 [00:49] 我得给AI编程设计一套课程体系 [00:52] 这事儿有点像噩梦 [00:54] 因为一切都在不停变化,对吧? [00:57] AI是一个全新的范式 [00:59] 按理说 [01:00] 肯定得把老规矩全扔掉 [01:03] 才能迎接新东西,对吧? [01:05] 围绕这种想法 [01:07] 还兴起了一个流派 [01:08] 叫Spec2Code运动 [01:11] Spec2Code主张式 [01:13] 你可以写一份规格书 [01:15] 描述一个应用应该怎么工作 [01:18] 然后用AI把它变成代码 [01:20] 应用出了问题 [01:22] 那就回到规格书 [01:23] 代码本身你基本不用看 [01:25] 改规格书就行 [01:27] 再跑一次编译器 [01:29] 然后又得到一批代码 [01:32] 听说过这套东西的 [01:33] 举个手 [01:35] 听过的里面 [01:36] 实际试过的手别放 [01:38] 好,我也试过 [01:39] 大家可以把手放下了 [01:41] 我发现我跑起来之后 [01:43] 本来尽量不去看代码 [01:44] 但最后还是会看 [01:46] 第一轮出来一批代码 [01:48] 跑一遍得到更差的代码 [01:50] 再来一轮代码更差 [01:52] 又来一轮编译器跑个不停 [01:55] 最后得到的全是垃圾 [02:00] 有过同样经历的 [02:01] 举个手 [02:02] 我认为这条路走不通 [02:04] 完全不看代码 [02:06] 让代码自己管自己 [02:08] 这不过是换了个名字的 [02:10] Vibcoding [02:13] 但当时我还不愿意承认这一点 [02:16] 我当时想的是 [02:17] 怎么把这台编译器修好 [02:19] 怎么让它别每跑一次 [02:21] 就产出更差一等的代码 [02:24] 于是我想得用英语跟大模型 [02:27] 讲清楚好的代码库长什么样 [02:30] 我翻出了自己最喜欢的一本老书 [02:33] Joel Osterhout [02:34] 写的《软件设计的哲学》 [02:37] 去Amazon上买一本 [02:40] 他给坏代码下过一个定义 [02:43] 他管它叫复杂代码 [02:45] 复杂度是软件系统结构中 [02:48] 任何让你难以理解 [02:50] 难以修改这个系统的东西 [02:53] 所以坏的代码库 [02:54] 就是难以修改的代码库 [02:57] 一改就出bug的代码库 [02:59] 就是坏代码库 [03:00] 好的代码库改起来很轻松 [03:03] 我心想这个说法真好 [03:05] 再试一本书 [03:06] 这本叫《程序员修炼之道》 [03:09] 也去Amazon买一本 [03:11] 这本书有一整张讲的就是《软件商》 [03:14] 而这正好就是我看到的情形 [03:17] 商讲的是 [03:18] 事物总在滑向灾难 [03:21] 四散飘离走向崩塌 [03:24] 大多数软件系统也正是如此 [03:27] 每次改代码 [03:28] 如果你只盯着这一次改动 [03:30] 不去想整个系统的设计 [03:33] 代码库就会越来越糟越来越糟 [03:36] 我看到的就是这个 [03:38] spectacode那套反复跑编译器的想法 [03:42] 产出的是越来越差的代码 [03:45] spectacode运动背后 [03:47] 还有一个观念叫代码很便宜 [03:50] 听过代码很便宜这句话的举个手 [03:53] 好 [03:55] 我觉得这话不对 [03:57] 我认为代码一点都不便宜 [04:00] 事实上坏代码的代价 [04:02] 从来没像今天这么高过 [04:05] 因为你的代码库要是难以修改 [04:07] AI能给你的那些红利 [04:10] 你就接不住 [04:11] 因为AI在好的代码库里 [04:13] 表现真的非常好 [04:17] 这意味着好代码库 [04:19] 钱所谓有地重要 [04:20] 也就意味着软件基本工钱所谓有地重要 [04:24] 这就是今天这场演讲的论点 [04:27] 那我们进入实操部分 [04:29] 我会讲几种失败模式 [04:32] 有的你可能已经经历过 [04:33] 有的还没遇到 [04:35] 而避开他们的方法 [04:36] 就是回到那些老书里 [04:38] 回到好的软件实践 [04:40] 可以吗 [04:42] 第一个失败模式 [04:44] AI做出来的不是我要的 [04:47] 我脑子里明明想得挺清楚 [04:50] AI却做出完全不同的东西 [04:52] 或者给了些我 [04:54] 总之它做出来的根本不是我想要的 [04:56] 壮过这种模式的 [04:58] 举个手 [04:58] 好可以 [05:00] 程序员修炼之道里有一句话 [05:04] 没有人确切知道自己想要什么 [05:07] 也就是说你和AI之间存在一道沟通的墙 [05:11] 对吧 [05:13] 你跟AI对话的过程 [05:15] 其实就是在帮它做需求收集 [05:19] 它是在从你身上弄清楚 [05:21] 你到底需要什么 [05:23] 后来我意识到 [05:24] 还有一本书 [05:25] Frederick P. Brooks写的 [05:27] The Design of Design [05:29] 里面讲到一个概念 [05:30] 叫设计概念 [05:32] 他说的是 [05:33] 当不止一个人一起设计某个东西时 [05:37] 你们之间会漂浮着一个想法 [05:39] 一个关于我们在造什么的 [05:41] 稍纵即逝的念头 [05:43] 你们在造的那个东西 [05:45] 或者说对它的那个构想 [05:48] 就叫设计概念 [05:50] 它不是一份资产 [05:51] 不是能塞进Markdown文件的东西 [05:54] 它是关于你在造什么的那个 [05:57] 看不见的理论 [06:00] 于是我明白了 [06:01] 问题出在这儿 [06:03] 我和AI没有共享同一个设计概念 [06:06] 所以我写了一个skill [06:08] 这个skill非常非常简单 [06:10] 它叫Grill Me [06:11] 长这个样子 [06:13] 就这份方案的每一个方面 [06:16] 毫不留情地追问我 [06:17] 直到我们达成共同理解 [06:20] 沿着设计数的每一个分支走一遍 [06:23] 设计数也是Brooks的概念 [06:25] 把决策之间的依赖一个一个解决掉 [06:29] 这个skill收录它的那个仓库 [06:32] 现在大概有13000个star [06:34] 直接就火了 [06:36] 直接病毒似传开了 [06:38] 大家特别喜欢它 [06:40] 就这么两行字 [06:42] AE会问你40个60个问题 [06:45] 我见过它问满100个问题 [06:47] 才确认双方达成了共同理解 [06:51] 这等于把AI变成了某种对手 [06:54] 它不断向你抛出问题 [06:56] 逼着你们对其理解 [06:59] 而这样聊出来的对话 [07:00] 你可以直接拿去整理成 [07:02] 产品需求文档之类的东西 [07:05] 改动小的话直接拆成issue就行 [07:09] 然后你的AFK agent就会接手去干 [07:12] 大家别来干我 [07:13] 但我个人认为 [07:15] 它比我用的工具自带的默认plan mode [07:18] 更好用 [07:19] 那个工具就是cloud code [07:22] plan mode特别急于产出一份资产 [07:25] 它就是想赶紧写完计划 [07:27] 马上开工 [07:29] 而我觉得先达成共同的设计概念 [07:32] 要舒服得多 [07:35] 这是第一条建议 [07:37] 第二个失败模式 [07:38] AI话太多了 [07:41] 感觉你跟AI几乎在鸡同鸭讲 [07:44] 有过这种感受 [07:45] 经历过这个失败模式的举个手 [07:49] 就像AI在说话的时候 [07:51] 总要用一大堆词 [07:53] 才讲得清它在干什么 [07:55] 你们说的根本不是同一种语言 [07:58] 这个感觉对我来说太熟悉了 [08:01] 对吧 [08:02] 如果你做过多年开发 [08:04] 跟领域专家合作过 [08:06] 比如对方要你做一个应用 [08:08] 领域是芯片什么的 [08:10] 你对芯片一无所知 [08:12] 你们就得先建立某种共同语言 [08:15] 对吧 [08:16] 不然的话 [08:16] 他们满嘴都是你听不懂的术语 [08:19] 你再把这些翻译成代码 [08:22] 可能连你自己都看不懂 [08:24] 领域专家就更看不懂了 [08:26] 所以你和领域专家之间 [08:29] 就横着一道语言的鸿沟 [08:32] 于是我回去翻了领域 [08:33] 驱动设计 [08:34] 滴滴地 [08:36] 这块我还在初学阶段 [08:38] 但读到的滴滴内容 [08:40] 句句都说到我心坎里 [08:42] 我简直是爱死了 [08:44] 滴滴地里有个概念叫统一语言 [08:49] 有了统一语言 [08:51] 开发者之间的交流 [08:53] 代码里的表达 [08:54] 跟领域专家的对话 [08:56] 全都来自同一个领域模型 [08:59] 落到实处 [09:00] 它就是一个markdown文件 [09:02] 列着你和AI共同使用的一串术语 [09:06] 你要真正聚焦在这些术语上 [09:09] 确保每个术语都对准它真实的含义 [09:12] 写代码的时候用 [09:13] 聊代码的时候用 [09:14] 跟领域专家沟通的时候用 [09:16] 在我们这个场景里 [09:17] 就是跟AI沟通的时候用 [09:20] 所以我做了一个scale [09:21] 这个scale就叫统一语言scale [09:24] 它会扫描你的代码库 [09:26] 找出里面的术语 [09:27] 然后生成一个markdown文件 [09:31] 生成的统一语言markdown文件里 [09:34] 是一张张装满术语的表格 [09:37] 然后我把它交给AI [09:39] 我自己也随时能读 [09:41] 事实上我平时跟AI做盘问 [09:44] 做规划的时候 [09:45] 它一直开着 [09:46] 后来我去读AI的思考轨迹 [09:49] 发现它不仅改善了规划 [09:50] 还让AI的思考不再啰嗦 [09:53] 最终写出的实现 [09:54] 也更贴合你真正规划的东西 [09:57] 所以这一招是真正的杀手锏 [10:00] 效果好的难以置信 [10:02] 这是第二条建议 [10:04] 和AI建立共同语言 [10:07] 好 现在假设你已经跟AI对齐了 [10:10] 你们清楚自己该造的是什么 [10:13] AI也把东西做出来了 [10:14] 但它跑不起来 [10:17] 遇到过这种情况的举个手 [10:20] 对就是跑不起来 [10:22] 有个显而易见的改进办法 [10:25] 用反馈回路 [10:26] 用静态类型 [10:27] 不用typescript [10:29] 那真是疯了 [10:30] 做前端应用 [10:32] 却不给大模型浏览器访问权限 [10:35] 让它自己看看页面长什么样 [10:38] 这是绝对必要的 [10:40] 当然还需要自动化测试 [10:44] 还有一个 [10:46] 我注意到的现象是 [10:48] 就算有了这些反馈回路 [10:50] 大模型也用不好 [10:52] 它不像资深开发者那样 [10:55] 能把反馈回路的价值榨干 [10:58] 它的毛病是一次做太多 [11:00] 先花花产出一大堆代码 [11:03] 然后才想起来 [11:05] 好像该做一下类型检查 [11:07] 或者要不要跑个测试之类的 [11:11] 程序员修炼知道 [11:12] 管这个叫开的比车灯还远 [11:15] 说白了就是开太快 [11:17] 因为反馈的速度就是你的限速 [11:20] 反馈的速度就是你的限速 [11:22] 也就是说 [11:23] 你应该边走边测 [11:25] 卖小步 [11:26] 有意识的卖步 [11:28] 而AI默认状态下 [11:30] 真的不擅长这个 [11:32] 第三个skill是TDD [11:35] 应该用测试驱动开发 [11:37] 因为TDD会逼着大模型真正小步走 [11:42] 先写测试 [11:43] 让测试通过 [11:44] 然后重构代码 [11:46] 顺手把设计琢磨清楚 [11:50] 问题是测试真的很难 [11:52] 测试从来都难 [11:54] 难就难在写一个测试 [11:57] 你要做一大堆各不相同的决定 [12:00] 要测的单元多大合适 [12:02] 要Mock哪些东西 [12:04] 一开始到底要测哪些行为 [12:06] 而这些决定全都相互依赖 [12:09] 比如你测一个特别大的单元 [12:11] 向整个应用 [12:12] 那测试就很容易flaky [12:14] 你可能就不想测那么多行为了 [12:17] 只测这个单元就得Mock掉这个单元 [12:20] 全都缠在一起 [12:22] 整个开发生涯里 [12:23] 这件事我想了很多年 [12:27] 而我们注意到好的代码库 [12:29] 就是好测的代码库 [12:32] 这里又绕回代码本身很重要了 [12:35] 代码库越好反馈回路就越好 [12:37] 你能给大模型的反馈就越好 [12:40] 它产出的代码就越好 [12:43] 于是我想 [12:44] 好的代码库可测试的代码库 [12:47] 到底长什么样 [12:49] 又要请出John Alsterhout了 [12:51] 他说代码库里要有深模块 [12:54] 不是浅模块 [12:55] 也不是一堆暴露一大把函数的模块 [13:00] 理想状态是 [13:01] 数量相对少、体量大 [13:03] 接口简单的深模块 [13:05] 我们快速对比一下 [13:07] 深模块 [13:08] 大量功能藏在简单接口的背后 [13:11] 把复杂度一并藏起来 [13:14] 想看模块内部可以看 [13:16] 但没必要 [13:17] 直接用接口就行 [13:19] 浅模块功能没多少 [13:21] 接口倒挺复杂 [13:23] 我等大家拍完照 [13:26] 代码库里全是浅模块 [13:29] 就长这样一堆零碎的小块 [13:31] AI的一个一个走过去 [13:33] 一个一个摸清 [13:35] 这真的让AI很难探索 [13:38] 于是你常会看到这种局面 [13:40] 这种代码库 [13:41] AI又特别擅长造出来 [13:44] 到最后 [13:45] AI根本不理解你的代码在干什么 [13:49] 它也试图去探索 [13:51] 但是布局乱、浅模块遍地 [13:54] 它可能来不及走到正确的模块 [13:56] 也可能漏掉依赖关系 [13:58] 各种问题 [13:59] 它就是没懂你的代码 [14:02] 那满是深模块的代码库长什么样 [14:05] 长这样 [14:07] 同样的代码 [14:08] 只是被组织进了边界里 [14:11] 接口都放在每一块的顶部 [14:15] 这些接口你最好牢牢把控精心设计 [14:19] 不然AI可能把设计搞砸 [14:22] 但模块内部的实现 [14:24] 倒可以适当放手交给AI [14:27] 那怎么把这样的代码库 [14:30] 变成那样的代码库 [14:33] 我有个skill专门干这个 [14:35] 它叫improve codebase architecture [14:39] 这是其实挺复杂 [14:41] 但它是一套可以反复复用的步骤 [14:44] 去探索代码库 [14:46] 找出彼此相关的代码 [14:48] 把它们包进一个深模块 [14:52] 这样的代码库是可测试的 [14:54] 因为代码周围的边界极其简单 [14:58] 在接口上测试 [14:59] 用接口验证就完事了 [15:02] 这样的代码库最配得上TDD [15:06] 再看第六种失败模式 [15:08] 假设你的反馈回路都转起来了 [15:11] 假设一切开始上轨道 [15:14] 你能交付前所未有的代码量 [15:17] 但脑子跟不上了对吧 [15:19] 开发生涯里从没这么累过的举个手 [15:22] 我也是太熬人了 [15:25] 而且我觉得就是这种代码库 [15:28] 让脑子更累 [15:30] 因为你和AI一样 [15:31] 得把全部信息都装在脑子里 [15:34] 而换成这种结构 [15:36] 不仅独着省力 [15:38] 你还能把这些深模块 [15:40] 当成灰盒来对待 [15:43] 你可以说 [15:44] 好我只设计接口实现部分 [15:47] 不用太操心 [15:48] 也不必逐行去审 [15:51] 当然这适用于应用里 [15:53] 不那么关键的部分 [15:54] 设计金融之类的东西 [15:56] 就不能这么干了 [15:58] 但应用里非常多的模块 [16:00] 只要它外面有可测试的边界 [16:03] 你理解它的用途 [16:04] 能从外部设计它 [16:06] 内部实现就不用想太多 [16:09] 这真的救了我的脑子 [16:11] 我可以直接说 [16:12] 好了AI大块里面的部分 [16:14] 交给你了 [16:16] 我只从外面测试验证它 [16:20] 这是第五条建议 [16:21] 设计接口下放实现 [16:25] 但这也意味着 [16:26] 每次动代码 [16:27] 每次做规划 [16:29] 我们都得想着应用里的模块 [16:31] 这张地图必须滥书于心 [16:34] 它得成为我们统一语言的一部分 [16:37] 也要把它编进规划类的skill里 [16:40] 比如我的2PoolRD在PRD里 [16:43] 我会写清楚改哪些模块 [16:45] 模块里哪些接口 [16:46] 怎么改 [16:47] 我时时刻刻都在想这些 [16:48] 这条来自Cantback [16:50] 每天都对系统的设计投资 [16:53] 这才是核心 [16:54] 对吧 [16:55] 因为Spectacode根本没在 [16:57] 对系统设计投资 [16:59] 它是在撤资 [17:00] 是在把设计扔掉 [17:02] 而这件事 [17:04] 我认为才是绝对的关键 [17:07] 所以代码不便宜 [17:09] 这就是我想让大家带走的一句话 [17:12] 代码很重要 [17:15] 如果我们把AI看成一名出色的地面程序员 [17:19] 一名战术型程序员 [17:21] 一个在前线改代码的军士 [17:24] 那上面就需要有人 [17:26] 需要有人在战略层面思考 [17:29] 那个人就是你 [17:31] 而这需要的正是我们用了20年 [17:34] 甚至更久的那一套软件基本功 [17:38] 对我刚才展示的这些skill感兴趣的话 [17:42] 都在GitHub仓库MatePolcockSkills里 [17:45] 想了解我的课程或者免费内容 [17:48] 我在YouTube、Twitter [17:49] 也在iHerodev [17:51] 那有我的newsletter [17:53] 非常感谢大家 [17:54] 希望这能让你在这个新的AI时代 [17:57] 更有底气 [17:58] 你是真的能做出影响的

贡献者

文件历史