从面向对象到面向注释——如何管理AI来辅助编程

严肃使用过 AI 进行编程的人都会有个明显的感觉。不论是 GPT-4、Claude V3,还是 Copilot,它们对我们编程的效率、效果和方法都产生了巨大的影响。由于大多数情况下,实战的程序里用的数据结构和算法都非常简单,人类可以通过面向 Stack Overflow 编程,AI 也可以基于巨量的训练数据来轻松搞定。但是,这篇文章不是想渲染编程不存在了,AI 要卷掉人类这种焦虑感,而是想思考一下,在这个新的工具的加持下,我们如何有效地利用这个工具,从而实现效果和速度的巨大提升。

虽然 AI 的使用看起来非常简单,只要把代码贴进去或者用自然语言让它干一件事情就好,但是任何一个新工具,要想有效地利用它,都需要经历一个摸索、沉淀和思考的过程,都有一些诀窍。尤其是 AI 这种突破性的工具。如果我们仍然照着以前的思维定势来看待它的话,往往会陷入一些习惯的盲区,从而无法有效地收敛到最佳的利用方式上去。在试图摒弃我过往的编程教育和经验,试着用一种全新的视角来体验 AI 之后,我有了一个意外的体验心得。那就是在 AI 辅助编程的年代,我们编程的核心产品可能不再是代码,而变成了注释。

让我们首先把目光放到一个典型的计算机科学的人才的培养上。对于传统的计算机科学的训练,数据结构和算法是核心中的核心。在本科阶段,我们要先上一整年的课来学习各种不同的数据结构和算法,然后在各种专业课中继续学习每个专业里面所需要的独特的数据结构和算法。比如计算机网络的指数后退,比如操作系统的进程树等等。在找工作的时候,数据结构和算法题,比如leetcode,也是大家准备的重点。进入工作以后,我们的大脑中无时无刻不在统筹规划数量繁多的变量状态,以及让这些状态相互转化的算法。我们骄傲于对数据结构的深刻理解,看到一个需求就可以条件反射,用这种数据结构速度最快,用那种数据结构最省空间。我们对分析时间复杂度非常熟练,拿到一个要求可以迅速地把它大卸八块翻译成运行时间最短的代码。不论是我们学习的过程还是工作的过程,整个编程的环节都是高度围绕着数据结构和算法来进行的。实际上,现代编程的重要基石——面向对象编程,强调的就是对数据结构(域)和算法(方法)的封装。

但是在使用了一段时间AI辅助编程工具,比如GPT和Copilot以后,我的感受是,有效利用AI编程的核心不再是数据结构和算法了。即使我不知道在这种情况下最优的数据结构是什么,没关系,AI会给我建议不同的选项,甚至分析比较它们的优劣,引导我根据实际情况选择最适合的数据结构。即使我不知道最优的算法,没关系,AI会告诉我这里可以使用什么库来解决,每个相关的库函数的时间复杂度是多少。最坏的情况,AI甚至可以直接把我的代码写好,我就只要在实际数据上跑一遍,来选择最适合的算法。而这整个写代码加上实验的过程,甚至比我手工分析时间复杂度还要快。从另一个角度来说,即使我不知道库函数的细节,不记得每个参数分别是什么含义,AI也可以轻松提示,帮我补全函数调用时的每一个参数。

因此,写码的水平对能不能写出优秀的代码来说并不是很重要了。这句话看起来很奇怪,但我的意思是,比如有两个人,一个人熟练掌握了各种数据结构和算法的知识和技巧,另一个人只是有一般的了解。在传统的编程时代,前者写的代码会比后者写的质量高很多,开发的速度也会更快。但是在AI辅助编程的年代,这两个人在能不能有效利用AI又快又好地写出代码上,差别往往并不是很明显。

相反,我感觉AI对我的开发尤其有帮助的时候,是当我认真写了注释的时候。对Python来说,是当我非常详细地写了Docstring的时候(Docstring指的是针对函数接口和参数的详细注释)。这是因为Docstring或者类似的注释可以详细精确地描述函数的接口,让AI可以直接在这个基础上写出正确的代码。比如说,如果在给AI的prompt里面我们提到“你可以使用这个函数def extract_fwhm(self, image, verbose)”,基于这些信息,AI不是不能写出代码,但是因为其中有着太多可能发生歧义的地方,比如这个image的具体格式到底是什么,AI能够一遍成功的概率几乎为零。

但如果我们把它写成这样一种详细的,含有Typing Hint和Docstring的形式:

def extract_fwhm(self, img_data: npt.ArrayLike, verbose: bool = False) -> float:
        """
        Extract the FWHM of the given image.
        Note this function assumes that the input image has been debayered if it is a color image.
        Args:
            - img_data (npt.ArrayLike): The image to extract the FWHM from.
            - verbose (bool): Whether to print the progress of the extraction.
        Returns:
            The FWHM of the given image.
        """

AI就可以非常轻松地一遍成功。所以,如果有两个人比赛写代码,一个人详细地写了Typing Hint和Docstring,并且把它们包括在prompt里,而另一个人还是照传统的方法,主要强调代码的质量,而忽视注释的质量,那么前者的效率(可能和正确率都)会高很多。甚至当后者其实是个传统意义上写代码的高手的时候,也是这样。这是为什么我觉得在AI辅助编程的新时代,编程的产出重点已经从以代码为中心,转向了以注释为中心。写出代码的质量和效率直接决定于注释的质量。换言之,如果说面向对象编程暗含了数据结构和算法这个传统编程的核心,面向注释编程则是高效使用AI辅助编程的关键。

这个观察其实很有意思。一个浅显的拓展就是,如果我们从稍微更抽象的角度来考虑这个问题,我们写注释的目的是保证我们给AI的问题本身是自洽的,是AI有足够的信息和能力解决的。换言之,要想高效利用AI,我们不能把遇到的一切问题都无脑地扔给它,而是要时刻思考:提的这个问题是不是被恰当地定义了?AI有没有足够的信息可以完成这个任务?我们能不能合理地期待一个人或者一个AI可以正确地实现这个任务?而这恰恰是开发经理(SDM)天天在思考的问题。

沿着这个思路想的话,结合实际使用AI辅助编程的经验,我觉得要想高效使用AI编程,最关键最需要的素质其实就是开发经理的核心素质:

  1. 了解你要管理的对象:了解它的能力边界在哪里,比如对AI来说,要了解context window,hallucination的概念和场景;以及怎样去激励你要管理的对象,比如对人可以画饼,可以pip,对AI可以给小费等等。
  2. 决定是否和什么时候delegate:根据管理对象的能力边界,决定哪些事情必须要自己亲自去抓,哪些事情则可以放心delegate,放权给下属。
  3. 如何delegate:如何把问题分解成适合下属能力的小块,并且放手给他们去做,比如对AI而言,因为它的context window是有限的,在使用长prompt的时候,往往会产生遗忘或者偷懒的情况,所以如果我们能够把问题分解成适合context window的小块,一步步引导AI去回答,就可以大幅提高成功率和编码的质量。
  4. 质量检查:如何评价AI的产出确保代码质量,尤其是避免hallucination的影响。比如可以使用自动化或手动的测试,当然这个测试的撰写本身也可以使用AI辅助。
  5. 向管理对象学习:人类开发经理更新知识结构的一大来源就是向下属学习。这没什么不好意思的,因为开发经理本来就不应该比专精编程的下属更加technical。对于普通的编程人员来说,在管理AI的时候,AI也是一个非常好的学习工具。

那是不是未来是不是在这个AI辅助编程的年代,人人都要转岗开发经理,码农这个职位就逐渐消亡了呢?我对此比较乐观。这是因为软件工程师的核心竞争力,从来就不是写代码写得有多快,数据结构和算法学得有多好。一个高级软件工程师能升到senior,不是因为他的库函数记得更熟,或者他会手写翻转红黑树,而是因为他会做设计决策。如果让一个刚入职场的软件工程师来做设计决策的话,很有可能会因为做出错误的决策而导致整个组全部返工。而这个返工浪费的时间,是就算这个人写代码再快十倍也救不回来的。类似的,staff工程师为什么升成staff,也不是因为他写代码比senior还要快,或者因为他知道senior还不知道的更难的算法,而是因为他可以发现一些非常重要,但是别人都忽略了的问题,并且说服大家这是个重要的问题。所以从这个角度来说,AI的出现,其实是提高了编程的上限,而不是要取代软件工程师这个职业。

然而AI也确确实实带来了深远的改变。就是它让写程序侧重的能力,由传统的对数据结构和算法的熟练度变成了开发经理所更侧重的能力。比如说了解AI能力的边界,如何把问题分解成AI能搞定的小块等等。类似的事情在历史上已经发生过很多次了。比如在计算器出现以前,我们的学校教育非常强调熟练的算术运算,甚至出现了珠心算这种复杂且创新的高速运算技巧。但是当计算器出现以后,一方面珠心算逐渐在课程中消失了,而我们进行算术运算的速度和准确率得到了大幅提升。另一方面,那些依赖于算术运算的职业也没有消亡,相反,上限反而得到了提高。所以,虽然AI辅助编程是一个非常根本的革命性的变化,会让一些能力变得更加重要,让一些能力变得不那么重要,但也不必急着给软件工程师这个职业判死刑。

这是最好的时代,也是最坏的时代。这个AI辅助编程的时代,对不同的人有着不同的影响。但是可以确定的是,这是个变革的时代。即使是这篇文章本身,它的内容也会随着新的AI技术的出现而过时。唯一不变的是,只要我们保持思考,保持热情,我比较乐观,在更智能、更好用的工具的帮助下,我们的竞争力可以一次次的成倍提升。

Comments