[I.3]个人作业:结课总结
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 课程社区首页 |
| 这个作业的要求在哪里 | 作业要求 |
| 我在这个课程的目标是 | 系统学习现代软件工程的开发流程、方法与规范,在实践中提升个人工程能力,并深入体验团队合作开发的过程。 |
| 这个作业在哪个具体方面帮助我实现目标 | 做最后的总结 |
个人作业:结课总结
一、提问回顾
我的第一次博客I1
在学期开始时,我围绕《构建之法》提出了几个问题。当时这些问题更多来自阅读教材时的直觉和困惑:我能理解书中的说法,但还没有真正经历过一个较完整的软件项目,所以很多判断其实停留在“看上去有道理,但实际会怎样”的阶段。经过个人项目、结对编程和团队项目之后,我对这些问题有了更具体的理解。
1. 软件工程中的“度量”真的能准确反映一个人的贡献吗?
我最初的问题是:缺陷率、返工次数、平均交付时间、交付时间方差等指标,是否真的能准确反映一个软件工程师的贡献?
经过这个学期的实践后,我的答案是:度量有价值,但不能单独作为评价贡献的核心依据。
在结对项目中,我们填了 PSP 表格,记录预估耗时和实际耗时。这个过程确实让我意识到,度量可以帮助我们看到一些主观感觉之外的事实。例如 T1、T2 比较接近预估,而 T3 的实际耗时明显超过预估,这说明策略设计的不确定性比我们一开始想得更高。如果没有记录,只凭印象总结,可能只会说“这一部分比较难”,但 PSP 表格让这种难度变得更具体。
在团队项目 Z-Spire 中,这种体会更明显。项目最终包含战斗、地图、卡牌、事件、商店、存档、奖励、教程、结算等多个模块,也有约 30 个自动化测试文件。仅从代码行数或者提交次数看,很难判断每个人真实贡献的大小。因为有些工作是直接写代码,有些工作是设计战斗规则、调平衡性、处理资源、修 bug、梳理模块接口、解决合并冲突,甚至只是把一个模糊想法说清楚。这些贡献未必都能被简单量化,但它们都影响项目能不能跑起来。
所以我现在的理解是:度量更适合作为“发现问题的线索”,而不是“评价人的结论”。例如,如果某个模块 bug 很多,它提示我们需要检查设计、测试或协作方式;如果某个任务延期严重,它提示我们要复盘估计是否过于乐观、需求是否变化、任务是否拆得不够细。但如果直接用这些数字评价个人能力,就容易忽略任务难度、需求不确定性和协作成本。
比较合理的做法应该是将度量和上下文结合起来:既看可观察的数据,也看任务本身的复杂度、团队成员之间的互评、代码复审结果,以及一个人是否承担了沟通、风险识别和关键决策等难以量化的工作。
2. 在 coding agent 能力日渐强大的今天,传统结对编程是否还有必要?
我一开始怀疑:既然 AI 工具已经能够解释代码、生成代码、检查 bug、提出测试建议,那么传统结对编程是不是会被替代?
经过结对项目和团队项目后,我的看法变成了:AI 可以替代一部分“辅助编码”的工作,但不能完全替代人和人之间的结对协作。
在结对项目中,我们确实使用了 Claude 辅助理解题意、讨论策略设计,并且在 T3 的策略设计中帮助我们打开了一些思路。AI 在查资料、解释陌生概念、生成候选方案方面很高效。比如 Wasm、AssemblyScript、花见小路策略设计这些内容,如果完全靠自己查资料,会花更多时间。
但真正做项目时,我发现 AI 和人类搭档的作用并不一样。AI 能给出建议,却不会真正承担项目责任;AI 能指出可能的问题,却不一定理解我们当前的进度、分工、时间压力和课程要求。结对编程中的搭档不只是“第二双眼睛”,还是共同决策者、节奏约束者和责任共同体。我们在 T1、T2 中互相检查规则是否漏判,在 T3 中一起讨论奖励函数和策略取舍,这种讨论不只是得到一段代码,而是在形成共同理解。
团队项目中也是如此。Z-Spire 的开发涉及多人协作、模块边界、合并冲突、功能优先级和发布前修 bug。AI 可以参与某个局部任务,但团队仍然需要人来决定什么功能应该做、什么功能应该先放弃、怎样把不同成员写的模块接起来。
因此,我现在认为,AI 不会让结对编程失去意义,而是会改变结对编程的形态。未来更合理的模式可能是:人类搭档负责需求判断、设计取舍和协作决策,AI 负责提供代码建议、补充测试、解释上下文和加速实现。也就是说,AI 更像是协作中的工具,而不是完整替代协作本身。
3. 敏捷强调“拥抱变化”,那项目还需要多大程度的前期计划?
我最初的困惑是:敏捷开发强调拥抱变化,那么项目开始前到底要不要做详细计划?计划太多会失去灵活性,计划太少又容易混乱。
现在我的理解是:敏捷不是不要计划,而是不要把所有细节在一开始永久锁死。
在团队项目 Z-Spire 中,这一点非常明显。我们早期选题评审材料中曾经设想使用 Unity 和 C#,但实际项目最后采用了 TypeScript + Phaser 3 + Vite,并支持 Electron 打包。这说明项目前期设想和最终实现之间可能会发生变化。如果一开始把技术路线和所有细节都完全锁死,后面调整成本会很高。
但另一方面,如果完全没有计划,项目也很难推进。Z-Spire 能够逐步成型,是因为我们至少明确了核心目标:做一个 PvZ 主题的 Roguelike 卡牌策略游戏,围绕“探索地图 - 遭遇战斗 - 获得卡牌 - 强化牌组”形成核心循环。这个目标让地图系统、战斗系统、卡牌系统、奖励系统、事件系统等模块有了共同方向。
所以我现在认为,项目早期最应该明确的是产品目标、核心玩法、最小可行版本、模块边界和近期迭代目标;而具体数值、视觉细节、部分交互方式和非核心功能,可以在实现和反馈中逐步调整。计划的作用不是预言未来,而是让团队在当前阶段对“下一步做什么”达成一致。
4. 需求分析真的能在项目早期说清楚吗?
我最初的问题是:教材强调需求分析的重要性,但实际项目中用户或者开发者自己在早期也未必知道真正想要什么,那么需求分析是否真的能在项目早期说清楚?
经过团队项目后,我的回答是:需求分析很重要,但它不是一次性完成的,而是持续澄清的过程。
Z-Spire 的早期需求可以用 NABCD 描述出来:我们希望结合 PvZ 的熟悉感和 Roguelike 卡牌游戏的策略性,做一款轻量但有深度、易上手但耐玩的单机游戏。这个需求描述对确定方向很有帮助,但它并不能直接回答所有实现细节。例如地图到底是节点式还是开放式探索?卡牌效果怎么设计?敌人意图如何显示?奖励如何发放?商店、休息点、事件、存档这些系统优先级如何排列?这些问题都需要在实现中不断变清楚。
从项目目录也能看出,最终产品不是一个单独功能,而是由多个模块组成:scenes 负责菜单、地图、战斗、奖励、事件等场景;battle 负责回合、单位、敌人 AI 和状态效果;card 负责卡牌数据、效果和渲染;core 负责状态、事件总线和存档;map 负责地图数据和生成。很多需求只有当这些模块真正接起来时,才会暴露出新的问题。
因此,我现在不再把需求分析理解成“项目开始时把所有需求写完”,而是理解成“在每个阶段尽量形成当前最清晰的共识,并为后续验证留下调整空间”。早期需求分析解决方向问题,迭代中的需求分析解决细节问题,测试和用户反馈则帮助我们发现原来没有意识到的真实需求。
5. 创新要兼容大众习惯和已有系统,那真正颠覆式创新怎么办?
我一开始担心:如果创新过于强调兼容已有习惯,会不会限制真正有突破性的创新?
现在我的理解是:兼容性不是创新内容本身必须保守,而是创新落地时需要考虑用户接受路径。
Z-Spire 其实就是一个很好的例子。它借用了 PvZ 的角色、美术和音乐,让玩家一进入游戏就能理解基本世界观;但玩法上并不是传统塔防,而是卡牌构筑、地图探索和回合制战斗。也就是说,我们在表现层面保留了用户熟悉的元素,在玩法层面做了重新组合。
如果完全抛开 PvZ 的习惯和符号,玩家可能很难在短时间内理解这个游戏的趣味;但如果只复制原来的塔防玩法,又缺少创新。比较可行的做法是:在入口处降低理解成本,在核心体验中提供新东西。
所以我现在认为,教材强调兼容大众习惯,并不是说创新不能改变用户,而是在提醒我们:改变用户习惯需要过程。真正有价值的创新可以在方向上大胆,但在落地路径上要让用户有台阶可走。什么时候妥协,什么时候坚持,取决于这个“不兼容点”是不是创新价值的核心。如果只是交互入口、术语、视觉表达,适当兼容可以减少阻力;如果是产品真正的核心价值,就不能为了迎合习惯而轻易放弃。
仍然没有完全解决的问题与新问题
经过一学期实践后,原来的问题大多有了更具体的答案,但并不是全部彻底解决。
我仍然觉得“如何评价难以量化的贡献”是一个很难的问题。团队项目中,代码、测试、文档、调试、协调、创意、资源整理都很重要,但它们之间很难用同一个尺度衡量。尤其是在 AI 工具参与越来越多的情况下,如何区分人的设计判断、AI 的生成能力和团队协作的综合结果,会变得更复杂。
我也产生了新的问题:在使用 coding agent 辅助开发时,团队应该如何制定更清晰的协作规范?例如哪些代码可以由 AI 生成,哪些必须人工复审;AI 参与的代码如何记录;当 AI 生成内容出现问题时,责任如何归属;以及在课程项目中,AI 辅助到什么程度才仍然能体现学生自己的工程能力。这些问题在未来的软件工程实践中可能会越来越重要。
二、六个阶段中的知识点与实践理解
软件工程这门课强调“做中学”。在真正经历项目后,我对需求、设计、实现、测试、发布、维护这六个阶段有了比读书时更具体的理解。
1. 需求阶段:需求不是一句想法,而是可验证的目标
我学到的知识点是:需求分析要把模糊愿望转化为可讨论、可实现、可验证的目标。
在 Z-Spire 中,最初的想法可以很简单地说成“做一个 PvZ 主题的卡牌肉鸽游戏”。但这句话本身还不是可执行需求。后面我们通过 NABCD 分析,逐渐明确了目标用户、核心玩法、竞品参考和发布方式。尤其是核心循环“探索地图 - 遭遇战斗 - 获得卡牌 - 强化牌组”,让团队知道游戏最重要的体验是什么。
我的体会是,需求阶段最重要的不是写出很多漂亮表述,而是让团队对“我们到底要做什么”和“什么东西必须先做出来”形成共识。
2. 设计阶段:模块边界决定协作成本
我学到的知识点是:好的设计要把复杂系统拆成边界清晰的模块。
在结对项目中,我们从 T1 到 T3 都经历了这个过程。T1 是判胜规则,适合把计分、标记统计、最高档位判断拆成辅助函数;T2 是根据历史记录还原局面,适合把解析历史和处理单个行动拆开;T3 是策略决策,最重要的是把候选动作生成、状态解析、价值评估和最终选择分离。
在团队项目中,这种模块化更重要。Z-Spire 的代码按 battle、card、map、core、scenes、data 等目录组织,实际上就是在降低多人协作时的互相干扰。否则所有逻辑都堆在一个地方,不仅难以维护,也更容易产生冲突。
3. 实现阶段:代码不是一次写对的,而是在约束中迭代出来的
我学到的知识点是:实现阶段要在正确性、可读性、性能和进度之间不断取舍。
结对项目 T3 给我的感受最强。策略函数一开始不可能直接写到最好,只能先实现一个能跑的版本,再根据测试和对局效果调整奖励函数。我们从简单的分值奖励,逐渐加入倾心标记、牌数量、对手收益、终局优先级等因素。这让我意识到,复杂功能往往不是“想清楚再一次写完”,而是需要不断实验。
团队项目中也一样。Z-Spire 最终包含战斗音效、动画、地图、小地图、商店、存档、奖励、Boss 演出等许多细节。实现这些功能时,不可能每个想法都完全实现,必须先保证核心流程可玩,再逐步补充体验。
4. 测试阶段:测试不只是证明代码能跑,而是保护规则和体验
我学到的知识点是:测试要覆盖核心规则、边界情况和曾经出错的地方。
在结对项目 T1 中,我们针对胜负规则设计了多类测试,包括 11 分获胜、4 枚倾心标记获胜、前两轮继续、第三轮比分、最高档位和平局等情况。这让我第一次比较明确地感受到,测试不是随便跑几个普通样例,而是要对应规则分支。
在 Z-Spire 中,测试范围更大。仓库中有 battle-balance-rules.test.js、save-manager.test.js、map-generator.test.js、reward-scene.test.js、shop-wheel.test.js、battle-summon-regression.test.js 等约 30 个测试文件,覆盖战斗、地图、存档、商店、奖励、状态显示、动画回归等方面。团队项目越复杂,测试越像是一张安全网,帮助我们在修改功能时不轻易破坏已有行为。
5. 发布阶段:能在自己电脑跑不等于能交付
我学到的知识点是:发布阶段关注的是用户能否稳定获得和运行软件。
Z-Spire 的 README 中不仅写了开发运行方式,也写了生产构建和 Electron 打包方式。项目可以通过 npm run build 输出 dist/,也可以通过 Electron 打包为 Windows 或 macOS 应用。这让我意识到,发布不是简单地说“代码写完了”,而是要考虑依赖安装、构建命令、运行环境、资源路径、打包体积和分发方式。
对课程项目来说,发布阶段还包括向老师、助教和同学展示一个可运行版本。哪怕内部代码还有很多想优化的地方,最终也必须形成一个别人能打开、能理解、能试玩的版本。
6. 维护阶段:项目后期主要工作是修 bug、调体验和处理遗留问题
我学到的知识点是:维护不是项目结束后的附加工作,而是软件真正可用前必经的一部分。
从 Z-Spire 后期提交可以看到,很多工作都是 bug 修复、平衡性调整、音效同步、状态显示、自动存档、战斗结束流程修复、Boss 演出增强等。这些工作不像最初开发新功能那样显眼,但对最终体验非常关键。
维护阶段也让我认识到,前期设计是否清晰会直接影响后期修 bug 的成本。如果模块边界清楚,修一个问题通常只需要定位到某个系统;如果逻辑耦合严重,改一个地方就可能影响很多地方。维护阶段其实是在检验前面需求、设计、实现、测试阶段的质量。
三、结合项目经历的个人心得
这个学期最大的收获,是我终于比较完整地看见了一个软件是如何被开发出来的。
以前我对软件开发的理解更多停留在“写代码实现功能”。但经过个人项目、结对编程和团队项目后,我发现真正的软件工程远不止写代码。一个项目从想法到成品,中间要经历需求讨论、功能拆分、模块设计、接口协调、代码实现、测试验证、资源整理、构建发布、bug 修复和体验打磨。每一步都可能出问题,每一步也都需要团队协作。
结对项目让我第一次明显感受到合作写代码和一个人写代码的不同。一个人写代码时,思路可以完全按照自己的习惯走;两个人一起做时,就必须把想法说出来,让对方听懂,也要理解对方的判断。我们在 T1、T2 中主要解决规则正确性问题,在 T3 中则一起面对策略设计的不确定性。这个过程让我认识到,结对编程的价值不只是提高效率,更重要的是促成共同理解。
团队项目 Z-Spire 则让我进一步体会到多人协作的复杂性。不同成员负责不同模块,就需要分工;多人同时修改代码,就会有冲突;功能之间存在依赖,就需要约定接口;临近发布时发现 bug,就需要判断优先级。以前我可能会觉得“处理冲突”只是 Git 操作问题,现在才发现它本质上也是协作问题:代码冲突背后往往是模块边界、沟通时机和任务分配的问题。
我最有收获的一点,是弄明白了软件不是靠某一个灵感突然完成的,而是靠很多小步骤不断推进出来的。Z-Spire 最后能够成为一个包含地图探索、卡牌战斗、奖励、事件、商店、存档、Boss 和结算的游戏,不是因为一开始就有完美方案,而是因为团队不断把一个个模块补上、接起来、修好、再调整。
当然,这个项目也有遗憾。我们还有很多想法没有实现。比如更丰富的卡牌流派、更完整的剧情、更精致的地图事件、更深入的平衡性调整、更强的重玩性设计等。现在回头看,会觉得如果时间更多、分工更细、前期规划更充分,也许还能做得更完整。但这也是软件工程真实的一部分:资源永远有限,项目必须在有限时间内做取舍。
最后,我对“做中学”有了更具体的理解。很多软件工程知识点,只看书时会觉得抽象,比如需求分析、模块化、测试、度量、敏捷、维护、发布。但当自己真的做过项目以后,这些词就不再只是概念。需求变化会带来返工,模块边界会影响冲突,测试会保护已有功能,度量能帮助复盘,发布会暴露环境问题,维护会检验代码质量。
这门课让我最大的变化,是我开始用“工程”的眼光看软件开发:不仅关心代码能不能写出来,也关心它能不能被别人理解、能不能和别人的代码合在一起、能不能稳定运行、能不能被测试保护、能不能在需求变化后继续维护。对我来说,这就是这个学期最重要的收获。

浙公网安备 33010602011771号