(一)规格化设计的发展
人们在脱离了面向机器的语言,创建了当时看来更高级的面向过程的语言后,大大地提升了编程效率,但一些面向过程的语言中的goto语句极大地限制了程序的规模。规格化程序设计采用子程序(比如函数)、代码区块、for循环以及while循环等结构来替换传统的goto,以此来改善计算机程序的明晰性、质量以及开发时间。
随着计算机硬件的飞速发展,应用复杂度越来越高,原有的程序开发方法已经越来越不能满足人们的需求。19世纪60年代爆发了表现为软件质量低下、项目无法如期完成、项目严重超支等情况的软件危机。
经过一段时间的探索,人们提出了“规格化程序设计”来解决软件危机。1968年戴克斯特拉发表了著名的《GOTO有害论》,引起了人们多方的探讨,在这个过程中,规格化程序设计方法诞生。与此同时,第一个结构化的程序语言Pascal诞生,并迅速流行。
规格化程序设计的主要特点是抛弃 goto 语句,采取“自顶向下、逐步细化、模块化”的指导思想。规格化程序设计通过“自顶向下、逐步细化、模块化”的方法,将软 件的复杂度控制在一定范围内,从而从整体上降低了软件开发的复杂度。结构化程序方法成为了 1970 年 代软件开发的潮流。
(二)规格BUG
没有被报规格bug,可能是测试者偷懒,又或者测试者也坚定地维护和谐六系。但是不报不等于没有,个人检查发现的bug还是有。比如有两个方法的规格是用自然语言写的。以及,存在不规范的使用现象。
(三)规格BUG产生的原因
1、诚如老师所言,许多方法都是先写了代码,再回头写的规格,所以有差错;
2、对于JSF规范的掌握不够牢固,很多时候写的时候还要对照回去,导致出现语法的错误;
3、规格其实是为了写好代码服务的,但代码以及写好了,再回头写规格,有种多余之感,认识上的误差;
4、某些情况不知道如何表达,展开又过于庞大,只好用自然语言代替。
(四)错误写法和改进
@REQUIRES:
1、偷懒型
public Taxi(int i,TaxiGUI g,mapInfo map,int _type);
/** * @REQUIRES:Null * @MODIFIES:this.num * this.state * this.waitTime * this.credit * this.rtime * this.gui * this.taxiCoordinate[0] * this.taxiCoordinate[1] * this.m * @EFFECTS: this.num=i; * this.state=2; * this.waitTime=0; * this.credit=0; * this.rtime=0; * this.gui=g; * this.taxiCoordinate[0]=new Random().nextInt(80); * this.taxiCoordinate[1]=new Random().nextInt(80); * this.m=map; */
显然在这个构造器中,对于输入的出租车编号以及地图是有要求的,无脑写Null,就为了简化工作量。
改进:
public Taxi(int i,TaxiGUI g,mapInfo map,int _type); /** * @REQUIRES:(0<=i<80 && map is Connecting diagram) * @MODIFIES:this.num * this.state * this.waitTime * this.credit * this.rtime * this.gui * this.taxiCoordinate[0] * this.taxiCoordinate[1] * this.m * @EFFECTS: this.num=i; * this.state=2; * this.waitTime=0; * this.credit=0; * this.rtime=0; * this.gui=g; * this.taxiCoordinate[0]=new Random().nextInt(80); * this.taxiCoordinate[1]=new Random().nextInt(80); * this.m=map; */
2、自创符号代替规范语法型
public void setCoordinate(int x,int y) ; /** * @REQUIRES:0<=x<80, 0<=y<80 * @MODIFIES:this.taxiCoordinate * @EFFECTS:set the taxi's coordinate to be(x,y) */
其中 “,” 是作者自己想当然使用的表达并且的符号,应该替换为 “&&”
改进:
public void setCoordinate(int x,int y) ; /** * @REQUIRES:0<=x<80 && 0<=y<80 * @MODIFIES:this.taxiCoordinate * @EFFECTS:set the taxi's coordinate to be(x,y) */
3、自然语言型:
public synchronized int [][] getto(int[] coordinate,Order o,int sta) ; /** * @REQUIRES:\exist coordinate in map * \exist o * @MODIFIES:coordinate,state * @EFFECTS:set the taxi to coordinate * record the pass point information in o */
显然是伪装成正确语法的自然语言
public synchronized int [][] getto(int[] coordinate,Order o,int sta) ; /** * @REQUIRES:map.contains(coordinate) * o!=Null * @MODIFIES:coordinate,state * @EFFECTS:set the taxi to coordinate * record the pass point information in o */
4、不完整型
public Order(int scx,int scy,int dcx,int dcy,Taxi[] t,int ind); /** * @REQUEST:0<=scx,scy,dcx,dcy<80 * @MODIFIES:Order * @EFFECT:initial the order */
对照代码我发现其实实现的功能中对参数的要求不止于此,还有对于t以及ind的要求
public Order(int scx,int scy,int dcx,int dcy,Taxi[] t,int ind){ /** * @REQUEST:0<=scx,scy,dcx,dcy<80 && t!=null && 0<=ind<100 * @MODIFIES:Order * @EFFECT:initial the order */
5、忘写型
public void SetarriveSrctime(long t) ; //空空如也
改正:
public void SetarriveSrctime(long t) ; /** * @REQUIRES:None * @MODIFIES:arriveSrctime * @EFFECTS:arriveSrctime=t */
@EFFRCTS:(同上)
1、偷懒型:
public void SetarriveSrctime(long t) ; /** * @REQUIRES:None * @MODIFIES:arriveSrctime * @EFFECTS:None
Modifiels都说有改动,然后骗我说EFFECTS没有
public void SetarriveSrctime(long t) ; /** * @REQUIRES:None * @MODIFIES:arriveSrctime * @EFFECTS:arriveSrctime=t */
2、自创符号型:
public int[] getDstCoordinate() ; /** * @REQUIRES:None * @MODIFIES:None * @EFFECTS:\result=dstCoordinate */
不该是“=”,而是“==”
public int[] getDstCoordinate() { /** * @REQUIRES:None * @MODIFIES:None * @EFFECTS:\result==dstCoordinate */
3、自然语言型:
public Order(int scx,int scy,int dcx,int dcy,Taxi[] t,int ind); /** * @REQUEST:0<=scx,scy,dcx,dcy<80 && t!=null && 0<=ind<100 * @MODIFIES:Order * @EFFECT:initial the order */
可能是因为规范写的话,要写的太多了吧
public Order(int scx,int scy,int dcx,int dcy,Taxi[] t,int ind){ /** * @REQUEST:0<=scx,scy,dcx,dcy<80 && t!=null && 0<=ind<100 * @MODIFIES:Order * @EFFECT: * this.srcCoordinate[0]=scx; * this.srcCoordinate[1]=scy; * this.dstCoordinate[0]=dcx; * this.dstCoordinate[1]=dcy; * this.ordtime=System.currentTimeMillis()/500*500; */
4、不完整型
public void iteration() ; /** * @REQUIRES:NONE * @MODIFIES:None * @EFFECTS: * (type==1)==>\result==iter */
事实上,还有一个分支条件
public void iteration() { /** * @REQUIRES:NONE * @MODIFIES:None * @EFFECTS:
* (type!=1)==>\result=="the taxi is not vip!" * (type==1)==>\result==iter */
5、忘写型
public void SetarriveSrctime(long t) ; //空空如也
改正
public void SetarriveSrctime(long t) ; /** * @REQUIRES:None * @MODIFIES:arriveSrctime * @EFFECTS:arriveSrctime=t */
(五)功能BUG和规格BUG的聚集关系
序号 | 功能BUG | 出现BUG的方法 |
1 | 边界的出租车在判断流量是忘记越界问题,导致CRASH | Taxi类,getto函数 |
2 | 车辆回头现象 | 流量的刷新时间与车辆运行时间不协调 |
(六)心得体会
1、在写代码的时候,应该提前想好自己想要实现什么,如何实现,一个方法需要哪些数据,他会对我的类产生什么样的影响,这样写出来的代码有据可循,无论是debug还是将来改动都会方便得多;
2、撰写JSF可以很好地表现一个方法的特性,就像是这个方法的使用说明书,也是编程者的生产设计图。无论是自己再看代码,或者其他使用者使用你的方法,都会十分便捷。