【作业4.0】HansBug的第四次面向对象课程思考

嘛。。不知不觉这门课程要结束了,那么就再说点啥以示庆祝呗。

测试vs正确性论证

说到这个,相比很多人对此其实很有疑惑,请让我慢慢分析。

逻辑概览

首先我们来看看两种方式各自的做法和流程是什么样的:

单元测试

在测试中,我们是这样的一个流程
【作业4.0】HansBug的第四次面向对象课程思考

此外,为了保证测试能覆盖到工程代码的每一个区域,需要保证测试的覆盖率

正确性证明

在证明中,我们是这样的一个流程
【作业4.0】HansBug的第四次面向对象课程思考

在这一过程中

  • 基于行为分析的repOk永真性证明依赖于JSF中的modifies
  • 方法正确性将基于JSF中所描述的effectsrequires
  • 各方法内其他方法的调用需要依赖被调用方法的正确性,具体来说
    • 对于系统自带的类与方法实现一律默认正确
    • 对于其他位置的调用,正确性则依赖于其具体方法或类的正确性证明

关键细节

基于以上的逻辑,我们不难发现一个细节:

  • 在单元测试的流程图上,当程序通过测试后,是假定程序为正确而不是程序为正确

或者更具体地说,这里多出了一个名为假定的字眼。

这是什么原因的?其实说来也非常简单——因为测试,只能证明程序有错,而不能证明程序是对的

虽然有大数定律的理论支撑(即只要测试集数量无限大,则必定可以覆盖一切情况),可是实际上并不存在无限大的测试集,故测试上的死角总还是会存在的。

设一个有限集 $ T $ ,为测试集(单元测试中的测试集不可能做到无穷),而 $ S $为全集。然而,在实际情况下,可能遇到的情况常常是无穷多的,故 $ S $ 是一个无穷集。

故,$ \complement^{S}{T} $ 即为测试集没有覆盖到的地方。又 $ T $ 有穷, $ S $ 无穷,故 $ T \subset S $ 恒成立,$ \complement^{S}{T} \neq \emptyset $

故永远有覆盖不到的数据,且对于这部分无法覆盖到的区域,是无法仅依靠测试来证明正确性的。

基于测试的正确性验证的严谨性问题是不可避免的若要严格意义上地论证正确性,基于程序逻辑的正确性证明是唯一的选择

异与同、取与舍

在上面的分析中,我们论证了单元测试方法存在的硬伤。

然而,我们为啥还要保留这样的方法呢?

因为,实际问题与应用大都不是一元线性的,而是时间、经济、人力等多方面成本以及多方面效益指标所构成的高维量

其实,在工业界各类应用中,常常有以下两种模式可以长久而稳定的存在:

  • 较高的成本,绝对高的质量(或者说其质量水准具有不可替代性),但是部署门槛稍高
  • 成本低廉,较高的质量,且易于广泛普及与部署,易于操作易于维护

实际上,不仅在计算机行业,在其他工业界乃至于商业中,也常常会形成这样两种模式并存的局面

而反映在软件质量保证领域,则分别是基于程序设计逻辑的正确性证明(正确性从原理层面上就有绝对的保障,可是成本嘛,各位都写过一次论证,体验过其成本之高昂)和面向数据期望的单元测试(操作非常简便,方便大范围部署,且能覆盖绝大部分实际情况)。

所以,在实际应用中

  • 严格的正确性证明常常只会被运用在一些对产品质量要求绝对高的局部区域(例如航天器的核心控制程序,对错误的容忍度为零)
  • 普通的单元测试则会被广泛运用在一般工程项目的测试中(对错误有一定的容忍限度,但务必兼顾时间、经济成本和效益,创业公司的项目中更是如此)

说到底,这两者其实很难去严格区分一个优劣。很多问题,根本上还是一句话——具体问题具体分析,适合的就是对的

OCLvsJSF

何谓OCL

OCL,英文全称object constraint language,翻译过来就是对象约束语言

顾名思义,其作用在于对设计的对象进行约束,且保证不存在二义性。且实际上,OCL和UML(统一建模语言,Unified Modeling Language)捆绑使用。

异与同

从以上的一些基本概述中,我们不难发现OCL实际上和JSF有着相似之处:

  • 都是对于程序设计上的约束(其中包含了类合法性、以及方法行为等要素)
  • 最终目标都是描述程序设计的预期行为,作为一个统一的标准

然而进一步研究与分析,其区别也是很大的:

  • 首先,OCL约束的核心对象和JSF有较大差别。JSF在围绕方法和类,而OCL则在对象,以及对象内、对象间所包含的数据项
  • 基于以上的原因,OCL的表达能力远远比JSF丰富。OCL作为约束语言,可以*地约束各处的数据项和设计规范。而JSF的不变式约束相比之下就逊色了非常多。
  • 也正是由于OCL的丰富性和完备的可计算性,所以OCL完全具备类似SQL那样的查询能力。
  • 但是,为了支撑如此庞大丰富的能力,且保证无二义性,OCL所付出的代价就是重量化。而JSF则相比之下更轻便更快捷。

而至于具体应用呢,则还是老规矩——适合的就是最好的。在不同的工程项目,不同的场合下,自然会有不同的选择。

关于第十四次作业

UML类图

【作业4.0】HansBug的第四次面向对象课程思考

顺序图

【作业4.0】HansBug的第四次面向对象课程思考

状态图

【作业4.0】HansBug的第四次面向对象课程思考

其他

知识点之间的关系

首先,我们来回顾下我们这学期四章的各个标题:

  • 第一章 Java与对象(Java和面向对象基本概念入门)
  • 第二章 并发与安全(多线程程序设计入门)
  • 第三章 抽象与规格(规格化与整体设计进阶)
  • 第四章 测试与论证(工程化质量保证措施学习与体验)

其实这很明显,是一个循序渐进的过程,体现在两个不同的层面上:

  • 从学生学习的角度而言,知识体系是层层递进的
  • 从工业生产的角度而言,这个也很接近一个产品从设计到交付,自底向上的一个完整流程

个人收获与小结

实际上,笔者在多年前,就已经接触并使用了面向对象程序设计语言。

所以,实际上在这个学期,笔者的主要收获如下:

  • 通过十几次作业对程序框架设计的反复揣摩,笔者在整体框架设计上的水平更加趋于成熟
  • 更加深入的了解了严格工业界的一些做法(例如广泛地规格化程序设计,以及正确性证明等)
  • 此外,笔者结合之前多年的实践经验(理论课上讲到过的坑,笔者当年几乎全都亲自踩过一遍)和对工业界的一些基本了解(笔者已经做过多笔的外包项目,目前仍在着手运营的项目也有数个),对面向对象和工程化的理解也更加深入了

工程化的个人见解

关于工程化呢,其实说难也难,说简单也简单得很。

一些具体的好处呢,笔者在前三次博客作业中均有不同程度的论述(此处不再赘述):

不过说到底呢,其实就几件事:

  • 任何时代任何情况下,左右战局的决定性因素,永远是人
  • 因此,工程化的一个基本思想就是以人为本
    • 从开发者角度,为开发者提供方便提高效率(无论是短期还是长期,无论是单人还是团队,都是需要考虑的)
    • 从商业团体角度,提高整体战斗力,创造更大的效益和价值
    • 从用户角度,让用户体验更优(或者说给用户提供足够的方便),让用户更加愿意直接或间接地掏腰包(统计意义上的)
  • 此外,对于不同的解决方案,一般情况下存在即合理(或者说,对于还没有被淘汰的解决方案,其存在终究是可以良好满足某些场合下的需求的)。对此,我们该做的,就是具体问题具体分析,选择在具体情况下最优的方案

课程思考与建议

个人的思考与建议

关于这个问题,笔者在两三个月前,就已经开始思考了。

众所周知,面向对象课程的槽点还是不算少的。

不过,据笔者看,这些问题看似庞杂,但是只要仔细去理一理背后的逻辑关系,其实也很简单

笔者根据自身了解的一些事实,和大半个学期以来的观察与分析,粗略的得到了下面的这张逻辑图:

【作业4.0】HansBug的第四次面向对象课程思考

不过这样一来,看似错综复杂的事情也就清楚了。

稍加观察,便可以发现问题的根源——没有一个相对公平合理的横向比较机制。(稍微了解拓扑排序的概念,便可以得出这样的结论,找到节点的上游)

其实,很多同学(包括16级的和以前的学长学姐们)之前所吐槽过的问题,根源都在这边。

假如,我们有一个很靠谱的自动化横向比较机制

  • 那么,我们的分数将更具有梯度和区分度,且评分核心依据将是程序的真实质量
  • 那么,互测的实际门槛将可以考虑提高,互测人员的整体素质也将提高
  • 那么,基于上一条,我们将不再需要每次祈祷不遇上坏人(指的是为了自己的分数可以不要脸良心还从不痛的那种)
  • 那么,基于上一条,我们的助教们将不再需要面临巨大的仲裁任务压力
  • 那么,基于上一条,我们的同学们将不再需要承受等待助教仲裁的痛苦煎熬
  • 那么,我们的评测将可以考虑部分模糊化,以适应模糊化的需求
  • 那么,基于上一条,我们的同学可以不再不停地纠结需求细节(常常还是无关紧要的细节),助教们也将大大减少issue答疑时间
  • 那么,基于以上所有条,我们的同学们的整体体验将有质的飞跃
  • 那么,基于上一条,同学们将更加愿意积极努力学习这门课程

实际上,想做出改变,也并不难,比如:

  • 公测不再严格面向bug出数据。或者至少不完全面向bug,面向bug的部分可以作为功能性弱测。
  • 自动化公测引入模糊化测试。比如类似于oj中的Special Judge和提交答案题里面的部分分机制相结合,让程序只要不违背基本法(例如电梯不准瞬移不准分身)就能有分数,且各个水准的程序得分有梯度。
  • 可以将面向bug的功能性弱测和模糊化性能强测相结合,构建出更有游戏性的制度(也可以允许在一定时间内公测多次提交,多次刷分,追求卓越)。
  • 由此,可以基于公测最终成绩,设立一定的互测门槛,通过门槛者方可进入互测环节。
  • 在互测环节中,可以设计类似codeforces那样的多对多大混战hack模式(也可以考虑待测程序不匿名,从此不再有无效作业的坑),保证互测的运气成分降到最低

当然以上只是一些初步构想,笔者对于这个(自认为)靠谱的新制度,已经有了更深层次的计划和构想,更具体的计划等细节将在另一篇文章中详细阐述。

想对接下来的分析者们说的一些话

笔者写到这里之前,看过之前不少同学的一些思考与建tu议cao。

不得不说,虽然大部分的所谓分析完全流于表面,透过现象看本质的几乎没有(截至2018.6.25 6点整),但是,大家反映的问题,也很真实,或者说很真实地描绘了大众水平同学眼中的面向对象课程

说这个,其实不是想吐槽各位(实际上,笔者更希望大家能继续描述内心的真实体验)。

引用笔者之前说过不止一遍的一句话

没法带来丝毫改变,甚至只会让事情更坏的怒火,是毫无意义的。

所以呢,希望接下来看到笔者文章的各位,能在吐槽的基础上和自身能力所及的情况下,进行更深入的思考,可以的话也多想想到底如何才能让事情变得更好,而不是一味地抱怨与泄私愤。

抱怨没有用,实干才能解决问题

上一篇:Taro开发微信小程序


下一篇:【转】如何查看linux版本 如何查看LINUX是多少位