调研,然后总结介绍规格化设计的大致发展历史和为什么得到了人们的重视


emmm为这个问题翻遍百度谷歌知乎也没有得到答案,那我就把自己认为最重要的两点简要说明一下吧,欢迎大家补充~

1、便于完成代码的重用交接。

  乌鸡老师上课说到,一个代码被重用的频率越高,说明设计的水平越高。好的代码一定是为他人提供便利的。而这种便利也包括引用时的确定性,调用者可以按照自己的需求和这份代码规格对照,因此确定自己使用这个接口的安全性可靠性。并且,代码规格也说明了调用者可视范围内变量的变化情况,否则这种重用将是非常非常危险的。因此,规格和代码的贴合性也变得很重要。

2、便于程序员按照真正的意愿做好代码实现和测试。

  编程语言毕竟是自然语言之外的第二种语言,人是按照思维生成的逻辑去构造代码实现的。而把要实现的内容完全放在脑子里没有进行仔细的分类梳理,在代码越来越复杂的情况下很容易产生疏漏,也就是实现有BUG。但测试也是按照代码逻辑产生惯性思维,所以很难找到思维漏洞的BUG。然后...然后你就变成了“我司雇来写专门BUG的程序员”,然后你就凉了。

  但规格是一种思维强制,强迫你按照你的预想去实现、去测试(有点像BUG树的作用原理)、去分类,只要规格和实现完全一致,最初有思维漏洞或许可以降低检查难度到规格层。


按照作业,针对自己所被报告的规格bug以及雷同的规格bug(限于 bug树的限制,对手无法上报),列一个表格分析


规格BUG类别 每个出现所对应方法的代码行数
modified不完整 78
modified不完整 145
   

分析自己规格bug的产生原因


这两个JSFbug都出现在第九次作业,而且错误原因基本都一样。这次作业因为一些特殊原因完成的特别仓促,也没有进行检查测试。产生的主要原因当然有时间方面的原因,更重要的是这两个方法的确也比较长。

当然,我的JSFbug水平咋样我心里还是很有笔数的,用自然语言也比较多。只是碰上的同学都比较友好,水平不高也没有被针对,但在三次作业中,我每次都对JSF进行优化,存在的问题选五个在下面介绍。


分别列举5个前置条件和5个后置条件的不好写法,并给出改进写法


前置条件部分:

参数范围描述不准确

例1

修改前:

/**
* @REQUIRES:(\all int id;);
* (\all int X;);
* (\all int Y;);
* @MODIFIES: cars_ID;carX;carY;carCredit;carStatus;hasTask;now_request;load_result;
* @EFFECTS: Set these variables to their initial values;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public CarInformation(int id,int X,int Y) {
this.carID=id;
this.carX=X;
this.carY=Y;
this.carCredit=;//信用值0
this.carStatus=;//等待服务状态
this.hasTask=false;//没有任务
this.now_request=null;
this.load_result=false;
// System.out.println("出租车信息初始化成功");
}

修改后:

/**
* @REQUIRES:(\all int id;0<=id<100);
* (\all int X;0<=X<80);
* (\all int Y;0<=Y<80);
* @MODIFIES: cars_ID;carX;carY;carCredit;carStatus;hasTask;now_request;load_result;
* @EFFECTS: Set these variables to their initial values;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public CarInformation(int id,int X,int Y) {
this.carID=id;
this.carX=X;
this.carY=Y;
this.carCredit=;//信用值0
this.carStatus=;//等待服务状态
this.hasTask=false;//没有任务
this.load_result=false;
// System.out.println("出租车信息初始化成功");
}

例2

修改前:

/**
* @REQUIRES:(\all int carX2;);
* (\all int carY2;);
* (\all ArrayList<Vertex> nei_Lis;);
* @MODIFIES: None;
* @EFFECTS: \result==new_aim;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public int Find_WhenCase2(int carX2, int carY2, ArrayList<Vertex> nei_Lis) {//在等待状态寻找一条流量最小的道路
int min_flownum=;
int new_aim=-;
for(int i=;i<nei_Lis.size();i++) {
int ID=nei_Lis.get(i).getID();
int index=transIndex(ID,carX*+carY);
//System.out.println("进入循环,CARX CARY"+carX+" "+carY);
if((Flow_List[carX*+carY][index].Get_open())&&(Flow_List[carX*+carY][index].Get_Lastflow()<min_flownum)) {
min_flownum=Flow_List[carX*+carY][index].Get_Lastflow();
new_aim=i;
}
}
return new_aim;
}

修改后:

/**
* @REQUIRES:(\all int carX2;0<=carX2<80);
* (\all int carY2;0<=carY2<80);
* (\all ArrayList<Vertex> nei_Lis;);
* @MODIFIES: None;
* @EFFECTS: \result==new_aim;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public int Find_WhenCase2(int carX2, int carY2, ArrayList<Vertex> nei_Lis) {//在等待状态寻找一条流量最小的道路
int min_flownum=;
int new_aim=-;
ArrayList<Integer> roadaim=new ArrayList<Integer>();
for(int i=;i<nei_Lis.size();i++) {
int ID=nei_Lis.get(i).getID();
int index=transIndex(ID,carX*+carY);
//System.out.println("进入循环,CARX CARY"+carX+" "+carY);
if((Flow_List[carX*+carY][index].Get_open())&&(Flow_List[carX*+carY][index].Get_Lastflow()<min_flownum)) {
min_flownum=Flow_List[carX*+carY][index].Get_Lastflow();
roadaim.clear();
roadaim.add(i);
}else if((Flow_List[carX*+carY][index].Get_open())&&(Flow_List[carX*+carY][index].Get_Lastflow()==min_flownum)) {
roadaim.add(i);
}
}
Random random=new Random();
int begin=;
int end=roadaim.size()-;
new_aim=roadaim.get(random.nextInt(end - begin + ) + begin);
return new_aim;
}

例3:

修改前:

/**
* @REQUIRES:(\all int x;);
* @MODIFIES: carX;
* @EFFECTS: carX==x;
* @THREAD_REQUIRES:\locked(this);
* @THREAD_EFFECTS: \locked();
*/
public synchronized void setcarX(int x) {this.carX=x;}

修改后:

/**
* @REQUIRES:(\all int x;0<=x<80);
* @MODIFIES: carX;
* @EFFECTS: carX==x;
* @THREAD_REQUIRES:\locked(this);
* @THREAD_EFFECTS: \locked();
*/
public synchronized void setcarX(int x) {this.carX=x;}

例4:

修改前:

/**
* @REQUIRES:(\all int i;);
* @MODIFIES: carStatus;
* @EFFECTS: carStatus==i;
* @THREAD_REQUIRES:\locked(this);
* @THREAD_EFFECTS: \locked();
*/
public synchronized void setcarStatus(int i) {this.carStatus=i;}

修改后:

/**
* @REQUIRES:(\all int i;i=0/1/2/3;);
* @MODIFIES: carStatus;
* @EFFECTS: carStatus==i;
* @THREAD_REQUIRES:\locked(this);
* @THREAD_EFFECTS: \locked();
*/
public synchronized void setcarStatus(int i) {this.carStatus=i;}

例5:

修改前:

/**
* @REQUIRES:(\all int beginX;);
* (\all int beginY;);
* (\all int endX;);
* (\all int endY;);
* (\all long request_time;);
* @MODIFIES: beginX;beginY;endX;endY;request_time;AreaX1 to AreaX4;AreaX1 to AreaX4;AreaY1 to AreaY4;
* @EFFECTS: Set these variables to their initial values;Create area;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public Request(int beginX,int beginY,int endX,int endY,long request_time) {
this.beginX=beginX;
this.beginY=beginY;
this.endX=endX;
this.endY=endY;
this.request_time=request_time;
CreateArea();
}

修改后:

/**
* @REQUIRES:(\all int beginX;0<=beginX<80;);
* (\all int beginY;0<=beginY<80;);
* (\all int endX;0<=endX<80;);
* (\all int endY;0<=endY<80;);
* (\all long request_time;request_time>=0;);
* @MODIFIES: beginX;beginY;endX;endY;request_time;AreaX1 to AreaX4;AreaX1 to AreaX4;AreaY1 to AreaY4;
* @EFFECTS: Set these variables to their initial values;Create area;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public Request(int beginX,int beginY,int endX,int endY,long request_time) {
this.beginX=beginX;
this.beginY=beginY;
this.endX=endX;
this.endY=endY;
this.request_time=request_time;
CreateArea();
}

后置条件:

主要是自然语言描述以及没有对输入非法参数的情况描述

例1:

修改前:

/**
* @REQUIRES:(\all int id;0<=id<100);
* (\all int X;0<=X<80);
* (\all int Y;0<=Y<80);
* @MODIFIES: cars_ID;carX;carY;carCredit;carStatus;hasTask;now_request;load_result;
* @EFFECTS: Set these variables to their initial values;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public CarInformation(int id,int X,int Y) {
this.carID=id;
this.carX=X;
this.carY=Y;
this.carCredit=;//信用值0
this.carStatus=;//等待服务状态
this.hasTask=false;//没有任务
this.load_result=false;
// System.out.println("出租车信息初始化成功");
}

修改后:

/**
* @REQUIRES:(\all int id;0<=id<100);
* (\all int X;0<=X<80);
* (\all int Y;0<=Y<80);
* @MODIFIES: cars_ID;carX;carY;carCredit;carStatus;hasTask;now_request;load_result;
* @EFFECTS: this.carID==id;this.carX==X;this.carY==Y;this.carCredit==0;this.carStatus==2;this.hasTask==false;this.load_result==false;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public CarInformation(int id,int X,int Y) {
this.carID=id;
this.carX=X;
this.carY=Y;
this.carCredit=;//信用值0
this.carStatus=;//等待服务状态
this.hasTask=false;//没有任务
this.load_result=false;
// System.out.println("出租车信息初始化成功");
}

例2:

修改前:

/**
* @REQUIRES:(\all Flow_Count fl;);
* (\all CarInformation[] cars_info;);
* (\all Request_List list;);
* @MODIFIES: flowlist;cars_info;list;
* @EFFECTS: Set these variables to their initial values;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public MakeMap(Flow_Count fl,CarInformation[] cars_info,Request_List list,TaxiGUI g) {
this.flowlist = fl;
this.cars_info=cars_info;
this.list=list;
this.gui=g;
}

修改后:

/**
* @REQUIRES:(\all Flow_Count fl;);
* (\all CarInformation[] cars_info;);
* (\all Request_List list;);
* @MODIFIES: flowlist;cars_info;list;
* @EFFECTS: this.flowlist == fl;
this.cars_info==cars_info;
this.list==list;
this.gui==g;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public MakeMap(Flow_Count fl,CarInformation[] cars_info,Request_List list,TaxiGUI g) {
this.flowlist = fl;
this.cars_info=cars_info;
this.list=list;
this.gui=g;
}

例3:

修改前:

/**
* @REQUIRES: A file with the correct format and content;
* @MODIFIES: The neighbor's sequence of vertices and the value of the adjacency matrix;
* @EFFECTS:Convert the values in a file to node connections;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public void CreateMap() {//根据文件创建地图
}

修改后:

/**
* @REQUIRES: A file with the correct format and content;
* @MODIFIES: The neighbor's sequence of vertices and the value of the adjacency matrix;
* @EFFECTS:for(\all char c;c in file)
(c=='1')==>road is opened;
(c=='0')==>road is closed;
(!((c=='0')&&(c=='1')))==>system.exit(0);
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public void CreateMap() {//根据文件创建地图
}

例4:

修改前:

/**
* @REQUIRES: (\all int id;);
* @MODIFIES: System.out;
* @EFFECTS: find taxi by id;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public void checkBYcarID(int id) {// 通过汽车ID查询
if (id >= ) {
System.out.println("ID越界,查询失败");
return;
}
FileWriter fw;
File printFile = new File(String.format("e://taxi3.txt",id));
if (!printFile.exists()) {
try {
printFile.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} try {
fw = new FileWriter(printFile, true);
@SuppressWarnings("resource")
PrintWriter pw = new PrintWriter(fw); CarInformation info = car_list[id];
System.out.println("查询时刻(100ms为基本单位):" + (long) System.currentTimeMillis() / (long) );
pw.println("查询时刻(100ms为基本单位):" + (long) System.currentTimeMillis() / (long) );
pw.flush();
System.out.println("出租车当前坐标:(" + info.getcarX() + "," + info.getcarY() + ")");
pw.println("出租车当前坐标:(" + info.getcarX() + "," + info.getcarY() + ")");
pw.flush();
String status = null;
switch (info.getcarStatus()) {
case :
status = "服务状态";
break;
case :
status = "接单状态";
break;
case :
status = "等待状态";
break;
case :
status = "停止状态";
break;
default:
status = "非法未知状态";
break;
}
System.out.println("出租车当前状态:" + status);
pw.println("出租车当前状态:" + status);
pw.flush();
} catch (IOException e) {
}
}

修改后:

/**
* @REQUIRES: (\all int id;);
* @MODIFIES: System.out;
* @EFFECTS: (0<=id<100)==>find taxi by id;
(!(0<=id<100))==>return;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public void checkBYcarID(int id) {// 通过汽车ID查询
if (id >= ) {
System.out.println("ID越界,查询失败");
return;
}
FileWriter fw;
File printFile = new File(String.format("e://taxi3.txt",id));
if (!printFile.exists()) {
try {
printFile.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} try {
fw = new FileWriter(printFile, true);
@SuppressWarnings("resource")
PrintWriter pw = new PrintWriter(fw); CarInformation info = car_list[id];
System.out.println("查询时刻(100ms为基本单位):" + (long) System.currentTimeMillis() / (long) );
pw.println("查询时刻(100ms为基本单位):" + (long) System.currentTimeMillis() / (long) );
pw.flush();
System.out.println("出租车当前坐标:(" + info.getcarX() + "," + info.getcarY() + ")");
pw.println("出租车当前坐标:(" + info.getcarX() + "," + info.getcarY() + ")");
pw.flush();
String status = null;
switch (info.getcarStatus()) {
case :
status = "服务状态";
break;
case :
status = "接单状态";
break;
case :
status = "等待状态";
break;
case :
status = "停止状态";
break;
default:
status = "非法未知状态";
break;
}
System.out.println("出租车当前状态:" + status);
pw.println("出租车当前状态:" + status);
pw.flush();
} catch (IOException e) {
}
}

例5:

修改前:

/**
* @REQUIRES: (\all int status;);
* @MODIFIES: System.out;
* @EFFECTS: find taxi by status;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public void checkBYcarStatus(int status) {// 通过状态查询
if (!((status == ) || (status == ) || (status == ) || (status == ))) {
System.out.println("查询状态非法,查询失败");
return;
}
for (int i = ; i < ; i++) {
CarInformation info = car_list[i];
if (info.getcarStatus() == status) {
System.out.println("满足条件的出租车编号:" + info.getcarID());
}
}
}

修改后:

/**
* @REQUIRES: (\all int status;);
* @MODIFIES: System.out;
* @EFFECTS:
((status == 0) || (status == 1) || (status == 2) || (status == 3))==>find taxi by status;
(!((status == 0) || (status == 1) || (status == 2) || (status == 3))) ==>return;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
public void checkBYcarStatus(int status) {// 通过状态查询
if (!((status == ) || (status == ) || (status == ) || (status == ))) {
System.out.println("查询状态非法,查询失败");
return;
}
for (int i = ; i < ; i++) {
CarInformation info = car_list[i];
if (info.getcarStatus() == status) {
System.out.println("满足条件的出租车编号:" + info.getcarID());
}
}
}

按照作业分析被报的功能bug与规格bug在方法上的聚集关系


这里就不放表格了,因为测试的同学(虽然不知道是哪位仁兄)没有对我特别严格,而且实名承认自己是先写的代码后补的JSF,被报的JSFBUG和功能BUG没有对应关系,但不代表JSF的书写没有问题。

下面分析一下功能BUG中的问题,都截取自没有测试没有debug的第九次作业,共3个。

1、等待状态出租车走了回头路:

没有使用真正的随机,而是使用的循环break;使得每次选路都有一定规律,而且使用500ms清空一次流量的办法,数据访问一定的卡顿滞后。

2、等待服务状态20s未停止1s:

在输出和判断逻辑里使用了假时间,但初始为等待状态的出租车在假时间增加上有漏洞,不能按时增加到20s

3、测试接口没有正确实现:

这个Bug....实在是太低级了emmm  因为没有进行任何测试所以也没看出来。原因是逻辑表达式(!((status==0)||(status==1)||(status==2)||(status==3))) 写成了&&

所以,无论多忙,还是要好好测试,好好测试,好好测试!不然八成会凉。


归纳自己在设计规格和撰写规格的基本思路和体会


因为都是写好了代码才补的规格,所以谈不上什么太有价值的体会,只好把自己撰写jsf的主要方法简要谈一谈。

REQUIRES:我一般是光标点到变量上面,利用eclipse自带的阴影检查这个变量是方法内部声明的还是外部可见的。

MODIFIES:特别注意对非内部声明变量的赋值和return。

EFFECTS:一般就讲述什么条件下会得到什么样的返回结果。不要提及算法本身的过程。以及特别注意写明对非法输入参数的处理结果。

THREAD_RQUIRES\THREAD_EFFECTS:查看方法是否带锁。


总结


总之,OO课程虽然接近尾声了,一路遇到了很多很多友好的测试者感觉很幸运很感恩,但并不能因此掩盖自己的问题,我自己心里很明白作为一个预备程序猿和优秀的同学差距还是非常非常大,要学的东西还是太多,以后无论是自学还是正常学习课程都要多向身边比自己强的人谦虚请教,进步,永不止步。

OO课程第三次总结QWQ的更多相关文章

  1. OO课程总结

    OO课程总结 OO终于划上了句号,这学期熬夜熬得最多的一门课,掉了最多头发的一门课. 一.测试与正确性 测试是最最最常见的用来找到程序错误以及验证程序正确的手段,在之前的作业中,写完代码还是会存在很多 ...

  2. 面向对象设计与构造:oo课程总结

    面向对象设计与构造:OO课程总结 第一部分:UML单元架构设计 第一次作业 UML图 MyUmlInteraction类实现接口方法,ClassUnit和InterfaceUnit管理UML图中的类和 ...

  3. OO第四单元总结——查询UML类图 暨 OO课程总结

    一.本单元两次作业的架构设计总结 作业一.UML类图查询 1. 统计信息图 2. 复杂度分析 基本复杂度(Essential Complexity (ev(G)).模块设计复杂度(Module Des ...

  4. 【OO学习】OO第四单元作业总结及OO课程总结

    [OO学习]OO第四单元作业总结及OO课程总结 第四单元作业架构设计 第十三次作业 第十四次作业 总结 这两次作业架构思路上是一样的. 通过将需要使用的UmlElement,封装成Element的子类 ...

  5. BUAA OO 2019 第三单元作业总结

    目录 总 JML规格化设计 理论基础 工具链 规格验证 验证代码 代码静态检查 自动生成测试样例 生成结果 错误分析 作业设计 第九次作业 架构 代码实现 第十次作业 架构 代码实现 第十一次作业 架 ...

  6. OO课程的完结,软件工程学习的开始

    目录 UML小结 阅读学习 大象:Thinking in UML UML精粹 UML和模式应用 本单元作业的架构设计 四个单元中架构设计及OO方法的演进 四个单元中测试与实践的演进 课程收获 三个具体 ...

  7. OO第四单元——基于UML的UML解析器总结&OO课程总结

    OO第四单元--基于UML的UML解析器总结&OO课程总结 前言:一学期愉快(痛苦)的OO课程学习结束了,OO几个单元作业都各有特色,实验也各有特色,仔细回味起来,不再是单纯的敲代码(但自己还 ...

  8. OO第四单元总结暨OO课程总结

    一.第四单元作业总结 本单元的主要任务是对 Uml 图元素进行管理和查询,测试一开始会输入一个静态图,之后会对图中相关内容进行查询. 第13,14次作业 第14次作业新增内容很少,故与第13次作业放在 ...

  9. OO第四单元UML作业总结暨OO课程总结

    目录 目录一.第四单元UML两次作业架构设计第一次作业第二次作业二.架构设计总结与OO方法理解演进三.测试理解与实践演进四.课程收获总结五.课程改进建议六.尾声 一.第四单元UML两次作业架构设计 第 ...

随机推荐

  1. 学习笔记 urllib

    第一步: get # -*- coding:utf-8 -*- # 日期:2018/5/15 19:39 # Author:小鼠标 from urllib import request url = ' ...

  2. 使用NPM安装Vue项目

    使用NPM安装Vue项目步骤如下: 一.先安装node.js,下载node.js安装包,node.js安装成功之后,左击电脑左下角>运行>输入cmd,如下图所示: 二.点击确定进入,分别在 ...

  3. zuul ci

    . ├── a_module ├── b_module ├── lib ├── zuul │   ├── check │   ├── ci │   ├── gate │   ├── layout.ya ...

  4. ios端滚动优化

    加入css -webkit-overflow-scrolling: touch;

  5. leetcode1035

    class Solution: def maxUncrossedLines(self, A: 'List[int]', B: 'List[int]') -> int: m = len(A) n ...

  6. thinkphp5.1 退出登陆操作

    使用Session:: 静态方法即可

  7. 云栖大会day2总结 上午

    第二天上午主要是参与了开发者专场 上 09:00-09:40 线上线下融合时代的工程师成长 李佩 饿了么高级算法总监 09:40-10:20 如何统一阿里巴巴代码规范:探寻工程师文化之路 玄坛 阿里巴 ...

  8. python中线程的知识点

    什么是线程? 程序的执行线路.每个进程默认有一条线程.线程包含了程序的具体步骤. 多线程就是一个进程中有除主线程(默认线程)外还有多个线程. 线程与进程的关系(进程包含线程,而线程依赖进程存在) 1. ...

  9. Why Everyone Should Lift Weights

    Why Everyone Should Lift Weights by James Clear I'll say it plain and simple: you should be lifting ...

  10. 把http网站变成https网站

    所需条件: 一个网站域名,必须是注册的合法域名,国内域名最好已经通过备案: 一个空间,可以是虚拟空间或者云主机: 一张SSL证书. 操作步骤: 域名注册.国内的有万网和国外GoDaddy,当然域名注册 ...