首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

经典软件工程复兴?大模型驱动的软件工程实践标准化

TL;DR。

简单来说,本文探讨了大模型驱动的软件工程实践标准化,以及如何将需求和设计规范化为 DSL 格式。通过这种方式,可以让 AI 更自动化、高效地编写代码。

随着大语言模型在软件开发中的应用越来越广泛,传统的软件工程实践开始被重新关注和提及。在诸如于编写清晰的文档、进行代码审查和单元测试等领域,我们可以看到 LLM(大语言模型) 能带来极多在提升。而在其它的一些领域,诸如于辅助接口设计、辅助架构设计、架构治理,我们看到人们有了越来越多的尝试。

而不论是架构设计,还是接口设计,最后还依赖于需求的表达上。而从需求到模型的标准化设计,正是经典软件工程(如 UML,即统一建模语言)等特别擅长的方式。在过去,我们对于编写详细的需求疲惫不堪,而 LLM 正好能在一定程度上帮助我们。

这是否意味着经典软件工程的复兴?又是否我们需要新一代的软件工程方式?

引子:回顾过往

你是否试过提供一个详细的需求或者 API 接口,以让 ChatGPT 绘制 PlantUML(支持 UML 实现的开源软件) 图?

引子 1:手工艺人的编程时代

我刚在学编程那会,学校用的二手计算机还是蓝底白字的 DOS。由于那时计算机很慢,脑子也不灵光,一个小小的函数,老师也会要求你先在纸和笔上写写画画,然后再输入到计算机里。上大学的时候,搞的是嵌入式开发,写个只带任务调度的 OS 都得先理论验证一波,再扔到芯片上跑跑。今天,设计个 Web 系统、框架,还都是 PoC 验证起步,写个功能都是一个测试起手。

印象中,不同层次、不同领域的实现方式里,我很少能做到设计与实现是完全一致的,所以我对于经典的软件工程方法一直都是不看好。

在 Web 应用开发上,我们一直在追求一种快速验证的方式,诸如于:

创建应用模板,及其 hello, world。

第一个单元测试的成功运行。

第一次 CI/CD 的成功验证。

第一个功能的本地桌面检查。

第一个功能的端到端交付。

产品的 MVP 上线。

在追求稳定的基础设施,诸如于运行在资源受限设备的嵌入领域里,由于用户同样在期待类似互联网的交付方式,所以也受到一系列的冲击。像过去我们认为的汽车软件,也搞起了 OTA 升级方式,以出现、也避免你在路上因操作系统升级导致抛锚。

引子 2:软件工程方法:思考 LLM + 经典软件工程设计

当工作以后,我开始习惯于标准的敏捷软件开发流程,它意味着在开发项目里,我需要(由 ChatGPT 生成):

确定需求:与利益相关者合作,识别和记录需求。这通常通过用户故事、用例和需求规范等方式实现。

计划和设计:确定项目的范围、时间和资源,并创建一个项目计划。在这个阶段,团队还需要设计系统的架构和技术方案。

执行迭代开发:敏捷方法采用迭代开发方式,每个迭代通常持续 1-4 周。团队根据需求和设计创建可工作的软件,并在每个迭代结束时进行演示和回顾。

持续测试和集成:在迭代和开发过程中,团队需要持续测试软件,并进行持续集成。这有助于确保软件的质量和稳定性,并减少缺陷和技术债务。

交付和部署:在每个迭代结束时,团队交付可工作的软件,并进行部署。这样,利益相关者可以尽早地了解软件的功能和特性,并提供反馈。

评估和持续改进:团队需要定期评估过程和结果,以便持续改进。这包括回顾迭代、评估团队绩效和采取行动来解决问题。

在敏捷软件开发里,我们会强调:工作的软件 高于 详尽的文档。而现在我们多了一个新的团队成员:LLM,这个新的团队成员它需要文档详尽的文档更种详细的文档。(PS:当然了文档的方式是多种多样的,比如代码信息也是文档的一部分。)

引子 3:LLM as Copilot

随后,我们尝试在软件开发领域引入 LLM 之后。在进行了一系列的内部头脑风暴之后,我们认为它会在不同的成熟阶段,扮演不同的角色:

阶段 一:LLM as Copilot。不改变软件工程的专业分工,但增强每个专业技术,基于AI的研发工具平台辅助工程师完成任务,影响个体工作。

阶段 二:LLM as Co-Integrator。跨研发职责及角色的协同增效,基于AI的研发工具平台解决不同的角色沟通提效,影响角色互动。

阶段 三:LLM as Co-Facilitator。影响软件研发流程的角色分工,基于AI的研发工具平台辅助决策。辅助计划、预测和协调工作,影响组织决策。

回到经典软件工程开发上,我们为什么不愿意去画 UML 图呢?一来,它只适合提供参考;二来,学习成本不低。简单来说,就是性价比太低。

而恰好 LLM 能在一定程度上解决这两个问题,LLM 可以作为一个 Copilot 解决“我懒得做”及“我重复做”的事儿,诸如于你可以让它生成 UML,虽然不是那么靠谱,但是改一改也就能用。

而在有了 “改一改就能用” 的这一基础,那么剩下的事情就变得非常简单了。

动态构建上下文:LLM + 软件工程的核心

在探索了 LLM + 软件工程的一系列实践与应用开发之后,我们着手构建 ArchGuard Co-mate 用于指导软件架构设计与软件架构治理。

位于其背后的瓶颈是:如何动态的构建软件开发所需要的上下文?

隐性知识:为什么 ChatGPT 无法生成满意的 API?

多数人或许都尝试过让 ChatGPT 生成 RESTful API,修改过一个又一个的 prompt,诸如于:

您是一个软件架构师,请生成 博客 entity 的所有 API。使用表格返回,格式:方法、路径、请求参数、返回参数、状态码。

然后,ChatGPT 就开始生成 API 了,这时候你发现了,它生成的 API 可能并不符合内部的 API 规范。于是,我们尝试和它对话去生成更准确的 API,然而,这时可能并不如你直接修改来得快。又或者,我们可以提供一个精炼的 API 规范给它,诸如于我们在 Co-mate 中所设计的:

然后,随着我们提供越来越多的上下文之后,ChatGPT 终于可以像你一样工作了。尽管,这时结合 ChatGPT 生成 API 的时间已经远超过我们动手去设计 API 的时间 —— 因为我们一直需要提供上下文所需要的时间,我们一直在将知识进行显性化。

LLM 就像 “新来的毕业生”:毕业生需要什么上下文?

在这时,你就会发现:“哦,LLM 就像我们团队新来的毕业生”。你需要教给他一系列的知识:

系统的功能:核心系统是做什么的?它有哪些主要的功能模块?这些模块如何为用户提供价值?

系统的优势:相比于其他同类系统,核心系统有哪些独特的优势和特点?它的性能如何?它是否提供了更好的用户体验?

系统的应用场景:核心系统适用于哪些应用场景?它可以为哪些行业或领域提供帮助?

系统的技术架构:核心系统的技术架构是怎样的?它使用了哪些技术和工具?它的可扩展性和灵活性如何?

系统的用户群体:核心系统的主要用户群体是谁?他们的需求和行为模式是怎样的?

顺便给了毕业生一堆文档,让他花两天的时间阅读。随后,你开始让他去实现某个功能,以让他去练手。最后,你发现 10 个毕业生里有 9 个写不出符合要求的代码。还有一个写得出来的是因为,他在这个团队实习过。

思考一下,我们在实现一个 API 的功能时,分别需要:

设计 API 时,需要遵循 API 规范设计的规范。

编写测试时,需要按照最佳的测试实践规范。

实现 API 代码时,需要遵循代码规范的规范。

编写提交信息时,需要遵循条件的 API 规范。

……

没错,每一小步我们都需要一个精确的 spec 才能写出符合要求的代码。而在多数的团队里,这些都是隐性的知识,又或者是由过时的文档所维护。(PS:所以,事实上,就算工作几年的团队成员,也不一定能写出符合规范的代码)

所以,我们更倡导采用结对编程的方式来分享知识,以让团队新人更快上手。

LLM 驱动的软件工程实践标准化

现在,在绕了一大圈之后,让我们回到文章的主题。我们把 LLM 看成是一个团队的新人,它需要知道团队的上下文,才能辅助我们更高效的完成工具。

在构建架构治理平台 ArchGuard 时,我们围绕三态架构(设计态、开发态、运行态)的思想所实现。对于软件来说,它也是颇为相似的,我们会基于初期的需求来设计架构,也就是设计态架构。而在实现时,是基于细化的、响应市场变化的架构,也就是开发态架构。如果想具备快速的市场响应力,我们往往会平衡花在两部分上的时间,所以往往两者不会完全一致。

实现架构之下:实现过程标准化

相信大部分人没用过 GitHub Copilot 写代码,但是大部分人都用过 ChatGPT 写代码。我想大家都会得到一个结论:当我们给定足够精确的上下文时,AI 能与出非常准确的代码,尽管还存在一定的随机性。(PS:当然,第二个结论还是先前提到的那个:如果我给了足够精准的上下文,那我早写完了。)

所以,为了让 AI 更自动化的写代码,我们就需要探索实现过程标准化,诸如于:

从需求管理系统获取需求,并进行需求分析。

结合源码与需求系统,选择最适合变更的入口(如 Java 中的 Controller)

将需求与 Controller 交给 AI 分析,以实现代码的代码。

根据 Controller 逐步自动完成其它部分代码(实现中…)

……

在当前的软件开发流程之下,我们只能让 LLM 模拟现在的流程工作。这也就是我们创建了 AutoDev 的初衷,用 ChatGPT 分解需求,将分析需求流程编写到工具中,以让 ChatGPT 去分析单个的需求,基于此来自动写代码。

而在这时,我们会发现另外一个问题:ChatGPT 缺乏一种全局观。它只拿到了单个的需求,表现得就是一个新人一样。它还需要更多的设计、规范相关的信息。

设计架构之下:规范 DSL 化

作为一个 AI + 软件工程的实践者,我并不相信文档能帮助 LLM 解决这个问题。因为文档总是落后的,缺少人维护的,而且无法自动化。

所以,我们在 Co-mate 中探索的是规范 DSL 化,即在原先 ArchGuard 规范代码化的基础上进行了二次封装。即可以让 LLM 按 DSL 来生成设计,还可以通过 DSL 来检查生成的设计是否符合规范。

诸如于在 Co-mate 的 Foundation Spec 里,我们可以用如下的方式来检查命名:

而在生成代码里,也可以以此作为 LLM 的上下文提供。由于它是一个 DSL,而不是一个文档,所以可以动态地拿出作为上下文的一部分。

经典软件工程的新 DSL

在过去,我们的行业积累了一系列的 DSL,诸如于大量的 ADL(架构设计语言)、UML(统一建模语言)、BDD 语言(如 Cucumber)等等。

Cucumber 是背后的 Gherkin 是一种很有意思的 DSL,特别适合于与 LLM 结合。它也符合那篇《[语言接口:探索大模型优先架构的新一代 API 设计](https://www.phodal.com/blog/language-api-llm-first-api/)》所提及的新一代流式(Streaming) DSL 格式。如下:

所以,我们可以通过上述的方式将需求格式化。

但是我们又遇到了一个问题,如何去表述更宏观的需求呢?

所以,我又从经典的工程方法里,找到了 UML。我依旧还是“相信”,很多人已经尝试过让 LLM 生成 PlantUML,以辅助进行架构设计。尽管有一定的概率生成的 UML 不生效,或者不准确,但是都觉得挺好玩的。

因为,我一直不擅长标准的 UML 写法,所以我并不看好它。而因为大部分后端开发人员都写过 Gradle 配置,所以我觉得类似于 Kotlin DSL 的方式,更方便于理解和修改:

我一直尝试在平衡用例与用户故事,并尝试将它们结合在一起,以为未来生成代码时,提供一种动态的上下文。

所以呢?

为了更好将 LLM 应用于软件开发过程,那么我们需要:

构建软件开发过程的标准化,以将其工具化。

将文档规范 DSL 化、代码化,动态提供,降低 AI 思考成本。

封闭经典的软件工程方式,以新瓶方式提供。

而这一些还需要相当长的时间。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OEAdYXjrtTSicgJb7dTcKeag0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

相关快讯

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券