【北航软件工程】[I.3] 个人作业:结课总结

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

项目 内容
这个作业属于哪个课程 北航2026年春季软件工程
这个作业的要求在哪里 [I.3] 个人作业:结课总结 - 作业 - 2026年春季软件工程 - 班级博客 - 博客园
我在这个课程的目标是 积累【当大模型不直接协助的】开发经验,提升自己的代码能力
这个作业在哪个具体方面帮助我实现目标 回顾整个学期的学习历程,对知识和经验进行系统性梳理

一、对第一次作业问题的回顾与解答

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

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

这个问题在我学期初读《构建之法》时让我有些困惑。当时我以OO课中补测试凑覆盖率的经历为由,对单元测试的价值提出了怀疑。

经过这个学期的实践,我对这个问题有了更清晰的认识——问题的核心不在于"要不要写单元测试",而在于"测什么"。

在团队项目 Paradice 的后端开发中,我们最终写了 53 个 Go 测试文件,覆盖了从 RNG 与骰子、HSM 状态栈,到 Buff、Item、Boss 战等各个核心模块。回头看,正是这些测试在 Alpha 阶段帮助我们稳住了高复杂度的规则逻辑——Buff 与 Phase 系统相互交织,触发顺序影响最终效果,没有测试几乎不可能在快速迭代中保证正确性。

但与此同时,我的原有担忧也并非完全没有道理。单元测试的真正成本,不在于写测试本身,而在于为了让代码"可测"而强行拆散原本内聚的模块。书中的理想状态与实际工程之间确实存在落差:单元测试在模块边界清晰、依赖关系简单的场景下价值最高;对于状态机、事件系统这类强上下文依赖的代码,更合适的往往是集成测试或 CLI 自动化回归,而不是对每一个内部函数都套一层 Mock。

因此,不要为了测试而测试,要根据系统特性选择合适的测试粒度。


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

学期初我对结对编程的顾虑主要来自对"心流"被打断的担忧:两个思路不同的人强行坐在一起,容易产生"试图说服对方"的内耗。

结对项目结束后,我对这个问题的看法有所转变,但不是完全推翻,而是更细粒度地理解了它。

在花见小路项目中,结对最有价值的时刻,恰恰是在设计层面的讨论,而不是在具体编码时的"双人驾驶"。当我们一起讨论规则判定逻辑、分析 AI 决策框架时,两个视角的碰撞确实有助于发现单人思考的盲区;而当进入具体实现阶段,"领航员"的主要价值在于实时审查和查缺补漏,而不是不断打断驾驶员的思路。

我在结对总结博客【北航软件工程】结对项目:花见小路 - iiFF - 博客园里曾提到:结对最大化了知识共享与代码审查的实时性,但代价是双方需要高度的沟通成本与时间契合度。 这个认识现在看来是准确的。至于对"心流"的破坏,确实存在,但它是可以被分工机制缓解的——领航员主动克制打断,驾驶员主导实现节奏,就能在一定程度上兼顾专注度与审查质量。

这个问题不再是"结对好不好",而是"结对的哪个阶段适合用什么方式"。


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

我们的团队项目是一个规则明确的游戏,而非 AI 系统。但是ZBB并非毫无意义。

从 Paradice 的经历来看,ZBB 的精神依然是有效的,“在发布前把所有已知的阻断性 Bug 清零”。Beta 阶段我们定义了清晰的发布条件:25 个已记录 Bug 全部修复,P0 为 0,P1 修复率 100%。这套标准让团队在发布前有了明确的"完成"边界,避免了模糊交付。

对于 AI 项目,这个问题确实更复杂,因为"模型在某类数据上准确率偏低"到底算不算 Bug,边界是模糊的。我目前的理解是:ZBB 在 AI 项目中需要替换而非废弃——用指标阈值(比如"关键场景的误判率低于 X%")代替"零 Bug"来作为发布的出口条件,本质上是同一种思维的不同形式。


问题四:在缺乏强制约束的大学小组作业中,如何建立合理机制以避免搭便车?

这个问题在几周的团队开发中得以解答。

在 Alpha 和 Beta 两个阶段的团队开发中,我们使用了三个工具:飞书任务看板把每个人的任务拆到具体条目,GitHub PR 和 CI 让代码贡献有了明确的记录,每周例会让进度偏差在早期就能被发现。虽然我们没有企业里的 KPI,但是上述三个隐性约束让分工变得可见和可追溯。

在没有物质约束的环境里,降低"搭便车"概率的最有效手段不是道德约束,而是让贡献量可见、让任务边界清晰、让进度同步及时。团队里能力差异是客观存在的,但只要分工合理、任务可追溯,大多数人在有明确边界的前提下都会认真完成自己的部分。


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

回顾团队作业,该问题其实已经出现过,Nakama 联机框架作为后端联机层,需要在前端代码具备意义之前先被打通。

我们在初期的选择是:把底层框架调通作为最高优先级的 P0 任务,在此之前不排新功能的 Sprint。 这实际上是一种对敏捷节奏的局部调整,而不是放弃敏捷——底层跑通之后,后续的迭代依然以两到三周为一个节奏推进。

回头看,问题的本质是:敏捷的"每个迭代交付可用增量"并不意味着每个迭代都必须对用户可见。对于底层强依赖的项目,前期几个迭代的"增量"可以是"CLI 测试通过"或"联机握手成功",这同样是有意义的可验证成果,只是受众是开发团队本身而非终端用户。

敏捷与底层系统开发并非根本矛盾,关键在于如何定义"可交付的增量"。


二、六个阶段的新知

需求阶段:用户故事的粒度问题

需求不等于功能列表。在 Paradice 的规划中,我们最初定义了"支持 2~4 人游玩"这样的宏观目标,但真正驱动开发决策的,是"4 个室友饭后想来一把不超过 30 分钟的轻量联机游戏"这样的具体用户场景。

需求不是我想做什么,而是用户想要玩什么。需求要从用户场景出发,而不是从技术可行性出发。 把用户的一次完整体验拆解成可操作的故事,才能在开发时做出正确的优先级判断。我们把"完整对局可玩"定为 Alpha 的出口条件,而不是"功能尽可能多",就是这种思路的体现。


设计阶段:边界清晰比架构精妙更重要

在后端设计中,核心决策之一是把前后端通信协议、HSM 状态机、Action 系统的接口定义在项目早期就固定下来。这让前端和后端可以在同一时期并行开发,各自按约定的接口对接,大幅减少了集成时的摩擦。

因此,模块边界的清晰度比内部实现的优雅度更重要。 一个设计稍显笨拙但边界明确的系统,远比一个内部优雅但接口模糊的系统更容易维护和扩展。Beta 阶段很多返工都源于"跨模块的验收标准定得偏晚",而不是某个模块自身的质量问题。


实现阶段:先打通主流程,再填充细节

在 Paradice 的 Alpha 阶段,我们面临一个共同的诱惑:每个人都想把自己负责的模块做得尽量完善,才提交给整体联调。但实践证明这条路很危险——各自"完善"的模块一旦拼在一起,接口对不上、状态不一致的问题往往比预想的多得多。

后来我们改变策略:后端先用 CLI 脚本跑通完整对局的主流程,哪怕很多细节是硬编码的占位值;前端先连上后端拿到真实数据,哪怕 UI 还很粗糙。以"能跑一局完整对局"为第一里程碑,而不是以"某个模块功能齐全"为目标。

不光是这次软工作业,像大模型课的大作业同样遵循这个道理。实现阶段要优先打通主干路径,而不是优先完善单一模块的细节。 主流程跑通之后,每个人在自己的模块里做细化,问题就能在真实的集成环境中尽早暴露,而不是积压到发布前的联调周。


测试阶段:测试要跟着规则同步更新

Beta 阶段我们踩过一个典型的坑:Buff/Item 的规则在实现中调整了多次,但对应的测试用例没有同步更新,导致"构建通过但规则实际上是错的"。发布前的复测中发现了好几个这类问题,花了不少时间修复。

总结经验,测试不是一次性的产物,它和代码一样需要维护。 规则变更时,对应的测试用例应该同步修改,而不是等到集成测试或人工验收时才发现测试已经过时。这个原则说起来简单,在快速迭代的压力下很容易被忽视。


发布阶段:发布条件要写成可核查的清单

Alpha 和 Beta 发布前,我们都梳理了一份发布检查清单,包括:核心流程能否跑通、P0/P1 Bug 是否修复完毕、CI 是否通过、关键场景是否复测。这份清单的价值在于,它把"感觉差不多了"这种模糊判断,转变成了逐项可核实的标准。

如果没有这份清单,在ddl的压迫下,难免遗漏一两条“TODO”,最后在发布以后亡羊补牢。发布的"完成"需要被明确定义,而不是靠感觉判断。 这和 ZBB 的思路是一脉相承的——团队对"什么叫做好了"有共同认知,才能在压力下做出一致的判断,而不是各自为政。


维护阶段:变更记录的代价在事后才会显现

Beta 总结中我们坦诚了一个问题:规则变更时,配套的功能规格、技术规格、测试矩阵和新手引导文案有过不同步的情况。当时觉得只是"没时间更新文档",但在后期排查 Bug 时,才发现"代码改了但文档没跟上"会让每一次追溯都变得极其费力。

文档必须和软件(代码)一起更新,软件的长期成本很大程度上取决于变更记录的质量。 写代码的人知道"改了什么",但如果没有记录,这个知识就只存在于他一个人的脑子里。文档不是给"以后的人"看的,而是给"一个月后的自己"看的。


四、结合个人经历的心得

这个学期的软工主要包含三个部分:一个人读书提问 → 两个人结对编程 → 六个人组团做游戏。每个阶段的视角都不一样。

个人项目(阅读与软件案例分析)软件工程不只是开发一个软件,而是作为一门学问,它处理的很多问题不是技术问题,而是"人"的问题:为什么团队会懈怠,为什么进度会延期,为什么测试会流于形式。这些问题在课本里读起来像是说教,但在经历过之后会发现它们描述的都是真实发生的事。

结对编程给了我一次真正意义上的代码审查体验。不是事后对着历史记录看,而是实时在旁边看对方写、实时提出质疑。这种即时反馈的密度是单人开发时完全没有的。缺点是磨合成本,优点是代码质量的下限被拉高了很多。

团队项目让我理解了一件事:工程能力和协作能力之间有很强的互补关系,但两者不能互相替代。技术上再强,如果跨模块的接口没有定义清楚,联调时依然会出问题。协作流程再规范,如果技术选型踩了坑,也会让整个团队的努力打折扣。Paradice 之所以能在 Alpha 结束时交出一个真正可玩的版本,很大程度上依赖于后端架构设计在早期就奠定了一个稳定的基础。虽然我只负责了整个项目的小游戏部分,但是如果没有xxk预留好的接口,小游戏的开发不可能这么流畅。

课程快结束的时候,我重新看了一遍学期初提出的五个问题,发现它们其实都是同一个核心问题的不同切面:在真实的工程约束下,教科书里的理论该怎么落地? 这个学期给的答案不是"理论是对的"或"理论是错的",而是:理论描述的是一个方向,落地需要结合具体的上下文做判断。认知是实践的基础,实践是认识的来源。


iiFF | 2026年6月

posted @ 2026-06-28 22:17  iiFF  阅读(0)  评论(0)    收藏  举报