第三次博客作业
面向对象9-11次作业总结
一、规格化设计发展
1.
二十世纪60年代以前,程序设计使用的主要是机器语言、汇编语言等,由于它们是针对特定型号计算机的语言,在不同计算机之间的可移植性差,而且不同计算机一般具有不同的指令系统,使得这类语言可读性极差。
从60年代后,软件开始作为一种产品被广泛使用。早期那些被认为是优秀的程序常常很难被别人看懂,通篇充满了程序技巧。现在人们普遍认为优秀的程序除了功能正确,性能优良之外,还应该容易看懂、容易使用、容易修改和扩充。
1980年代的编程语言与之前相较显得更为强大。C++合并了面向对象以及系统程序设计。在语言设计上有个重大的新趋势,就是研究运用模块或大型组织化的程序单元来进行大型系统的开发。这一阶段程序的模块化、标准化程度进一步提高。
2.
不同的开发者之间由于协作的需要,只要能通过规格化方式进心方法的使用交互,那么无疑能使工作更有效率,也有利于后期对于软件的维护与修改,所以得到人们重视。
二、规格bug分析
作业次数 |
规格bug出现次数 |
代码数量 |
9 |
0 |
0 |
10 |
4 |
30/12/13/18 |
11 |
0 |
0 |
出现的规格bug
规格名称 |
相关函数 |
Bug问题 |
@EFFECTS |
Open |
自然语言表意不明 |
@EFFECTS |
Close |
自然语言表意不明 |
@EFFECTS |
Run1 |
自然语言表意不明 |
@EFFECTS |
Light |
不为布尔表达式 |
Bug分析
从自己出现的bug的类型上来看都是后置表达式的问题,由于对规格格式撰写的不熟练,自己在后置表达式的写法上大量使用了自然语言的方式,导致自己的规格往往出现不能很好地表达后置条件的问题。并且由于是先写代码再写规格的方式,导致自己对以前写过的方法内容产生遗漏而不能准确地通过规格进行表达。
三、规格改进
前置条件:
1指定范围不明
/** * @REQUIRES: * this.edges[s] !=null; */
/** * @REQUIRES: * this.edges[s] !=null; * 0<=s<=6399; * 0<=e<=6399; */
2.对于方法基本属性不必写
/** * @REQUIRES: * period !=null; * state !=null; * Light !=null; * gui !=null; * map!=null */
/** * @REQUIRES:None; */
3.未对输入进行充分判断
/** * @REQUIRES: c!=null; */
/** * @REQUIRES: (c=='S'||c=='X'||c=='Z'||c=='Y'); */
4.未对参数访问数组元素时对数组元素进行判断
/** * @REQUIRES: * 0<=t<=6399; */
/** * @REQUIRES: * this.edges[t] !=null; * 0<=t<=6399; */
5.未对方法中使用的变量判断
/** * @REQUIRES: 1<=n<=100; */
/** * @REQUIRES: 1<=n<=100; * this.cars!=null; */
后置条件
1.自然语言表意不明
/** * @EFFECTS: * e exists in edges[s],print "exists" * s adjoins e * gui.SetRoadStatus(new Point(s/80,s%80),new Point(e/80,e%80),1) edges[s].addElement(e) edges[e].addElement(s); * s not adjoins e,print"error".; */
/** * @EFFECTS: * if e exists in edges[s],print "exists" * if s adjoins e * gui.SetRoadStatus(new Point(s/80,s%80),new Point(e/80,e%80),1) edges[s].addElement(e) edges[e].addElement(s)(更新地图道路打开); * if s not adjoins e,print"error".; */
2.未对同一变量使用/old
/** * @EFFECTS: * (s=='S')==>(location=location-80); * (s=='X')==>(location=location+80); * (s=='Z')==>(location=location-1); * (s=='Y')==>(location=location+1); */
/** * @EFFECTS: * (s=='S')==>(location=\old(location)-80); * (s=='X')==>(location=\old(location)+80); * (s=='Z')==>(location=\old(location)-1); * (s=='Y')==>(location=\old(location)+1); */
3.未对程序异常进行说明
/** * @EFFECTS: * 对每次加入流量统计队列的流量信息在500ms后删除,只保留当前-当前500ms之前的流量信息 */
/** * @EFFECTS: * normal_behavior: * 对每次加入流量统计队列的流量信息在500ms后删除,只保留当前-当前500ms之前的流量信息 * exception_behavior(Throwable e): * exit; */
4.未用准确的布尔表达式表达
/** * @EFFECTS: * 判断道路是否存在 */
/** * @EFFECTS: * (\exist int i; edges[x].get(i) ==y) ==> \result == true ; * (\all int i; edges[x].get(i) !=y) ==> \result ==false; */
5.未对方法内变量的范围进行限制
/** * @EFFECTS: * \result == (g!=null&&edges!=null&&edges1!=null&&gui!=null&&t!=null&&a!=null)&& * (\all int i ;edges[i]!=null&&edges1[i]!=null)&& * (g[i][j]==(0||1||2||3) for all 0<=i<80 && for all 0<=j<80)&& * (a.get(i).t[j][k]>=0 for all 0<=i<a.size */
/** * @EFFECTS: * \result == (g!=null&&edges!=null&&edges1!=null&&gui!=null&&t!=null&&a!=null)&& * (\all int i ;edges[i]!=null&&edges1[i]!=null)&& * (g[i][j]==(0||1||2||3) for all 0<=i<80 && for all 0<=j<80)&& * (a.get(i).t[j][k]>=0 for all 0<=i<a.size && for all 0<=j<6400 for all 0<=k<4); */
四、功能bug分析
作业次数 |
功能bug数量 |
规格bug数量 |
9 |
1 |
0 |
10 |
2 |
4 |
由于功能bug基本上是由于未实现相应功能而造成的,与规格聚合度不大。
功能bug名称 |
解决方法 |
未实现最小流量 |
对于最小流量的判断有问题,重新采用新的判断方法 |
程序卡死 |
对于计算流量的map线程未start,导致map线程未启动 |
未按最小流量 |
Map未启动 |
五、体会
正确的撰写规格的方式应该是:
确定方法功能和作用,确定方法的Require,确定方法参数的范围;
确定方法内容和处理过程,确定方法会更改的属性,确定Modifies;
确定方法的处理结果,撰写effects。
但是由于再第九次作业中为已经写好的代码添加规格,所以基本上是 先实现了功能再写规格。
写好一个简介准确的JSF规格是十分重要的,有助于别人读懂你的代码和思路。根据现有代码写规格的体会并不是很好。