扫码阅读
手机扫码阅读

资深程序员撰文:LLM将从根本上改变软件工程(上)

446 2023-07-13

(来源:Blog | the scapegoat dev)

我的背景是系统编程

首先,我自己是一个程序员。我从5岁起就想按下按钮让机器做事,从那时起,我最大的兴趣之一就是计算机。甚至我的音乐、绘画、写作都与这些神奇的机器密不可分。我已经写了数百万行的代码,几乎没有一天不提交代码。所有这一切都说明,我对那些有效的东西非常感兴趣,而且我已经尝试了很多不同的东西。我对编码非常关心,如果LLM没有用,我也不会每天都在使用它们。
从GitHub Copilot的测试版开始,我就一直在用它进行大量的编程,并且从它向公众开放的那一周开始,我就一直用chatGPT来解决我所能想到的每一个现实世界的问题。我主要工作是系统编程,即构建操作系统、嵌入式系统、分布式系统等,主要写那些 "无聊的胶水代码(boring glue code 或说以许多不同的复杂方式写memcpy,它是指将软件系统的不同部分连接在一起的代码,不会让人兴奋、也缺少创新,但该代码通常负责管理不同组件或服务之间的数据流,并确保它们无缝地协同工作,这对于构建健壮可靠的软件系统是必不可少的)。
先亮出我的观点
围绕这些技术的炒作另一个方面,我经常遇到,那就是这些技术由于某种原因还不够好("它们是随机的鹦鹉","它们制造废话","它们不能推理","它们编造事实","它们可能取代初级开发人员,但它们不会取代高级开发人员"),却忽略了一个更大的问题:如果你是从事编写软件的工作,这些东西是可行的。
事实上,LLM工作得非常好,以至于我们将看到软件构建方式的根本转变,而且编程可能是最容易被这些技术取代的工作之一。
我们正处于构建软件方式的巨大革命的原点,即将在软件架构、系统架构、编程实践、沟通模式和组织结构方面产生根本性的转变。这是一个令人兴奋的时代,因为我们正处于塑造未来编程方式的人。

Copilot帮我完成不可思议的任务

我喜欢 "质朴 "的编程语言,"质朴" 意味着没有那么多的修饰,你从代码所看到的就是作者的意图,其中最喜欢的是PHP和Javascript、Java、Go等,这些也是GitHub Copilot表现得很好的语言。这类语言常用的编程模式,一般直截了当(flat),一个符号的意义不受隐藏特性、抽象或模块系统的影响。这并不是说,语言的 "复杂性 "或抽象水平导致了低劣的结果,而是说,从训练语料库中难以推断出代码完成度应该是什么样子。
我已经习惯了Copilot在我写完第一行代码之后就能准确无误地推断出我想要做什么。事实上,我已经注意到:在编程过程中我的身体肌肉记忆发生了变化。如果网络断了,我不得不自己输入代码,我就得进行一次心理转换。起初,我会写下3个字,并期望10行代码能被生成出来。过了几秒钟,我才意识到:我那神奇的朋友副驾驶(Copilot)已经擅离职守了,因为网络断了。

随机的鹦鹉,还是有效的代码?

对大型语言模型(LLM)的常见批评之一是:它们经常输出错误的代码。这是真的(ChatGPT4的水平明显提高了,但要让它输出错误的代码也不是太难)!但是我认为,没有仔细研究才会得出这样的结论!然而,快速写出的错误代码很容易被纠正,这只是好代码的另一个名字。
我的大部分编程都是由长篇大论地写一些琐碎的想法组成的。我会以 "我需要把这个数据从这里复制到这里 "开始(这就是为什么把它称为 "memcpy编程"),然后通过HTTP调用进行通信、Promise来处理异步操作、SQS事件来触发其他操作、批处理作业来处理大量数据等,只要写上注释:call the HTTP api /api/products and send the result to our SNS topic /products,就足以让Copilot基本完成整个事情。
因为我不是一个火箭科学家,所以这些方法将是类似于(用fake Javascript):
如果你在写完上面的评论后自动完成copilot,它很可能出现:
如果你纠结于它使用validateProducts而不是validator.checkProducts的事实,我认为,你是忽视了重点。实际工作中的好处是,我现在通常花10分钟就能完成原本要花2小时的事情。
我认为这个事实的含义比 "好吧,现在我们只是取代了代码猴子 "要深刻得多。我认为,能够以这样的速度写出乏味的代码,可以关闭许多反馈回路,从而产生意想不到的效果,也必将改变我们构建软件的方式。

旁白1:帮助Copilot输出有效代码

尽管Copilot非常渴望发现我们的代码库,但它更想知道我们喜欢什么风格。它需要了解我们已经掌握了哪些API和辅助方法,以及需要导入哪些包。
如果我们想用Copilot完成(tab-complete)计划写的90%左右的代码,解决办法是什么?访问几个希望Copilot "学习 "的文件,或者写一个它应该生成的例子。如果我们想让Copilot流畅地使用一个晦涩的库,只需浏览它的源代码、访问几个例子,然后我们回去疯狂地用Copilot完成程序。
同样的技巧也适用于ChatGPT。如果想让ChatGPT有一个体面的输出,只需在前面复制粘贴大量的示例代码。复制粘贴类的定义及其注释,也许再加上一些DDL、CSV的例子。经常粘贴它,每次分歧都粘贴它。拿出它的代码,纠正它,再粘贴回来。粘贴文档页面、粘贴整个StackOverflow主题、粘贴……上下文是这里需要的。

方法论转变#1:写文档

这是我们遇到的第一个方法论的变化。比起为人类编写API文档,我们更需要编写代码(或工具),使API对LLM来说是可发现和可 "理解 "的。在大多数情况下,这两者是携手并进的。编写清晰简洁的注释是给LLM提供在训练集中看到的上下文,从而帮助它推断出正确的答案。清晰简洁的API,以及有意义的名称,使我们能够有效地(越少的标记越好)向我们的工具传达我们的意图。
我们将看到这样的做法,即把文档暴露为人类可读的,并易于 "机器解析"(短小精悍,有一些具体任务的例子)。我们将不再使用UML、ODL、SOAP、Swagger、JSON Schema等正式语言,而是回到简单、言简意赅(no-nonsense)的README,给出一个简短的概述和几个使用例子。这并不是因为简单就好。它之所以有效,是因为README很好地说出了我们的 "人 "的意图,而源代码则体现了我们打算让系统做的极度详细的事情,而LLM可以将这两者结合起来,生成更 "正式 "的代码供机器解释,或者更详细的文本供人解释。
我不认为我们已经意识到,与人类交流的最有效方式现在也是与机器交流的有效方式。
这当然是双向的。大型语言模型在将蹩脚的评论转化为写得很好的、有说服力的段落方面有着不可思议的效果。它们可以在我说 "请 "的时间里生成5个有趣的例子。他们可以在几秒钟内更新现有的文档,以配合重构后更新的API(而且这是因为目前需要复制粘贴到ChatGPT,比较麻烦)。Copilot实验室正在试验 "刷子",未来效率还会有很大的改善。
我们能以同样的方式更新代码以配合文档的变化,或者从简明的、写得好的文档中生成有效的代码。我们可以在客户端上抓取一些输出(endpoints),然后不需要任何编辑、直接粘贴到ChatGPT上,就可以要求它创建一个包含Mock、单元测试、示例和文档的API库。其结果,通常会比我们写得还要好。
我已经懒得再手动编写这些数据挖掘/API包装/结果验证的代码了。最近我不得不完成与谷歌标签管理器(Google Tag Manager)的服务器之间的集成。我把网页复制粘贴到一个简单的3行提示符中,现在可以用一个简单的shell命令生成PHP类、typescript接口、事件日志分析器、SQL序列化等。
现在,写好的文档是最基本的,而且几乎是免费的,我们该怎么做呢?我们会成为作家吗?我们会成为编辑吗?
就我个人观点:是的。没有任何借口不写出优秀的文档(或者用tab键完成文档)。文档风格和文档质量可以轻松实现,如果有问题,将及时得到提示,而且代码注释将不再过时(以后IDE会及时标记与代码行为不匹配的注释)
如果我们成为编辑,这是否意味着学习成为一个程序员,从一开始就是学习阅读、批评和纠正代码?这些技能是在专业软件工程爆发后的30/40年里痛苦地转化为实践的,而且通常是留给 "高级 "工程师,初级工程师则对着编译器时常忙于敲打着自己的脑袋。但是现在,作为一个初级人员则会成为一个批判性的读者,代码审查就是新的编程。

方法论的转变#2:白板和橡皮图章

使用LLM教给我们的另一件事是:软件架构是关于模式匹配的,而这些模式是相当简单的。问题是,在默认情况下,例如ChatGPT就类似于一个 "设计面试的扯淡者"。它将自信地使用很多聪明的词汇,在白板上画出正确的图表,而在提出一个真正有价值的观点方面却完全无能。问ChatGPT如何设计某个应用程序,结果会出现一堆不符合现实的陈词滥调(ChatGPT4会有更好的表现)。
说出正确的事情很容易,查找一个有效的事件驱动架构是什么样子也很容易,但要弄清楚到底需要做什么、什么是容易的、什么是困难的、什么是运行良好的、什么会在现实世界的场景中失败等,则要难得多。但是,使用上面的技术,一旦我们开始询问ChatGPT:如何通过勾画出潜在的API来充实基础设施、决定使用哪些协议来建立一个具体的应用程序,我们往往会得到很多看似很合理的具体代码
我发现生成 "可信的 "代码本身就很有用。我不需要相信代码是正确的--整体的结构和氛围让我感觉到这个东西将如何工作,哪些是有问题的,哪些是明智的。它有大量的高质量的代码,可以依靠这些代码找到有趣的模式和命名良好的类;当我想到什么时,我可以引导它。用ChatGPT进行头脑风暴的感觉很像和同事一起坐在白板前想象东西,只是你最后往往能得到相当接近工作的代码。虽然我从来没有与人和ChatGPT进行过 "三方 "白板/橡皮擦会议,但我认为这将成为一些人的常规做法。

方法论转变#3:建立更多的原型

ChatGPT对于生成大大小小的原型非常有用。向它询问一个话题,它不仅会回答,而且通常会用所选择的编程语言提供一个完全可运行的例子。一旦LLM生成了一个玩具的例子,我可以把这个简单的例子改造成更多的东西:
  • 一个完整的命令行应用程序

  • 一个单元测试集

  • 一个模糊测试集

  • 一个文档的例子。

  • 一个压力测试工具

  • 一个简单的网页用户界面("为一个发布到/api/product的字段编写HTML,并将生成的JSON显示为一个表格。然后,编写CSS,使其像geocities页面一样风格化。"这就是需要做的......)

  • 在CI/CD中使用的Docker容器

  • ...

LLMs将探索的成本降低到几乎为零。
我最近想为OBS写一个插件,如果我没有在1分钟内关闭一个模态,就会停止录音。我以前从未对OBS进行过编程,但在三个小时内我就完成了以下工作:
  • 建立一个Python脚本,看起来很有希望

  • 与OBS较量,直到我意识到试图让arm64 python工作太令人沮丧了(失去了1小时...)。

  • 用LUA重写脚本,让它运行起来

  • 意识到那奇怪的幻觉其实是在LUA中做类似modal的最好方法。这个决定依旧很糟糕。

  • 编写一个Go CLI应用程序,通过websocket控制录音。

  • 用Go写一个跨平台的用户界面,让我看到模态和其他各种按钮来控制录音。


我能够尝试两个死胡同(说实话,这不是LLM自己的错),最后得到了一个强大的运行工具。我讨厌写UI,我讨厌和我不知道的晦涩的API战斗。我曾经只在一些事情变得非常令人讨厌,以至于我再也无法忍受的时候才写工具。我有一个坏习惯,我正在积极地与之作斗争:把个人的工具当作是为大规模生产准备的(意思是:在做了3天的 "专业 "软件工程后,我就精疲力尽了,工具最终被扔在了沟里,充满了希望,但还没有完成。)
这对专业编程人员来说意味着,你现在可以写代码,写大量的代码,然后就把它扔掉。没有人会责怪你与ChatGPT的对话产生了5000行的代码,然后停下来。但是,事实是,你写了5000行代码,并决定不值得做下去。你上次这么做是什么时候?
如果标准做法是对手头的问题进行简明扼要的描述(见上一节),然后向LLM索取go中的微服务架构草图、rust中的同步多线程草图、TypeScript Deno版本以及潜在的lambda。如果我们让它为AWS生成Terraform,也为Azure和GCP生成Terraform呢?如果一个架构方案只有在尝试了A、B、C、D之后才能进入审查阶段,而不是无休止地与同事争论A与B的问题,那会怎么样?我们都知道我们有偏见。我们都持有强烈的观点,而这些观点只能由n为1的证据来支持。当我看到实际的代码草图时,我通常会更加信服。
我们曾经嘲笑 "用嘴的速度(speed of mouth)写代码",但现在这已成为现实。

(敬请期待下半部分,好消息是AiDD门票今起618特惠)
原文链接: https://mp.weixin.qq.com/s?__biz=MjM5ODczMDc1Mw==&mid=2651857102&idx=1&sn=0957e733e84afde5c2e3b8a53135c894

本公众号致力于健康、安全、绿色的软件生态,分享软件质量管理、软件测试的思想、方法、技术与优秀实践,追踪软件质量领域的热点,及时报道软件质量管理的成功案例或质量事故,以及分享深度思考、有温度的技术文章等,努力成为您工作中的朋友。

22 篇文章
浏览 8927
加入社区微信群
与行业大咖零距离交流学习
软件研发质量管理体系建设 白皮书上线