☰
AI编程时代:代码信任、类型安全与开发者核心能力
2026/10/14 12:49:49 网站建设 项目流程

1. 当AI开始写代码,我们到底在焦虑什么

第一次看到AI能自动补全一整段函数的时候,我承认心里咯噔了一下。那种感觉就像你苦练了十年的手艺,突然有人告诉你,隔壁新来的学徒工用一台机器三秒钟就能做出差不多的东西。但用了大半年之后,我的心态慢慢从“要被替代了”变成了“这玩意儿到底该怎么用才不坑自己”。这个转变过程里,我踩了不少坑,也总结出了一些实实在在的经验。

Matt Pocock这个名字,如果你平时关注TypeScript生态或者前端工程化,大概率不会陌生。他在类型系统、工具链和开发者体验方面有大量高质量的输出,而这次他聊的是AI编程这件事。我仔细看了他的观点,结合自己这段时间在真实项目里用AI辅助编码的体会,发现他提到的几个关键问题,恰好也是我和身边不少开发者反复争论的焦点。这些问题不是“AI好不好”这种空泛的讨论,而是非常具体的:AI写的代码你敢不敢直接合并?类型安全在AI时代是更重要了还是更不重要了?我们花时间学的那些底层原理还有没有价值?

这篇文章我想把这些问题一个一个拆开,结合Matt Pocock的思路和我自己的实操经验,聊清楚AI编程到底改变了什么、没改变什么,以及作为一个还在写代码的人,你应该怎么调整自己的姿势。不管你是刚入行的新手,还是写了十几年代码的老手,只要你现在还在用AI辅助开发,或者正在犹豫要不要用,这些内容应该都能帮你少走一些弯路。

2. 问题一:AI生成的代码,到底能不能信

2.1 信任危机的根源在哪里

Matt Pocock提到的一个核心观点让我印象很深:AI编程最大的问题不是它写不出代码,而是它写出的代码看起来太像那么回事了。你让它写一个防抖函数,它三秒钟给你一个结构完整、注释清晰、命名规范的实现。你扫一眼觉得没问题,直接复制粘贴到项目里,跑起来也没报错。但过了一个月,你发现某个边缘场景下这个函数的行为不对劲,回头一查,发现AI在闭包变量的处理上有一个非常隐蔽的逻辑错误。

这种情况我遇到过不止一次。最典型的一次是让AI帮我写一个数组去重的工具函数,它用了filter加indexOf的组合。表面上看没问题,但当我传入一个包含NaN的数组时,结果就不对了,因为indexOf用的是严格相等判断,而NaN !== NaN。这个bug在常规测试里根本发现不了,直到线上数据出现了异常才暴露出来。

注意:AI生成的代码有一个特点——它在“常见路径”上的正确率很高,但在“边缘路径”上往往经不起推敲。这不是因为AI笨,而是因为它的训练数据里,常见场景的代码量远远大于边缘场景。

2.2 我的代码审查策略调整

基于这些教训,我现在的做法是:AI生成的代码,一律按照“实习生提交的PR”来对待。什么意思呢?就是我会逐行看,但看的重点和看人类写的代码不太一样。看人类代码的时候,我更多关注的是架构合理性和业务逻辑对不对。看AI代码的时候,我会额外关注几个特定的点。

第一个是边界条件。AI特别喜欢假设输入是“正常”的,比如数组不为空、字符串不为空、数字不是NaN、对象属性一定存在。所以我会专门检查这些地方有没有做防御性处理。第二个是类型收窄。TypeScript里AI经常写出as any或者非空断言!来绕过类型检查,这种代码在运行时是有风险的。第三个是异步逻辑。AI在处理Promise链、async/await的错误捕获、并发控制这些方面,出错率明显比同步代码高。

我整理了一个简单的检查清单,每次审查AI代码的时候过一遍:

检查项常见问题我的处理方式
空值处理未判断null/undefined手动补充可选链或默认值
数组边界假设数组非空加长度判断或使用安全方法
类型断言滥用as any替换为类型守卫或泛型约束
异步错误缺少try/catch补充错误捕获和降级逻辑
副作用意外修改外部变量检查闭包和引用传递

这个清单看起来简单,但实际用起来能挡掉大概七八成的潜在问题。剩下的那些更隐蔽的bug,就得靠测试覆盖率和代码审查的经验来兜底了。

2.3 一个真实的翻车案例

说一个我印象最深的翻车经历。当时我在做一个数据可视化的模块,需要根据时间范围动态计算坐标轴刻度。这种逻辑说复杂也不复杂,但边界情况特别多,比如跨年、跨月、闰年、时区偏移等等。我让AI帮我写了一个刻度生成函数,它给出的实现逻辑清晰,注释也写得很到位,我看了之后觉得没问题就用了。

结果测试的时候发现,当时间范围跨越夏令时切换的那一天时,刻度会少一个。原因是AI在处理日期加减的时候,用的是毫秒数直接运算,没有考虑夏令时导致的小时偏移。这个问题在大部分情况下不会出现,但偏偏我们的用户群体里有相当一部分在实行夏令时的地区。

修复这个bug花了我大概两个小时,但如果一开始就自己写,可能四十分钟就搞定了。所以我的体会是:AI能帮你省时间,但省下来的时间有一部分要还回去,还的就是审查和调试的时间。净收益是正的,但没有想象中那么大。

3. 问题二:类型安全在AI时代是更重要还是更不重要

3.1 一个反直觉的结论

很多人可能会觉得,既然AI能帮我们写代码了,那类型系统这种“约束”是不是就没那么重要了?反正AI会帮我们处理类型问题。但Matt Pocock的观点恰恰相反,他认为在AI编程的时代,类型安全变得比以往任何时候都更重要。

我一开始不太理解这个逻辑,后来想明白了。类型系统的本质是什么?是给代码加上一层“机器可验证的约束”。在没有AI的时候,这层约束主要是给人看的,帮助人类开发者理解代码的意图和边界。但在有AI的时候,这层约束变成了人和AI之间的“契约”。你给AI一个明确的类型签名,它就能在这个约束下生成更靠谱的代码。你如果不给约束,AI就会自由发挥,而自由发挥的结果往往就是各种隐式any和运行时错误。

3.2 类型即提示词

这个思路让我豁然开朗。以前我写TypeScript的时候,有时候会觉得类型定义太繁琐,尤其是那些复杂的泛型约束和条件类型,写起来费劲,运行时又没有任何开销。但在AI辅助编程的场景下,类型定义其实扮演了一个“提示词”的角色。

举个例子,假设你要让AI帮你写一个函数,从对象数组中按照某个字段分组。如果你只给一个模糊的描述,AI可能会写出各种不同的实现,有的返回Map,有的返回普通对象,有的用reduce,有的用for循环。但如果你先写好类型签名:

function groupBy<T, K extends keyof T>( items: T[], key: K ): Map<T[K], T[]>

AI看到这个签名之后,生成的实现就会精确很多。它知道要返回Map,知道键的类型是T[K],知道值的类型是T[]。类型签名在这里起到了“精确描述需求”的作用,比自然语言的描述要准确得多。

3.3 我的类型策略调整

基于这个认知,我现在的做法是:在让AI写实现之前,先把类型定义写好。这个过程本身也是对我自己思路的一次梳理。如果我发现某个函数的类型签名很难写清楚,那通常意味着我对这个函数的职责边界还没想明白,这时候让AI来写实现,大概率也是写不好的。

另外,我会刻意避免在AI生成的代码里出现any。如果AI写了any,我会要求它改成具体的类型或者泛型。这个习惯坚持下来之后,我发现代码的整体质量有了明显的提升。因为any就像是一个黑洞,一旦出现,类型检查就失效了,后续的代码也会跟着变得不可靠。

提示:你可以把类型定义看作是给AI的“接口文档”。接口定义得越清晰,AI的实现就越靠谱。这个投入产出比非常高。

4. 问题三:底层原理还值不值得花时间学

4.1 一个让我纠结了很久的问题

这个问题困扰了我很长时间。既然AI能帮我写排序算法、能帮我实现数据结构、能帮我处理各种复杂的逻辑,那我花时间去学这些底层原理还有什么意义?我是不是应该把精力放在更高层的架构设计和业务理解上?

Matt Pocock对这个问题的回答让我比较信服。他说,底层原理的价值不在于你能手写出来,而在于你能判断AI写出来的东西对不对。这个判断力,是建立在你自己对原理的理解之上的。如果你不懂事件循环的机制,AI给你写了一个有内存泄漏风险的异步代码,你根本看不出来。如果你不懂闭包的工作原理,AI写了一个循环里创建函数的代码,你也发现不了变量捕获的问题。

4.2 从“会写”到“会看”的转变

这个转变对我来说是关键的。以前学底层原理,目标是“我能手写一个Promise”。现在学底层原理,目标是“我能看懂AI写的Promise实现有没有问题”。这两个目标看起来差不多,但侧重点完全不同。前者要求你能从零构建,后者要求你能快速识别。

我举个例子。AI帮你写了一个简单的状态管理工具,用了发布订阅模式。代码看起来没问题,但你如果懂事件循环,就会发现它在通知订阅者的时候用的是同步调用。这意味着如果某个订阅者的回调函数执行时间很长,会阻塞后续订阅者的通知。在UI场景下,这可能导致页面卡顿。这个问题的修复方式也很简单,把同步调用改成微任务或者宏任务就行了。但如果你不懂事件循环,你根本意识不到这里有问题。

4.3 我现在的学习策略

所以我现在学底层原理的方式变了。以前是看书、看源码、自己实现一遍。现在更多是“带着问题去学”。比如AI给我生成了一段代码,我觉得哪里不太对劲,但说不上来,这时候我就会去查相关的原理,搞清楚为什么不对劲。这种学习方式效率更高,因为它是问题驱动的,学完马上就能用上。

另外,我会刻意去读一些高质量的库的源码,但不是逐行读,而是带着问题读。比如我想知道某个库是怎么处理并发请求的,我就去找到相关的模块,看它的实现思路。这种“按需深入”的方式,比从头到尾啃源码要高效得多。

学习方式传统方式AI时代的方式
学习目标能自己实现能审查AI的实现
学习驱动系统性学习问题驱动学习
深度要求全面深入按需深入
验证方式手写代码代码审查和调试

这个表格是我自己总结的,不一定对所有人都适用,但至少对我自己来说,这个转变让我的学习效率提高了很多。

5. 问题四:AI编程会不会让开发者同质化

5.1 一个容易被忽视的风险

这个问题是我自己在使用AI的过程中慢慢意识到的。当我越来越依赖AI来生成代码的时候,我发现自己的代码风格开始变得“标准化”了。以前我写代码会有一些个人的习惯和偏好,比如变量命名的方式、函数的组织方式、注释的风格等等。但用了AI之后,这些个人特色在慢慢消失,因为AI生成的代码有一套固定的模式,我如果直接采用,就会不自觉地被同化。

Matt Pocock也提到了类似的观点。他认为AI编程的一个潜在风险是,它会让开发者的代码趋于同质化。因为大家用的都是同样的模型,模型生成的代码又有固定的模式,久而久之,整个行业的代码风格可能会变得越来越像。

5.2 同质化的两面性

这个问题要分两面看。好的一面是,代码风格的统一确实能降低协作成本。如果团队里每个人都用AI生成代码,那代码审查的时候,大家看到的风格是一致的,理解起来会更快。坏的一面是,同质化意味着创新的减少。那些独特的、非主流的、但可能更优雅的解决方案,可能会因为AI不擅长而逐渐消失。

我自己的应对方式是:把AI当作一个“初稿生成器”,而不是“最终代码生成器”。AI生成的代码,我会把它当作一个起点,然后在这个基础上进行修改和优化。我会刻意保留一些自己的风格,比如在关键逻辑处加上详细的注释,解释“为什么这么做”而不是“做了什么”。这些注释是AI写不出来的,因为它们需要对业务背景和团队约定的深入理解。

5.3 保持差异化的具体做法

具体来说,我会在以下几个方面刻意保持自己的风格。第一是命名。AI倾向于使用通用的、描述性的命名,比如handleClick、processData。我会根据具体的业务语境,使用更有业务含义的命名,比如handleOrderSubmit、processPaymentResult。第二是错误处理。AI的错误处理往往比较模板化,我会根据具体的业务场景,设计更精细的错误分类和降级策略。第三是代码组织。AI倾向于把逻辑写在一个函数里,我会根据职责单一原则,把逻辑拆分成更小的、可复用的单元。

这些做法看起来是小事,但积累起来,就能让你的代码在AI生成的“标准件”中保持一定的辨识度。而且这些做法本身也是对你自身能力的锻炼,让你不至于在AI的辅助下变成一个“只会按按钮的人”。

6. 问题五:未来的开发者需要什么核心能力

6.1 从“写代码”到“描述问题”的转变

Matt Pocock提到的一个趋势是,开发者的核心能力正在从“写代码”向“描述问题”转变。这个观点我深有体会。以前我们花大量时间在“怎么做”上,比如怎么实现一个算法、怎么优化性能、怎么处理边界情况。现在这些“怎么做”的问题,AI能帮你解决很大一部分。但“做什么”和“为什么做”的问题,AI帮不了你,或者说帮得很有限。

你需要能够清晰地描述你要解决的问题,包括输入是什么、输出是什么、约束条件是什么、优先级是什么。这个描述能力,其实比写代码的能力更难培养。因为写代码是一个确定性的过程,你写错了编译器会告诉你。但描述问题是一个模糊的过程,你说得不清楚,AI给你的东西就不对,而且它不会告诉你哪里没说清楚。

6.2 我总结的四个核心能力

结合我自己的经验和Matt Pocock的观点,我认为未来的开发者需要四个核心能力。

第一个是问题拆解能力。一个复杂的需求,你能不能把它拆成若干个AI能独立解决的小问题?这个能力决定了你使用AI的效率。如果你把一个大问题直接丢给AI,它大概率会给你一个能跑但不够好的方案。但如果你把它拆成几个小问题,每个小问题都有明确的输入输出和约束条件,AI的表现会好很多。

第二个是代码审查能力。前面已经聊了很多,这里不展开。核心就是你要能快速判断AI生成的代码有没有问题,问题在哪里,怎么修。

第三个是系统设计能力。AI能帮你写一个函数、一个模块,但整个系统的架构设计、模块划分、数据流向、接口定义,这些还是需要人来把控。因为系统设计涉及到大量的权衡和取舍,这些权衡需要考虑业务需求、团队能力、技术债务、未来扩展等多个维度,AI目前还很难做好。

第四个是快速学习能力。AI工具本身在快速迭代,今天好用的工具明天可能就被替代了。你需要能够快速上手新工具、新范式、新流程。这个能力的基础是扎实的计算机科学基础和良好的抽象思维能力。

6.3 一个具体的练习方法

如果你想知道自己的这些能力处于什么水平,我有一个简单的练习方法。找一个你熟悉的业务场景,比如用户注册登录,然后让AI帮你实现。实现完之后,你问自己几个问题:AI的实现有没有考虑并发注册的情况?有没有考虑密码强度校验?有没有考虑登录失败次数限制?有没有考虑token过期和刷新?如果你能快速发现这些遗漏,说明你的问题拆解和代码审查能力不错。如果你发现不了,那说明你还需要在这些方面多下功夫。

这个练习我做过好几次,每次都能发现自己的盲区。有一次我让AI写一个文件上传的功能,它写完之后我觉得挺完整的,后来仔细一想,它完全没有考虑文件类型校验和大小限制。这两个问题在实际项目中是必须处理的,但AI默认你不会传非法文件,所以就没写。这个经历让我意识到,AI的“默认假设”和实际项目的“安全要求”之间是有差距的,而这个差距需要你来填补。

7. 我在实际项目中的AI编程工作流

7.1 从需求到代码的完整流程

说了这么多理论,最后分享一下我在实际项目中是怎么用AI的。我的工作流大概分为五步。

第一步是需求分析。这一步我完全不用AI,自己把需求想清楚,把边界条件列出来,把输入输出定义好。这一步花的时间大概占整个流程的百分之二十,但非常重要。如果这一步没做好,后面用AI生成的代码大概率要返工。

第二步是接口设计。我会先写好类型定义和函数签名,这一步也不用AI。类型定义写完之后,我会让AI帮我检查一下有没有遗漏或者不合理的地方。有时候AI能发现一些我没想到的边界情况,这个环节的交互效率很高。

第三步是让AI生成实现。我会把类型定义和需求描述一起给AI,让它生成一个初版实现。这一步AI的表现通常不错,因为约束条件已经很明确了。

第四步是代码审查和修改。我会逐行审查AI生成的代码,重点看边界条件、类型安全、异步逻辑和副作用。发现问题就自己改,或者让AI重新生成。这一步花的时间最多,大概占整个流程的百分之四十。

第五步是测试。我会针对AI生成的代码写单元测试,重点覆盖边界情况和异常路径。这一步也不能省,因为AI代码在边缘场景下的表现确实不太稳定。

7.2 哪些场景适合用AI,哪些不适合

根据我的经验,AI在不同场景下的表现差异很大。我整理了一个简单的对照表:

场景类型AI表现我的建议
工具函数很好可以直接用,但要审查边界
业务逻辑一般需要详细描述需求,仔细审查
架构设计较差自己设计,AI辅助检查
性能优化一般AI给思路,自己实现和验证
测试用例很好可以大量使用,但要补充边界
文档注释很好可以直接用,稍作修改

这个表格是基于我自己的使用经验总结的,不一定适用于所有人,但至少反映了一个趋势:AI在“确定性高、边界清晰”的任务上表现好,在“需要权衡、需要判断”的任务上表现差。所以你应该把AI用在它擅长的地方,而不是指望它解决所有问题。

7.3 一个完整的实操示例

让我用一个具体的例子来演示这个工作流。假设我要实现一个“根据用户权限过滤菜单项”的功能。

第一步,需求分析。我需要明确:权限有哪些类型?菜单项和权限的对应关系是什么?如果没有权限,是隐藏菜单项还是禁用菜单项?父菜单和子菜单的权限是独立的还是继承的?

第二步,接口设计。我定义类型:

type Permission = 'read' | 'write' | 'delete' | 'admin'; interface MenuItem { id: string; label: string; requiredPermission: Permission; children?: MenuItem[]; } function filterMenuByPermission( menu: MenuItem[], userPermissions: Permission[] ): MenuItem[]

第三步,让AI生成实现。我把上面的类型定义和需求描述给AI,它生成了一个递归过滤的实现。

第四步,代码审查。我发现AI的实现里,对于父菜单没有权限但子菜单有权限的情况,处理得不太对。它直接把父菜单过滤掉了,导致子菜单也显示不出来。但实际上,如果子菜单有权限,父菜单应该保留,只是父菜单本身不可点击。这个逻辑AI没有考虑到,我手动补充了。

第五步,写测试。我针对以下几种情况写了测试:用户有全部权限、用户没有任何权限、用户只有部分子菜单的权限、菜单为空数组、菜单有多层嵌套。这些测试跑下来,发现了一个AI实现里的另一个问题:当菜单项没有children属性时,递归调用会报错。修复之后,整个功能才算完成。

这个例子很典型,它展示了AI编程的完整流程:AI能帮你快速生成一个可用的初版,但你需要通过审查和测试来发现和修复它遗漏的边界情况。这个过程需要你的专业判断,而不仅仅是会写代码。

8. 一些踩过的坑和总结的经验

8.1 不要过度依赖AI的“自信”

AI有一个特点,它对自己的输出非常自信。即使它写错了,它也会用一种很确定的语气告诉你“这是正确的实现”。这个特点很容易让人放松警惕。我踩过好几次这样的坑,AI给了一个看起来没问题的方案,我就直接用了,结果出了问题。

所以我现在养成了一个习惯:不管AI说得多确定,我都会自己验证一遍。验证的方式包括写测试、查文档、手动推演边界情况。这个习惯看起来费时间,但实际上省了很多调试的时间。

8.2 保持对代码的“手感”

还有一个坑是,用AI用久了之后,自己写代码的“手感”会下降。以前我写一个复杂的函数,脑子里会自动浮现出大致的结构和关键步骤。用AI多了之后,这种直觉变弱了,因为大部分时候都是AI先给一个初版,我在这个基础上改。改和从零写,对大脑的锻炼是不一样的。

为了保持手感,我会刻意留一些场景不用AI,比如一些核心的业务逻辑、一些需要仔细设计的算法。这些场景我自己写,虽然慢一点,但能保持自己的编码能力和直觉。这个做法不一定适合所有人,但对我来说挺有用的。

8.3 建立自己的代码片段库

最后一个经验是,我会把AI生成的、经过我审查和修改的代码,整理成自己的代码片段库。这些片段是经过实战检验的,比AI直接生成的更可靠。下次遇到类似的场景,我可以直接从片段库里拿,而不是重新让AI生成一遍。这个做法不仅提高了效率,也保证了代码质量的一致性。

这个片段库我按场景分类,比如“数组操作”、“异步控制”、“类型工具”、“错误处理”等等。每个片段都附带了使用说明和注意事项。时间长了之后,这个库就成了我自己的“私有AI”,比通用的AI模型更懂我的需求和风格。

提示:代码片段库不需要很复杂,一个Markdown文件或者一个简单的笔记应用就够了。关键是坚持积累和整理。

8.4 关于AI编程的几个常见误区

最后整理几个我经常听到的误区,顺便说说我的看法。

第一个误区是“AI会取代程序员”。我的看法是,AI会取代那些只会写“标准代码”的程序员,但不会取代那些能解决复杂问题、能设计系统、能判断代码好坏的开发者。所以与其担心被取代,不如想想怎么提升自己的不可替代性。

第二个误区是“用了AI就不需要学基础了”。前面已经聊过,基础决定了你能不能判断AI的输出质量。没有基础,你连AI写错了都看不出来,更别说修复了。

第三个误区是“AI生成的代码不能用于生产环境”。这个说法太绝对了。经过严格审查和测试的AI代码,完全可以用于生产环境。关键不在于代码是谁写的,而在于代码有没有经过足够的验证。

第四个误区是“AI编程会让开发变得简单”。实际上,AI编程让“写代码”这个环节变简单了,但让“保证代码质量”这个环节变难了。因为你需要审查的代码量变大了,需要判断的场景变多了。整体来看,开发的复杂度并没有降低,只是转移了。

这些经验都是我自己的体会,不一定对所有人都适用。但如果你刚开始用AI辅助编程,或者用了一段时间觉得效果不如预期,希望这些内容能给你一些参考。AI是个好工具,但工具的价值取决于使用它的人。把AI用在合适的地方,保持自己的判断力和学习能力,这才是关键。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询