【做業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課程更好,爲了讓你們更能有所收穫而不斷努力的前輩們,報以崇高的敬意
  • 對於對筆者提出善意批評和提出意見的人,筆者也表示很歡迎
  • 對於帶着滿滿惡意的人,不管是對於筆者本人仍是這門課程,筆者只能******(請自行腦補)
相關文章
相關標籤/搜索