Xiaowu/20230509 (#793)
* update * update * update * Update 17.2 GPT大模型软件开发辅助.md * update * update * update * update * Update 17.2 智能化时代的软件工程.md * Update 17.1 GPT大模型软件开发辅助.md
|
@ -0,0 +1,4 @@
|
|||
梯度下降
|
||||
反向传播
|
||||
损失函数
|
||||
激活函数
|
|
@ -0,0 +1,4 @@
|
|||
一元回归
|
||||
二元回归
|
||||
多元回归
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
二分类
|
||||
多分类
|
До Ширина: | Высота: | Размер: 32 KiB После Ширина: | Высота: | Размер: 32 KiB |
До Ширина: | Высота: | Размер: 46 KiB После Ширина: | Высота: | Размер: 46 KiB |
До Ширина: | Высота: | Размер: 28 KiB После Ширина: | Высота: | Размер: 28 KiB |
До Ширина: | Высота: | Размер: 41 KiB После Ширина: | Высота: | Размер: 41 KiB |
До Ширина: | Высота: | Размер: 33 KiB После Ширина: | Высота: | Размер: 33 KiB |
До Ширина: | Высота: | Размер: 37 KiB После Ширина: | Высота: | Размер: 37 KiB |
До Ширина: | Высота: | Размер: 31 KiB После Ширина: | Высота: | Размер: 31 KiB |
До Ширина: | Высота: | Размер: 56 KiB После Ширина: | Высота: | Размер: 56 KiB |
До Ширина: | Высота: | Размер: 385 KiB После Ширина: | Высота: | Размер: 385 KiB |
До Ширина: | Высота: | Размер: 86 KiB После Ширина: | Высота: | Размер: 86 KiB |
До Ширина: | Высота: | Размер: 62 KiB После Ширина: | Высота: | Размер: 62 KiB |
До Ширина: | Высота: | Размер: 42 KiB После Ширина: | Высота: | Размер: 42 KiB |
До Ширина: | Высота: | Размер: 71 KiB После Ширина: | Высота: | Размер: 71 KiB |
До Ширина: | Высота: | Размер: 253 KiB После Ширина: | Высота: | Размер: 253 KiB |
До Ширина: | Высота: | Размер: 66 KiB После Ширина: | Высота: | Размер: 66 KiB |
До Ширина: | Высота: | Размер: 115 KiB После Ширина: | Высота: | Размер: 115 KiB |
До Ширина: | Высота: | Размер: 189 KiB После Ширина: | Высота: | Размер: 189 KiB |
До Ширина: | Высота: | Размер: 65 KiB После Ширина: | Высота: | Размер: 65 KiB |
До Ширина: | Высота: | Размер: 96 KiB После Ширина: | Высота: | Размер: 96 KiB |
|
@ -0,0 +1,16 @@
|
|||
# 第十七章 前沿探索
|
||||
|
||||
本章中的 17.1 和 17.2 两个小节,各自是一篇文章,是复旦大学计算机科学技术学院副院长彭鑫教授在微信公众号 CodeWisdom 发布的,笔者征得彭教授的同意后摘抄下来的。在此特别感谢彭教授的支持!
|
||||
|
||||
以下是 CodeWisdom.net 的自我介绍(原文为英文),希望对现代软件工程感兴趣的读者给与关注:
|
||||
|
||||
*CodeWisdom 是中国复旦大学的软件工程研究团队。我们的研究兴趣主要集中在人工智能的软件工程方法和工具(即 AI4SE 和 SE4AI)。在 AI4SE 的方向上,我们正在探索使用人工智能技术进行软件开发、维护和运营的数据驱动软件工程技术和工具,包括:软件分析和大数据分析,以提高软件开发质量和效率;使用深度学习和知识图谱等人工智能技术进行智能代码推荐和软件开发问答;云原生(微服务)架构和 AIOps(用于 IT 运营的人工智能)。在 SE4AI 的方向上,我们正在探索人工智能应用程序的开发、维护和运营所需的软件工程技术和软件基础设施,包括:泛在计算的软件基础设施和敏捷应用程序开发;用于机器人和机器人程序的测试/调试/操作的程序合成;用于机器学习和基于深度学习的应用程序的软件开发、测试、维护和操作方法。我们的作品获得了 ICSM 2011 最佳论文奖、ASE 2018/2021 ACM SIGSOFT 杰出论文奖、ICSME 2018/2019/2020 IEEE TCSE 杰出论文奖和 IEEE 软件工程汇刊 2018 最佳论文奖。除了发表论文,我们还与领先的 IT 和互联网公司密切合作。与此同时,我们正在基于我们的研究开发软件系统和工具。该网站提供我们正在开发的一些软件系统和工具的演示和在线服务。欢迎对我们的系统和工具提出任何建议和反馈。*
|
||||
|
||||
### 作者简介
|
||||
|
||||
彭鑫,复旦大学计算机科学技术学院副院长、教授,中国计算机学会(CCF)杰出会员、软件工程专委会副主任、开源发展委员会常务委员,IEEE 高级会员,《Journal of Software: Evolution and Process》联合主编,《ACM Transactions on Software Engineering and Methodology》编委,《软件学报》编委,《Empirical Software Engineering》编委。主要研究方向包括软件智能化开发与运维、人机物融合泛在计算、机器人软件工程等。
|
||||
|
||||
### 参考资料
|
||||
|
||||
- 《浅评ChatGPT在软件开发上的辅助能力》,彭鑫,CodeWisdom 微信公众号
|
||||
- 《智能化时代的软件工程》,彭鑫,CodeWisdom 微信公众号
|
|
@ -0,0 +1,561 @@
|
|||
|
||||
## 17.1 浅评 ChatGPT 在软件开发上的辅助能力
|
||||
|
||||
笔者对于原文的修改有以下几处:
|
||||
|
||||
- 原文中 GPT 的回答是用截图方式展示的(图片分辨率较低),笔者使用 OCR 软件把截图转变成文字。
|
||||
- 修改了部分章节编号以便于排版阅读,顺序不变,并不影响原文思想。
|
||||
- 由于篇幅有限,省略了 ChatGPT3.5 部分,有兴趣的读者可以阅读原文。
|
||||
- 由于篇幅有限,在后面的代码部分省略了一些环节,有兴趣的读者可以阅读原文。
|
||||
|
||||
|
||||
### 17.1.1 背景
|
||||
|
||||
ChatGPT 于 2023 年正式公测后,凭借其强大的自然语言处理能力迅速获得业内广泛关注,特别是辅助软件开发上,初步表现出了令人满意的能力,然而正当业内积极探索引入 ChatGPT 后的新工作模式之时,OpenAI 又发布了基于 GPT4 架构的升级版本,在语言理解、逻辑推理、情感分析等方面赋予了 ChatGPT 更优的表现,甚至引入了多模态的能力。这一升级让人印象深刻的同时,也让人对 ChatGPT 的能力有了更多的不确定:
|
||||
|
||||
- ChatGPT 在软件开发上究竟能提供多大的辅助?
|
||||
- 在 GPT4 的加持之下,ChatGPT 在软件开发辅助上的表现是否真的更加优秀?
|
||||
- 传统软件开发究竟又会因此发生怎样的变化?
|
||||
|
||||
带着这些疑问,我们以两个前后端分离的本科课程项目为素材,以具体的项目场景为背景,对 ChatGPT 在软件开发上的辅助能力进行了简要的测评。
|
||||
|
||||
注:为方便行文,后文提及的 GPT3.5 指“基于 GPT3.5 的 ChatGPT ”,GPT4 则指“基于 GPT4 的 ChatGPT ”。
|
||||
|
||||
|
||||
### 17.1.2 需求生成
|
||||
|
||||
|
||||
第一部分,我们模拟一个从零开始的开发场景,开发者只有一个关于目标系统的基础概念,将需求分析和细化工作全部交给 ChatGPT 生成。为了结果尽可能细致,我们在prompt时加入了功能和非功能性需求的拆分。
|
||||
|
||||
#### 1. 对目标系统的概念描述
|
||||
|
||||
问题:我们现在需要痞建一个基于 Spring 框架的教务管理系统,你能否帮我们尽可能完善地进行功能和非功能的需求设计?
|
||||
|
||||
#### 2. GPT4 生成的需求
|
||||
|
||||
```
|
||||
当然可以!在设计一个基于 Spring 框架的教务管理系统时,我们首先需要明确功能需求和非功能需求。以下是一个概括性的需求设计:
|
||||
|
||||
一、功能需求:
|
||||
|
||||
1. 用户管理:
|
||||
a. 学生管理:注册、登录、修改个人款查看成绩、选课、退选课程等。
|
||||
b. 教师管理:注册,登录修改个人信发布课程、发布成绩、审核选课申请等。
|
||||
c. 管理员管理:录管理用户(增删改查),管理课程、管理教室等。
|
||||
|
||||
2. 课程管理:
|
||||
a. 课程信息管理:课程的增删改查、查看选课学生名单、课程安排等。
|
||||
b. 选课管理:学生选课、退选、查看已选课程等。
|
||||
c. 成绩管理:师录成绩、发布成绩、查看成绩统计等。
|
||||
|
||||
3. 教室管理:
|
||||
a. 教室信息管理:教室的增删改查、查看教室使用情况等。
|
||||
b. 教室预约:教师申请教室、审-室申请、看教室预约情况等。
|
||||
|
||||
4. 系统公告:
|
||||
a. 公告管理:发布公告、修改公告、删除公告等。
|
||||
b. 公告查看:查看系统公告、查看个人通知等。
|
||||
|
||||
二、非功能需求:
|
||||
|
||||
1. 性能需求:
|
||||
a. 系统具备较高的响应速度,保证用户操作的流畅性。
|
||||
b. 系具备良好的并发处理能力,能在高并发场景下正常运行。
|
||||
|
||||
2. 可用性需求:
|
||||
a. 用户界面应简洁易用,方便用户进行操作。
|
||||
b. 系统提供详细的操作说明和帮助文档,以便用户快速上手。
|
||||
|
||||
3. 安全需求:
|
||||
a. 系统采用安全的身份认证机制,OAuth2.0、JWT 等。
|
||||
b. 感进行力嘧存储和传输,保证数据的安全性·
|
||||
c. 应对常则网络攻击进行防护,如 SQL 注入、XSS 攻击等。
|
||||
|
||||
4. 可维需求:
|
||||
a. 系统具备良好的模块化设计,方便进行功能扩展和维护。
|
||||
b. 代码应遵循一定含程规范,保证代码质量和可读性。
|
||||
|
||||
5. 可扩展性需求:
|
||||
a. 系统考虑未来可功能扩展,采用灵活的架构设计。
|
||||
b. 应使用可扩展的数据库设计,方便后期迁移和功能扩展。
|
||||
|
||||
6. 兼容性需求:
|
||||
a. 系统充应能兼容主流览器(如 Chrome、Firefox、Safari、Edge 等)。
|
||||
b. 适应不同设备和屏幕尺寸,实现响应式布局。
|
||||
|
||||
7. 数据备份与恢复:
|
||||
a. 系定期进行备份,防止数据丢失。
|
||||
b. 提供数据恢复功能,以便在系统出现问题时速恢复。
|
||||
|
||||
8. 日志管理:
|
||||
a. 系统记录详细的操作日志,便于后期排查问题和审计。
|
||||
b. 对日志进行定期以减少存储压力。
|
||||
|
||||
9. 系统监控:
|
||||
a. 实时监控系运行状态,如CPU、内存、磁盘使用情况等。
|
||||
b. 对异常情况进行报警通知,以便及时发现并解决问。
|
||||
```
|
||||
#### 3. 小结
|
||||
|
||||
仅从功能性需求上看,双方的答复整体没有太大偏差,GPT3.5 的结果更加详细,GPT4 的结果相对比较“概括”,与我们问题中的“尽可能完善”有一定出入。
|
||||
|
||||
在非功能性需求上看,GPT4 的结果涉及的内容更加丰富,但缺点是内容与教务系统场景结合并不紧密,反而是 GPT3.5 考虑到了实际的业务场景。例如关于高并发,GPT3.5 提到“能够在繁忙的选课期间保持稳定的性能”,而 GPT4 只是笼统地说“系统应能在高并发场景下正常运行”。
|
||||
|
||||
### 17.1.3 需求细化
|
||||
|
||||
第二部分,我们模拟实际开发过程中收到初步需求描述,需要进一步细化进行开发和验收的场景。
|
||||
|
||||
我们给定一个较为具体的需求描述,要求 ChatGPT 根据该描述进行需求的条目化,同时还要求其识别出尽可能多的用户故事,并写出相应的验收标准。
|
||||
|
||||
#### 1. 基于简单需求描述进行细化
|
||||
|
||||
我们提前告知 ChatGPT 对后一段文字进行需求的识别和条目化,然后将项目的初步需求描述分别喂给 GPT3.5 和 GPT4。
|
||||
|
||||
项目初步需求描述:
|
||||
|
||||
为了方便学生自习,学校开放了一批自习室。自习室中的座位利用率不高,经常出现一座难求,同时又有书包占座人却不在的现象。
|
||||
|
||||
为了提升座位利用率和周转率,学校一方面考虑动态调整自习室的数量,另一方面也希望采用信息技术手段提升座位的利用率。通过自习座位预约系统,管理员可以设定可用的自习室以及开放时间。大部分自习室是早 7 点到晚 10 点开放(不排除将来有个别教室会通宵开放)。学生则可以查看可用自习室,并预约习时间。
|
||||
|
||||
为了提高座位利用率并考虑咸少学生连续学习造劳,每次预约均以整点小时为单位。最多一次性预约 4 小时(系统参数可调)。学生按到达座位后,最好有签到功能。签到应当需要考虑位置信息,比如用手机小程序或类似机制。引入签到功能后在预约时间之前 15 分钟会有推送(邮件推法或微信服务号准送等)提醒;在预约时间之后 10 分钟如果还未签到,则会再次提醒;预约时间 15 分钟后如果还未签到,则自动取消预约、释放座位,并提醒学生,同时后台记录一次违约。
|
||||
|
||||
在任意一个时间点,如果当前有空闲的座位,学生发现自己就在附近并且希望使用的话,可以马上抢位并根据整点时间段选择使用时间。在有签到功能情况下,必须在 5 分钟内签到,从而减少座位资源浪费。为了便于使用,学生可以对所需的座位进行搜索。也可以查看历史预定并再次预定该座位。系统可以增加个性化服务,通过收集预定习惯给用户相应的预定推荐。
|
||||
|
||||
管理员通过查看自习室和座位的预定情况来调整管理策略,提升资源利用率。为了便于学生在线资料获取和学习,靠近固定插座或者移动导轨座的座位有会有特殊标记,以便学生携带电子设备使用。每个座位目前都是普通座位,为了便于预约,会给予唯一编号并在桌面进行标记(比如贴一个号码,但目前还没有这个号码,需要自己几排哪个座)。末来计划将这个标记做成号码和二维码一体化标签,从而便于预约的学生签到。另外,为方便留学生使用,希望有多语言的版本,可以便捷切换界面语言。
|
||||
|
||||
#### 2. GPT4 的需求分解
|
||||
|
||||
```
|
||||
根据您提供的描述性文字,我总结了以下软件开发需求:
|
||||
|
||||
1. 自习室座位系统,包括管理员端和学生端。
|
||||
2. 管理员可以i可用的自习室及开放时间·
|
||||
3. 学生可以資看可用自习室并预约自习时间,最多一次性预约 4小时(系统参数可调)。
|
||||
4. 学生按预约到达座位后,需要实现签助能,结合位置信息(如手机小程序或类似机制)。
|
||||
5. 预约提醒功能,包括预约前 15 分钟提醒和预约后 10 分钟醒。
|
||||
6. 自动取消迟到超过 15 分钟的预约,释放座位,并记录违约情况。
|
||||
7. 当前有空闲座时,学生可以即时预约并选择使用时间。
|
||||
8. 学生可搜索所需座位,看历史预定并再次预定。
|
||||
9. 增加个性化服务,根据预定习惯给用户准荐座位。
|
||||
10. 管理员可以看自习室和座位的预约情况,以调整管理策略。
|
||||
11. 靠近插座的座位有持殊标记,方便学生从带电子设备使用。
|
||||
12. 座位有唯一编号和二维码一体化标签(未来计划),便于学生签到。
|
||||
13. 多语言版本,方便留学生使用,可以便捷切换界面语。
|
||||
|
||||
这些需求可以作为您软件开发项目的基本需求,后续可以根据实际情况进行调整和优化。
|
||||
```
|
||||
|
||||
#### 3. 小结
|
||||
|
||||
从结果观察, GPT4 生成的条目更多,对有些需求进行了更细粒度地拆分,对于相同需求的描述也显得更为简单。例如 GPT3.5 回复的第二条座位签到功能,在 GPT4 生成的结果中被细分为了4、5、6三条。
|
||||
|
||||
但是需要注意的是,GPT3.5 和 GPT4 都存在需求遗漏的情况。例如 GPT3.5 的结果中缺少关于“靠近插座的座位应该有特殊标记”的需求, GPT4 的的条目化结果中忽略了“预约必须以整点为单位”这个较为重要的约束。
|
||||
|
||||
|
||||
|
||||
### 17.1.4 生成用户故事
|
||||
|
||||
#### 1. 基于需求识别用户故事
|
||||
|
||||
做完初步需求分析后,我们尝试让 ChatGPT 生成用户故事,进一步分解任务的细节。
|
||||
|
||||
问题:根据上述开发需求,你能写出对应的用户故事么?
|
||||
|
||||
#### 2. GPT4 生成的用户故事
|
||||
|
||||
```
|
||||
根据您提供的软件开发需求,我为您列举了以下用户故事:
|
||||
|
||||
1. 作为管理员,我希望能设定可用的自习室及开放的实时间,以便管理和调整自习室资源。
|
||||
2. 作为学生,我希望能查看并预约可用的自习室座位,以便安排自习时间。
|
||||
3. 作为学生,我希望预约仔细作为是最多一次性预约 4 小时,以便合理安排自习时间并避免过度疲劳。
|
||||
4. 作为学生我希望能按预约到达座位后进行签到、以证明我按时到达自习室。
|
||||
5. 作为学生,我希望在预约时间前后收到提醒,以便按时到达自习室。
|
||||
6. 作为管理员,我希望系统能自动取消迟到超过 15 分钟的预约,释放座位并记录违约情况,以提高座位利用率。
|
||||
7. 作为学生,我希望在有空闲座位时能即时预约并选择使用时间,以便充分利用学供的自习资源。
|
||||
8. 作为学生,我希望搜索所需座位并查看历史预定,以便史方便地预约自习。
|
||||
9. 作为学生,我希望系统能根据我的预定习惯推荐合适的座位,以提高预约效率。
|
||||
10. 作为管理员,我希望能查看自习室和座预约情况,以便根据实际情况调整管理策略。
|
||||
11. 且作为学生我希望清楚地看到靠近插座的座位,以便从带电子设备使用。
|
||||
12. 作为学生我希望座位有唯一编号和二维码化标签,以便更方便地签到。
|
||||
13. 作为留学生,我希望系统有多语言版本,以便在熟悉的语言环境下使用。
|
||||
|
||||
这些用户故事可以作为您软件开发项目的基本参考,帮助您更好地理解和满足用户需求。
|
||||
```
|
||||
|
||||
#### 3. 小结
|
||||
|
||||
从结果上看, GPT4 表现得要比 GPT3.5 要丰富和细致,值得注意的是 GPT4 在用户故事中使用了第一人称“我”而不是第三人称来进行讲述,或许正是基于这一点,它能够更加“体会”需求中的一些人性化成分,比如第 11 条的故事中讲述道:“我希望能够清楚地看到靠近插座的座位”,这十分贴合我们日常学习生活中的想法和感受。
|
||||
|
||||
此外,前一轮分析中的遗漏在这里的影响也进一步扩大,ChatGPT 构建的系统中似乎彻底遗忘了原始需求中的一部分要求,如果缺少人为检验,这部分的缺失会引起较多后续问题。
|
||||
|
||||
*笔者按:在需求上的最后一步尝试时让 ChatGPT 为我们生成对应需求的验收标准。所谓验收标准其实和需求的用户故事差不多,在此不再赘述。有兴趣的读者可以阅读原文。*
|
||||
|
||||
|
||||
### 17.1.5 编码辅助
|
||||
|
||||
|
||||
第三部分,我们模拟项目的迭代场景,在项目出现新的需求或挑战时,考察 ChatGPT 能否在现有的项目代码基础之上直接为我们生成可用代码及必要的辅助提示。
|
||||
|
||||
我们主要考虑以下三个问题:
|
||||
1)给定一段较长的功能性需求的文本,让其进行代码生成以满足需求。
|
||||
2)向其询问非功能性需求的具体实现方式。
|
||||
3)给定部分已经实现的功能性代码,要求其添加非功能性优化代码。
|
||||
|
||||
#### 1. 根据功能性需求生成代码
|
||||
|
||||
|
||||
我们给定了下方这段很长的功能性需求描述,要求 ChatGPT 直接为我们生成代码,尝试它是否具备跨文件设计系统的能力。
|
||||
|
||||
项目功能需求描述:
|
||||
|
||||
|
||||
请完成一个基于 Java Web 的教务管理系统,系统中我已经实现了用户注册/登录、管理员录入单条用户信息的功能,现在我们的主要目标是对信息管理,课程管理相关功能进行完善。需要增加的功能如下,每行写了对应的功能列表,操作者和详细功能描述,中间以分号隔开。
|
||||
|
||||
- 个人信息维护;教师、学生;教师、学生可以直看自己的个人信息、修改个人信息。可以修改手机号、邮箱、登陆密码。
|
||||
|
||||
- 学院/专业信息维护;管理员;新增一个可以使管理员对专业和学院信息进行管理的界面。在该界面中,管理员可对学院和专业的信息进行增删改查。注意:一个学院对应多个专业。
|
||||
|
||||
- 查看用户信息;管理员;在管理员的用户信息管理界面上展示用户列表。
|
||||
|
||||
- 录入单条用户信息;管理员;原先我们实现了管理员录入单条用户信息劝能。现在需要我们在录入单条信息时,新增加如下两个功能:在原来的管理员录入信息的地方新增一个“学院”下拉列表,使得管理员在录入信息时,可以选择学生/教师所属的学院。在原来的管理员录入信息的地方新增一个“专业”下拉列表,使得管理员在录入信息时,可以选择学生/教师所属的专业。
|
||||
|
||||
- 批量导人用户信息;管理员;在原来的基础上增力批量导入功能。实现能够通过上传 CSV 文件,导入已经在 CSV 文件里面写好的教师/学生信息,从而批量插入数据擞据库。CSV文件的格式可以自己设计。
|
||||
|
||||
- 修改用户信息;管理员;管理员可以修改用户的除学号/工号外的所有信息。
|
||||
|
||||
- 修改用户状态;管理员;如果学生毕业了或者者离职了,那么他们就不能再用自己号/工号去登学校的系统。因此我们要给他们设置权限。要求管理员能够修改用户的状态,包括:正常毕业/离职、在读/在岗等,具体每种状态可以自己罗列。实现通过这些状态来控制系统访问权限打开限关闭,例如毕业的学生或者离职的教师不能登录系。
|
||||
|
||||
- 新增课程;管理员;课程包括课程名、课程编号、开课院系、学时、学分、任课教师、课程介绍,上课时间、上课地点、选课容量等属性。可能存在多个编号相同且课程名相同的课程,每个课程都对应一个讲授该课程的老师。
|
||||
|
||||
- 对已有课程的维护;教师;教师可以申请新增课程、修改已有课程的名称、上课时间、上课,以及删除课程。
|
||||
|
||||
- 审核课程申请;管理员;管理员可以审核教师发送的增加课程/删除课程/修改课程申请。只有管理员审批过后,教师的操作才能生效。
|
||||
|
||||
- 对所有课程的维护;管理员;管理员可以查看现有课程的信就也可删除现有课程,修改课程信息。管理员可以通过 CSV 批量导入课程,也可以单条录入课程。
|
||||
|
||||
|
||||
#### 2. GPT4 生成的代码
|
||||
|
||||
而在 GPT4 上进行相同的尝试,我们发现 GPT4 在面对最初的长篇需求时,就直接按照要求进行了代码的生成。
|
||||
|
||||
```java
|
||||
由于篇幅有限,我将为您提供部分功能的代码实现,并给出实现思路,您可以参考这些代码和思路来实现其它功能。
|
||||
|
||||
首先,创建实体类,包括 User、College、Major、Course 等。
|
||||
|
||||
User.java:
|
||||
|
||||
@Entity
|
||||
public class Major{
|
||||
@Id
|
||||
@GenerateValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
private String username;
|
||||
private String password;
|
||||
private String email;
|
||||
private String phoneNumber;
|
||||
private String userType; // "student" or "teacher"
|
||||
private String status; // "毕业/离职,在读/在岗"
|
||||
|
||||
@ManyToOne
|
||||
private College college;
|
||||
|
||||
@ManyToOne
|
||||
private Major major;
|
||||
}
|
||||
|
||||
College.java:
|
||||
|
||||
@Entity
|
||||
public class College{
|
||||
@Id
|
||||
@GenerateValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
private String name;
|
||||
|
||||
@OneToMany(mappedBy = "college")
|
||||
private List<Major> majors;
|
||||
}
|
||||
|
||||
Major.java:
|
||||
|
||||
@Entity
|
||||
public class Major{
|
||||
@Id
|
||||
@GenerateValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
private String name;
|
||||
|
||||
@ManyToOne
|
||||
private College college;
|
||||
}
|
||||
|
||||
Course.java:
|
||||
|
||||
@Entity
|
||||
public class Course {
|
||||
@Id
|
||||
@GenerateValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
private String name;
|
||||
private String courseCode;
|
||||
private int hours;
|
||||
private int credits;
|
||||
private String description;
|
||||
private String schedule;
|
||||
private String location;
|
||||
private int capacity;
|
||||
|
||||
@ManyToOne
|
||||
private College college;
|
||||
|
||||
@ManyToOne
|
||||
private User techer;
|
||||
}
|
||||
|
||||
然后,创建相应的 Repository 接口,继承在JpaRepository:
|
||||
|
||||
public interface UserRepository extends JpaRepository<User, Long>{}
|
||||
public interface CollegeRepository extends JpaRepository<College, Long>{}
|
||||
public interface MajorRepository extends JpaRepository<Major, Long>{}
|
||||
public interface CourseRepository extends JpaRepository<Course, Long>{}
|
||||
|
||||
接下来,创建相应的 Service 接口及其实现类:
|
||||
|
||||
public interface UserService{
|
||||
// ...
|
||||
}
|
||||
|
||||
@Service
|
||||
public class UserServiceImpl implements UserService{
|
||||
// ...
|
||||
}
|
||||
|
||||
创建相应的Controller类,处理HTTP请求:
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class UserController{
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
// ...
|
||||
}
|
||||
|
||||
以个人信息维护功能为例,在UserService接口和UserServiceImpl实现类中添加get和update方法:
|
||||
|
||||
public interface UserService{
|
||||
User getUser(Long id);
|
||||
User updateUser(Long id, User user);
|
||||
// ...
|
||||
}
|
||||
|
||||
@Service
|
||||
public class UserServiceImpl implements UserService{
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Override
|
||||
public User getUser(Long id){
|
||||
return userRepository.findById(id).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User updateUser(Long id, User user){
|
||||
User existingUser = userRepository.findById(id).orElse(null);
|
||||
if (existingUser == null){
|
||||
return null;
|
||||
}
|
||||
existingUser.setEmail(user.getEmail());
|
||||
existingUser.setPhoneNumber(user.getPhoneNumber());
|
||||
existingUser.setPassword(user.getPassword());
|
||||
return userRepository.save(existingUser);
|
||||
}
|
||||
}
|
||||
|
||||
在UserController类中添加相应的HTTP处理方法:
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class UserController{
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@GetMapping("/user/{id}")
|
||||
public ResponseEntity<User> getUser(@PathVariable Long userId){\\...}
|
||||
}
|
||||
```
|
||||
|
||||
GPT4 不仅进行了完成了从需求分析、设计、实体抽取到代码框架的编写,而且以用户模块为例,展示了 controller 层和 service 层的具体写法,相较于 GPT3.5,还考虑到了 service 层的接口和实现,内容非常细致。以它呈现的大体框架为出发点,还可以针对相应的部分进行进一步的代码生成,逐渐形成系统级别的代码。
|
||||
|
||||
#### 3. 小结
|
||||
|
||||
接下来,我们还要求 ChatGPT 生成其他模块的代码,略。这里值得注意的是,在进行进一步提问以获取更加详细的功能代码时,需求描述应尽量清晰。例如即便第一轮提问已经涉及了全部功能,但要求 ChatGPT 实现具体功能代码时,列出需要实现的具体功能名称(例如提问”能否给出个人信息维护、学院/专业信息维护的具体实现代码“)比简单使用代词(例如提问”能否给出上述功能的具体实现代码“)的效果要更好。
|
||||
|
||||
现在我们已经得到了 ChatGPT 为教务管理系统生成的一个大体的代码框架,接下来我们将在 IDEA 中新建一个 Maven 项目,并把这些代码放入相应的 java 文件中观察代码是否存在错误,并且根据代码来让 ChatGPT 回答、解决相关的问题。略。
|
||||
|
||||
|
||||
总体来看,当 ChatGPT 收到一个较为宏观、复杂度较大的需求时,它通常可以从整体上对其作出分析,并能够在框架上生成出代码,但是这些代码可能不够完整、正确、缺少必要的依赖,不能直接拿来运行,而是需要根据开发者进一步的询问来逐渐引导其生成粒度更小的代码片段或代码文件、或是询问其所需要的依赖。但是在这个诱导的过程中,ChatGPT 可能会“遗忘”之前生成过的代码,造成如方法名、方法返回值前后不一这样的问题,譬如在上面的过程中另外还发现CollegeController 中调用了collegeService的createCollege方法,但 ChatGPT 却在此次生成时把createCollege方法替换(更名)成了saveCollege方法;也会有依赖版本不对应这样的问题,但如果开发者注意到了问题并提醒 ChatGPT ,那么它就能意识到并尝试纠正这些问题。
|
||||
|
||||
|
||||
|
||||
### 17.1.6 迭代新需求
|
||||
|
||||
#### 1. 在现有代码上迭代新需求
|
||||
|
||||
我们尝试在一个现有系统上添加一些非功能性优化,首先询问 ChatGPT 关于优化的措施与具体代码,再让它将这些代码直接嵌入我们现有的系统中。
|
||||
|
||||
问题:我现在做了一个基于 Spring 框架的教务管理系统,但是随着访问量的上升,我的服务响应时间开始演唱,有什么优化性能的方式吗?
|
||||
|
||||
#### 2. GPT4 的优化建议
|
||||
|
||||
```
|
||||
当面临访问量上升导致的性能问题时.可人多个方面来优化亻懂〕基于S@四
|
||||
框架的教务管理系以下是一些建议:
|
||||
1. 代码优化:
|
||||
· 重构代码,避免冗余和不必要的逻辑。
|
||||
· 使用高效的算法和数据结构。
|
||||
· 免全局变量和同步锁。
|
||||
2. 数据库优化:
|
||||
· 优化SQL查询,避免过多的联表查询、子查词和不必要的全表扫描。
|
||||
· 增加索引以加速查询。
|
||||
· 使用缓存,如 Redis 或 Memcached 来存储热点数据。
|
||||
· 数据库分库分表,将大表拆分为小表,以提高查询速度。
|
||||
3. 应用服务器优化:
|
||||
· 调整线置,合理设置最大线程数和最小线程数。
|
||||
· 开启Gzip压缩,减少当专输数据的大小。
|
||||
· 使用负衡器,将流量分散到多个应用服务器上。
|
||||
4. Spring框架优化:
|
||||
· 使用Spring Boot Actuator监控应用性能。
|
||||
· 配置JVM参数,调整内存分配和垃圾回收策略。
|
||||
· 减少自动装配的Bean数量,优化SpringBean的初始化时间。
|
||||
5. 异步处理:
|
||||
· 将耗时较长的任务放入队列中,使用异步方式行,如使用RabbitMQ或Kafka.
|
||||
· 使用Web异步技术,如WebFlux或aservlet异步处理。
|
||||
6. 服务架构:
|
||||
· 将单体应用拆分为多个微服务,每个微服务复杂一个特定的业务功能。
|
||||
· 使用API网关统一管理微服务的请求,实现负载均衡和服务降级。
|
||||
|
||||
涌过以上方法对系统进行优化,可以有效提高你的教务管理系统的性能和响应速度。
|
||||
需要注意的是,优化过程中要结合情况进行分析,以找到合你的系统的优化方案。
|
||||
```
|
||||
|
||||
在理论性的知识上,双方都可以出了很多可行的措施,相较之下, GPT4 给出的建议更丰富、更具统领性。针对双方建议中都提及的缓存,我们要求给出具体的代码,GPT4 回复:
|
||||
|
||||
```java
|
||||
缓存技术可以显出提高应用性能,减少队数据库的访问。
|
||||
在Spring框架中,可以使用Spring Cache来实现缓存。以下是使用Spring Cache和Redis做为缓存的示例。
|
||||
|
||||
1. 首先,添加Redis和Spring Caceh依赖到pom.xml
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Cache -->
|
||||
<dependency>
|
||||
<groupId>oeg.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-cache</artifactId>
|
||||
</dependency>
|
||||
<!-- Redis -->
|
||||
<dependency>
|
||||
<groupId>oeg.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
2. 在application的properties中配置Redis连接信息
|
||||
|
||||
properties:
|
||||
spring.redis.host=localhost
|
||||
spring.redic.post=6379
|
||||
|
||||
3. 在你的Spring Boot主类或者一个配置类上,添加@EnableCaching注解以启用缓存
|
||||
|
||||
@EnableCaching
|
||||
@SpringBootApplication
|
||||
public class Application{
|
||||
public static void main(String[] args){
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
}
|
||||
|
||||
4. 配置Redis做为缓存管理器
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public class CacheConfig{
|
||||
@Bean
|
||||
public CacheManagercacheManager(RedisConnectoinFactory redicConnFactory){
|
||||
RedisCacheConfiguration redisCC = RedisCacheConfiguration()
|
||||
.entryTtl(Duration.ofMinutes(30))
|
||||
.serializeValueWith(SerializationPair.fromSerializer());
|
||||
return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(redisCC)
|
||||
.cacheDefaults(redicCC).build();
|
||||
}
|
||||
}
|
||||
|
||||
5. 在需要缓存的方法上添加@Cacheable注解。例如,对一个学生信息查询方法添加缓存:
|
||||
|
||||
@Service
|
||||
public class StudentService{
|
||||
@Cacheable(value="students", key="#id")
|
||||
public Student findStudentById(Long id){
|
||||
// 数据库查询逻辑
|
||||
}
|
||||
}
|
||||
|
||||
这样,当调用findStudentById方法时,Spring Cache会首先检查Redis缓存中是否有对应的数据。
|
||||
|
||||
```
|
||||
|
||||
#### 4. 小结
|
||||
|
||||
尽管 GPT3.5 给出的结果已经让人很满意,但是 GPT4 依然胜在给出了详细的配置缓存的步骤,说明其考虑到了实际开发中代码以外的因素。
|
||||
|
||||
最后,我们给出了一段实际的代码,要求 ChatGPT 在原来代码的基础上添加缓存功能。
|
||||
|
||||
*略,有兴趣的读者请阅读原文。*
|
||||
|
||||
GPT3.5 和 GPT4 都能以不同的方式为代码添加缓存机制,但是 GPT4 考虑得情况更加多变,几乎生成了一篇关于缓存机制的示例博文。例如它考虑移除过多的缓存条目可能会对性能有较大影响,因此给用户提供了另一个选择。
|
||||
|
||||
|
||||
### 17.1.7 总结
|
||||
|
||||
总体上说,在我们结合实际项目的上手体验后,认为 GPT4 和 GPT3.5 在通用知识上的能力是比较一致的,都可以生成可解释性很强的回答,准确性也非常高,相较于传统的大模型而言,ChatGPT 的能力是遥遥领先的。而 GPT4 相较于 GPT3.5 的主要优点可能在于它在保留了通用知识的高准确性的同时,能够考虑更多任务中的细节,并更适配具体的场景。对于开发人员来说,这种能力可以帮助他们快速地将 ChatGPT 接入自己项目的特定上下文中,并且生成更可靠的代码。
|
||||
|
||||
此外,我们也总结出了一些其他实践经验和感受。
|
||||
|
||||
|
||||
#### 1. 提示质量对于 ChatGPT 性能的影响
|
||||
|
||||
ChatGPT 可以为程序员编写代码提供强有力的帮助和支持已经是软工领域的共识。然而,我们发现,ChatGPT 能够提供多大的帮助,很大程度取决于提问的方式和提示的质量。
|
||||
|
||||
|
||||
1)精准的需求描述
|
||||
|
||||
在提出问题之前,提问者需要仔细地考虑问题的范围和具体需求。无论是期望使用的语言,框架,还是期望实现的功能或非功能代码,都应尽可能详细地进行描述,避免使用较为笼统的词汇和指代不明的代词,以便 ChatGPT 能够根据这些提示产生更加准确的回答。
|
||||
|
||||
2)划分子任务,提问由浅入深
|
||||
|
||||
提问者需要擅长拆解问题,将一个庞大的项目拆解成为一个个需求明确的小任务,提问时问题需要由浅入深,由粗到细,才能一步步引导 ChatGPT 给出更加具体切实的回答。
|
||||
|
||||
从 17.1.5 的尝试结果中我们可以看出,如果一开始将一个完整的大项目直接让 ChatGPT 完成,ChatGPT 只能给出较为通用笼统的答案,GPT4 的表现好于 GPT3.5,但依然无法一次性生成项目所需的全部代码。因此,提问时应该先将背景信息提供给 ChatGPT,再在此基础上让 ChatGPT 依次实现拆解后代码量不大的的子任务,以此引导 ChatGPT 提供最大限度的帮助。
|
||||
|
||||
3)提问“刨根问底”
|
||||
|
||||
提问者想要得到尽可能详细和准确的答案,还需要发挥”刨根问底“的精神。一方面,从我们的尝试中可以看出,很多代码细节 ChatGPT 并不会在一开始就给出,但通过不断追问细节,ChatGPT 其实有能力给出非常具体的回答。此外,ChatGPT 生成的内容不一定总是正确的,如果对生成的内容有质疑,可以直接向 ChatGPT 提出,让其进行解释或引导它更正回答,而不要盲目轻信。
|
||||
|
||||
因此,为了最大限度发挥 ChatGPT 的优势,未来程序员需要具备精准详细提问、拆解问题以及逐步深入引导 ChatGPT 生成具体代码的能力。只有这样才能与 ChatGPT 高效合作,共同完成软件开发任务。
|
||||
|
||||
#### 2. ChatGPT 的不足
|
||||
|
||||
1)无法支持复杂软件的端到端开发
|
||||
|
||||
从 17.1.5 的尝试中可以看出,从自然语言的需求描述到最终可以编译运行的代码中间,需要不断的细化提问。 ChatGPT 更偏向于给出一个代码实现框架,内部很多具体的方法和所需依赖都难以一次性生成,而需要提问者在实际编译运行中不断发现问题,进一步细粒度提问。但在进一步诱导生成更细粒度代码的过程中,ChatGPT 可能会“遗忘”之前生成的代码(例如随着轮次的增加,ChatGPT 新生成的代码变得不符合之前轮次中所生成的代码上下文)。因此,目前 ChatGPT 对于软件开发的辅助仍然难以达到完全端到端的程度,软件开发的”最后一公里“仍然需要程序员自身不断进行调试修改与完善。
|
||||
|
||||
2)具有较大随机性
|
||||
|
||||
相同的问题,多次提问 ChatGPT 后产生的回答可能截然不同,总体来说生成结果具有较大随机性,这对于一些想要利用 ChatGPT 进行的科学研究可能存在一定程度的影响。例如,如果想要研究不同提示模板对于生成内容的影响,可能无法确定是提示模板更换带来的生成效果改善,还是单纯随机生成的结果。
|
||||
|
||||
3)无法保证正确性
|
||||
|
||||
“一本正经地胡说八道”是很多人诟病 ChatGPT 存在的问题,这一问题目前仍然没有得到很好的解决,即使是 GPT4 生成的内容也依然无法保证正确性。这就要求利用 ChatGPT 辅助软件开发的程序员自身拥有一定的背景知识和项目理解,仔细评估 ChatGPT 的回答,并进行必要的修改和调整,以确保生成的代码符合实际需求。
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
## 17.2 智能化时代的软件工程
|
||||
|
||||
以 ChatGPT 为代表的大模型技术对于包括软件工程在内的很多领域都带来了巨大的冲击,也引发了广泛的焦虑。为了在迷雾中看清一点方向,近期我们基于各种技术文献和实践分享以及我们自身的一些初步探索不断地在讨论和思考“大模型时代的软件工程”这一命题。同时我也参加了几次线上访谈,触发了我更多的一些认识和思考,在此基础上撰写了这篇文章,希望与大家分享并倾听大家的意见。由于到目前为止大模型在很大程度上仍然是一个黑盒,并且大模型技术还在快速迭代和发展之中,同时目前看到的以及我们自己实践的基于大模型的软件开发案例还比较初步,因此本文的很多认识和思考不一定准确,未来还可能会随着技术和实践的发展而不断刷新。
|
||||
|
||||
### 17.2.1 大模型冲击波
|
||||
|
||||
ChatGPT(基于GPT3.5)的热潮还未褪去,GPT4 又横空出世,所带来的冲击是全领域、全方位的。在软件工程领域,学术界和工业界都被大模型在软件开发方面的全方位能力所震撼。一些技术专家纷纷上手体验,通过与大模型对话完成需求分析、软件设计、代码实现、软件测试、代码重构、缺陷检查与修复等各种开发任务,甚至尝试用大模型实现端到端的软件应用开发。其结果自然是震撼式的,以至于很多人惊呼“编程要被终结了”、“程序员要大批下岗了”。随之而来的是各种“软件工程新时代即将到来”的论断,有人称之为“软件工程3.0”,有人称之为“软件2.0”,意思都是软件开发要迈入全面智能化的新时代了。
|
||||
|
||||
|
||||
大模型在软件开发方面强大的能力应该已经是毋庸置疑了,它对于软件开发的颠覆性影响应该也可以预见,也就是说大模型助推软件开发进入新的智能化时代应该是可以确定的了。但我们不清楚的是这样的一种新时代会是什么样的,在可见的未来软件开发模式将会发生什么样的变化,有哪些开发岗位会消失又有哪些新的开发岗位会出现?无论学术界还是工业界,很多人都很迷茫和焦虑,因为看不清楚前面的道路。例如,前哈佛大学计算机科学教授、谷歌工程主管 Matt Welsh预测生成式AI将在3年内终结编程,到那时候软件开发团队中只有两类人会保留,即产品经理和代码评审人员。如果他的预测成真,那么当前软件工程领域的很多研究方向以及相关的工作岗位都不需要了,例如软件架构和软件维护。
|
||||
|
||||
|
||||
### 17.2.2 冷静思考
|
||||
|
||||
|
||||
ChatGPT 包括基于 GPT4 的版本)作为一种智能化工具在软件开发的各个环节发挥显著作用已经是一种既成现实了。这让我想起了20年前所研究的软件复用和软件产品线:通过代码复制粘贴和API调用广泛实现局部复用并不难,难的是通过需求和设计规划实现系统性的定制化产品开发(例如软件产品线所宣称的那样)。与之相似,利用 ChatGPT 在软件开发过程中广泛实现局部的智能化辅助支持(例如代码片段生成和技术问答)并不困难,难点在于如何利用它们实现端到端、系统性的生成式开发。
|
||||
|
||||
|
||||
在这个方面,一些业界专家已经做了一些探索并在各种公众号上分享了自己的体验。从这些探索可以看到,对于俄罗斯方块、贪吃蛇这类常见的小规模软件应用 ChatGPT 可以在适当的引导下通过自然语言对话逐步生成完整的可执行程序,产生的代码质量也比较高。由此带来的问题是,这种端到端的生成式软件开发能力能否推及规模更大、复杂度更高的企业软件项目中?这让我想起了Brooks在他的经典著作《No Silver Bullet-Essence and Accident in Software Engineering》中对于软件开发的根本性(Essence)困难和偶然性(Accident)困难的论述:根本性的困难在于对于构成抽象软件实体的复杂概念结构的构思,而产生这种抽象软件实体的编程语言表示只是偶然性的困难。软件工程过去几十年所取得的进展大多在于偶然性的困难方面,而在根本性困难(主要集中在需求和设计)方面则进展不大。
|
||||
|
||||
|
||||
|
||||
端到端的生成式软件开发显然需要逾越需求分析和软件设计这两座大山,那么 ChatGPT 在这两个方面的能力如何呢?从目前分享的端到端生成式软件开发案例来看,似乎 ChatGPT 已经具有一定的分析和设计能力,具体表现在:
|
||||
|
||||
- 根据给定的高层需求自动生成细化需求,还可以进行条目整理;
|
||||
- 根据要求自动生成需求描述的规范化表示,例如UML顺序图;
|
||||
- 根据需求自动生成包含多个类的设计结构;
|
||||
- 根据开发人员的提示以一种增量的方式逐步生成应用代码(这要求对原有的代码实现结构有理解);
|
||||
- 根据一般的设计原则对代码进行自动化重构以提高可理解性和可扩展性。
|
||||
- 根据需求自动生成数据库表结构设计以及相应的建表SQL语句;
|
||||
|
||||
|
||||
|
||||
那么 ChatGPT 真的会做分析和设计吗?从目前各路专家分享的实践经验看,不能说它不会,但所尝试的软件应用规模较小(例如百行到千行代码),需求较简单(例如俄罗斯方块游戏、图书馆管理等简单信息系统)甚至网上存在大量同类应用的代码和文档。此外,要想通过对话式的过程让 ChatGPT 端到端地生成完整代码,开发人员需要具有很强的对话和引导能力,不断能清晰表达要求而且还要能将开发要求分解为一系列要求明确的任务并按照合理的顺序引导 ChatGPT 完成。例如,在张刚的分享《ChatGPT 结对编程实录:提升生产力,还是被代替?》中,一个简单的俄罗斯方块游戏的实现过程被拆分为了10个任务,分别是:创建游戏框架、使用GUI替换控制台、在GUI上显示一个L形方块、移动方块并且进行碰撞检测、旋转方块、落下方块并且创建一个新的方块、检测游戏结束、增加整行消除功能、加入所有类型的方块、增加计分能力。这个任务拆解体现了一个非常合理的增量和迭代开发过程,后面的任务依赖于前面的任务,同时每一个任务完成后效果都可以确认(例如程序可运行)。虽然这个任务拆解过程也受到了 ChatGPT 输出的启发,但仍然需要开发人员掌握整体的迭代过程,而且其中还融入了一定的设计思考。此外,开发人员还需要不断检查 ChatGPT 产生的结果,及时发现 ChatGPT 的错误并提醒修正。特别是在需求分析过程中,ChatGPT 进行需求细化主要依据常识或某类软件的共性特征,可能遗漏一些重要需求,同时创新性或个性化需求也需要开发人员进行补充。
|
||||
|
||||
我们再从大模型的训练方式以及软件开发的本质性问题出发进行一下思考。以下几点是我目前得到的一些认识。
|
||||
|
||||
|
||||
#### 1. 软件开发的规模和复杂性可能会从人机两个方面限制大模型的能力
|
||||
|
||||
|
||||
首先,生成式的开发过程高度依赖于开发人员对于大模型的分步引导,这就要求开发人员自身能够完整和深入掌握整个软件的设计和实现过程,这样才能以合理的方式进行任务拆解并按照合理的顺序引导大模型逐步生成代码。当一个软件的规模达到几万、几十万甚至几百万行代码时,人的大脑可能已经无法掌控整个代码生成过程了。而且对于大规模复杂软件系统而言,任务的拆解和实现并不是一个串行的过程,而是存在很多条平行的线索并伴随着不断的分叉与合并。因此,在传统的软件开发中,开发人员需要对大规模复杂系统进行多层拆解,不同的开发小组和个人分别负责不同层次和不同部分的工作,同时开发团队根据需要随时进行沟通协调和设计方案调整。这一过程目前还很难被大模型所取代。其次,大模型本身对于复杂系统开发过程的全局掌握能力也是有限的。例如,我们团队的分享《浅评 ChatGPT 在软件开发上的辅助能力(附GPT-4对比)》中提到,即使是在规模很小的软件的生成过程中,ChatGPT 也可能会“遗忘”之前生成的代码(例如方法名、方法返回值前后不一致)。这导致大模型可能会顾此失彼,难以生成大规模的软件实现代码。最后,人工代码审核的存在使得软件设计和代码质量仍然有着重要的意义。即使目前最乐观的估计也承认大模型生成的代码仍然需要人工审核。如此一来,对于大规模软件系统而言,模块化、信息隐藏、关注点分离、代码可理解性等原则仍然十分重要,否则审核代码的开发人员将难以理解大模型生成的代码并成为软件开发过程中的瓶颈。
|
||||
|
||||
#### 2. 大模型可能缺少抽象思维能力同时在精确性上存在不足
|
||||
|
||||
软件设计特别是高层架构设计往往涉及复杂的抽象思考。其中有一些设计抽象存在清晰的逐层精化脉络,例如从接口设计逐渐细化得到具体实现。但还有一些设计抽象涉及全局性的系统抽象,其中往往还包含复杂的权衡决策,例如软件架构风格和模式的选择。这类复杂的设计抽象可能是大模型所不擅长的。大模型的训练方式使得它善于基于平面化的上下文以及提示信息产生相关内容,同时通过细粒度(例如单词级别)的灵活组合实现举一反三、触类旁通的效果,但对于大范围的抽象设计决策可能缺少相应的掌握和应用能力。此外,大模型概率性的本质与软件所追求的精确性之间存在冲突,因此大模型在局部编码任务上经常可以做到八九成正确但同时要求开发人员能够及时发现问题进行提醒纠正甚至直接修改和补充。
|
||||
|
||||
#### 3. 软件需求和设计中存在大量难以捕捉的“暗知识”
|
||||
|
||||
大模型的成功很大程度上来自于对已有的互联网文本语料(含代码)和专业书籍等资料的学习。与之相对比,软件开发中的很多需求和设计知识并不存在明确的文字记载,它们可能存在于开发人员(包括架构师)的脑海中、曾经画在白板上或者出现在项目会议的讨论内容中。即使开发团队提供了详尽的需求和设计文档,一般也没有谁会相信关于需求和设计的重要信息都能在文档中找到。此外,需求和设计背后经常有大量的方案对比和推敲,这些决策过程一般都不会明确地被记录下来。虽然我们可以说只要有足够的数据大模型就可以学到需求和设计知识,但这些“暗知识”本身就很难被捕捉到,“足够的数据”这一前提可能难以满足。此外,即使我们通过拍照、会议纪要等方式记录了一些这方面信息,但因为其高度的抽象性甚至模糊性(例如设计图中某个元素的含义以及对代码实现的影响)大模型可能也难以学习和应用这些知识。
|
||||
|
||||
#### 4. 大模型对于复杂软件系统的长期维护支持能力存疑
|
||||
|
||||
企业软件系统一般都有着很长的生存周期,在此期间可能由于多种原因(如需求变更、使用环境变化、缺陷修复、性能提升等)进行修改,同时也可能会面向不同客户进行定制。这些软件维护和演化过程中蕴含着很多软件工程问题和挑战。要实现系统的软件智能化开发支持,大模型显然不能只做一锤子买卖(即只负责最初的代码生成)而需要在长期的软件维护和演化过程中根据需要完成各种功能扩展和代码修改任务。这要求大模型能够理解代码中业已实现的各种需求、设计方案以及需求/设计元素与代码元素之间的精确对应关系,同时需要知晓并处理代码修改与各个部分之间的交互关系(如修改带来的直接或间接影响)。此外,大模型生成的代码本身可能存在很多重复的地方,这些重复代码(代码克隆)的长期维护特别是一致性修改可能成为一种负担。
|
||||
|
||||
|
||||
|
||||
### 17.2.3 拥抱大模型的正确姿势
|
||||
|
||||
大模型在一些编程任务上的优异表现让很多人感到很兴奋,同时也对大模型颠覆软件工程、实现全面的生成式软件开发的前景感到很乐观。但我觉得,要谈大模型的软件开发能力首先要区分所开发的软件类型。对于小规模的软件应用,甚至适合最终用户编程(End User Programming)的应用开发任务,利用大模型实现端到端的完整代码生成是完全可能的。而对于大规模的复杂软件系统而言,根据需求陈述实现端到端的完整代码生成还不太现实。
|
||||
|
||||
拥抱大模型对于软件企业提质增效而言肯定是一个正确甚至必要的方向。事实上,如果不考虑信息泄露风险的话,在企业研发过程中直接使用 ChatGPT 这类大模型就可以直接获得显著的开发效率和质量提升。然而,要想实现系统和全面的软件智能化开发,还有很多基础性的工作需要去做,同时还有一些关键问题需要探索。以下是相关的几点思考和建议。
|
||||
|
||||
#### 1. 扎实做好软件开发的数字化和知识化积累
|
||||
|
||||
软件开发为很多不同的行业提供数字化解决方案,然而软件开发自身的数字化程度却很低。例如,通用软件资产(如公共组件)未得到有效整理和复用,重新发明轮子(如重复实现相同的功能)的现象十分普遍;每次代码修改的前因后果不清楚,例如引发代码修改的开发任务(如特性实现或缺陷修复)以及代码修改所带来的影响(如引入代码问题以及度量指标的变化)缺少系统化的记录。此外,软件中所蕴含的需求和设计知识缺少明确的描述以及与代码的清晰映射关系,导致开发人员经常就相同的问题重复思考。在这种情况下奢望大模型直接带来跨越性的全面智能化开发体验可能是不切实际的。正确的做法可能是扎实做好软件开发的数字化和知识化积累,在此基础上再与大模型结合实现更系统的智能化开发支持。例如,构建特定领域的通用组件库并建立描述体系,建立软件代码克隆以及软件供应链的全面跟踪和管理体系,建立开发任务(特性实现、缺陷修复等)、开发人员、代码提交和修改内容之间的追踪关系,建立并维护高层设计描述及其与代码单元之间的映射关系。这些数字化和知识化建设本身就可以提高软件开发质量和效率。而大模型不仅可以为软件开发的数字化和知识化提供技术和业务背景知识,而且还为我们整合数字化和知识化平台中的信息和知识提供了一种有力的手段。
|
||||
|
||||
|
||||
#### 2. 更加重视需求、设计、验证等软件工程基本能力建设
|
||||
|
||||
我比较认同 Bertrand Meyer 在《Communications of the ACM》的一篇博客文章中所提到的观点,即: ChatGPT 这类大模型并不会带来编程的终结,而是会复兴软件工程领域的一些根本性的技术,例如需求分析、精确的规格说明以及软件验证(包括动态测试和静态分析)。这些软件工程传统技术有望在大模型时代重新焕发青春,但可能需要考虑如何与数据驱动的大模型技术有机结合。同时,如前所述,也需要加强需求、设计、测试等方面的数字化和知识化基础设施建设。
|
||||
|
||||
|
||||
#### 3. 探索能有效整合大模型、开发人员以及各种工具能力的智能交互引擎
|
||||
|
||||
我们当前在软件开发领域所面临的局面与Gartner近几年力推的超级自动化(Hyperautomation)所针对的问题很像,也就是存在很多自动化工具系统(如调试与测试工具、编译构建工具、代码静态检查工具等)同时形成了丰富的资源库和过程库(如通用组件库、开源代码仓库、软件开发在线问答系统、缺陷跟踪系统、版本管理系统等),但面临的问题是如何在人工智能技术的支持下将这些自动化能力和资源无缝衔接构成全过程的智能化体验。对于软件开发而言,还有一个重要的问题是如何将人(开发人员)和机(大模型及各种工具)的能力有机融合、实现高效的人机协同。如前所述,大模型在生成式软件开发过程中所发挥的作用与人的交互和引导能力密切相关,同时人的经验在高层决策以及代码审核等环节还要发挥重要作用。因此,系统性的智能化开发过程不能完全依赖于开发人员自身与大模型的交互能力,而是应该追求建立一种能够统一调度并有效整合大模型、开发人员以及各种工具能力的智能交互引擎。例如,依托下一代IDE形成的开发人员统一门户可以通过一个智能交互引擎理解当前的开发任务及进展态势,在基础上灵活调度和利用大模型的生成能力(如细化一段需求或生成一段代码)、已有的数字化信息和知识积累(如代码依赖关系、通用组件、软件设计决策等)、各种工具能力(如运行代码静态检查或自动化测试、查询相关的缺陷报告信息以及提交新的缺陷报告等)以及开发人员的主观判断(如作出需求和设计决策、审核大模型产生的结果等)。这一过程的一个突出特点是智能交互引擎主导,将开发人员的经验判断与各种工具的能力以及大模型的智能有机结合,并实现高度顺畅的智能化和自动化开发过程。此外,智能交互引擎还需要实现开发人员与大模型之间的人机交互过程的会话管理,支持以“多线程”的方式与大模型开展交互式探索同时支持这些探索线索的按需拆分(fork)和归并(join)。在此过程中,智能交互引擎需要做好会话状态和上下文的管理和切换。
|
||||
|
||||
|
||||
### 17.2.4 结束语 Ending
|
||||
|
||||
拥抱大模型对于软件企业提质增效而言肯定是一个正确甚至必要的方向。但是,如何实现系统和全面的软件智能化开发还需要冷静思考,同时还有很多基础性的工作需要去做。对于企业而言,扎实做好软件开发的数字化和知识化积累以及需求、设计、验证等软件工程基本能力建设仍然是十分重要的,而且也是实现更高水平的智能化开发的基本条件。对于学术研究而言,面向系统和全面的软件智能化开发还是有很多工作可以做的,这也要求我们在理解大模型能力的基础上对于软件系统的复杂性以及软件需求和设计有更深的理解。
|