【作业4.0】HansBug的第四次面向对象课程思考
嘛。。不知不觉这门课程要结束了,那么就再说点啥以示庆祝呗。
测试vs正确性论证
说到这个,相比很多人对此其实很有疑惑,请让我慢慢分析。
逻辑概览
首先我们来看看两种方式各自的做法和流程是什么样的:
单元测试
在测试中,我们是这样的一个流程
此外,为了保证测试能覆盖到工程代码的每一个区域,需要保证测试的覆盖率。
正确性证明
在证明中,我们是这样的一个流程
在这一过程中
- 基于行为分析的
repOk
永真性证明依赖于JSF中的modifies
项 - 方法正确性将基于JSF中所描述的
effects
和requires
项 - 各方法内其他方法的调用需要依赖被调用方法的正确性,具体来说
- 对于系统自带的类与方法实现一律默认正确
- 对于其他位置的调用,正确性则依赖于其具体方法或类的正确性证明
关键细节
基于以上的逻辑,我们不难发现一个细节:
- 在单元测试的流程图上,当程序通过测试后,是假定程序为正确而不是程序为正确
或者更具体地说,这里多出了一个名为假定的字眼。
这是什么原因的?其实说来也非常简单——因为测试,只能证明程序有错,而不能证明程序是对的。
虽然有大数定律的理论支撑(即只要测试集数量无限大,则必定可以覆盖一切情况),可是实际上并不存在无限大的测试集,故测试上的死角总还是会存在的。
设一个有限集 $ 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类图
顺序图
状态图
其他
知识点之间的关系
首先,我们来回顾下我们这学期四章的各个标题:
- 第一章 Java与对象(Java和面向对象基本概念入门)
- 第二章 并发与安全(多线程程序设计入门)
- 第三章 抽象与规格(规格化与整体设计进阶)
- 第四章 测试与论证(工程化质量保证措施学习与体验)
其实这很明显,是一个循序渐进的过程,体现在两个不同的层面上:
- 从学生学习的角度而言,知识体系是层层递进的
- 从工业生产的角度而言,这个也很接近一个产品从设计到交付,自底向上的一个完整流程
个人收获与小结
实际上,笔者在多年前,就已经接触并使用了面向对象程序设计语言。
所以,实际上在这个学期,笔者的主要收获如下:
- 通过十几次作业对程序框架设计的反复揣摩,笔者在整体框架设计上的水平更加趋于成熟
- 更加深入的了解了严格工业界的一些做法(例如广泛地规格化程序设计,以及正确性证明等)
- 此外,笔者结合之前多年的实践经验(理论课上讲到过的坑,笔者当年几乎全都亲自踩过一遍)和对工业界的一些基本了解(笔者已经做过多笔的外包项目,目前仍在着手运营的项目也有数个),对面向对象和工程化的理解也更加深入了。
工程化的个人见解
关于工程化呢,其实说难也难,说简单也简单得很。
一些具体的好处呢,笔者在前三次博客作业中均有不同程度的论述(此处不再赘述):
不过说到底呢,其实就几件事:
- 任何时代任何情况下,左右战局的决定性因素,永远是人
- 因此,工程化的一个基本思想就是以人为本
- 从开发者角度,为开发者提供方便提高效率(无论是短期还是长期,无论是单人还是团队,都是需要考虑的)
- 从商业团体角度,提高整体战斗力,创造更大的效益和价值
- 从用户角度,让用户体验更优(或者说给用户提供足够的方便),让用户更加愿意直接或间接地掏腰包(统计意义上的)
- 此外,对于不同的解决方案,一般情况下存在即合理(或者说,对于还没有被淘汰的解决方案,其存在终究是可以良好满足某些场合下的需求的)。对此,我们该做的,就是具体问题具体分析,选择在具体情况下最优的方案。
课程思考与建议
个人的思考与建议
关于这个问题,笔者在两三个月前,就已经开始思考了。
众所周知,面向对象课程的槽点还是不算少的。
不过,据笔者看,这些问题看似庞杂,但是只要仔细去理一理背后的逻辑关系,其实也很简单。
笔者根据自身了解的一些事实,和大半个学期以来的观察与分析,粗略的得到了下面的这张逻辑图:
不过这样一来,看似错综复杂的事情也就清楚了。
稍加观察,便可以发现问题的根源——没有一个相对公平合理的横向比较机制。(稍微了解拓扑排序的概念,便可以得出这样的结论,找到节点的上游)
其实,很多同学(包括16级的和以前的学长学姐们)之前所吐槽过的问题,根源都在这边。
假如,我们有一个很靠谱的自动化横向比较机制
- 那么,我们的分数将更具有梯度和区分度,且评分核心依据将是程序的真实质量
- 那么,互测的实际门槛将可以考虑提高,互测人员的整体素质也将提高
- 那么,基于上一条,我们将不再需要每次祈祷不遇上坏人(指的是为了自己的分数可以不要脸良心还从不痛的那种)
- 那么,基于上一条,我们的助教们将不再需要面临巨大的仲裁任务压力
- 那么,基于上一条,我们的同学们将不再需要承受等待助教仲裁的痛苦煎熬
- 那么,我们的评测将可以考虑部分模糊化,以适应模糊化的需求
- 那么,基于上一条,我们的同学可以不再不停地纠结需求细节(常常还是无关紧要的细节),助教们也将大大减少issue答疑时间
- 那么,基于以上所有条,我们的同学们的整体体验将有质的飞跃
- 那么,基于上一条,同学们将更加愿意积极努力学习这门课程
实际上,想做出改变,也并不难,比如:
- 公测不再严格面向bug出数据。或者至少不完全面向bug,面向bug的部分可以作为功能性弱测。
- 自动化公测引入模糊化测试。比如类似于oj中的
Special Judge
和提交答案题里面的部分分机制相结合,让程序只要不违背基本法(例如电梯不准瞬移不准分身)就能有分数,且各个水准的程序得分有梯度。 - 可以将面向bug的功能性弱测和模糊化性能强测相结合,构建出更有游戏性的制度(也可以允许在一定时间内公测多次提交,多次刷分,追求卓越)。
- 由此,可以基于公测最终成绩,设立一定的互测门槛,通过门槛者方可进入互测环节。
- 在互测环节中,可以设计类似
codeforces
那样的多对多大混战hack模式(也可以考虑待测程序不匿名,从此不再有无效作业的坑),保证互测的运气成分降到最低。
当然以上只是一些初步构想,笔者对于这个(自认为)靠谱的新制度,已经有了更深层次的计划和构想,更具体的计划等细节将在另一篇文章中详细阐述。
想对接下来的分析者们说的一些话
笔者写到这里之前,看过之前不少同学的一些思考与建tu议cao。
不得不说,虽然大部分的所谓分析完全流于表面,透过现象看本质的几乎没有(截至2018.6.25 6点整),但是,大家反映的问题,也很真实,或者说很真实地描绘了大众水平同学眼中的面向对象课程。
说这个,其实不是想吐槽各位(实际上,笔者更希望大家能继续描述内心的真实体验)。
引用笔者之前说过不止一遍的一句话
没法带来丝毫改变,甚至只会让事情更坏的怒火,是毫无意义的。
所以呢,希望接下来看到笔者文章的各位,能在吐槽的基础上和自身能力所及的情况下,进行更深入的思考,可以的话也多想想到底如何才能让事情变得更好,而不是一味地抱怨与泄私愤。
抱怨没有用,实干才能解决问题。
【作业4.0】HansBug的第四次面向对象课程思考的更多相关文章
- Angular 2.0 从0到1 (四)
第一节:Angular 2.0 从0到1 (一)第二节:Angular 2.0 从0到1 (二)第三节:Angular 2.0 从0到1 (三)第四节:Angular 2.0 从0到1 (四)第五节: ...
- 简单创建一个SpringCloud2021.0.3项目(四)
目录 1. 项目说明 1. 版本 2. 用到组件 3. 功能 2. 上三篇教程 3. 日志处理 1. 创建日志公共模块 2. Eureka引入日志模块 4. 到此的功能代码 5. 注册中心换成naco ...
- BUAA_OO_2020_第四单元与课程总结
BUAA_OO_2020_第四单元与课程总结 第四单元架构 第一次 架构设计 第一次作业要求实现UML类图解析器. 我才用自顶向下依次解析的方法,首先将类图中涉及的所有元素分成三层: 第一层 第二层 ...
- 【软件构造】第三章第四节 面向对象编程OOP
第三章第四节 面向对象编程OOP 本节讲学习ADT的具体实现技术:OOP Outline OOP的基本概念 对象 类 接口 抽象类 OOP的不同特征 封装 继承与重写(override) 多态与重载( ...
- JAVA之旅(四)——面向对象思想,成员/局部变量,匿名对象,封装 , private,构造方法,构造代码块
JAVA之旅(四)--面向对象思想,成员/局部变量,匿名对象,封装 , private,构造方法,构造代码块 加油吧,节奏得快点了 1.概述 上篇幅也是讲了这点,这篇幅就着重的讲一下思想和案例 就拿买 ...
- 【作业2.0】HansBug的5-7次OO作业分析与小结,以及一些个人体会
不知不觉又做了三次作业,容我在本文胡言乱语几句2333. 第五次作业 第五次作业是前面的电梯作业的多线程版本,难度也有了一些提升.(点击就送指导书) 类图 程序的类图结构如下: UML时序图 程序的逻 ...
- 【作业3.0】HansBug的第三次博客规格总结
转眼间第三次作业了,似乎需要说点啥,那就说点. 规格&工业 说到这个,不得不提一下软件开发的发展史. 历史的进程 早在上世纪50年代,就已经有早期的编程语言出现,也开始有一些程序编写者出现(多 ...
- 2018上C语言程序设计(高级)作业- 第0次作业
准备工作(10分) 1.在博客园申请个人博客. 2.加入班级博客(2班班级博客链接地址)(1班班级博客链接地址) 3.关注邹欣老师博客.关注任课老师博客. 4.加入讨论小组,学习过程中遇到问题不要随意 ...
- 小学生作业V2.0
211606320刘佳&211506332熊哲琛 一.预估与实际 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Plann ...
随机推荐
- Android高版本联网失败报错:Cleartext HTTP traffic to xxx not permitted解决方法
前言:为保证用户数据和设备的安全,Google针对下一代 Android 系统(Android P) 的应用程序,将要求默认使用加密连接,这意味着 Android P 将禁止 App 使用所有未加密的 ...
- 类 Calendar
简介 Java.util.Calendar是日历类,在Date后出现,替换掉了许多Date的方法.该类将所有可能用到的时间信息封装为静态成员变量,方便获取.日历类就是方便获取各个时间属性的.注意Cal ...
- iOS 快捷下载和安装并使用CocoaPods
CocoaPods是什么? 当你开发iOS应用时,会经常使用到很多第三方开源类库,比如JSONKit,AFNetWorking等等.可能某个类库又用到其他类库,所以要使用它,手动一个个去下载所需类库十 ...
- 深入Redis持久化
转载:https://segmentfault.com/a/1190000017193732 一.Redis高可用概述 在介绍Redis高可用之前,先说明一下在Redis的语境中高可用的含义. 我们知 ...
- Flutter控制屏幕旋转
特定页面旋转屏幕很简单: SystemChrome.setPreferredOrientations([ ... ]); 数组中是您要支持的屏幕方向. 如果想在特定页面固定横屏, 您可以这样写: @o ...
- Python进阶7--正则表达式
正则表达式*** 概述 分类 基本语法 元字符 ^ 匹配字符串的开头 $ 匹配字符串的末尾. . 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符. [.. ...
- XML fragments parsed from previous mappers already contains value for xxxxx
错误信息: Caused by: org.springframework.core.NestedIOException: Failed to parse mapping resource: 'file ...
- ES6 对象增强
对象字面量语法扩展: 1, 属性初始化语法简写:给一个属性赋一个变量值,如果变量名和属性名相同,可以省略变量名和冒号,直接写属性名,js引擎在执行代码的时候,自动查找 和属性命名相同的变量并赋值. l ...
- 红米Note 4X详细刷成开发版开启ROOT超级权限的教程
小米的手机不同手机型号正常情况下官方网站都提供两个不同的版本,大概分为稳定版和开发版,稳定版没有提供Root超级权限管理,开发版中就开启了Root超级权限,很多情况我们需要使用的一些功能强大的app, ...
- 与scrollTop相关的一些方法(更新)
刷新页面回到页面顶部 $(document).ready(function () { $(window).scrollTop(0); } 滑动到页面指定位置执行某项操作 $(document).rea ...