[I.3] 个人作业:结课总结

个人作业:结课总结

项目 内容
这个作业属于哪个课程 https://edu.cnblogs.com/campus/buaa/BUAA_SE_2026_LR
这个作业的要求在哪里 [I.3] 个人作业:结课总结
我在这个课程的目标是 了解软件工程的开发流程,尤其是模拟当前公司的开发流程,为进入公司进行相关实践做好准备
这个作业在哪个具体方面帮助我实现目标 通过回顾一学期提出的问题与项目实践,系统梳理软件工程各阶段的学习收获

提问回顾

在学期初的阅读作业中,我提出了以下问题([以前提问题的博客]):

  1. AI能否代替结对编程的领航员角色?
  2. 自动化测试脚本是否会让开发者忽视测试设计?
  3. 在大型软件工程中,追求某些局部优化解法,是否会破坏系统的通用性和可维护性?
  4. 软件项目的工程支架是否会成为一种负担?
  5. 在互联网细分领域都被占满时,NABCD 模型真的能帮助我们产生创新吗?

经过一个学期的学习、结对项目、团队项目以及转会实践,我对这些问题有了新的认识。


对自己曾经提出问题的解答

问题 1:AI能否代替结对编程的领航员角色?

我原来提出的问题是
既然AI无法提供人与人结对编程时的心理激励作用,那么这是否说明结对编程是无法被AI替代的?如果随着AI代码生成效率的提升,结对编程的投入产出比小于AI结对编程,那么是否还有必要为了促进交流与提供心理作用而保留结对编程的形式?

通过本学期的学习,我现在这样理解
结对编程的意义在当前的AI时代不仅仅局限于两个人互相纠正代码错误或是“心理激励”这么简单。我认为结对编程在当前反而更加重要。在之前代码全部都由个人来完成,人虽然可能会犯错误但是至少对于自己写出的代码是熟悉的。但是有了AI之后有时候会连自己产出的代码都不熟悉。但是由于人的意志力原因,在一个人和AI合作的时候总是有可能完全信赖AI,对于AI写的代码全盘接受,久而久之就会产生问题。而当一个人在场边时,由于两个人共同对于这一段代码负责,个人偷懒不审查代码的情况可能性大大降低,在监督之下会更仔细地检查代码,同时两个人同时找一段代码的漏洞,产出的代码质量也会大幅提升。在这个产出质量远大于数量的时期,这种保障质量的合作方式虽然看似降低了效率,但是提升了代码的质量,降低了修复bug所需要的时间,从长期来看反而不会造成效率的下降。

我是如何弄清楚的

  • 结对项目中,我对于结对编程场景下的模式和心态有了深刻的了解与体会。我原来认为结对只是会带来所谓的心理激励,但是真正面对队友开始编程时,我才明白了这份工作会让自己更负责地对待这个项目的代码,更频繁地指出可能的问题。我们在这个时候尝试了两个人驱动AI来写代码,从而得到了上述的理解。

问题 2:自动化测试脚本是否会让开发者忽视测试设计?

我原来提出的问题是
讲义主要介绍了:如何使用工具生成测试、如何运行单元测试、如何查看代码覆盖率,但对于 “如何设计高质量的测试用例” 的讨论相对较少。那么,虽然开发工具可以自动生成测试代码的框架,提高开发效率,但这种自动化是否可能让开发者忽视测试设计,从而导致测试质量下降?

通过本学期的学习,我现在这样理解
对于自动化的测试代码生成,自动生成的测试远远不足以覆盖所有情况。对于开发者来说,应该建立“自动测试只能测出最明显的错误”的观念,在自动测试之外主动构造复杂案例的测试用例。对于开发团队来说,在有条件的情况下要有专门的人负责构造与设计测试,并且这样的测试必须包含从用户的使用角度来构造可能出现Bug的情况。

我是如何弄清楚的

  • 团队项目的测试中,我们得到了深刻的体会。开发中,前后端的开发者会在编写代码的同时使用 AI 构造测试样例,这样的测试样例基本都可以通过,单元测试的覆盖率也看起来不错。但是当所有模块整合到一起进行联调试用时,就出现了大批的 Bug,不得不紧急召开会议,连夜修复。经过复盘,这些 Bug 要么是前后端的衔接出了问题——前端传的参数格式和后端期望的不一致,但各自的单元测试都只测了自己的理想输入;要么是程序在真实的服务器环境上出现了本地开发环境没有复现的问题,比如数据库连接超时、文件路径在不同操作系统下的差异等。这些问题,AI 生成的单元测试一个都没有覆盖到,因为它只会对着单个函数的签名生成看起来合理的输入,而不会站在整个项目整体衔接的角度去想。这次经历让我意识到,自动生成的测试框架解决的是有没有测试的问题,而不是测试好不好的问题。真正高质量的测试需要开发者主动思考:这个模块的边界在哪里?谁在什么情况下会调用它?如果调用方犯错了会发生什么?而这些思考,是自动化测试远远无法完成的。

问题 3:在大型软件工程中,追求某些局部优化解法,是否会破坏系统的通用性和可维护性?

我原来提出的问题是
作者在这里提出鸡兔同笼问题的另一种解法,背后的原因应该是为了鼓励作者在某些特殊情境下做一些对于特定问题的优化以实现提高效率等优化。但是在书里所说的软件工程的设计与实现里,最经常提到的就是设计的通用性以及在需求发生改变时的可维护性。那么在这个情境下,仍然采取这种取巧的方法是否可取?在这个情境下最简单的反例就是如果动物种类的数量变了,这种方法就不适用了。

通过本学期的学习,我现在这样理解
局部优化解法是否会破坏系统的通用性和可维护性,取决于它出现在什么场景、作用于什么层次。如果它出现在核心业务逻辑中,且以牺牲可读性和扩展性为代价换取微小的性能提升,那么它一定会成为未来的技术债。但如果它出现在性能瓶颈已被确实验证的路径上,并且被封装在良好的接口之后、不影响外部调用者,那么这种局部优化是可以接受的。关键是判断这个优化现在该不该做以及做了之后会不会产生其他副作用。

我是如何弄清楚的
Knuth 的"过早优化是万恶之源"论述给了我一个判断标准:优化的时机比优化本身更重要。抬腿解法的问题不是它不巧妙,而是它在需求还没稳定的时候就牺牲了通用性。

Martin Fowler 关于"认知负担"的观点"任何一个傻瓜都能写出计算机能理解的程序,只有写出人类容易理解的程序才是优秀的程序员"在团队项目的转会环节中我深有体会。接手别人代码时,一段取巧的逻辑往往比一段朴素的逻辑多花几倍的时间去理解。

团队项目中的一个小教训:有同学为了快速完成功能,把某个规则硬性设置成了常量。后来需求一变,这个值的修改牵动了前后端三四个文件。如果当初多花半小时写成配置项,后面根本不会有这些麻烦。

当然,我仍然认为,在软件工程而非算法竞赛的语境下,提出鸡兔同笼这样一个应用范围明显受限、推广性差的解法作为思考范例是有风险的。


问题 4:在互联网细分领域都被占满时,NABCD 模型真的能帮助我们产生创新吗?

我原来提出的问题是
如果真正困难的是“找到一个值得做的想法”,而不是“分析一个想法是否合理”,那么 NABCD 是否只能解决创新过程中的后半部分问题?

通过本学期的学习,我现在这样理解
我对于这个问题的答案是肯定的。我们不能指望NABCD可以帮助我们获得一个好的想法。然而,NABCD 确实不能直接帮你产生创新,但它能帮你把一个模糊的念头变成一个真实的项目。

我是如何弄清楚的

  • 在团队项目中,我们的灵感来源和NABCD完全没有关系,全是靠队员们生活中遇到的真实需求。在这个时候,凭借着对于生活的灵机一动往往可以比系统地分析获得更好的目标。例如我们的心运岛项目的灵感来源,就是爆火的SBTI等人格测试暴露出来的年轻人渴望了解自己、对于不确定的未来有一份精神寄托、并和别人分享的心理。当然,虽然灵感来源用这个模型不能代替,但是NABCD的分析(虽然是被迫的)还是为后来的软件设计奠定了基础。通过分析该如何满足用户需求等,我们最终设计出了最终产品的形态,包括分享广场、运势看板等。总的来说,虽然这个项目初期的灵感来自组员的灵光一现,但是最终的成品设计还是很大程度上归功于NABCD的系统分析。

仍未解决的问题

在现代高频率软件开发的项目过程中,这些源代码管理和构建系统的“脚手架”往往呈现出比业务代码更快的复杂度增加速度。当一个项目为了实现所谓的高质量的工程质量而引入了复杂的支架系统时,我们如何评估这些支架带来的负载是否已经超过了它所带来的对于开发效率的提升?如果“支架”本身需要随着需求频繁重构,那么它是否失去了本身应该有的作用?

仍然存在的困惑是
即使经过了一个学期的结对、团队编程的实践,我仍然没有对"工程支架"这个系统有很深刻的认识。原因在于,我们的团队项目规模较小、周期较短,所用的工具链也比较轻量,基本的 Git + CI 配置 + 一个简单的构建脚本就足以支撑整个开发流程。我没有经历过需要多环境部署配置或容器化编排的场景,因此也就无从体会支架比楼重到底是什么感觉。当初在第一次作业中质疑作者用"塔吊"类比的合理性这个困惑至今仍然成立,但它的答案可能需要等我参与一个真正长期维护的中大型项目之后,才能用自己的经验来回答,而非从书本或别人的论述中得出。


产生的新问题

新问题 1:对于团队成员的贡献,由于组员们互相认识,很难拉下脸来,如何设计出尽可能公平的机制来让组员们自我与互相评价时摒除个人的情感?


各阶段学到的"知识点"

需求阶段

知识点:需求没有固化就开始写代码,会在实现和运维阶段持续还账

来源:团队项目 —— 心运岛

具体说明
本项目在立项初期存在需求定义不够细致的问题,功能设想较多,但文档与成员理解尚未统一便开始了编码。作为基础设施管理者,我在数据库层面感受尤为明显:早期数据表直接创建于环境中,数据库迁移机制属于后期补充,导致生产库虽存在完整表结构,却缺少迁移版本记录,部署时升级流程无法正常识别。与此同时,需求在开发过程中不断扩展,从最初的运势、答案、日记,逐步增加了徽章、广场评论、运势 PK 等功能,对应的迁移文件累积至十余个。这一过程让我真正理解到:需求阶段省下的工作量并不会消失,只会以更高的成本在实现与运维阶段重新出现。


设计阶段

知识点:合理划分模块边界,是降低后续维护成本的前提

来源:团队项目

具体说明
在构建CI/CD工作流过程中,我最初将部署写成单一脚本一次性完成全部操作,但最终还是将其拆分为前端代码检查、后端构建、自动部署等多个相互独立的环节,且前置检查未通过便不会触发部署。本地环境同样借助 docker-compose 将数据库与后端服务解耦,后端需等待数据库检查通过后再启动。这种设计为我们团队后续的版本更新带来了很大的便利(不如说是避免了很多令人崩溃的神秘故障)。某些情况下前端代码检查未通过,但由于各环节相互独立,并未波及后端,也避免了将未完成的构建产物发布到服务器。


实现阶段

知识点:代码规范并非约束,而是团队协作的基础设施

来源:团队项目

具体说明
在alpha阶段开发时,我们在课程的要求下完成了对于提交的规则制定,包括提交名称、前端风格检查等。在一开始团队内部(包括制定规则的我)都存在一些不适应与抵触情绪,有时候交上去一版被拒了会在心里骂人。但随着合并频率提高,规范的价值逐渐显现:通过提交记录可以清楚地了解每次改动的内容,通过 PR 描述可以理解改动的原因,统一的代码风格也降低了阅读他人代码的成本。我由此认识到,这些检查与构建、部署本质上属于同一类工作,都应是流水线中的固定环节,而非额外负担。代码规范对于单人开发或许显得多余,但在多人协作的场景下,它是显著降低沟通成本的基础,让我们可以不用在后期出现问题时绝望。


测试阶段

知识点:未纳入 CI 的测试用例,难以发挥应有的保护作用

来源:团队项目

具体说明
在我们的团队任务中,后端实际上编写了较为完整的 pytest 用例,覆盖认证、运势、广场、徽章等模块,技术文档中也将pytest 通过率 100%列为发布出口条件之一。然而,CI 流程中并未真正执行 pytest,仅包含代码检查、Docker 构建与部署等环节。由此带来的问题是:某些已修复的缺陷会在后续迭代中再次出现,因为缺少在合并环节自动执行的回归测试。这让我认识到,编写测试用例本身并不等同于建立了有效保护,关键在于哪一项测试失败能够阻止代码合并。若答案是没有,那么这些用例更多只是开发者自身的参考。


发布阶段

知识点:本地可运行与生产可上线之间,隔着一整套环境差异

来源:团队项目

具体说明
在本地运行时,我们每个人全都顺利在本地跑通,但一到部署到我所购买的服务器上,问题就全都来了。我们所遇到的问题几乎都与功能本身无关,而是源于环境差异:生产库存在历史表却缺少迁移记录、pip 在国内网络环境下安装超时、生产配置强制要求环境变量而本地存在默认值因而难以提前暴露。经历这一过程后,我才真正理解可部署性同样是软件质量的组成部分。


维护阶段

知识点:技术债是需要以实际时间成本偿还的现实问题

来源:团队项目

具体说明:本项目最典型的技术债同样在数据库迁移。由于早期数据表直接创建于生产环境,Alembic 迁移机制为后期补充,每次部署脚本都需先判断当前数据库属于历史状态还是标准状态,再决定是补充版本号还是直接升级。随着功能不断增加,迁移文件累积至十余个,这段部署逻辑也逐渐演变为为兼容各种历史状态而不断叠加的补丁。


理解与心得

结对编程阶段

对于结对编程来说,我被课程强迫体会了一把之前只在课件上出现但从没有听过有人实践的结对编程。在结对编程里我确实体会到了理论课上所说的结对编程的好处,包括两个人互相监督鼓励、对于代码的审查等等,也让我对于这个抽象而遥远的概念有了新的理解。但是说心里话,我认为即使到了真实的工作环境中,除非要强制的要求,我不会选择和别人采取这种结对编程的策略,因为我相信大部分像我这样的人都不会愿意被一个人随时盯着看,哪怕是在工作中。

团队项目阶段

在团队阶段,我最深刻的感悟就是体验了一把必须要一群人合作才能完成的任务。之前不管是CPU还是编译器,我们都需关了单打独斗,但是这次的团队项目里,我们的长期积累下来的编程习惯遇到了考验,包括但不限于:如何合理地分配每个成员的任务、在开发时如何兼顾别人负责模块的兼容性、不同人的版本如何合并等。在解决这些问题的过程中,我们从问题的角度重新认识了Git版本管理、CI/CD、前后端协作模式、环境管理等等内容,对于之前不懂“为什么这么设计”的问题,当用这个解决了遇到的实际问题时,就一下子明白了。

在本项目中,我们采用了较为贴近敏捷的开发方式:以较小的功能单元为单位迭代推进,通过 Pull Request 提交改动,借助 CI 进行检查后再合并到主分支,而非等到所有功能完成后再统一集成。这种方式给我最直观的感受是,问题能够更早地暴露出来。由于每次合并都要经过代码检查、提交信息规范校验等门禁,许多潜在问题在进入主分支之前就被拦下,避免了最后集成阶段集中爆发的风险。

在项目管理与进度控制部分,我们将代码检查、构建与部署纳入统一的流水线,使得开发进度变得更加透明、可控。每一次合并的状态、每一次部署的结果都有迹可循,团队成员能够清楚地了解当前项目处于什么状态。这在一定程度上减少了功能合并了却不知道改了什么所带来的沟通成本。但是在实际的运作中还是出现了一些问题,由于每位同学不能实际的预判项目的工作量以及在工作中不可避免的出现了Bug等问题,我们的进度会落后于理想情况,这也导致了一些节点下我们不能实现对于全栈的测试。这也是我认为我们首次团队开发经验不足的一种体现。

当然,团队阶段也让我结识了很多同学,包括一位留学生,这对于我来说还是很新奇的体验,也让我收获了课程知识之外的东西。

总结

软件工程这门课带我领略了真正的互联网开发是什么样子的,也让我们体验了一把敏捷开发的真实强度。通过这门课我领悟到了开发并不只是把前后端的语言掌握就可以了,那些曾经单人开发中被我们忽视的东西才是真正的绊脚石。这也为我的后续职业方向选择提供了信息,判断自己到底适不适合这种的开发工作。总的来说,这门课是我在大学上过的比较贴近真实应用的一门课。

posted @ 2026-06-27 00:59  一百万  阅读(3)  评论(0)    收藏  举报