软件基本功在AI时代变得更加重要
|
Matt Pocock 是一位知名的 TypeScript 专家、在线教育者及软件工程师,目前专注于 AI 辅助编程教学。 |
AI 时代的软件基本功
核心观点:软件基本功比以往任何时候都更加重要。优秀的代码库是享受 AI 红利的前提,糟糕的代码是有史以来最昂贵的。
一、背景:从规范到代码运动的陷阱
当前流行一种”从规范到代码”(Spec-to-Code)的理念:
-
写一份应用规范,让 AI 将其转化为代码
-
出了问题不看代码,只修改规范,重新”编译”
-
反复运行,期望代码自动变好
现实却是:每次运行编译器,代码只会越来越糟,最终得到一堆垃圾。这种做法本质上只是换了个名字的”凭感觉写代码”(cowboy coding)。
二、为什么代码并不廉价
“代码很廉价”是一个流行但错误的前提。
-
糟糕的代码库难以修改,让你无法享受 AI 带来的好处
-
AI 在良好的代码库中表现非常出色
-
因此,优秀的代码库比以往任何时候都更加重要
两本经典著作的支撑
|
书籍 |
核心概念 |
启示 |
|
John Ousterhout《软件设计的哲学》 |
复杂性——让系统难以理解和修改的结构性因素 |
好的代码库 = 容易修改的代码库 |
|
《程序员修炼之道》 |
软件熵——事物趋向混乱、分崩离析 |
每次只顾眼前改动而不考虑整体设计,代码库只会越来越糟 |
三、AI 编程的五种失败模式与应对策略
失败模式 1:AI 没有按照我的意愿去做
你和 AI 之间存在沟通障碍,AI 做出了你不想要的东西。
根因:你和 AI 之间没有共享的”设计概念”(Design Concept)。
来自 Frederick P. Brooks《设计的设计》:当多人协作设计时,需要一个共同的无形概念——设计概念。它不是资产,不是 markdown 文件,而是你们正在构建的东西的共识。
应对——GrillMe 技能:
-
让 AI 不断采访你,确认计划细节,直到双方达成共识
-
深入设计树的每个分支,逐一理解决策之间的依赖关系
-
AI 会问你 40-100 个问题,在满意之前不会停止
-
对话结果可转化为 PRD 或任务,交给 AI 代理执行
-
核心思路:先达成共同的设计理念,再开始执行(比急于制定计划更好)
失败模式 2:AI 说话太啰嗦,鸡同鸭讲
你和 AI 之间没有共同语言,AI 用大量词语却表达不到点子上。
根因:这和开发者与领域专家之间的语言鸿沟完全一样。
应对——通用语言(Ubiquitous Language):
来自领域驱动设计(DDD):通过通用语言,开发者之间的交流、代码表达、与领域专家的对话,全部源自同一个领域模型。
具体做法:
-
扫描代码库,查找术语
-
生成一个 markdown 文件,包含所有术语的表格
-
确保术语含义与实际完全一致
-
在代码、讨论、与 AI 沟通中统一使用这些术语
效果:提升规划质量,让 AI 思考更简洁,最终实现更符合规划。
失败模式 3:AI 构建了正确的东西,但不能正常运行
应对——反馈循环:
必须为 AI 提供以下反馈机制:
-
静态类型检查(TypeScript)
-
浏览器访问(前端开发时让 LLM 查看页面)
-
自动化测试
但仅仅有反馈循环还不够——LLM 并不像资深开发者那样充分利用它们。
来自《程序员修炼之道》:”超越你的车灯”——开得太快,因为反馈的速度就是你的速度上限。
LLM 默认行为:一次性生成大量代码,然后才想起来做类型检查或跑测试。
应对——TDD(测试驱动开发):
-
先写测试 → 让测试通过 → 再重构
-
TDD 迫使 LLM 采取小步前进的方式
-
好的代码库是容易测试的代码库——又回到了”代码本身很重要”
失败模式 4:AI 不理解你的代码
代码库充满浅层模块,AI 需要在大量小块中穿梭导航,无法及时找到正确模块或理解依赖关系。
应对——深层模块(Deep Modules):
来自 John Ousterhout:代码库应拥有相对较少的大而深的模块,而非大量浅层模块。
|
深层模块 |
浅层模块 |
|
大量功能隐藏在简单接口后面 |
功能不多,接口却复杂 |
|
隐藏了复杂性 |
暴露大量函数,结构混乱 |
|
AI 擅长理解和探索 |
AI 难以探索和理解 |
重构方法:
-
探索代码库,寻找彼此相关的代码
-
将相关代码封装进深层模块
-
精心设计接口(否则 AI 可能搞砸设计)
-
具体实现可一定程度交给 AI
-
在接口层进行测试,通过接口验证
失败模式 5:交付更多代码,但大脑跟不上了
AI 加速了开发,但你却比以往更疲惫——因为你的大脑和 AI 一样需要记住所有信息。
应对——设计接口,把实现交给 AI:
-
把深层模块当作”灰盒”:只设计接口,不过多审查具体实现
-
在应用中不太关键的部分,无需在意内部实现
-
前提:模块外部有可测试的边界,你理解它的用途,能从外部验证
-
关键领域(如金融)仍需审查
进一步要求:
-
熟悉应用中的模块地图,将其纳入通用语言
-
在 PRD 中具体说明模块变更和接口修改方式
Kent Beck:每天都要投入到系统设计中。
从规范到代码的运动恰恰是在撤出对系统设计的投入——这是最危险的趋势。
四、总结:你就是那个战略层面的人
-
代码并不廉价,代码很重要
-
AI 是一位非常优秀的基层/战术型程序员——擅长做代码变更
-
但 AI 之上还需要有人在战略层面进行思考——那个人就是你
-
这需要我们过去 20 年甚至更久以来一直在使用的软件基础技能
不要因为 AI 的出现就抛弃经典的软件设计原则——恰恰相反,现在比任何时候都更需要它们。
夜雨聆风