OO2019第三次作业总结.

JML语言理论及工具链

JML语言

JML(Java Modeling Language)是用于对Java程序进行规格化设计的一种表示语言。Java程序中方法的JML规格主要包括三个部分:(1)requires子句定义该方法的前置条件(precondition);(2)副作用范围限定;(3)ensures子句定义了后置条件。一个功能正确的方法实现应该在满足前置条件的成立的状态下,一定返回后置条件所描述的结果,并且只修改范围限定内的变量。Java中对数据封装成类,因此类型也有相应的规格,主要以invariant和constraint的形式表示,其中invariant表示从构造函数函数执行完成后,该实例在任何可见状态下都应该满足的条件,即所有的方法的前置条件和后置条件中都隐式地包含不变式;constraint对前序可见状态和当前可见状态的 关系进行约束。

工具链

openJML工具提供了JML语言语法检查、静态分析和运行时检查,并可以应用z3、CVC4等SMT Solver进行验证;TestNG可以针对规格进行测试样例的自动生成;KeY可以用来对JML标记的Java程序进行完整的形式化验证,2015年CAV上有一篇用KeY验证OpenJDK库中Timsort排序算法的论文,文中用KeY验证出了Timsort实现中的bug,并产生测试样例进行了复现,非常有意义的工作。笔者去年用Isabelle/HOL交互式定理证明器复现了这篇论文里的工作。

相关工具的部署和使用

在讨论区大佬的指点下,我部署了openjml和testNG并进行了简单的实验,遗憾的是在实际的代码开发过程中,因为并不熟悉这些工具没有使用。
以下是我测试相关工具所使用的代码:

package path;

public class MySimplePath {

    //@ public instance model non_null int[] snodes;
    private int[] nodes;

    public MySimplePath(int... nodeList) {
        nodes = nodeList;
    }


    //@ ensures \result == snodes.length;
    public /*@pure@*/ int size() {
        return nodes.length;
    }

    /*@ requires index >= 0 && index < size();
      @ assignable \nothing;
      @ ensures \result == snodes[index];
      @*/
    public /*@pure@*/ int getNode(int index) {
        return nodes[index];
    }

    //@ ensures \result == (snodes.length >= 2);
    public /*@pure@*/ boolean isValid() {
        return size() >= 2;
    }

    public static void main(String[] args) {
        MySimplePath msp = new MySimplePath(1,2,3);
        int a = msp.size();
        boolean b = msp.isValid();
        int c = msp.getNode(1);
    }
}

用TestNG生成测试样例并进行测试得到的结果如下图所示:
1617954-20190522203603580-1585500254.png
用openjml添加运行时测试后再用TestNG生成测试样例的结果如下图所示:
1617954-20190522203956750-721533289.png
我不太会用也看不太懂。。。

作业架构

第一次作业类图如下图所示:
1617954-20190522205745396-260024069.png
第一次作业主要是实现Path和PathContainer两个类,在架构上没有复杂的地方,关键点在于是数据结构的选择和使用缓存避免重复计算。我使用了一个哈希表来存储Path和PathId和另一个哈希表用于存储每个节点的出现频率。
第二次作业类图如下图所示:
1617954-20190522205801330-303196349.png
第二次作业在第一次的作业的基础上新增了图结构运算,所以这次的关键点在于在第一次作业的基础上进行拓展、封装一个独立的图结构及其运算并考虑下次作业的拓展课。我在这次作业中的Graph类继承了上次的PathContainer类,从而提升了代码复用率,也更OO;不过我的图结构类不够抽象,它依赖于Path类,这是做的不好的地方,扩展性不强。
第三次作业类图如下图所示:
1617954-20190522205815382-1234468088.png
第三次作业在第二次作业的基础上拓展了更多的功能,从类图可以看出我实现了这次作业和上次作业之间的继承关系,在功能实现上,我又封装了一个新的图结构完成更加复杂的计算,不过做的不好的地方在于这个图结构依然依赖于Path,并且这次的图和上次作业中的图结构没有任何关系。我在作业中将计算和架构分离,这样避免了重构,不过计算和架构之间有些失衡,基本上大部分代码都集中在图结构上,更好的做法是实现更通用的图结构并且从架构中进行针对某次作业的特殊问题的计算。

bug和修复情况

这几次作业中,因为代码逻辑并不复杂,并没有像电梯那样的各种依赖关系和约束条件,因此并没有出现什么bug,主要问题都出现在性能上,我也不知道为什么课程组一遍强调架构一边严格地卡性能。

心得体会

  1. 在本单元作业中,感觉规格的存在感很低,然后是架构,每次作业最看重的算法和性能,也可能是我没有很好理解这几次的作业。不过好的地方在于在这个单元的作业中,因为每次作业中的严格迭代关系,我终于没有次次重构了,体验到了面向对象中继承的好处。
  2. 规格是很重要的东西,它将自然语言容易产生歧义或者疏漏的部分,通过形式化方法进行描述,从而形成了严格的数学描述,这一方面有助于形式化验证,另一方面在书写规格的过程中对代码的实现也有帮助,条理清晰的规格可以有效规避很多实现中的bug。
  3. 因为我的研究方向是形式化验证,所以我日常其实是和规格打交道的。其实规格是比想象中要复杂很多的,而且软件开发的实践中从抽闲需求层到算法设计层再到代码实现层都有不同规格需要设计;此外,规格的书写经常出现各种意想不到的问题,很多看起来简单的方法的规格往往不那么简单,在验证的过程中需要反复修改规格;而且描述同样的行为的规格可能因为表述方式的不同而造成验证难度上的巨大差异,一个条理清晰逻辑明确的规格可以使得验证工作顺利开展,反之则可能进展艰难;SMT Solver工具等在对稍微复杂的程序进行验证可能就不是很好用了,相比于自动定理证明(ATP),我更推崇交互式定理证明(ITP),通过人与定理证明器的交互来完成证明,在证明过程中也可以使用z3、cvc4等SMT Solver来辅助证明。

Happy OO,Happy Hacking!

转载于:https://www.cnblogs.com/huluobo7161/p/10907277.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值