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

项目 内容
课程 2026春季软件工程
作业要求 个人作业:结课总结
课程目标 学习软件工程的基本思想,理解软件开发的完整流程,并能在团队项目中应用这些方法
作业作用 总结反思这学期的心得收获

一、对原有问题的尝试性解答

提问博客:https://www.cnblogs.com/nice2cu2222/p/19698335
学期初,我们带着问题翻开了《构建之法》,快速阅读后提交了自己的困惑。那时的问题,更像隔着一层毛玻璃看软件工程——知道大概轮廓,却不清楚细节与真实。一个学期过去,经历了个人的词频统计项目、两个人的结对编程、转会前后的两次团队大项目,我重新翻出当初的五个问题,尝试用实践给出的答案进行回答、反思,并记录新的困惑。

问题一:个人开发流程在真实软件公司中是否真的会被严格使用?

原来的我怀疑 PSP 记录时间、缺陷数这套做法是“教学特供”。

现在我理解到,严格如教材所写的全套 PSP 表格,在大多数公司确实不会逐项执行。但其核心思想——度量化、数据驱动改进——已经渗透在成熟的工程实践中。我们团队项目虽然没有每日填写时间日志,但通过 GitHub 的 Issue、Pull Request、Project 面板,任务拆解粒度、实际耗时和代码审查意见都被隐式记录下来。讨论中一位有实习经验的同学分享:他的团队不要求“记录时间”,但会通过 Jira 的 Story Point 燃尽图衡量迭代速率;代码缺陷数虽不手工统计,但 SonarQube 等工具自动扫描的 Bug 数量和严重等级,会直接作为质量门禁。
所以回答是:形式上的 PSP 表格很少被严格使用,但“记录、量化、回顾、改进”的逻辑已经成为现代软件研发流程的血液。我从书本学到的是理想模型,实践中收获的是模型如何变形并融入日常工具链。

问题二:结对编程是否真的可以提高开发效率?

原来的我把结对编程看作“两个人干一个人的活”,担心效率低下和节奏冲突。

在结对项目中,我亲身经历了这种冲突与收益的博弈。我们前两次结对会话确实效率不高:导航员思维发散,驾驶员手速跟不上,半小时就累了。后来我们调整策略:不是全天结对,而是仅在难题或关键设计处采用“乒乓结对”——一人写测试,另一人使测试通过,再交换。这种方式下,代码评审在书写瞬间就完成了,一些隐蔽的空指针、边界条件错误确实比单独编码时少得多。
结合理论阅读和社区讨论,我现在认为:结对编程的核心价值不在于“写完功能的耗时”,而在于共同理解代码、降低返工风险和知识孤岛。它特别适合复杂业务逻辑、新人上手和关键模块。而简单 CRUD 或不涉及复杂逻辑的前端样式调整,确实可能没有必要结对。没有万能的方式,只有适配场景的选择。

问题三:软件需求是否可以在项目早期完全确定?

原先我被书中“先确定需求再设计实现”的线性描述迷惑,担心现实的变化会让传统分析失效。

经过两次团队项目,我亲眼看到需求如何“逃亡”。我们第一次团队项目的用户故事在开发第二周就因技术不可行而被迫砍掉,转会后的新项目更是经历了一次原型展示后的需求大改——用户真正看到可交互界面后,才意识到他们此前书面确认的需求并不是真正想要的。这正如书中后文所讲的“需求不仅来自用户,还来自对产品的理解和竞品分析”,更印证了敏捷宣言中“响应变化高于遵循计划”。
我现在这样回答:需求无法在项目早期完全确定,但这不意味着需求分析是无用功。相反,早期分析构建的是共识基线和风险地图。那些最初用功能列表、用户画像、场景描述绘制的地图,允许我们在变化到来时,能评估偏离的程度和代价,而不是盲目摇摆。书本上的传统分析方法与敏捷迭代并不矛盾,它们一同服务于“不断逼近真实需求”的过程。

问题四:团队如何保证所有成员遵守代码规范?

原来的我以为定一套规范文档就万事大吉,却发现总有人“跑偏”。

实践告诉我,靠自觉和文档是绝对不够的。在我们的团队项目中,我们最终形成了一套组合拳:

自动化强制:配置 ESLint + Prettier,并与 Git 提交挂钩,不规范代码根本无法进入仓库。

Code Review 文化:每次 PR 必须至少一人审核,审查清单第一项就是“是否符合团队代码规范”。

集体代码所有权:我们定期集体重构一小块代码,把不一致的命名或结构统一掉,像收拾公共客厅一样。
通过与其它组交流,我还听说大型团队会用“团队规范定制 + CI 静态检查 + 定期技术债梳理”来保证。答案不再是“怎么说服人遵守”,而是“如何让规范不必依赖人的记性”。

问题五:软件测试应该在开发之前还是开发之后进行?

起初我把“先开发后测试”和“测试驱动开发(TDD)”看成两个对立阵营。

现在我理解,它们不是先后问题,而是层次问题。在团队项目中,我们在实现阶段对核心算法尝试了 TDD:先编写单元测试描述期望行为,再写实现代码。这让我们对边界情况思考明显更早、更全面。但系统级测试、集成测试和用户验收测试,显然是在有一定可运行版本后才进行的。
我的回答是:在微观、代码级单元测试层面,先写测试(TDD)能带来更干净的设计和更早的缺陷发现;在宏观、系统行为层面,测试必然在开发之后,但其测试用例可以(也应该)在需求分析时就开始设计。用课本的话说,“测试用例的设计可以先于编码,这就是测试驱动开发的思想。”我们体验到的正是这种思想的分层落地。

二、是否还有不明白的问题?

原来五个问题通过实践、讨论与回顾都有了较清晰的阶段性答案。但仍有模糊地带:为什么明知道某些过程改进有效(比如持续重构、完善单元测试),在实际项目中却总是被压缩甚至忽略? 我在很多团队(包括我们的两次团队项目)中都观察到,进度压力一大,首先被牺牲的就是测试和代码清理。这和书中“软件工程的目标是创造足够好的软件”相关,但如何定义“足够好”?如何与利益相关者沟通质量代价?我还需要更多真实世界经验才能回答。

三、产生的新问题

在经历转会、接手他人代码后,我生出一个新问题:
“遗留代码的理解和交接,到底怎样做才高效?”
我们在第二个团队项目中接手了前一个团队的半成品代码库,虽然有文档,但文档和代码已经脱节。我们花了大量时间通读、画类图、跑测试,才逐渐理清结构。软件工程强调可维护性,但交接时刻往往充满混沌。有没有一种模式或方法,能像“承诺一致性协议”一样,保证代码的理解能低损耗地传递?这是我接下来想探索的。

四、“做中学”——每个阶段一个知识点

按照课程的要求,我提炼出在六个阶段中印象最深的“一个知识点”:

  1. 需求阶段:用户故事不等于需求文档。 学会用“作为…我想…以便…”的格式描述功能意图,并持续与用户确认优先级,才知道需求分析产物是动态的对话媒介,而不是一锤子买卖的规格书。
  2. 设计阶段:依赖倒置原则让系统更容易测试和扩展。 我们在设计时把数据库访问抽象成接口,上层依赖抽象而非具体实现,后期换数据源几乎零成本。这是从书本走入代码的真实收获。
  3. 实现阶段:持续集成的关键是“小步提交”。 实现功能时频繁集成到主干,每次提交都能通过自动化构建和测试,冲突和回归问题被切得极碎,修复成本极低。
  4. 测试阶段:边界值分析比穷举测试高效得多。 在编写测试用例时,我们不再盲目试图覆盖所有可能值,而是专注于等价类划分和边界值,用少量用例捕获了大多数缺陷。
  5. 发布阶段:发布是技术行为也是沟通行为。 我们第一次发布前只关注程序本身,结果用户不知道怎么更新、怎么回退。后来学会写 Release Notes、标注已知缺陷,用户反而更信任我们了。
  6. 维护阶段:日志和监控是维护的眼睛。 项目上线后,我们加入结构化日志和错误报警,才发现很多问题在用户察觉前就被修复了。维护不是等着报 Bug,而是主动感知。

五、个人项目·结对编程·团队项目中的心得

个人项目(词频统计)让我第一次完整走过需求、设计、编码、测试的闭环。最大的心得是:一个人的代码也是工程,不是脚本。 那时我体会到性能分析工具如何指导优化,单元测试如何避免改了这里坏了那里。初学时的“慢”,恰恰是在给后来的“快”打基础。

结对编程(搭档合作) 教会我的是如何说清楚自己的想法,以及如何承认“我不知道”。在导航时我被迫把脑袋里的模糊直觉翻译成对方听得懂的话,暴露了很多理解漏洞。这种沟通能力在后续团队协作中一直受用。

团队项目 两段经历,给我的最大礼物是信任与透明。第一次我们出于不信任,把任务分得极细却缺少交流,集成时到处是冲突。转会后的团队约定每日站立会、所有人可见的看板、频繁的代码评审,技术难题不再由一个人苦撑。我发现,软件工程课堂上讲“流程”“工具”,最终都是为了一件事:让人与人能更好地为同一个目标工作。 这也是我这学期最深的体会——软件工程不仅是建造系统,更是构建协作的秩序。

问题来自初读,答案来自实践。或许未来进入真正的工业环境,今天的答案又会被修正,但我已经学会了如何带着问题前行。

posted @ 2026-06-29 11:04  Nice2cu22  阅读(9)  评论(0)    收藏  举报