调研规格化
历史
在20世纪50年代,软件伴随着第一台电子计算机的问世诞生了。以写软件为职业的人也开始出现,他们多是经 过训练的数学家和电子工程师。
1960年代美国大学里开始出现授予计算机专业的学位,教人们写软件。
在计算机系统发展的初期,由于目的的单一性,软件的通用性是很有限的。大多数软件是由使用该软件的个人 或机构研制的,软件往往带有强烈的个人色彩。早期的软件开发也没有什么系统的方法可以遵循,软件设计是在某 个人的头脑中完成的一个隐藏的过程。而且,除了源代码往往没有软件说明书等文档。
从60年代中期到70年代中期是计算机系统发展的第二个时期,在这一时期软件开始作为一种产品被广泛使用, 出现了“软件作坊”专职应别人的需求写软件。这一软件开发的方法基本上仍然沿用早期的个体化软件开发方式,但 软件的数量急剧膨胀,软件需求日趋复杂,维护的难度越来越大,开发成本令人吃惊地高,而失败的软件开发项目却屡见不鲜。“软件危机”就这样开始了!
“软件危机”使得人们开始对软件及其特性进行更深一步的研究,人们改变了早期对软件的不正确看法。早期那 些被认为是优秀的程序常常很难被别人看懂,通篇充满了程序技巧。现在人们普遍认为优秀的程序除了功能正确, 性能优良之外,还应该容易看懂、容易使用、容易修改和扩充。
1968年北大西洋公约组织的计算机科学家在联邦德国召开的国际学术会议上第一次提出了“软件危机”(software crisis)这个名词。 概括来说,软件危机包含两方面问题:一、如何开发软件,以满足不断增长,日趋复杂的需求; 二、如何维护数量不断膨胀的软件产品。
1968年秋季,NATO(北约)的科技委员会召集了近50名一流的编程人员、计算机科学家和工业界巨头,讨论 和制定摆脱“软件危机”的对策。在那次会议上第一次提出了软件工程(software engineering)这个概念。
为什么要重视规格化
人类从原始的自然人开始,在与自然的生存搏斗中为了交流感情和传达信息的需要,逐步出现了原始的语言、符号、记号、象形文字和数字。从第一次人类社会的农业、畜牧业分工中,由于物资交换的需要,要求公平交换、等价交换的的原则,决定度、量、衡单位和器具标准统一,逐步从用人体的特定部位或自然物到标准化的器物。
当人类社会第二次产业大分工,即农业、手工业分化时,为了提高生产率,对工具和技术规范化就成了迫切要求,从遗世的青铜器、铁器上可以看到那时科学技术和标准化水平的发展。宋代毕昇发明的活字印刷术,运用了标准件、互换性、分解组合、重复利用等标准化原则,更是古代标准化里程碑。
进入以机器生产、社会化大生产为基础的近代标准化阶段。科学技术适应工业的发展,为标准化提供了大量生产实践经验,也为之提供了系统实验手段,摆脱了凭直观和零散的形式对现象的表述和总结经验的阶段,从而使标准化活动进入了定量地以实验数据科学阶段,并开始通过民主协商的方式在广阔的领域推行工业现代进程中,由于生产和管理高度现代化、专业化、综合化、这就使现代产品或工程、服务具有明确的系统性和社会化,一项产品或工程、过程和服务、过程和服务,往往涉及几十个行业和几万个组织及许多门的科学技术,如美国的 "阿波罗计划"、"曼哈顿计划",从而使标准化活动更具有现代化特征。
规格化设计也是如此,通过满足规格的设定来撰写相应程序,达到满足规格的效果,加强了编码的交互能力,加强了封装性和用户体验。
规格bug与分析
错误类型 |
代码行数 |
Modifies不完整 |
40 |
Effects 逻辑错误 |
124 |
规格的错误有的是第一次写没仔细看把effects的布尔表达式的“==”写成了赋值符号“=”,以及其他的一些用法不正确,modifies的错误多数是因为改动了函数方法体,忘记改规格了。
功能bug与分析
第九次作业——带流量和开关道路功能的出租车
Loadfile读入map部分为空,会出现重复输出一行错误提示符的crash现象,忘记输出出租车去接乘客过程中经过的地点和时间。
第十次作业——带红绿灯功能的出租车
出租车送完乘客会瞬移会接乘客的位置,原因是有几步的代码写错位置了,真假时间混用,结果造成有时候输出文件中使用的假时间显示已经到了目标位置,但其实真正的出租车还没有到,使得该抢的单没有抢。
第十一次作业——最后一次出租车
没看清指导书,将信用值+1在时间窗口结束后才实现,使得信用值输出结果不准确。第一次出租车作业对文件读取的实现比较粗糙,空格和制表符的过滤存在问题。
与规格bug的聚集关系
总体来说,有功能错误的地方规格一般写的也不太好,用自然语言概括得笼统,对实现代码的编写带来了麻烦,所以使得功能bug就出现了。
规格改进
前置条件漏写
修改前
/** *@REQUIRES: None; *@MODIFIES: None; *@EFFECTS: normal_behavior * pos == pos1; * time == time1; */
修改后
/** *@REQUIRES: 0<=pos1<6400; *@MODIFIES: None; *@EFFECTS: normal_behavior * pos == pos1; * time == time1; */
modifies漏写
修改前
/** *@REQUIRES: None; *@MODIFIES: map,change_time,System.out,clock,begin; *@EFFECTS: normal_behavior * 为一些数据作初始化工作; */
修改后
/** *@REQUIRES: None; *@MODIFIES: map,change_time,System.out,clock,begin,now_t; *@EFFECTS: normal_behavior * 为一些数据作初始化工作; */
后置条件逻辑不正确
修改前
/** *@REQUIRES: None; *@MODIFIES: map; *@EFFECTS: normal_behavior * map = map1; */
修改后
/** *@REQUIRES: None; *@MODIFIES: map; *@EFFECTS: normal_behavior * map == map1; */
多线程规格理解不正确
修改前
/** *@REQUIRES: (choice.get(i) exists); *@MODIFIES: queue; *@EFFECTS: normal_behavior * queue.add(r); * (!exist File(f_n)) ==> exceptional_behavior(Exception); *@THREAD_EFFECTS: locked(); *@THREAD_EFFECTS: locked(this); */
修改后
/** *@REQUIRES: (choice.get(i) exists); *@MODIFIES: queue; *@EFFECTS: normal_behavior * queue.add(r); * (!exist File(f_n)) ==> exceptional_behavior(Exception); *@THREAD_EFFECTS: locked(); */
使用自然语言过多
修改前
/** *@REQUIRES: (1<=ID<=100); *@MODIFIES: id,taxilist,map,credit,state,pos,x,y,MainClass.gui,System.out,begin_t,src; *@EFFECTS: normal_behavior * 初始化出租车;
*/
修改后
/** *@REQUIRES: (1<=ID<=100); *@MODIFIES: id,taxilist,map,credit,state,pos,x,y,MainClass.gui,System.out,begin_t,src; *@EFFECTS: normal_behavior * id == ID; * taxilist == tl; * map == map1; * credit == 0; * state == 2; * pos == getrandom(); * x == pos/80; * y == pos%80; * MainClass.gui.SetTaxiStatus(id,new Point(x,y),state); * begin_t == begin_t / 100; * begin_t == begin_t % 100; * src == -1; */
总结
我写jsf一般会先确定读入的参数,知道了参数根据要实现的方法确定范围,requiers就确定了。对modifies就是不能漏写,注意函数内部有没有对一些变量的值进行修改,还有返回值得问题。Effects都是写完了方法才完成,就是看代码和写之前的思路,能用布尔表达式的用,写不出布尔表达式的就用自然语言。
实话说,第一次补全jsf花了超级久的时间,因为格式问题又全部改了一次,绞尽脑汁写布尔表达式,结果知道可以用自然语言心如死灰,虽然知道规格应该在实现功能前完成,但是我一般都是最后写,感觉其实得到的训练很少。不过规格的存在使得阅读别人的代码变得稍微简单一点,写得好的规格可以知道这个函数具体实现的功能,还是有很大作用的。写了很久的多线程,这几次作业也都运用考察了规格,虽然暂时还没有完全消化吸收所有内涵,但是我相信只有坚持下去,应该对我的代码编写也很大帮助。