[I.3] 个人作业:结课总结
[I.3] 个人作业:结课总结
博客格式描述
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 2026年春季软件工程(北京航空航天大学 - 计算机学院) |
| 这个作业的要求在哪里 | [I.3] 个人作业:结课总结 |
| 我在这个课程的目标是 | 掌握现代软件工程的核心思想与实践方法,提升团队协作、测试设计与项目管理能力 |
| 这个作业在哪个具体方面帮助我实现目标 | 通过回顾提问、项目实践和团队协作,总结自己对软件工程从“写代码”到“交付软件”的理解变化 |
| 以前提问题的博客 | [I.1] 个人作业:阅读和提问 |
| 软件案例分析博客 | [I.2] 个人作业:软件案例分析 |
| 结对项目博客 | [P] 结对项目:花见小路 |
一、对开学阅读提问的回顾
开学时阅读《构建之法:现代软件工程》后,我提出了五个问题。现在回头看,这些问题大多不是靠继续查一个定义解决的,而是在结对编程和团队项目中被具体经历“磨”清楚的。
问题一:软件工程中“程序”与“软件工程”的边界如何界定?
我当时困惑的是,“软件 = 程序 + 软件工程”是否意味着没有文档、测试、协作流程的小项目就不能算软件。经过这一学期的实践后,我的理解变成:程序是可运行的核心产物,软件工程是让这个产物在真实约束下可理解、可协作、可验证、可演进的一组活动。
在个人作业里,写完一篇分析或一段代码,主要目标是“把事情做出来”;但到了团队项目《第四轴》,问题立刻变复杂了。游戏中的标签规则、数值规则、NPC 对话、地图切换、UI 拖拽、存档等模块需要多人并行开发。此时如果只有代码,没有接口文档、issue、测试用例和例会同步,即使某个人本地能运行,整个项目也很难稳定前进。
因此我现在认为,程序和软件工程不是二选一的边界,而是随着项目规模和风险逐步叠加的关系。个人玩具项目可以只强调程序,但一旦出现多人协作、需求变更、发布验收和维护成本,软件工程就不再是“额外负担”,而是让程序真正成为产品的条件。
问题二:结对编程在效率与成本之间的平衡点在哪里?
结对项目“花见小路”直接回答了这个问题。我们并不是把任务简单拆成两份各写各的,而是一起理解规则、讨论设计、实现并测试 Rust + WebAssembly 模块。T1 的胜负判定、T2 的历史记录解析、T3 的隐藏信息建模都很容易出现规则理解偏差。在这些环节里,结对的价值很明显:一个人编码时,另一个人能实时检查分支顺序、测试边界和规则理解。
但我也看到结对编程确实不是万能的。对于简单重复、机械录入或很明确的 UI 调整,两个人同时盯着同一段代码会浪费时间。它更适合逻辑复杂、风险较高、需求理解成本大的模块,例如规则引擎、状态机、策略算法和接口设计。
所以我的答案是:结对编程的收益不在于“用两个人写出两倍代码”,而在于降低复杂任务中的误解、返工和缺陷成本。成本平衡点取决于任务复杂度和错误代价。越是核心、复杂、不可轻易出错的模块,越值得结对。
问题三:敏捷流程中的“拥抱变化”与“需求冻结”是否矛盾?
团队项目让我理解到,二者并不矛盾。“拥抱变化”不是随时打断当前开发,也不是任何想法都立即进入代码;它更像是把变化放进可管理的节奏中。
在《第四轴》中,第一、二章剧情、标签交互、数值修改、NPC 对话、地图切换等需求都发生过调整。例如例会中提到标签修改属性未启用、NPC 对话系统失效、第二章地图与剧情触发仍需联调,这些都不是一开始能完全预测的。如果完全冻结需求,项目会无法回应真实实现中的问题;但如果所有变化都立刻插入,又会打乱当前迭代。
我现在的理解是:敏捷需要“迭代内相对稳定,迭代间主动调整”。本轮已经承诺的目标应尽量稳定,新增想法先进入 backlog,由团队根据优先级、风险和剩余时间决定是否进入下一轮。这样既不僵化,也不失控。
问题四:单元测试的覆盖率目标应如何设定?
这个问题在我负责团队测试时有了更实际的答案。覆盖率数字本身不是目标,关键是测试是否覆盖了高风险规则、核心路径和容易回归的边界。
团队项目中我添加了标签规则的单元测试,并参与数值规则相关测试。LabelRuleTests 覆盖了标签绑定、解绑、重复添加、事件回调、SmallObject/BigObject 持有标签等行为;NumericalRuleTests 覆盖了属性越界、规则接受/拒绝、规则作用域冲突、守恒规则补偿、非法表达式防御等情形。这些测试的共同点不是“凑够某个百分比”,而是围绕核心机制建立信心。
因此我现在会把覆盖率看作辅助指标,而不是质量本身。更合理的做法是:核心业务规则和容易回归的模块要求更高覆盖;UI 展示、简单胶水代码可以用集成测试或手工验收补充。覆盖率可以设门槛,但必须配合用例质量审查。
问题五:软件工程师的“成长阶梯”在不同规模公司是否通用?
这个问题仍然没有完全标准化的答案,但我的认识比开学时清楚了。书中的成长阶梯提供的是能力维度,而不是固定岗位模板。
在团队项目中,每个人都有主要分工:PM、ARCH、GAME、测试、美术、UI。但实际上边界并没有那么绝对。测试不仅是“找 Bug”,还需要理解规则设计、接口约定和用户流程;UI 同学需要配合标签系统与属性修改逻辑;架构同学也要关注关卡和剧情如何接入规则引擎。小团队中更常见的是一人承担多个维度的责任。
所以我现在认为,“成长阶梯”可以用来提醒自己持续提升能力,例如独立完成任务、影响模块设计、跨模块协作、推动质量改进等;但不能机械套用到每个组织。大团队强调职责清晰,小团队强调综合解决问题能力。真正通用的是:能否可靠交付、能否降低他人成本、能否在不确定性中推进项目。
是否仍有不明白的问题?
仍然没有完全明白的是:软件工程实践中的“度”如何把握。比如测试覆盖率、文档详细程度、结对编程投入比例、敏捷迭代粒度,都不存在一个放之四海而皆准的数值。经过实践后,我知道了它们要根据风险、规模、团队经验和时间约束来决定,但在更真实的工业项目中如何量化成本收益,仍然需要更多经验。
新产生的问题
经历团队项目后,我产生了三个新的问题:
- 对于游戏这类强交互软件,自动化测试和人工体验测试的边界应如何划分?哪些内容值得自动化,哪些必须依赖试玩反馈?
- 在短学期项目中,团队应优先保证“功能完整”还是“架构可维护”?当二者冲突时,如何决策?
- AIGC 辅助编码进入团队协作后,代码评审和测试策略应如何调整,才能既利用效率提升,又避免看不见的质量风险?
二、六个阶段中的知识点
1. 需求阶段:需求不是功能清单,而是对用户价值的假设
在 T.2 选题和需求分析中,我们为《第四轴》做 NABCD 分析时,最初容易把“数值守恒”“标签剥离”“四维时空”写成很酷的功能点。但进一步讨论后才发现,真正的需求是玩家希望获得“通过理解规则掌控世界”的成就感,以及“逻辑自洽的科幻叙事体验”。这让我意识到,需求分析的核心不是罗列想做什么,而是说明为什么值得做、给谁做、解决什么痛点。
2. 设计阶段:接口是多人协作的稳定边界
团队项目中 Docs/interface.md 记录了物品创建、恢复类物品使用、教程触发、历史教程可见性等接口。接口文档看起来不如写功能直接,但它降低了前后端、UI 和存档之间的沟通成本。我的收获是:设计阶段最重要的产物不一定是宏大的架构图,而是能让多人并行工作的边界约定。
3. 实现阶段:把复杂规则拆成状态、规则和行为
结对项目 T3 中,我们先把历史回放成 GameState,再推断隐藏信息,最后用 Evaluator 做期望打分。团队项目中标签系统和数值规则也有类似思路:先明确对象有哪些状态,再定义规则如何改变状态,最后由交互触发行为。这个经验让我理解到,实现复杂系统时不要急着堆 if-else,而要先找到稳定的数据模型和状态流转。
4. 测试阶段:测试应围绕风险设计
我在团队中主要负责测试,最深的体会是测试不是“把功能点都点一遍”,而是识别哪里最可能出错。标签规则的绑定/解绑、事件回调、重复添加,数值规则的越界、冲突、守恒补偿、非法输入,都是一旦出错会影响核心玩法的地方。测试用例应优先保护这些规则,而不是平均用力。
5. 发布阶段:可交付不等于能在本机运行
课程项目的发布不仅要有代码,还要有博客、仓库、验收材料、演示效果和说明文档。结对项目中,Wasm 模块必须能被课程提供的 Node.js 测试脚本调用;团队项目中,Unity 场景、资源、脚本、UI、音频都要在同一环境下配合运行。我学到的知识点是:发布阶段关注的是“别人能否复现和使用”,而不仅是“我已经写完了”。
6. 维护阶段:维护从第一个 Issue 开始
团队项目例会中不断出现“标签修改属性效果未启用”“NPC 对话系统失效”“场景功能仍在合入中,完整流程测试依赖联调进度”等问题。以前我以为维护是发布之后才发生的事,现在发现维护贯穿开发过程。每一次 bug 修复、回归测试、接口补充、需求调整,本质上都是维护。可维护性的基础是清晰的模块边界、可复现的问题描述和稳定的回归测试。
三、结合个人、结对和团队项目的理解
个人作业:从使用者视角看软件质量
在 I.2 软件案例分析 中,我评测了开源笔记软件 Joplin,并从功能完整性、数据安全、界面易用性、同步稳定性、扩展性等维度给出评分。当时我更多站在用户和产品经理视角看问题:一个功能是否解决需求、竞品有什么差异、Bug 会怎样影响使用体验。
这次经历让我意识到,软件工程不只是开发者内部流程,也包括对用户场景的理解。比如同步冲突提示不清晰,在代码层面可能只是一个边缘异常,但在用户层面会造成数据丢失焦虑。好的工程判断应该能把技术缺陷翻译成用户影响。
结对编程:交流本身就是质量保障
花见小路项目让我第一次比较完整地体验了结对编程。T1 看似只是胜负判定,但如果立即胜利条件、第三轮决胜条件顺序写错,就会造成错误结果;T2 的字符串解析需要准确理解 3BCC-C、4ACBD-BD 等记录含义;T3 又引入 1X、2XX 这样的隐藏信息。
在这些任务中,交流不是写代码之外的“额外时间”,而是编码的一部分。两个人一起把规则说清楚、把测试样例手算一遍、把设计拆成状态重建和决策评分,实际减少了后续调试成本。我对结对编程的理解也从“效率可能降低”变成了“在复杂问题上用沟通换确定性”。
团队项目:软件工程是让不确定性可管理
《第四轴》是一个比个人和结对项目都复杂得多的系统。它既有游戏玩法,又有剧情、地图、美术、UI、音频、规则引擎、存档和测试。团队推进过程中,变化几乎不可避免:剧情要接入,地图要联调,标签效果要修复,NPC 对话要回归,测试也要等功能合入后才能完整执行。
我在团队中负责测试,最大的感受是测试并不是项目末尾的“验收员”,而应该尽早介入需求和设计。只有理解标签系统、数值规则和关卡目标,才能知道哪些行为应该被单元测试保护,哪些流程需要手工回归。测试同学越早知道需求意图,越能帮团队减少后期返工。
对软件工程的总体理解
学期开始时,我对软件工程的理解还比较抽象:需求、设计、测试、发布、维护像是一组概念。现在它们变得具体了:
- 需求是团队对用户价值的共同假设;
- 设计是让多人能并行工作的约定;
- 实现是把规则、状态和行为稳定地落到代码中;
- 测试是用有限资源保护最重要、最高风险的行为;
- 发布是让别人能复现、能运行、能理解;
- 维护是面对变化时仍能继续前进。
我也意识到,软件工程的难点往往不在某个单独知识点,而在取舍。时间有限时测试到什么程度?需求变化时是否接受?架构要做到多通用?文档写到多细?这些问题没有固定答案,但这门课让我至少有了判断的框架:看风险、看收益、看协作成本、看未来变化的可能性。
四、总结
这一学期之后,我对软件工程最大的认识变化是:写代码只是起点,真正困难的是让代码在真实团队、真实需求、真实变化中持续产生价值。
从 I.1 的提问,到 I.2 的软件案例分析,再到结对编程和团队项目,我逐渐理解了为什么教材会反复强调实践。很多问题在书里只能得到原则,在项目里才会暴露细节。比如结对编程是否值得,只有在一起调复杂规则时才知道;覆盖率应设多少,只有写过测试才知道数字不能代替用例质量;敏捷是否矛盾,只有经历需求变更和迭代推进才知道它强调的是有节奏地管理变化。
如果用一句话概括我的收获:软件工程不是把开发过程变复杂,而是在复杂本来就存在时,给团队一套把事情做成的方法。
浙公网安备 33010602011771号