【做业2.0】HansBug的5-7次OO做业分析与小结,以及一些我的体会

不知不觉又作了三次做业,容我在本文胡言乱语几句2333。javascript

第五次做业

第五次做业是前面的电梯做业的多线程版本,难度也有了一些提高。(点击就送指导书php

类图

程序的类图结构以下:
css

UML时序图

程序的逻辑时序图结构以下:
html

代码分析报告

能够看出,此次的程序依然存在部分类或方法代码较为集中的状况,这样的状况在类LiftLiftController,甚至笔者本身的第三方库DebugLogger中较为明显。甚至在LiftLiftController类中能够发现其实业务逻辑已经很是的密集前端

公测

我方

不出意料,我方公测不存在问题。java

对方

此次对方的公测也不存在问题,能够说是赏心悦目了。git

互测

我方

不出意料,我方互测不存在问题(然而出了点别的情况23333,为了保证笔者博客的干净,笔者将在文末讲述,此处不作讨论github

对方

此次,笔者给对方找出了两个bug。正则表达式

这两个bug分别是:算法

  1. Invalid格式错误 这个,其实就是字面意思,这位同窗的程序Invalid请求输出信息的时候格式不正确(准确的说,是不符合指导书需求)。

  2. 线程同步错误 不知道你们是否记得,在此次做业中有两种不一样的请求类型:
    • 电梯内部请求ER 这样的请求进入调度器以后将直接转进对应电梯的子消息队列。
    • 楼层请求FR这样的请求将被暂存在调度器的消息队列,等能够接受这一请求的电梯出现后,将其发送至该电梯的请求队列中。

因而,在通常的架构中,在请求队列里,通常都会有这样的一个轮询逻辑:不断轮询各个电梯的状态,等能够合法接受请求的电梯出现后,将其进行分配。然而就是在这个地方,若是,在轮询的一半时,某个电梯的状态忽然改变了,该怎么办。

假设,有这样的三个请求:

  • 楼层请求,3层,向上
  • 楼层请求,7层,向上
  • 楼层请求,10层,向上

某电梯即将到达一层,目前还在运行中。其余电梯均正忙。

因而,假设这个时候开始了一个轮询:

  • 请求1,无人可接受
  • 请求2,无人可接受

然而,最不巧的是,偏在这个时候,这个电梯已经到达了一层且处于空闲状态,并且请求3还没判断,因而就会出现这样的尴尬局面:

  • 请求3,被该电梯接受

这还不算完,因为该电梯当前在一层,因而:

  • 请求1,被请求3捎带
  • 请求2,被请求3捎带

灾难性的后果发生了,这三个原本多半能够有效负载均衡的请求,由于一个线程同步问题,就这么被一波带走了。

事实上,这个bug在笔者本身进行测试的时候,就已经发现。笔者思考后,以为有两种思路解决这一问题:

  • 一种是不阻塞状态改变的策略。咱们能够在轮询的时候每次进行两次或者屡次全面状态断定,若是连续两次的状态断定结果彻底一致的话,则能够说明该状态断定有效,必定不存在中途状态改变的状况。
  • 另外一种是阻塞状态改变的策略。这个时候,多线程里面的锁机制就派上用场了,既然这种状况下没法阻塞掉轮询判断的过程(由于你没办法预知接下来会不会状态改变,且一旦发生,一切为时已晚),那就阻塞掉各个电梯的状态数据接口。在每次轮询开始后,将全部电梯的状态信息全面阻塞,等一次轮询结束后方可改变。这样一来也能有效杜绝这种半路改变的状况出现。

总结

此次做业能够说是笔者在多线程上一次工程化的尝试

笔者以前主要写的是C++(用于算法竞赛)、C#(GUI桌面应用编程)、Python(用于各类脚本)、Ruby(用于同袍和Questionor后端的维护)、php(偶尔也会用到)以及前端的html+css+javascript。虽然之前接触过多线程编程,不过也大都用于脚本编程(实际上,多线程的这种特性在网络请求等待的时候能够极大提升脚本效率),并且也大都是简单的并发+阻塞。在此次做业中,笔者真正在强类型OOP语言中进行系统化工程化的多线程编程仍是头一次。

此次笔者认真研究了线程相关的锁(lock)、监视器(monitor)等机制,而且仔细思考了在这样的一个工程中如何经过这些机制来避免由于同步问题致使的错误,且兼顾并发效率。能够说收获不小。

此外,笔者的程序结构依然存在高内聚的问题,再加上这是第一次设计真正的多线程工程代码,太多的时间花在了如何让程序没有bug上,因而代码风格仍是较差

第六次做业

第六次做业叫作IFTTT,大体意思就是基于IF ... THEN ... 逻辑的文件系统监视器(点击就送指导书

类图

此次代码的类图结构以下:

UML时序图

此次的UML时序图结构以下:

代码质量分析报告

此次的代码质量分析报告:

能够看见,整体的代码质量有较大的改观,不过仍是存在少数类的行数过大。

公测

我方

不出意料,公测没有出现错误。

不过这里有一个有趣的小插曲,笔者一开始公测被报了一个bug,理由是监视器没有作出响应。笔者打开了这位同窗提供的测试输入,用的是D:\这样的根目录,因而笔者想起来指导书上貌似规定过不要用规模过大的路径进行测试,并对于这一状况向这位测试人员进行了解释,因而呢,改为了经过。(至于文件系统监视器相关的问题,笔者将在这一节的总结中稍微讲些本身的见解)

对方

对方的程序,在公测环节彷佛出现了不少的bug。并且彷佛彻底不具有对于整个目录树的监视反应能力。(也许是功能就没设计全?)

互测

我方

不出意料,我方在互测环节没有出现任何bug。

对方

此次互测中,对方被笔者查出了两个bug:

  • 数组越界 恩,这位老铁还在使用传统的静态数组进行请求的存储,不只如此,数组容量还只开了100。因而嘛,轻松得手。
  • 程序不能正常结束 这位同窗的程序没法经过正常手段结束(只能强制中断)。应该是没有好好在顶层设计线程阻塞

总结与分析

总结

此次做业是笔者所写的第二次多线程工程代码,从代码分析数据来看,总体代码风格有了较大的改观,再也不有很明显高度集中的类设计,主要方法的代码密集程度也有所降低。

然而,笔者本身内心清楚,不少地方的代码仍旧不够成熟。同时,笔者已经开始探索着开发一套能够提供各种快速搭建和管理功能的java工程代码框架,而且已经从第七次做业开始使用这样的框架。

以及,此次貌似是指导书被吐槽最严重的一次。此次的issue也能够说是史无前例的庞杂,其中笔者以为一部分缘由是指导书没有去匹配大部分人对文件系统以及IFTTT的认知水平。

关于文件系统监视器

说到文件系统监视器,通常来讲有两种主要的解决方案:

  • 经过轮询等措施每次捕获指定目录树下的文件列表快照,并根据快照之间的增量进行事件断定
  • 经过系统钩子等系统底层途径直接监视文件系统事件

显然,此次做业通常采用的策略是前者。这是一种很廉价且在数据规模不大的状况下很靠谱的策略

可是,各位应该也已经发现这一方法的一些明显弱点:

  • 正如笔者在公测环节遇到的小插曲,当目录过深的时候,每一次轮询拍摄快照就须要很是长的时间,致使没办法在可接受的时间内对于文件系统变化作成正确反应。
  • 不只如此,在目录结构很庞大的时候,快照内将须要包含大量的文件项。只要路径足够大,内存占用必将趋于无穷,处于彻底不可控的状态(即使微调策略这一点也不会有本质的改善,只要全量检测还存在,这一点就是不可避免的)。
  • 也正是因为是增量比对,因此文件之间的转化关系也完全成了无解的坑。

关于第三点,笔者举例说明下。
例如,在两次快照拍摄之间,a.txt重命名为a1.txtb.txt目录更改到了dir\a.txt,这么一来,快照增量检测到的应该是这样的四条信息:

  • 【缺失】 a.txt
  • 【缺失】 b.txt
  • 【新增】 a1.txt
  • 【新增】 dir\a.txt

假如咱们的a.txtb.txt文件大小和修改时间再彻底一致的话(本次做业中判断文件等价的惟二依据是文件大小修改时间,并没采用各种文件指纹算法),问题就来了——a.txtb.txt到底去了哪呢?

  • 因为a.txtb.txt等价,因此解释为a.txt --> dir\a.txt, b.txt --> a1.txt,这样是说得通的。
  • 也正是因为a.txtb.txt等价,因此解释为a.txt --> a1.txtb.txt消失,dir\a.txt出现,其实也说得通。

实际上,快照+增量机制所带来的一个无解的难题就是增量事件变得再也不惟一可断定

然而,这还不算完。咱们此次采用的是多线程机制检测文件系统变化。因而呢,这样又不得不引入了线程同步问题。由于,按照原来课程组的要求,彷佛还得保证在出现同质文件的状况下事件不能够发生冲突(例如,对于上述的例子,不能够同时检测到a.txt --> a1.txtb.txt --> a1.txt)。实际上这样的要求自己彻底合理,这件事在单线程内的断定也很好办,HashMap判重一下便可。然而要是这样的断定分散在多个线程内呢?因而又有了一连串的问题:

  • 如何保证同步?
  • 对象是同步了,线程轮询不一样步怎么办?
  • 为了线程之间强制同步而将所有线程轮询均设置为同步?
  • 若是这样的话那和单线程又有何区别,多线程的意义又何在

因而这个问题又成了一个无底洞(因而,后来课程组决定不对这种极端状况进行测试)。

根据我的了解,在实际应用中,这样的问题经常是基于另一种思路——根据文件系统底层事件来检测文件系统变化

  • 实际上,JavaC#中均有现成的FileSystemWatcher类可供直接使用。
  • 因为基于事件机制,因此不只不会有很大的系统占用,并且理论上不管文件系统有多大,均可以作到即时反应,且具体的动做(尤为是上文中设计不惟一性断定的多个动做)不会存在歧义。

关于多线程程序设计的一点见解

此次做业中笔者所检查的程序存在程序不能正常结束的状况。笔者打开了这份程序进行了查看,这份程序在顶层,打开了各个线程后,就再也不对各个线程进行控制

笔者以为,多线程程序设计的一个基本原则是——任何线程在任什么时候候均不该该处于脱离控制的状态。不管是消息队列,仍是各个业务逻辑线程,甚至是GUI,在任何阶段都应该在上层线程的控制之下。即上层须要结束线程的时候能够随时正常下达指令,且下达指令后须要用join等命令进行阻塞等待,直到各个线程安全关闭,再结束程序。

第七次做业

第七次做业是出租车系统模拟。不得不说,事情终于开始变得有趣了(点击就送指导书

类图

本次做业的类图结构:

UML时序图

本次做业的UML时序图:

代码质量分析报告

本次做业的代码质量分析报告:

能够看见,排除GUI模块以外(GUI模块并不是出自笔者之手),代码局部复杂度已经获得了必定程度上的控制(三个红色的那个函数点开看了下,是因为代码重复性较高致使的)

公测

我方

不出意料,公测我方未被测出bug。

对方

对方的公测存在一个bug,即没有对于起点终点为同一个节点的状况进行断定。这样的bug添加一处断定便可。

互测

我方

最终,不出意料,我方未被测出bug。

不过中途也仍是出现了一些有趣的小插曲。这位测试者试了下在缺乏map.txt的状况下运行程序,而后看到笔者的程序输出了红色字,因而认为笔者的程序crash了。

然而实际上,笔者的程序外部包裹了try catch,只是在catch外面使用了printStackTrace。而且程序的实际返回值也是0,也就是说是正常且平稳的结束的。因而笔者摆事实讲道理,进行了申诉以后,对方撤回了这个bug。

然而程序也的确显示了红色字,这又是为啥呢?笔者经过研究java源码,找到了问题所在。

咱们知道,通常高级语言程序通常会带三种自带的Stream:

  • 输入流,通常用于输入,即Java中的System.in
  • 输出流,通常用于输出,即Java中的System.out
  • 异常流,通常用于异常信息输出,即Java中的System.err

接下来咱们来看看一切异常类的祖先类——Throwable类的部分源码:

public void printStackTrace() {  
        printStackTrace(System.err);  
    }  
  
    /** 
     * Prints this throwable and its backtrace to the specified print stream. 
     * 
     * @param s <code>PrintStream</code> to use for output 
     */  
    public void printStackTrace(PrintStream s) {  
        synchronized (s) {  
            s.println(this);  
            StackTraceElement[] trace = getOurStackTrace();  
            for (int i=0; i < trace.length; i++)  
                s.println("\tat " + trace[i]);  
  
            Throwable ourCause = getCause();  
            if (ourCause != null)  
                ourCause.printStackTraceAsCause(s, trace);  
        }  
    }

该源码片断截取自Throwable类,能够看到,默认不带参数的printStackTrace类,实际上是在调用System.err进行输出。因此难怪输出的会是红色字,由于的确输出到了异常流内

说到这里问题就解决了,之后若是须要避免相似的误解,调用printStackTrace(System.out)而非printStackTrace()便可。

对方

这位同窗的代码整体而言写的仍是挺不错的,不过在测试的过程当中发现有一个很坑爹的设定。

这份程序只有在按照指定的方式结束程序后,才会有detail.txt细节信息输出(也就是说用其余的方式,即使平稳结束程序尚未文件输出)。

这样一来,虽然实际上输出了,但也等于彻底不具有实时交互的特性。虽然指导书上并无明令禁止,但实际上已经违背了这个设计的初衷

因而笔者向多名助教求证过以后,报了一个imcomplete

做业总结

在此次做业中,笔者在开始动工以前,准备了一个简单的程序框架模板。使得程序搭建效率有了略微的提升(关于程序模板,笔者将在下文继续讲述)。

同时,笔者自我感受,从此次开始,笔者的多线程程序设计框架开始变得日趋成熟。

总结 & 一些想说的话

我的总结

笔者从这三次做业开始,真正接触了系统化工程化的多线程OOP程序设计,开始从零开始一步步思考,如何充分利用多线程的并发机制,协同各个进程,同时充分兼顾多线程并发效率。

从中,笔者仍是看到了自身的一些不足:

  • 部分局部函数仍存在复杂度较高或者设计稍微不合理的地方。

笔者将会从接下来进一步的实践当中,进一步改善代码风格,设计更完善更符合规范,人机性能更好的程序。

关于静态数组

据笔者观察,貌似不少的同窗至今仍热衷于使用静态数组来进行数据的存储。

起初,笔者十分不解,Java这样的OOP语言中,相关的数据结构封装类可谓至关完备,为啥还要使用数组呢?

通过一些观察,不少人仍离不开静态数组的缘由大抵以下:

  • 对于枚举性质的东西,例如IFTTT做业的四种事件,他们喜欢用012之类的数字表示(别问我他们为啥这么干,由于我也想知道为啥好端端的枚举类不用),而后统计的时候用数组索引便可
  • 不少人仍是彻底摆脱不了C语言的思惟方式,且数据结构基本功几乎为零
  • 不少人对工程性之类的事情全无认识,认为程序能运行便可

然而,静态数组实际上有很致命的缺陷:

  • 数据量较小的时候,空间浪费至关严重
  • 数据量较大的时候,会不可避免的数组越界致使crash。实际上,笔者至今为止,已经至少有抓住3个送上门的bug是由于被测试者使用静态数组形成的此外,笔者如今每次查程序以前,都喜欢用正则表达式+grep命令将对方程序里头的静态数组一口气揪出来,只要能找到,基本上很快就能开开心心的拿下此次的一血。这招一抓一个准,屡试不爽,并且基本是抓住的都是crash,通常人我不告诉他23333

静态数组这样的东西只在极少数特定场合下稍微方便些,然而带来的倒是不少性能和工程性上的不可控,可谓得不偿失。

建议使用Java内置的数据结构,诸如ListVectorArrayList类,这些类均进行过有效的代码封装和性能优化,各方面性能均有保证,且不会很容易的出现错误。

关于代码规范与程序设计

从第七次做业开始,引入了一些代码规范相关的考察。我的以为,其实这是一件很好的事情,毕竟真正的工程永远离不开维护,也很难离开teamwork

然而,据笔者观察,彷佛不少人对这件事颇为反感与不解,诸如如下的论调:

  • 为何咱们的程序能运行了,还要在乎这些麻烦的事情?
  • 这个东西卡的很严格嘛?若是不是很严格那我这12分直接不要了
  • 这个东西有明确的标准嘛?若是没有的话撕逼怎么办?算了。。这12分我仍是不要了得了

是的,上述的想法能够说很是广泛,笔者在第七次做业正式发布后的客服群里,基本天天都能看到这样的论调。感受至关多的人以为这个要求很不合理。

首先,关于代码规范的重要性,笔者在上次博客做业已经有说过,不想再重复唠叨一遍(或者说,唠叨了估计也没人爱听。。。)。

不过这样估计说服不了任何人,那容笔者来举几个亲自遇到的案例吧。

案例一

这个图,来自于第六次做业笔者测试的这位同窗的summary.txt

恩,没错,这就是summary.txt。为了防止各位看了一脸懵逼,我还能够告诉大家,冒号前的0123表示的是四种不一样的事件。

那么,请你如今告诉我,这个summary.txt是在表达什么?

是的,没错,看不懂的不止你一个,由于笔者当时看到这个的时候也仍是一脸懵逼(即使猜到了前面的数字表示的是各个事件类型)。

因而,笔者只好开始研究他的源代码。而后很惊喜的发现,这位老哥的全部代码全都写在了一个文件里头,并且右边滚动条上还密密麻麻的都是各类warning。

终于,功夫不负有心人,笔者终于找到了一丝线索:

恩,就是这里

public void addSummary(String trigger) {
        lock.lock();
        summary[trigger.equals("renamed") ? 0 : trigger.equals("Modified") ? 1 : trigger.equals("path-changed") ? 2 : 3]++;
        PrintWriter output;
        try {
            output = new PrintWriter("summary.txt");
            for (int i = 0; i < 4; i++) output.println(i + ":" + summary[i]);
            output.close();
        } catch (FileNotFoundException e) {
            System.out.println("Fail to output to summary.txt!");
        }
        lock.unlock();
    }

就是这句

summary[trigger.equals("renamed") ? 0 : trigger.equals("Modified") ? 1 : trigger.equals("path-changed") ? 2 : 3]++;

咱们来研究下这个超长的三元表达式在表达什么(emmm,笔者做为多年的老码农,表示愣是一眼没看懂):

  • 若是是renamed,返回0,不然继续
  • 若是是Modified,返回1,不然继续
  • 若是是path-changed,返回2,不然继续
  • 返回3

到这里,笔者费尽千辛万苦,终于看明白这个文件了

想到这里,假如,我不是一个测试人员,而是这位老哥的teammate,想要一块儿开发一个项目。

若是,须要对接的时候要是遇到了这样的状况,得费多大的劲才能搞清楚

试想一想,若是你每次开发项目,都要花一堆的时间在这种无谓的事情上,你以为值得么?有何效率可言?

若是,输出的不是

0:1
1:0
2:0
3:0

而是

renamed: 1
Modified: 0
path-changed: 0
size-changed: 0

若是,这个程序可以知足咱们所规定的:

  • 懂我原则 让人一眼就看懂意思,不用再一点一点去翻源代码
  • 显示表达原则 这样的东西封装成enum而后再用数组啥的搞搞也比一直传字符串而后弄那么一个又臭又长的三元表达式强啊

这么一来能够节省多少的时间

案例二

在第七次做业中,笔者分配到的测试程序,依然存在和上面相似的状况。

当笔者一次性输入多个请求的时候,等待3秒后,出现了一片的报错:

笔者当时瞬间就懵了,到底哪些指令执行了,哪些指令分配失败了

而后对detail.txt仔细研究了好半天后,才终于确认程序运行的是对的。

其实吧,在这种时候顺带输出下错误的详细状况(甚至不用太详细,输出一下哪条指令出错也是好的),对于编程者而言真的就是几秒钟的事情。

然而若是不加,不只给别人会带来很大的困扰,大家本身debug的时候,也会处于彻底摸不着头脑的状态——由于不管哪里错了,输出的都同样。

说了以上这些,其实我只想说明一点:

  • 这些规则,每一条都是有缘由的,都是实实在在帮助大家写出更好的程序提升团队协做效率的

固然,可能不少人仍是没法理解,这也正常。等有一天大家真正参与项目维护(尤为是多人团队项目)的时候,大家就会明白这些事情的重要性了。

工程框架

笔者在以前的屡次程序做业中,发现每次都要花上好半天的时间搭建程序框架,并且作得基本都是重复工做。

做为一个聪明的懒人,笔者因而本身写了一个简单的的工程代码模板。Git仓库,欢迎star

这样的一个框架能较好的符合笔者本人每次写代码的工程结构须要。同时对于一些常见需求也都进行了以行为逻辑为主的封装能够经过类继承等方式快速构建功能模块(尤为是多线程功能模块)。

这个库将会不断地维护和更新,但愿能够帮助到你们。

关于为什么而学习

笔者做为一个写了不少年代码(至今已有10年有余),且实际维护过不止一个工程项目的程序猿,每当想在群里分享一些我的对于程序、对于代码规范、对于工程的理解和见解时,永远会有一些人站出来针锋相对。

他们的主要逻辑以下:

  • 你说这些有什么用,咱们就是想完成做业啊!
  • 你说这些有什么用,个人程序是不能运行了仍是怎么着了?
  • 你说这些有什么用,你说的再多代码规范啥的同样会被钻牛角尖啊!

其实,笔者对于这样的想法仍是表示能够理解的。毕竟每一个人站的角度不一样,格局天然也有天壤之别(俗称:屁股决定脑壳)。

不过,笔者仍是但愿各位能好好想一想大家是为什么而学习的。仅仅就是为了赶快毕业拿文凭?

固然了,若是这就是你的所有想法,并且之后不想从事这方面的工做的话,那的确随意,只能说你和我们技术发烧友(或者最起码是打算靠这个吃饭的人)不是一路的人。

若是不是这样,那么你就该站在更高的格局上想问题:

  • 我究竟能从中收获到什么?

结论很简单,能有所收获的,就是对的能收获更大的,就是更好的

接下来我来逐个回应下这三个常见逻辑:

  • 咱们就是想完成做业啊 请想想仅仅就是完成一个做业的话,你能学到的东西有多少。。。
  • 个人程序是不能运行了仍是怎么着了 请想一想,程序能运行可是毫无维护性和可合做性,这种代码除了糊弄一下做业有任何价值么。。。
  • 你说的再多代码规范啥的同样会被钻牛角尖啊 请相信咱们的助教团,他们会给你公道的。你只管作好本身就是了。

另外,可能有些人(甚至包括一些著名大佬)受到知乎上一些所谓的6系人的影响,认为北航的OO课程就是一无可取毫无收获的。对于这样的无脑黑,我只能对您表示深深的同情和怜悯,由于您在用您的将来前途消费,而目的,仅仅只是为了证实一个帖子,和一些前人片面的话语的正确性。

其余

前方高能。接下来的章节可能会引发部分人的不适,请非战斗人员迅速撤离。






























挂人

时间过得真快,一不当心又过去了三次做业。不过这其中天然也有些不爽的事情发生。

虽然呢,笔者很清楚,这样的东西写进本身的技术博客实在是很是不雅,简直能够说弄脏了笔者的博客(事实上这也是笔者没在上面说这件事的缘由)。可是有些事情嘛。。。仍是不吐不快。

因此接下来讲件事,请你们自行评判。

笔者在第五次做业截止后的一个晚上,忽然被告知,本身被无效了???

而后,到群里问了下助教缘由,缘由是,我在readme.md的指导书url连接中包含了"我的信息"

连接地址全文以下:

https://files.cnblogs.com/files/HansBug/OO%E7%AC%AC05%E6%AC%A1%E4%BD%9C%E4%B8%9A%E6%8C%87%E5%AF%BC%E4%B9%A62018v1.2.pdf

当时,懵逼了。然而再仔细一想,发现事情并不简单。

  • 首先,这个url地址是在markdown中以连接的形式存在的
  • 其次,这个连接里头仅仅只是个博客园的文件地址,仅仅只是包含了一个叫作HansBug的名字
  • 再其次,这人是怎么经过HansBug这么快知道是个人,笔者在北航这个圈子不多以HansBug的名字示人。

越想越以为不对劲。因而笔者过后仔细一琢磨,能够推测出这我的的逻辑流程图:

个人天啊,老哥诶,您老人家为了避免测试别人的程序为了让本身睡大觉,可真是煞费苦心啊。走了这么多步终于找到了我,我佩服你那为了偷懒不怕艰难险阻过五关斩六将的精神,是在下输了。

或者,咱们甚至还能够在这个的基础上进一步扩展下:

也许可能各位还有点疑惑,甚至以为我是在用恶意揣测别人。很明显,有如此耐心历经那么多个环节,只是为了找别人的无效做业痕迹的人,我并不相信他有可能一上来就是想好好测试的

然而这样的人物,一个对学术毫无敬畏之心只想着偷懒万岁的人,竟然还能和笔者分到了相近的段位,笔者只能哀叹——“知人知面不知心”啊。

综上,我只想对这人说一句:你有种给我站出来,别玩阴的!!!

不过,再一想一想,人家如何如何,关我何事。笔者仍是想认真的对学术和工程负责到底的,以及,没法带来任何实质性改变的怒火是毫无心义的

正如上文所言,这类人挖地三尺的通常性动机,就是在于一旦把对方无效了,本身就能够不用测试了

事实上此次事情的后续进展也代表笔者的猜想彻底正确——截至互测时间结束,笔者这份被无效的做业依然一个点都没有进行测试(包括公测)。最后仍是在笔者的一再要求下,课程组的助教们帮笔者完成了测试(在此感谢默默支持的老师和助教们,真的很是感谢)。

至此,这人的动机能够说是很是明显了。若是他只是一个按照规则办事且对学术和工程质量负责的人,那如何解释到最后都一个点都没测试的状况

说到这里,笔者对于课程有个改进的思路,以遏制这种表面矫枉过正实则恶意满满的行为:

  • 规定只要对于有测试价值的程序(至少具有最基本的功能),即使是无效做业,也必须认真测试

理由其实也很是简单:

  • 做为一个认真完成做业的人,即使由于各类缘由无心中暴露我的信息,也有权知道本身的劳动成果到底怎么样
  • 这是课程,目的是学到知识和技能,目的是有所收获。对于无效做业这样一刀切的作法显然是在剥夺不少认真写做业的人有所收获的权利
  • 若是不这样要求,必然致使有些心术不正之人,不花心思在好好测试上,一样于有所收获这一目标背道而驰。(虽然笔者很清楚,这种事情防君子不防小人,不过能防得住几个伪君子也是好的)

以上是个人见解。

  • 很是感谢各位默默支持个人老师、助教和同窗
  • 对为了使OO课程更好,为了让你们更能有所收获而不断努力的前辈们,报以崇高的敬意
  • 对于对笔者提出善意批评和提出意见的人,笔者也表示很欢迎
  • 对于带着满满恶意的人,不管是对于笔者本人仍是这门课程,笔者只能******(请自行脑补)
相关文章
相关标签/搜索