【北航软件工程】[l.1] 个人作业:阅读与提问

北航软件工程 [l.1] 个人作业:阅读与提问

项目 内容
这个作业属于哪个课程 https://edu.cnblogs.com/campus/buaa/BUAA_SE_2026_LR
这个作业的要求在哪里 https://edu.cnblogs.com/campus/buaa/BUAA_SE_2026_LR/homework/15608
我在这个课程的目标是 积累【当大模型不直接协助的】开发经验,提升自己的代码能力
这个作业在哪个具体方面帮助我实现目标 了解软件工程的开发流程,为后续的小组作业打牢基础

问题一 单元测试的成本和收益

我看了第二章关于单元测试的描述,书中提到

单元测试应该在最低的功能/参数上验证程序的正确性。

单元测试应该测试程序中最基本的单元——如在C++/C#/Java中的类,在此基础上,可以测试一些系统中最基本的功能点(这些功能点由几个基本类组成),从面向对象的设计原理出发,系统中最基本的功能点也应该由一个类及其方法来表现。单元测试要测试API中的每一个方法及每一个参数。

我的问题:对于具有强上下文依赖的底层系统代码,强行追求单元测试是否会导致成本倒挂?

我们曾经在OO的作业中被要求写单元测试,但据我所知绝大数同学都是在通过项目代码的评测之后为了满足80%的覆盖率要求而补充单元测试,反复测试自己的覆盖率是否达到80,满足题目要求后再次提交整个作业即可万事大吉。

似乎单元测试是一件很繁琐,意义有限的事情,何况在构造单元测试用例的时候若能够考虑的十分周全,原本代码也很难出错。

我查阅了相关资料,通常软件工程建议使用Mock对象来隔离外部依赖。

对于具有强上下文依赖的底层系统代码(比如我们在OO作业中写过的电梯单元),使用 Mock 对象本身就成了一项巨大的工程。为了测试某一个处理核心逻辑的函数,我可能需要手动伪造几十种前置的系统状态、并发环境和依赖对象。这就导致了一种极度失衡的现象:写核心业务逻辑可能只需要 50 行,但为了把这个逻辑“隔离”出来进行单元测试,我得写 300 行的 Mock 代码和环境准备代码。

在业界,这种现象并非个例。Ruby on Rails 的创始人 David Heinemeier Hansson 曾发表过著名的文章《TDD is dead. Long live testing.》,明确批评了为了追求单元测试覆盖率而导致的“测试驱动带来的设计破坏”。为了让代码变得“可被Mock,可被测试”,开发者有时不得不把原本高内聚的系统强行拆散,暴露出大量不必要的中间接口,这反而破坏了面向对象设计中封装的初衷。

书中的理想化描述与我的直接经验产生了强烈的冲突。《构建之法》强调尽早、完备地写单元测试来保证正确性,并在早期发现Bug。

在实际的复杂工程(尤其是上下文状态极度复杂的系统)中,强行追求高覆盖率的单元测试,是否真的如教科书所说那般投入产出比极高?在真实的工业界,究竟是如何平衡“测试成本”与“代码质量”的?又是如何避免把“单元测试”变成像我们OO作业那样“先写代码,再补测试凑覆盖率”的形式主义的?

问题二 当思维模式存在差异时,结对编程是否会降低复杂问题的解决效率?

我阅读了第三章“两人合作”中关于“结对编程”的段落。

在结对编程中,因为有随时的复审和交流,程序各方面的质量取决于一对程序员中各方面水平较高的那一位。这样,程序中的错误就会少得多,程序的初始质量会高很多,这样会省下很多以后修改、测试的时间。

结对编程让两个人所写的代码不断地处于“复审”的过程

我的问题:当思维模式存在差异时,结对编程是否会降低复杂问题的解决效率?

软件开发不仅是工程实现,更是高度密集的脑力劳动。认知心理学中有一个重要的概念叫做“心流”,指的是人全身心投入某项复杂活动时的极度专注状态。多项针对程序员效率的研究表明,开发者在进行深度思考时一旦被打断,通常需要 15 到 30 分钟才能重新建立起被打断前的思维上下文。除此此外,不同程序员的思维模式往往千差万别——有人习惯自顶向下的宏观抽象,有人习惯自底向上的细节推演;在面对同一个问题时,切入点可能完全不同。

书中对结对编程的推崇与我的直接经验产生了强烈的矛盾。在我的实际编程体验中,当面对极高认知负荷的任务时,我极度需要安静和专注来维持思维的连贯性。如果这个时候旁边坐着一个人不断交流,我不仅无法集中注意力去思考底层逻辑,反而会因为要分心去向同伴解释自己尚未完全成型的“半成品思路”而感到烦躁。

此外,由于两人的思维模式可能截然不同,在解决同一个复杂问题时,沟通往往会演变成一场“试图说服对方接受自己解法”的拉锯战,不仅没能激发灵感,反而让开发停滞不前。因此我的困惑是:对于高度依赖个人深度推导和强认知负荷的模块,强推结对编程是否会成为一种对“心流”的破坏?在真实的工业团队中,究竟该如何界定哪些任务必须结对,哪些任务绝对应该留给个人的独立深度思考?

问题三 在非确定性的机器学习与AI项目中,传统的ZBB标准是否已经失效?

我阅读了第八章“稳定阶段,发布和维护”中关于 ZBB的论述。书中指出,ZBB 是项目从开发期迈向发布期的核心里程碑。它意味着开发团队将所有已知的、明确需要修复的 Bug 数量降到了零。达到 ZBB 标志着团队对项目重新取得了控制权,软件进入了可以准备打包发布的稳定状态。

团队要有把bug 都搞定的执行力。ZBB = Zero Bug Build,即这一版本的构建把所有已知的Bug都解决掉了。

Zero Bug Bounce:通常在一个Zero Bug Build之后,Bug数目会以惊人的速度反弹,故称Bounce。系统要经历几次bounce,像阻尼震荡一样,Bug的数目在反弹了几次之后,最后固定在(或者无限逼近于)0。

我的问题是:在非确定性的机器学习与AI项目中,传统的ZBB标准是否已经失效?

在传统的确定性软件工程中(如数据库管理或常规 App 开发),Bug 的定义非常明确:代码逻辑错误、系统崩溃或产生非预期的确定性输出。然而,查阅目前主流的 AI 工程化(MLOps)文献可以发现,现代机器学习系统的产出是基于概率和数据驱动的。 模型的表现不仅受代码逻辑影响,更受训练数据分布、超参数以及真实世界数据漂移的制约。在 AI 项目中,系统往往不会因为“代码报错”而直接崩溃,其面临的真正挑战是“准确率波动”、“模型幻觉”或“长尾分布下的误判”。

在我做有害图像检测的项目时,我发现模型在面对新分布的数据时,准确率出现波动或对某些特定样本产生误判是常态。这种“识别错误”具有极强的非确定性,它不像修改一行 C++ 或 Java 的 If-Else 逻辑那样能被确切地“修复”并确保以后绝对不再犯。

在海量数据面前,这个 Bug 的数量可能永远无法真正归零(即永远达不到物理意义上的 ZBB);但如果我们不把它定义为 Bug,那面对一个有缺陷的模型,我们又该如何评估系统的“稳定性”?在工业界,我们该采用怎样的新型指标或统计学验收标准,来向 PM 或非技术客户界定一个 AI 模型已经“足够稳定,可以发布”?

问题四:在缺乏强制约束的大学小组作业与竞赛团队中,如何建立合理的分配机制以避免“搭便车”现象?

我阅读了第十章“软件项目的管理”中关于绩效管理以及“人的问题”的论述。书中探讨了如何通过明确 PM(项目经理)、Dev(开发)和 QA(测试)的分工来推动项目,并提到了通过“事后诸葛亮会议”来复盘团队合作。这些理论为团队协作提供了一个结构化的企业级框架,强调了目标对齐和贡献量化。

在团队合作中每个成员的贡献度不仅仅取决于他的工作量,而且还取决于这份工作对团队的意义有多大。我认为贡献度的计算应遵循如下公式:

贡献度 = 工作量 × 工作的影响力 × 工作的不可替代性

这个等式给我们的评测提供了一个方向。与直接估计贡献度相比,分别估计三个分量显得更可操作,准确性也更高。

我的问题是:在缺乏强制约束的大学小组作业与竞赛团队中,如何建立合理的分配机制以避免“搭便车”现象?

在真实的工业界,敏捷开发和团队协作有薪酬、KPI 或 OKR 作为硬性约束,PM 拥有实质性的管理权限。然而,大学里的小组作业或学术项目属于典型的“无权力领导”和“弱契约关系”。一旦遇到难度大、周期长的任务,极其容易出现“社会懈怠”现象,也就是大学生常说的“组内混子”和“搭便车”。

实际经验中,许多课程大作业小组团队角色极度分化具有特殊性。有些同学负责核心代码编写,而有些同学只负责最后汇报的文档或ppt。

在这种情况下,如果没有企业那样的物质奖励机制,仅仅依靠书中所说的“明确角色”和“事后复盘”,很难在事前就让所有人觉得分工绝对公平。往往会出现干活多的人觉得吃亏而抱怨,能力稍弱或意愿不强的同学自然而然退化为“混子”,最终为了如期提交作品,核心成员不得不熬夜兜底。

在大学这种缺乏强制约束和物质激励的环境中,作为团队负责人,究竟该如何利用软件工程的管理思维,在项目初期就划定真正“合理且被全员认可”的分工?如何通过机制设计,而不是单凭个人情商或道德绑架,来激发每个组员的主动性,让他们能毫无怨言地完成自己的任务,共同为项目的如期交付贡献力量?

问题五 当项目存在强底层协议或硬件依赖时,敏捷开发的 Sprint 该如何划分?

我阅读了第四章“软件过程/方法论”中关于敏捷开发和 Scrum 框架的内容。

Sprint/Scrum 对项目的众多需求采取分而治之的办法, 能让相关人员集中精力, 在一定期限内解决部分问题。

它强调短时间的迭代 (iteration), 在多次迭代中不断总结, 改进团队的流程和产品功能。

它明确地指出不同人在一个项目中的投入和责任的不同 (猪和鸡), 并坚持让全身心投入的“猪”来主导项目。

它通过 daily scrum, ScrumMaster 等方法和角色,鼓励团队内部交流并优化团队和其他人员的交流方式。

它对团队成员提出了很高的要求, self-managing, self-organizing, cross-functional。 一般人不能马上做到这一点。

我的问题是:当项目存在强底层协议或硬件依赖时,敏捷开发的 Sprint 该如何划分?

查阅业界资料可以发现,敏捷开发的 Sprint 模式在前端 UI 迭代、纯互联网 Web 应用或 SaaS 软件中大放异彩。因为这类项目相对容易解耦,哪怕第一周的 Sprint 只做出了一个带有假数据的静态页面,用户也能点击体验,给出交互反馈。然而,当软件系统的核心价值建立在与特定物理硬件交互,或者必须严格遵循复杂的底层通信规范时,敏捷理论似乎遇到了瓶颈。硬件联调闭环如果没有打通,初期的代码往往是完全不可运行的。

书中强调的“每个 Sprint 都要交付可用软件”的敏捷理想,与我进行底层系统开发的实际经验产生了矛盾。

在我的实践中,开发涉及连续数据流解析的底层应用时,往往需要处理严苛的网络通信握手和二进制报文解析。在这种强协议依赖的场景下,“底层不通,全盘皆输”。如果没有把底层的通信链路完整地跑通,上层的应用根本获取不到任何有意义的数据。在开发的头几个星期里,系统在外部看来几乎是毫无反应的,我根本不可能在一个短暂的 Sprint 结束时,给用户展示哪怕一个“勉强能用”的软件增量。

因此我的困惑是:对于这种“底层协议没跑通,整个系统就彻底瘫痪”的硬核项目,强行要求团队每两周划分一个 Sprint 并演示成果,是不是一种形式主义?管理者该如何划分这种项目的迭代里程碑?传统的瀑布模型(强调前期进行周密架构设计),是否反而比敏捷开发更为稳妥和高效?

posted @ 2026-03-09 16:47  iiFF  阅读(9)  评论(0)    收藏  举报