OO2026 Unit3 博客作业
24371522唐昊
20260529
总结对JML和规格驱动开发的理解
经过一个单元的训练,我对JML有了深刻的认识:
- JML是面向对象编程过程中对属性/方法的行为规范与约束。在作业中,体现为我们要根据题目给出的JML规格进行符合规格的编程;在生产实践中,体现为不同工作小组之间对各种方法与接口的实现规范要求,从而减少bug的发生。
- JML的核心在于把“实现有哪些要求”从“如何实现”中剥离开来,从而实现更加规范、模块化的编程。
- 在给定的JML规格下可能有多种不同的实现方式。我们可以权衡时间复杂度、空间复杂度、实现难度等等方面来选择最合适的实现方式。
总结JUnit测试的经验
这个单元的JUnit测试要求能够测试出各种不同的错误代码。我使用了不同的方法来实现:
- 测试个别特殊情况:手动硬编码地检查一些特殊情况与小数据下的情况,来检测小范围的问题。
- 通过参数化测试,进行多轮随机数据的测试:通过与标准程序对比,来在较大的数据范围内进行错误的检测。
总结分析三次作业的迭代过程。总结如何发现已有方法/容器在迭代中的变化?如何发现程序的性能瓶颈?
这个单元的迭代没有前两个单元那么复杂:
- 第9次作业中,我们从头开始实现了提供的接口,初步创建了User、Video、Network的主体框架;
- 第10次作业中,我们增加了网络的一些功能,例如投币、贡献者等等,需要维护更多的容器,对数据结构的设计有一定要求;
- 第11次作业中,我们主要增加了一些网络中的推荐功能,这涉及许多跨对象的查询操作,更考验方法实现能力与个别算法掌握程度。
有关对程序的性能瓶颈的发现:
- 我会先尝试一种实现,然后推导调用关系来给出它的时间复杂度。若超过O(n^2),对较大的数据量会有一定的压力。
- 我还会对每个查询类的方法,去思考有没有记忆化查询结果的办法,以此来规避重复多次查询下的性能压力。
分析自己程序出现过的bug以及Bug出现的原因。
有一个bug给我的印象很深:对一个ArrayList<Integer>的对象调用remove()方法时出现了bug。具体原因是,ArrayList本身实现了两个remove()方法,一个根据索引来删除数据,一个根据括号内的对象的值去列表中查找相等的值来删除。但是来到ArrayList<Integer>的对象时,我误以为remove(5)会选择后者,实际上编译器会将其理解成依据索引来删除数据,由此导致了一个巨大漏洞。
[可选]如果你在Unit3使用了大模型,可以分享如下内容:在规格驱动开发时大模型具有什么优势大模型在根据JML编程的时候,会不会忽视效率问题,会不会忽视架构/容器问题?如何用大模型进行基础的单元测试?
实际上大模型对于JML的实现能力很强。
- 在效率方面,只要引导大模型思考有没有更高效的实现方式,大部分情况下大模型都能找到一个性能最佳的算法。
- 在架构/容器方面,最好需要手动做好数据结构的设计,再将这方面要求告知大模型,否则其可能忽视架构/容器问题。
- 对于单元测试,可以先手动实现一些储存状态、比较状态、标准程序的编写,然后让大模型基于这些方法构造几组基础测试数据。
[重点] Unit3第二次研讨课上,JML“击鼓传花”游戏的感悟:你是否发现了自己/别人的JML的bug?在传递过程中,需求,边界是否发生了变化?今后多人组队编程时,你认为怎么做才能统一所有人对任务需求和实现方法的理解?采用什么措施(或者指定规则)可以减少组内成员间的信息差?
我有发现别人的JML的问题:缺漏了@assignable \nothing或@pure的说明,但需求与边界的变化没有发现。
为了在组队编程中统一理解,我认为可以同时基于自然语言与JML二者来说明项目的规格要求,或是事前做好会议与讨论,从而降低组内成员之间的信息差。