JML规格驱动开发总结

24371113-刘鑫杰 2026-06-27 22:48:47

通过本单元的学习,我主要接触了以下几类JML语法构造:原子表达式、量词、前置条件、后置条件、不变式以及异常行为。这些语法构造为精确描述程序行为提供了基础。

 

规格驱动开发的核心价值在于将自然语言转化为机器能够理解并执行的语言,从而有效确保设计者的本意被清晰表达,没有二义性。我认为规格驱动开发有几点优势:首先是契约式设计,调用者需要保证前置条件满足,被调用者需要保证后置条件满足,这种契约思想让调用方和实现方都有了明确的责任边界;其次是便于测试,规格本身就是最精确的测试预言,可以根据JML规格逐条检查代码的正确性;第三是延迟过程设想,将延迟过程设想的面向对象原则扩展到了方法设计阶段,可以描述方法预期的功能而无需考虑具体实现;最后是工具链支持,JML拥有OpenJML、JMLUnit等丰富的工具链。

 

在JUnit测试的实践中,我接触并使用了黑箱测试、白箱测试、单元测试和压力测试等方法。黑箱测试根据不同的输入检测输出是否正确,但难以覆盖所有情况;白箱测试直接检查代码逻辑;单元测试针对特定方法构造测试点;压力测试对时间复杂度较高的方法进行大量调用。在为本单元编写JUnit测试时,我总结了以下经验:严格对照JML规格,不仅检验ensures后置条件,还要检查pure、assignable等语句,例如pure方法调用前后状态应一致;利用官方包提供的便利方法,如User.strictEquals()判断对象相等,避免大量遍历检查;兼顾正确性与性能,简单方法用白箱测试,复杂度高的方法结合黑箱和白箱;关注边界值测试,对int类型参数特别关注INT_MAX、0、INT_MIN等边界。我的测试策略主要是自己构造测试样例加JUnit单元测试,尽量覆盖每个分支,并与同学进行对拍验证正确性。但自己构造测试数据存在难以全面覆盖和对时间复杂度控制不足的问题。

 

本单元的三次作业是完全迭代开发的。第一次作业实现Network、Person、Group三个基础类,核心功能是构建社交网络框架,包括人的管理、关系的建立、连通性查询和连通块数量查询,关键是用并查集优化图操作。第二次作业在原有基础上新增了硬币经济体系,用户拥有硬币属性,可以对视频进行点赞、投币、转发和评论等互动操作,同时引入了粉丝勋章系统,用户可以为关注的UP主购买勋章。这一阶段的难点在于事务性操作的处理——多个操作需要同时成功或同时失败,以及各种新增异常类(如VideoUnmatchedException、InvalidCoinsException、InsufficientCoinsException、DuplicateMedalException等)的正确抛出。第三次作业进一步细化了消息类型,新增了通知消息、红包消息、表情消息等,并引入了智能推荐系统,需要实现推荐视频和推荐UP主的功能,难点在于最短路径求解和推荐算法的效率优化。

 

在迭代过程中,已有方法和容器的变化体现在多个方面:功能扩展方面,如互动相关方法从无到有的完整新增;属性新增方面,User类在第一次作业中只有基本个人信息,第二次作业新增了coins、watchedVideos、likedVideos、medals、contributors、contributions等属性,第三次作业又新增了typeCounts和videos;容器选择也需要随需求调整,从最初的ArrayList到后续大量使用HashMap实现O(1)查找。为了发现这些变化,我仔细阅读每次作业的新增JML规格,对比新旧规格找出新增和修改的方法,关注异常类的变化(第一次作业有少量异常,第二次新增8个异常类,第三次又新增5个)。

 

发现程序性能瓶颈的方法包括:进行压力测试,构造大规模数据观察运行时间;分析算法复杂度,特别关注规格中使用量词或遍历容器的方法;动态维护代替实时计算,将频繁查询的指标降为O(1);选择合适的容器,如使用HashMap实现O(1)查找。

 

在本单元作业中,我遇到的Bug主要有三类:异常处理顺序问题,在数据操作之前未完成所有异常判断,导致部分数据已存入后才抛出异常,这在第二次作业的事务性操作中尤其致命;照搬JML导致性能问题,如直接按JML遍历实现某些查询方法在大规模数据下超时;容器选择不当,初期使用ArrayList存储人员导致查找O(n),后改为HashMap。这些Bug的根本原因是对JML规格理解不够深入,忽略了做什么与怎么做的区别;对异常处理流程认识不足,特别是对事务性操作中回滚语义的理解不到位;以及缺乏性能意识,初期只关注功能正确性而忽视大数据量下的表现。

 

在击鼓传花研讨课活动中,我发现了JML规格在传递过程中的一些问题:边界条件模糊,不同人对同一条规格理解不同;前置条件遗漏,导致异常处理不完整;后置条件不完整,对异常情况下的状态变化描述不足。需求和边界在传递过程中确实会发生变化,因为每个人基于自己的经验和认知理解规格,存在偏差和曲解。基于这次研讨课的感悟,我认为在多人组队编程中应该采取以下措施来统一理解、减少信息差:建立统一的规格文档,使用JML等形式化语言消除二义性;定期进行规格评审,让每个成员阅读和解读规格;建立Code Review机制,确保实现与规格一致;编写单元测试作为规格的活文档,作为团队沟通的桥梁;明确接口契约,让调用方和实现方都有明确的责任边界。

 

总结本单元的学习,我深刻体会到了规格驱动开发的价值和挑战。JML为程序的正确性提供了严格的数学保证,也为团队协作提供了清晰的契约。但规格驱动开发并非银弹,需要我们既要忠实于规格,又要超越规格去思考架构和性能问题。通过三次迭代作业,我学会了如何阅读和理解JML规格,如何根据规格编写正确的代码,以及如何通过JUnit测试验证代码的正确性。更重要的是,我认识到在规格驱动开发中,算法优化、容器选择和架构设计同样重要,规格告诉我们要做什么,而如何高效地做到,是我们作为开发者需要思考的问题。

 

...全文
400 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

309

社区成员

发帖
与我相关
我的任务
社区描述
2026年北航面向对象设计与构造
java 高校
社区管理员
  • 孙琦航
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧