OO第三次博客作业
规格化设计的发展历史
自从20世纪50年代第一台电子计算机的问世,软件也同时诞生。1960年代美国大学里开始出现授予计算机专业的学位,教人们写软件。在计算机发展的初期,由于软件编写没有规范,它们的通用性是十分有限的。人们除了源码和注释外无法获取有关软件的更多信息。最初的程序设计是纯粹面向机器的,而机器码的可读性太差。对于程序规模的需求增大,面向过程的设计思想也应运而生。
20世纪60年代,软件作为计算机的刚需,覆盖的范围越来越广泛,与此同时的是软件的维护成本越来越高,由软件错误而引起的信息对视、系统报废事件屡有发生。为此,1968年,荷兰学者E.W.Dijkstra提出了程序设计中常用的GOTO语句的三大危害:破坏了程序的京东一致性,程序不易测试,限制了代码优化,此举引起了软件界长达数年的论战,并由此产生了结构化程序设计方法,同时诞生了基于这一设计方法的程序设计语言Pascal。
然而在20世纪70年代末,随着计算机科学技术的进一步发展,面向过程的程序设计已经难以用户需求的变化。于是程序员们开始寻找更加先进的软件开发技术,也就是后来的面向对象的程序设计。
至此,就简洁的概括了程序设计的发展历史,在接下来的几十年程序设计还有更多的发展和优化,但为了与课程相呼应,就简单的到此为止吧。
bug分析
四次编程作业我总共被找了六个功能性bug,请由我一一道来。
(1)
第一次作业中,我的两个bug来自于系统运行时间过长的bug,简单来说就是200ms的一段路,我的出租车实际要走300多秒,这是因为get_path()方法太复杂的原因。同样的还有stop状态停了超过1s的情况。这个bug在之后我的处理方法是sleep(time+200-System.currenttime),这里sleep是系统记录的时间,并在sleep之后加上200,在输出端则严格使用假时间,避免在这种地方再丢分。
(2)
第二次作业中,由于流量问题的诞生,我使用了gui类中的getFlow()方法,并且无论怎么修改都会有回头的情况,于是被细心的测试者发现,分别在wait状态闲逛和流量路两个点给我扣了分。在之后的编写中我使用了一个新的获得流量的方法,就避免了这样的问题。
(3)
第三次作业中我的程序因为引进了light功能,所以在map的初始化部分稍微改了一下位置,这一改就改出问题了,原本程序支持的load中map不存在会有默认地图现在成了个bug,被纠正之后很后悔,也很自责。作为一个程序员,每次的编程都要添加新的功能,如果不能保证之前的功能正确性,那就是自掘坟墓了。另外一个bug则是被数据攻破,也修复了。
(4)
第四次作业并没有被找到bug,很幸运。
规格bug中的两个,一个是纯输出类Output的effect被揪出错误,这一点我也不知道算不算bug,所以申请了仲裁,另一个是modified少写了一个被修改的参数,测试者很细心。
总结一下自己给别人找bug的流程吧,首先是文件读入,确保map文件存在与否都能运行,map文件格式问题,出租车初始化接单,同时执行两条指令,信誉值不同取车等等。。。
1.
/** * *@REQUIRES: this.light!=null; *@MODIFIES: this.LightMap; *@EFFECTS: (\all Point e in this.light; this.LightMap[e.x][e.y]==true); */
其中 this.light 是由Point组成的队列,这里有点自然语言的风格,改为。 (\all i; 0<=i<this.light.size(); .......
2.
/** * *@REQUIRES: None; *@MODIFIES: None; *@EFFECTS: \result==this.LightMap[x][y]; */
前置条件应该有限制,改为0<=x<=79&&0<=y<=79
3.
/** * *@REQUIRES: None; *@MODIFIES: None; *@EFFECTS: \result==1; */
在这一系列作业当中,run()方法我都写了好些行,导致方法规格根本没法写。在和大佬们的交流学习中,我认识到这个是不对的,以后重构之后希望能够做的更好
4.
/** *@REQUIRES: None *@MODIFIES: this.credit; *@EFFECTS: this.credit==\old(this).credit+a; */
这是出租车的增加信誉值的方法,该方法应该有限制,即Require中 a>0
5.
/** *@REQUIRES: None *@MODIFIES: None *@EFFECTS: \result==this.taxi_list; */
该方法是获得路径的方法,后置条件写错,应该为 this.queue == getRoad()
6.
/** *@REQUIRES: None *@MODIFIES: None; *@EFFECTS: \result==distance(); */
前置条件加一个guigv.m != null
7.
/** * @REQUIRES:None; * @MODIFIES:None; * @EFFECTS:read.start(),sf.start();Output.start(); */
这是main方法的规格,说实话,惨不忍睹。。。最后决定直接删除掉了,毕竟main方法功能多,比较难写
8.
/** *@REQUIRES: File(path) == A File; *@MODIFIES: None *@EFFECTS: 1==1; */
前置条件很奇怪, 改为 File(path).exist()
9.
/** *@REQUIRES: None; *@MODIFIES: this.time_list; *@EFFECTS: this.time_list.contains(t); */
方法为添加一个点,这里前置条件和后置条件都有误。前置条件为this.time_list!=NULL。后置条件是this.time_list.contains(t)&&\old(this).time_list.size==this.time_list.size()-1;
10.
/** * *@REQUIRES: this!=null; *@MODIFIES: None; *@EFFECTS: \result==this.num; */
前置条件有点无谓,删掉。
基本思路和体会
撰写类规格和方法规格都是第二次出租车作业才有的事情,所以实际上这是一个先写方法再写规格的过程,我并没有感受到太多先写规格再写方法的必要性。但通过写规格,我不得不将几个方法的功能打碎并且细化,从而写出有用的规格。方法规格还是有用的,在之后添加方法的过程中都有注意这一点。但回归到课程本身,则是跟分数挂钩的问题,很多人不找功能bug就指望着jsf来过日子,而jsf本身还不成熟,很容易被钻空子扣很多,到最后申诉半天还是被判有效,这是课程组需要解决的问题。还是那句话,出现问题时该解决问题,而不是解决提出问题的人