309
社区成员
发帖
与我相关
我的任务
分享规格驱动开发的核心在于“先契约,后实现”。JML 就像是在架构设计者和实际开发者之间的一份具有强制性的合同。
requires)、后置条件(ensures)以及副作用(assignable / pure)。在编写代码时,不再需要去猜测业务的隐藏逻辑,一切以规格为准。\forall、\exists、\sum 等量词的组合,JML 能够绝对精确地定义状态的变化。@pure 方法中修改了对象的内部状态),即便在当前业务流中看似无害,在更庞大的系统中也往往为未来可能的致命 Bug 埋下伏笔。@pure 契约时,我曾构建了一个全知快照系统(Omniscient Snapshot System)来进行 before 和 after 的深度对比。最初,我直接使用了 this.profileSnapshot = user.getProfile();,导致快照仅仅拷贝了引用。当被测方法违背契约偷偷修改了底层列表时,快照和当前状态一起被“污染”了,导致 assertEquals 永远返回 true。ColdStartUserException)。良好的测试不仅要断言异常被成功抛出,更要利用连续调用测试,在异常发生后再次调用并比对快照,确保抛出异常的整个过程中系统的任何状态都未发生脏写。recommendNthUp 这种具备同分排序(分数降序,同分 ID 升序决胜)逻辑的方法,测试用例必须能够自动化生成同分偶对,去强行冲撞决胜逻辑,否则 Off-by-one (差一错误) 极难被暴露。随着三次作业的推进,系统的核心由简单的增删查改逐渐向复杂的图算法和排行推荐演进。应对变化最有效的方法是对 JML 进行 Diff 比对。例如在新增视频点赞或投币逻辑时,仔细比对规格会发现,它不仅影响了视频本身的热度,还隐式地要求同步更新发布者的全局影响力(Influence)。这种级联更新促使我将原本独立的散列容器封装成具有联动更新能力的管理器。
JML 给出的是逻辑层面的定义,如果照搬 JML 将量词翻译为 for 循环,极易写出 O(N^2) 甚至 O(N^3) 的代码(典型的 TLE 场景)。
queryShortestPath 时,最初简单的 BFS 如果不配合优秀的去重和双向搜索,在稠密图中会极易超时。queryGlobalBestContributor 或获取最高影响力 UP 主这类高频查询,决不能在每次查询时全量排序。必须在 coinVideo 等修改状态的方法中,引入动态维护机制(使用 TreeSet 或 PriorityQueue 等数据结构缓存 Top N)。 1. computeUpScore 隐式调用导致的推荐算分错误
recommend_Nth_up 时,原本应当推荐得分更高的 UP20,系统却输出了得分为 0 的 UP10。getInterest(...) * up.getInfluence(...)。然而在代码实现时,我将后半段错写成了 long influence = getInfluence(type);。由于漏掉了 up. 前缀,导致程序默认调用了 this.getInfluence(即当前请求推荐的观众自身的影响力)。因为观众的影响力为 0,所有候选人的得分都变成了 0,最后触发了同分按 ID 升序的决胜规则,导致输出了小 ID。 2. JUnit 快照测试失败:原生数组的 .equals() 陷阱与状态漏判
@pure)时,自己编写的深拷贝测试用例 strictEquals 总是无故返回 false,导致 Case 无法通过。User 对象的 typeCounts(一个 int[] 原生数组)时,错误地使用了 this.typeCounts.equals(user.typeCounts)。在 Java 中,原生数组并没有重写 Object 的 equals 方法,这导致它实际上比较的是堆内存地址(==),对于深拷贝出来的对象必然返回 false。strictEquals 漏写了对内部关键状态数组 influences 的一致性比对。Arrays.equals();对于对象的严格相等比较,必须对着类属性声明列表,挨个字段进行不遗漏的校验。 3. uploadVideo 导致的状态机不同步(个人主页漏维护)
Network 的 uploadVideo 时,只记得把新建的视频放入了全局的 videos HashMap 中,却忘了调用发布者(Uploader)自身的 addUploadedVideo 方法。全局网络和 UP 主个人对象的视频列表出现了状态割裂。\old 容器大小加一的描述,通常意味着需要同步维护多个数据结构。局部状态与全局状态的一致性是 OO 系统稳定性的基础。\exists 和 \forall 组合)时,大模型能非常迅速地将其翻译为人类可读的业务逻辑约束。同时,在搭建 JUnit 基础脚手架、生成样板数据时效率极高。\sum 翻译成嵌套循环,完全无视这会引发超时。< 变成了 <=,原本应该维持不变的 \old 状态被直接遗忘,甚至异常的抛出优先级也发生了颠倒。