【做业3.0】HansBug的第三次博客规格总结

转眼间第三次做业了,彷佛须要说点啥,那就说点。java

规格&工业

说到这个,不得不提一下软件开发的发展史。git

历史的进程

早在上世纪50年代,就已经有早期的编程语言出现,也开始有一些程序编写者出现(多为资深电子工程师,和半路出家的数学家)。程序员

然而那个时代,软件开发基本局限于本身或本身部门内部的使用,需求并无不少,也并不复杂(或者说人们并无意识到有那么多事情能够经过软件解决)。因此基本都是靠早期的程序猿们的自由开发,也并无现代代码规范的概念。github

然而等到了60到70年代,随着硬件技术和工业界思想的进步,软件层面上的需求愈来愈多,愈来愈杂,且再也不局限于本身的使用,开始有了各种外包的需求(早期的软件做坊、外包公司)。这时候,人们发现代码规模一上来,工程质量将再也不那么可控。不只开发成本随规模急剧上升,且开发过程当中的人员与工程管理也出现了很大的麻烦。失败的案例不在少数,工期拖延数月甚至数年的也经常发生,并且还颇有可能没法知足用户的需求或者可靠性极差。软件工程迎来了一个动乱的年代正则表达式

1968年,北大西洋公约组织的计算机科学家在联邦德国召开的国际学术会议上第一次提出了“软件危机”(software crisis)这个名词。算法

归纳来讲,软件危机包含两方面问题:编程

  • 如何开发软件,怎样知足对软件日益增加的需求
  • 如何维护数量不断膨胀的已有软件

1968年秋季,NATO的科技委员会召集了近50名一流的编程人员、计算机科学家和工业界巨头,讨论和制定摆脱“软件危机”的对策。在那次会议上第一次提出了软件工程(software engineering)这个概念。软件工程正式被列为工程的一种,并开始走向专业化系统化,以全新的面貌从新步入工业界。数组

现代的软件工程是一门研究如何用系统化、规范化、数量化等工程原则和方法去进行软件的开发和维护的学科。经过前人的不断努力,人们逐渐解决了软件危机,并认识到规格化设计的重要性,在此期间,一些重要的文档格式的标准被肯定下来,包括变量、符号的命名规则以及源代码的规范式。后来随着发展,这些规范逐渐造成了软件开发中的规格化设计,而且因为其高效性与高可靠性,愈来愈受到软件开发人员的重视。架构

我的的奋斗

结合我我的嘛,其实也是能说上一些的。因为笔者在早年长期处于自由成长阶段,因此其实不少发展历程,和历史的进程十分类似。编程语言

笔者从2年级初学编程(2005年,豆腐块+win2000的年代),最初写的都是一些很小的程序(基本不存在超过100行的状况),用的是面向过程语言和原始的面向对象语言。(Pascal、VB6,后来进阶VB.NET)

说实话,笔者之因此喜欢编程,喜欢计算机,很大程度上喜欢的是创造的快感,尤为是计算机这种低成本高回报即刻见效的创造。因而呢,笔者逐渐在试着编写规模更大程序,来知足一些更加实际的需求。在那个阶段,笔者的开发彻底是怎么顺手怎么来,毕竟急于得到那种看到成果的快感,且尚未造成工程的思惟(和不少同窗现阶段的状态相似)。

然而,笔者在初中那会就发现了一件很头疼的事情——但凡程序超过500行,不管再简单的需求,再明确的目的,本身都会开始控制不住局面。具体的表现为,只要规模一上去,哪怕本来早就想清楚了一切,在debug的时候仍是不是这里出错就是那里出错,甚至自觉得改好了一边,而后另外一边又被带出毛病的状况也时有发生。

那个阶段,能够说,笔者本身软件开发的投入成本随代码量上升而上升的幅度是指数级别的。

笔者曾经被这个问题困扰了很是久,一直处于这样的一个瓶颈期,难以突破。

直到高中,接触了github,上去看了一些各个语言的开源代码以后,才恍然大悟。笔者发现:

  • 不少的开源代码,都配备了相关的说明文档,并且格式整齐内容齐全,查找相关信息至关的方便。
  • 点开代码以后,发现不少地方都有注释(甚至注释行数和代码行数比例已经接近1:1),说明相关位置的功能与需求。(相似于规格的requires和effects)
  • 不只如此,连类、方法,甚至局部变量的命名,格式都十分整齐。(求读者别笑,笔者曾经一切数组命名均为abbd,其余变量都乱用单个字母)
  • 各个类、方法,各司其职,或者说谁都自扫门前雪,无论他人瓦上霜。

因而,解决方案就很是明显了——代码规范化。由于,多花这些时间作好这些工做,对于全局而言,实际上并不下降效率,正所谓磨刀不误砍柴工。

当笔者得到进一步能力提高以后,就开始开发更大规模的程序。

然而,当正式步入工业界时,另外一个很现实的问题产生了——对于上层的工程师或架构师,该如何对全局化系统化地设计一个系统

亲手码代码显然速度太慢,且只能一我的干,不具有可合做性,没法发挥并行优点。然而设计不实现好的话,又该如何描述设计?

答曰——规格。架构师只须要将各个部分的规格设计好,规定好出入口条件等信息,由下位程序猿进行完成便可。既准确描述需求又提供了测试根据,一箭双雕。

规格与bug相关性分析

规格错误

笔者未被报过规格错误。

bug分析

笔者

在第十一次做业中,被友善好心素质优良情商天下第一的测试者找到了bug,分别是:

  • 未过滤map.txt内的空白字符
  • 未过滤lights.txt内的空白字符
  • 在直路或者断头路加上红绿灯后未输出错误信息

很明显,这三个均不是内部功能性上的错误。

能够说是笔者的需求分析失误。(前两个隐藏在指导书上的一个角落中,后一个隐藏在第十次做业的issue区。)

相关性分析

因为笔者未被报过规格错误,且bug均为需求研究层面上的疏漏,故不存在相关性。

规格举例

笔者认为,实际上,只要搞清楚规格的做用与意义,不少问题就应该迎刃而解,无需举过多的例子

反面教材

说到规格的一些不太好的用法,其实最典型的有如下几种

过分使用天然语言

字面意思,有些很好用布尔表达式表达的却恰恰用了天然语言

/**
 * @requires: true;
 * @modifies: None;
 * @effects: result will be the equation between a and b;
 */

应该改成

/**
 * @requires: true;
 * @modifies: None;
 * @effects: \result == (a == b);
 */

使用具体算法表示规格

规格,讲究的是个对于局部抽象功能的描述。说白了,它只关心这个方法或者类应该实现什么样的一个功能,而不关内心头具体是怎么实现的,同时,给出的规格条件必须具有可断定性

例如程序(GenericPair为泛型二元对类):

public static GenericPair<Integer, Integer> whatCanYouSee(int a, int b) {
    int c = a + b;
    b = c - b;
    a = c - a;
    return new GenericPair<>(a, b);
}

仔细看的话,应该不难发现其实功能是交换了ab的顺序后存入了GenericPair内。

然而规格很容易被写成以下的形式:

/**
 * @requires: true;
 * @modifies: None;
 * @effects: 
 *                 c == (\old(a) + \old(b));
 *                 b == (c - \old(b));
 *                 a == (c - \old(a));
 *                 result will be new GenericPair<>(a, b);
 */

而正确的应该是改成先后置约束条件。

/**
 * @requires: true;
 * @modifies: None;
 * @effects: (\result.first == b) && (\result.second == a);
 */

方法内局部变量写入modifies

实际上,笔者见过一些同窗,在初学阶段把局部变量的修改也写入了modifies。相似这样:

/**
 * @requires: true;
 * @modifies: z;
 * @effects:
 *                 z = x * y;
 *                 \result == (z + x + y);
 *                 
 */
public static void privateVariableSample(int x, int y) {
    int z = x * y;
    return z + x + y;
}

不过,仍是那句话——规格只关心这个方法或者类应该实现什么样的一个功能,而不关内心头具体是怎么实现的

局部变量彻底是属于方法内部的东西,并不属于外部设计者须要关心的范畴。因此,不该写在modifies内,与之相关的表达式在effects关键字中也应该展开表达。

/**
 * @requires: true;
 * @modifies: None;
 * @effects:
 *                 \result == (x * y + x + y);
 */
public static void privateVariableSample(int x, int y) {
    int z = x * y;
    return z + x + y;
}

不符合javadoc基本格式规则

其实,这一点是ppt上的错误示范致使的。笔者在第十次做业报了对方一个这样的JSF错误,然而鉴于对方认为ppt上有相似的格式,因此笔者只好先选择了仲裁。

实际上,JSF这样的东西,从一设计,就是要面向自动化的,同时继承了doclet(笔者有幸阅读过JSF源代码),就是为了完美兼容和扩展javadoc。而违反javadoc基本格式规范的行为,显然与这一设计初衷不符。建议课程组看到以后对相关部分进行全面的修改。

错误示范一(第九次PPT,P16):

javadoc基本格式中间行开头都是须要*的,且首行(两个*的行)不要写东西。开头的*也最好严格对齐。

错误示范二(第十次PPT,P9):

理由同上

相似这样的错误示范还有很是多

此外,其实关于javadoc的格式,在idea(或者说jetbrains系列IDE)中,直接键入/**并回车便可生成正确规范的格式。

感想

关于规格

其实,根据笔者的了解,严格工程开发是这样的一个流程:

能够看出,规格、不变式在开发、测试环节中扮演了至关重要的角色

  • 为开发组提供了实现程序内部具体代码的需求依据
  • 为测试组提供了编写单元测试的需求依据
  • 为架构师提供了架构依据,和严格论证正确性的依据(在航空航天等对软件质量有极高要求的行业内,这一点尤为重要)

固然,实际上,在一些非高度严格的工程代码中,甚至不写规格也是很常见的。例如笔者参与过的创业公司内的开发,多为敏捷开发,且攻城狮开发经验均较为老道,彻底有能力紧紧掌握全局

不过,敏捷开发对攻城狮自身素养要求是很高的。而若是想普遍地扩大生产力,则这样子成本无疑太高。

这时候,强类型面向对象语言、代码规范、文档规范、规格就得以体现其做用:

  • 对底层开发者而言,开发只须要严格按照规格需求,便可撰写程序和文档。程序员工做技能门槛变得很低,有利于普遍招募廉价生产力,创造更多效益
  • 严格约束底层开发者的开发行为,而且能够进行严格的量化考核,管理起来很方便
  • 对于上层的攻城狮和架构师,其编程行为即为规格编写,再也不须要具体地去实现每个内部的细节(或者说只要规格需求能知足,内部实现细节并不那么重要)。工程师工做效率得以提升

生产力决定生产关系,生产力量变引起社会质变,这样的结论在计算机行业同样适用。由于,工业界,其终极目标永远只有一个——创造更多价值

关于JSF

JSF根据笔者了解,彷佛是之前的某位学姐的毕业论文。以及,彷佛课程组对这样一个东西情有独钟。

咱们先来看看JSF为人称道的地方:

  • 采用布尔表达式,便于自动化生成单元测试*(的确,有了require、effects条件,就彻底具有单元测试的基本属性了)
  • 轻量级,继承自doclet,可扩展进javadoc

看似,的确是个好东西,并且理论上确实如此。然而,理论和实际老是存在着不可忽视的差距的:

  • 采用布尔表达式,因而不少东西变得再也不有正常表达的可能(例如,正则表达式断定,难道使用者还须要把整个正则表达式庞大的逻辑像写verilog似的表达出来?)
  • 对override,继承的支持至关贫乏(这意味着,若是想要彻底完整的表达表达式,在继承层数较多的状况下,表达式规模将无限膨胀,友好性极差)
  • 容错性将是另外一个很棘手的问题。用布尔表达式为了什么?很明显最终目的是实现自动化。然而用户只要写的稍有欠缺(哪怕小到彻底不影响人工编程和人工测试的地步),单元测试的生成都将出现巨大问题。
  • 不只如此,对于一些没法表达的东西怎么办?
    • 用天然语言?那么还打算怎么自动化?自动化生成一小部分而后人工再写?这样高不成低不就的解决方案用户体验并很差
    • 进一步扩大语法?咱们暂且先认为存在这种完备的语法设计,就算全都能用布尔表达式表达了,那么这样一个东西轻量化的优势将不复存在。同时,你也会发现,这种完备的表达式,已经和直接写单元测试差很少少了。那么自动化难道就是帮人近似的抄一遍程序?很抱歉,这样的自动化毫无心义,工程师们不可能买帐的。与其这样还不如直接写单元测试,而后用脚本将单元测试程序拷贝到对应的方法注释上。

这么看下来,彷佛惟一还能够的地方就是javadoc的兼容性设计了。

JSF的设计宗旨是为自动化提供可能,而且具有轻量级特性。然而就目前的JSF而言,能够说是很是尴尬的存在——本是追求自动化的,但是自动化却作得局限这么大,作得这么不到位,并且实际写起来对用户要求还极高,和天然语言比起来体验只差很差。

综上,笔者以为,若是JSF不良好的解决自动化问题,或者从新对这种工具进行需求定位的话,这样的东西将不存在实际应用到工业界的可能性。(笔者也对这种东西的前景持消极态度)

关于某位大佬

emmm。。。说在前面,若是读者您看不懂这段话在说啥的话,那说明不是写给您的,您能够直接跳至下一个段落,感激涕零

我相信您老人家此次必定又在看个人博客。嘛。。。本菜的博客有您这样的粉丝,实属蓬荜生辉。

以前已经给您写了一些话,我已经深入沉痛深切地检讨了个人过错,还望大佬您海涵。

做为本菜对友善好心素质优良情商天下第一的大佬您的赔礼道歉,我为大佬送上一句大佬本身说出来的金句——“对了,情商是个好东西”

emmm。。。笔者认为,对于这样的大佬这一句还不够,那么,再来两句——“种瓜得瓜种豆得豆”“己所不欲勿施于人”

其余更多的话,本菜坐卧不安,不敢多言。由于您这样神通常的大佬哪里是我这样的人能够教育的了的呢。

好的,可爱的笔者抽风完毕。接下来正文继续。

关于规格制度设计上的我的意见

其实,规格的意义与重要性,笔者在上面均已经进行了论述。这一点丝绝不值得怀疑。

可是,这样的制度直接照搬进了一个面向小白的OO课程,并且还如此草率地归入互测考核,真的合适么?

笔者给出的答案是否认的。

首先,在目前这样的课程制度设计下,彻底不能体现规格的重要性。最典型的一点,就是先写程序后写规格。这显然是错误的作法,然而,这样作的不只仅是大部分同窗们,还包括课程的设计——出租车做业第一次并不要求规格,从第二次才开始要求。这意味着什么?这意味着你们第二次出租车做业将花费大量的时间补第一次的规格(甚至花在这上面的时间远远多于正确使用规格的时间)。给第一次接触规格的同窗们上来就是这样的彻底错误的引导,显然是不合适的。

其次,JSF的各类槽点,上面已经吐槽过了,用户体验至关差,此处再也不赘述。并且当JSF归入考核以后,因为不得不使用部分天然语言,而致使你们都使用天然语言描述的状况不断地发生,然后课程组还给出了require必须布尔表达式的要求,然而根据笔者的调查和了解,并无起到预期的效果。能够说,JSF的强行推广是至关失败的

不只如此,咱们来回想一下,JSF互测,评判者都是些什么人——同样还没有造成工程思惟,同样不熟悉规格设计的小白同窗。把这样的东西的评价权力直接交给自顾不暇的初学者,或者说得更直接点,让不懂工程的人强行评判工程的好坏,这样的作法显然很荒唐。这样只会致使测试者无从下手(甚至干脆选择不讲道理乱扣分),而被测试者的公平与利益毫无保障

不一样于BUG互测(实际上笔者支持保留BUG的互测),JSF这东西不少同窗都是第一次接触,工程思惟不少同窗都尚未造成。也许对于职业攻城狮和其余从业人员而言,他们内心都一把评判的尺子,也具有最最基本的职业道德和职业素养。可是对于初学阶段,各方面水准参差不齐的学生而言,这样的作法显然太过于理想化了。

此外,课程组还彷佛单纯的想依靠高伤害和仲裁机制来保证你们的重视与制度的公平性。可是,在目前这样双方都一脸迷茫的情况下,这样是毫无效果的(甚至能够说弊远远大于利)。盲目的高伤害只会致使你们愈来愈没有努力的动力(由于再努力再踏实也没有有些良心历来不会痛的投机分子过得舒服,本身的努力在高伤害面前一文不值),而滞后至关严重的仲裁制度更是致使你们再也不那么相信正义的存在,可谓雪上加霜(迟来的正义,经常和没来没有区别)。

然而,据笔者所知,课程组彷佛在根据经过这样收集到的数据来进行数据分析,并且彷佛还分析了与bug的相关性,不只如此,甚至还得出了同窗们不够重视JSF的结论。对此,我只想说,这样的数据,与其说是JSF评判的最终结果,倒不如说是博弈的最终结果,公平性真实性根本保证不了。用了个错误的前提条件,获取了所谓预期的分析结果,是毫无心义的

综上,笔者以为不该该在使用互测制度来考核JSF,而应该将评价权交给更加专业的人士。一方面保证同窗们能受到正确的引导,另外一方面也保证制度的公平与合理,此外,也保证数据收集工做真正的客观性与有效性

相关文章
相关标签/搜索