不知不覺又做了三次作業,容我在本文胡言亂語幾句2333。
第五次作業是前面的電梯作業的多線程版本,難度也有了一些提升。(點選就送指導書)
程式的類圖結構如下:

程式的邏輯時序圖結構如下:
可以看出,這次的程式依然存在部分類或方法代碼較為集中的情況,這樣的情況在類<code>Lift</code>、<code>LiftController</code>,甚至筆者自己的第三方庫<code>DebugLogger</code>中較為明顯。甚至在<code>Lift</code>和<code>LiftController</code>類中可以發現其實業務邏輯已經非常的密集。
不出意料,我方公測不存在問題。
這次對方的公測也不存在問題,可以說是賞心悅目了。
不出意料,我方互測不存在問題(然而出了點别的狀況23333,為了保證筆者部落格的幹淨,筆者将在文末講述,此處不做讨論)
這次,筆者給對方找出了兩個bug。
這兩個bug分别是:
Invalid格式錯誤 這個,其實就是字面意思,這位同學的程式Invalid請求輸出資訊的時候格式不正确(準确的說,是不符合指導書需求)。
線程同步錯誤 不知道大家是否記得,在這次作業中有兩種不同的請求類型:
電梯内部請求<code>ER</code> 這樣的請求進入排程器之後将直接轉進對應電梯的子消息隊列。
樓層請求<code>FR</code>這樣的請求将被暫存在排程器的消息隊列,等可以接受這一請求的電梯出現後,将其發送至該電梯的請求隊列中。
于是,在一般的架構中,在請求隊列裡,一般都會有這樣的一個輪詢邏輯:不斷輪詢各個電梯的狀态,等可以合法接受請求的電梯出現後,将其進行配置設定。然而就是在這個地方,如果,在輪詢的一半時,某個電梯的狀态突然改變了,該怎麼辦。
假設,有這樣的三個請求:
樓層請求,3層,向上
樓層請求,7層,向上
樓層請求,10層,向上
某電梯即将到達一層,目前還在運作中。其他電梯均正忙。
于是,假設這個時候開始了一個輪詢:
請求1,無人可接受
請求2,無人可接受
然而,最不巧的是,偏在這個時候,這個電梯已經到達了一層且處于空閑狀态,而且請求3還沒判斷,于是就會出現這樣的尴尬局面:
請求3,被該電梯接受
這還不算完,由于該電梯目前在一層,于是:
請求1,被請求3捎帶
請求2,被請求3捎帶
災難性的後果發生了,這三個本來多半可以有效負載均衡的請求,因為一個線程同步問題,就這麼被一波帶走了。
事實上,這個bug在筆者自己進行測試的時候,就已經發現。筆者思考後,覺得有兩種思路解決這一問題:
一種是不阻塞狀态改變的政策。我們可以在輪詢的時候每次進行兩次或者多次全面狀态判定,如果連續兩次的狀态判定結果完全一緻的話,則可以說明該狀态判定有效,一定不存在中途狀态改變的情況。
另一種是阻塞狀态改變的政策。這個時候,多線程裡面的鎖機制就派上用場了,既然這種情況下無法阻塞掉輪詢判斷的過程(因為你沒辦法預知接下來會不會狀态改變,且一旦發生,一切為時已晚),那就阻塞掉各個電梯的狀态資料接口。在每次輪詢開始後,将所有電梯的狀态資訊全面阻塞,等一次輪詢結束後方可改變。這樣一來也能有效杜絕這種半路改變的情況出現。
這次作業可以說是筆者在多線程上一次工程化的嘗試。
筆者之前主要寫的是<code>C++</code>(用于算法競賽)、<code>C#</code>(GUI桌面應用程式設計)、<code>Python</code>(用于各種腳本)、<code>Ruby</code>(用于同袍和Questionor後端的維護)、<code>php</code>(偶爾也會用到)以及前端的<code>html</code>+<code>css</code>+<code>javascript</code>。雖然以前接觸過多線程程式設計,不過也大都用于腳本程式設計(實際上,多線程的這種特性在網絡請求等待的時候可以極大提高腳本效率),而且也大都是簡單的并發+阻塞。在這次作業中,筆者真正在強類型OOP語言中進行系統化工程化的多線程程式設計還是頭一次。
這次筆者認真研究了線程相關的鎖(lock)、螢幕(monitor)等機制,并且仔細思考了在這樣的一個工程中如何通過這些機制來避免因為同步問題導緻的錯誤,且兼顧并發效率。可以說收獲不小。
此外,筆者的程式結構依然存在高内聚的問題,再加上這是第一次設計真正的多線程工程代碼,太多的時間花在了如何讓程式沒有bug上,于是代碼風格還是較差。
第六次作業叫做IFTTT,大緻意思就是基于<code>IF</code> ... <code>THEN</code> ... 邏輯的檔案系統螢幕(點選就送指導書)
這次代碼的類圖結構如下:
這次的UML時序圖結構如下:
這次的代碼品質分析報告:
可以看見,總體的代碼品質有較大的改觀,不過還是存在少數類的行數過大。
不出意料,公測沒有出現錯誤。
不過這裡有一個有趣的小插曲,筆者一開始公測被報了一個bug,理由是螢幕沒有做出響應。筆者打開了這位同學提供的測試輸入,用的是<code>D:\</code>這樣的根目錄,于是筆者想起來指導書上貌似規定過不要用規模過大的路徑進行測試,并對于這一情況向這位測試人員進行了解釋,于是呢,改成了通過。(至于檔案系統螢幕相關的問題,筆者将在這一節的總結中稍微講些自己的看法)
對方的程式,在公測環節似乎出現了很多的bug。而且似乎完全不具備對于整個目錄樹的監視反應能力。(也許是功能就沒設計全?)
不出意料,我方在互測環節沒有出現任何bug。
這次互測中,對方被筆者查出了兩個bug:
數組越界 恩,這位老鐵還在使用傳統的靜态數組進行請求的存儲,不僅如此,數組容量還隻開了100。于是嘛,輕松得手。
程式不能正常結束 這位同學的程式無法通過正常手段結束(隻能強制中斷)。應該是沒有好好在頂層設計線程阻塞。
這次作業是筆者所寫的第二次多線程工程代碼,從代碼分析資料來看,整體代碼風格有了較大的改觀,不再有很明顯高度集中的類設計,主要方法的代碼密集程度也有所下降。
然而,筆者自己心裡清楚,很多地方的代碼仍舊不夠成熟。同時,筆者已經開始探索着開發一套可以提供各類快速搭建和管理功能的java工程代碼架構,并且已經從第七次作業開始使用這樣的架構。
以及,這次貌似是指導書被吐槽最嚴重的一次。這次的issue也可以說是前所未有的龐雜,其中筆者覺得一部分原因是指導書沒有去比對大部分人對檔案系統以及IFTTT的認知水準。
說到檔案系統螢幕,一般來說有兩種主要的解決方案:
通過輪詢等措施每次捕獲指定目錄樹下的檔案清單快照,并根據快照之間的增量進行事件判定
通過系統鈎子等系統底層途徑直接監視檔案系統事件
顯然,這次作業一般采用的政策是前者。這是一種很廉價且在資料規模不大的情況下很靠譜的政策。
但是,各位應該也已經發現這一方法的一些明顯弱點:
正如筆者在公測環節遇到的小插曲,當目錄過深的時候,每一次輪詢拍攝快照就需要非常長的時間,導緻沒辦法在可接受的時間内對于檔案系統變化做成正确反應。
不僅如此,在目錄結構很龐大的時候,快照内将需要包含大量的檔案項。隻要路徑足夠大,記憶體占用必将趨于無窮,處于完全不可控的狀态(即便微調政策這一點也不會有本質的改善,隻要全量檢測還存在,這一點就是不可避免的)。
也正是由于是增量比對,是以檔案之間的轉化關系也徹底成了無解的坑。
關于第三點,筆者舉例說明下。
例如,在兩次快照拍攝之間,<code>a.txt</code>重命名為<code>a1.txt</code>,<code>b.txt</code>目錄更改到了<code>dir\a.txt</code>,這麼一來,快照增量檢測到的應該是這樣的四條資訊:
【缺失】 <code>a.txt</code>
【缺失】 <code>b.txt</code>
【新增】 <code>a1.txt</code>
【新增】 <code>dir\a.txt</code>
假如我們的<code>a.txt</code>和<code>b.txt</code>檔案大小和修改時間再完全一緻的話(本次作業中判斷檔案等價的唯二依據是檔案大小和修改時間,并沒采用各類檔案指紋算法),問題就來了——<code>a.txt</code>和<code>b.txt</code>到底去了哪呢?
由于<code>a.txt</code>和<code>b.txt</code>等價,是以解釋為<code>a.txt</code> --> <code>dir\a.txt</code>, <code>b.txt</code> --> <code>a1.txt</code>,這樣是說得通的。
也正是由于<code>a.txt</code>和<code>b.txt</code>等價,是以解釋為<code>a.txt</code> --> <code>a1.txt</code>,<code>b.txt</code>消失,<code>dir\a.txt</code>出現,其實也說得通。
實際上,快照+增量機制所帶來的一個無解的難題就是增量事件變得不再唯一可判定。
然而,這還不算完。我們這次采用的是多線程機制檢測檔案系統變化。于是呢,這樣又不得不引入了線程同步問題。因為,按照原來課程組的要求,似乎還得保證在出現同質檔案的情況下事件不可以發生沖突(例如,對于上述的例子,不可以同時檢測到<code>a.txt</code> --> <code>a1.txt</code>和<code>b.txt</code> --> <code>a1.txt</code>)。實際上這樣的要求本身完全合理,這件事在單線程内的判定也很好辦,HashMap判重一下即可。然而要是這樣的判定分散在多個線程内呢?于是又有了一連串的問題:
如何保證同步?
對象是同步了,線程輪詢不同步怎麼辦?
為了線程之間強制同步而将全部線程輪詢均設定為同步?
如果這樣的話那和單線程又有何差別,多線程的意義又何在?
于是這個問題又成了一個無底洞(于是,後來課程組決定不對這種極端情況進行測試)。
根據個人了解,在實際應用中,這樣的問題常常是基于另外一種思路——根據檔案系統底層事件來檢測檔案系統變化。
實際上,<code>Java</code>和<code>C#</code>中均有現成的<code>FileSystemWatcher</code>類可供直接使用。
由于基于事件機制,是以不僅不會有很大的系統占用,而且理論上無論檔案系統有多大,都可以做到即時反應,且具體的動作(尤其是上文中設計不唯一性判定的多個動作)不會存在歧義。
這次作業中筆者所檢查的程式存在程式不能正常結束的情況。筆者打開了這份程式進行了檢視,這份程式在頂層,打開了各個線程後,就不再對各個線程進行控制。
筆者覺得,多線程程式設計的一個基本原則是——任何線程在任何時候均不應該處于脫離控制的狀态。無論是消息隊列,還是各個業務邏輯線程,甚至是GUI,在任何階段都應該在上層線程的控制之下。即上層需要結束線程的時候可以随時正常下達指令,且下達指令後需要用join等指令進行阻塞等待,直到各個線程安全關閉,再結束程式。
第七次作業是計程車系統模拟。不得不說,事情終于開始變得有趣了(點選就送指導書)
本次作業的類圖結構:
本次作業的UML時序圖:
本次作業的代碼品質分析報告:
可以看見,排除GUI子產品之外(GUI子產品并非出自筆者之手),代碼局部複雜度已經得到了一定程度上的控制(三個紅色的那個函數點開看了下,是由于代碼重複性較高導緻的)
不出意料,公測我方未被測出bug。
對方的公測存在一個bug,即沒有對于起點終點為同一個節點的情況進行判定。這樣的bug添加一處判定即可。
最終,不出意料,我方未被測出bug。
不過中途也還是出現了一些有趣的小插曲。這位測試者試了下在缺少<code>map.txt</code>的情況下運作程式,然後看到筆者的程式輸出了紅色字,于是認為筆者的程式<code>crash</code>了。
然而實際上,筆者的程式外部包裹了try catch,隻是在catch外面使用了<code>printStackTrace</code>。并且程式的實際傳回值也是<code>0</code>,也就是說是正常且平穩的結束的。于是筆者擺事實講道理,進行了申訴之後,對方撤回了這個bug。
然而程式也的确顯示了紅色字,這又是為啥呢?筆者通過研究java源碼,找到了問題所在。
我們知道,一般進階語言程式一般會帶三種自帶的Stream:
輸入流,一般用于輸入,即<code>Java</code>中的<code>System.in</code>
輸出流,一般用于輸出,即<code>Java</code>中的<code>System.out</code>
異常流,一般用于異常資訊輸出,即<code>Java</code>中的<code>System.err</code>
接下來我們來看看一切異常類的祖先類——<code>Throwable</code>類的部分源碼:
該源碼片段截取自<code>Throwable</code>類,可以看到,預設不帶參數的<code>printStackTrace</code>類,其實是在調用<code>System.err</code>進行輸出。是以難怪輸出的會是紅色字,因為的确輸出到了異常流内。
說到這裡問題就解決了,以後如果需要避免類似的誤解,調用<code>printStackTrace(System.out)</code>而非<code>printStackTrace()</code>即可。
這位同學的代碼總體而言寫的還是挺不錯的,不過在測試的過程中發現有一個很坑爹的設定。
這份程式隻有在按照指定的方式結束程式後,才會有<code>detail.txt</code>細節資訊輸出(也就是說用其他的方式,即便平穩結束程式還沒有檔案輸出)。
這樣一來,雖然實際上輸出了,但也等于完全不具備實時互動的特性。雖然指導書上并沒有明令禁止,但實際上已經違背了這個設計的初衷。
于是筆者向多名助教求證過之後,報了一個<code>imcomplete</code>。
在這次作業中,筆者在開始動工之前,準備了一個簡單的程式架構模闆。使得程式搭建效率有了略微的提高(關于程式模闆,筆者将在下文繼續講述)。
同時,筆者自我感覺,從這次開始,筆者的多線程程式設計架構開始變得日趨成熟。
筆者從這三次作業開始,真正接觸了系統化工程化的多線程OOP程式設計,開始從零開始一步步思考,如何充分利用多線程的并發機制,協同各個程序,同時充分兼顧多線程并發效率。
從中,筆者還是看到了自身的一些不足:
部分局部函數仍存在複雜度較高或者設計稍微不合理的地方。
筆者将會從接下來進一步的實踐當中,進一步改善代碼風格,設計更完善更符合規範,人機性能更好的程式。
據筆者觀察,貌似很多的同學至今仍熱衷于使用靜态數組來進行資料的存儲。
起初,筆者十分不解,在<code>Java</code>這樣的OOP語言中,相關的資料結構封裝類可謂相當完備,為啥還要使用數組呢?
經過一些觀察,很多人仍離不開靜态數組的原因大抵如下:
對于枚舉性質的東西,例如IFTTT作業的四種事件,他們喜歡用<code>0</code>、<code>1</code>、<code>2</code>之類的數字表示(别問我他們為啥這麼幹,因為我也想知道為啥好端端的枚舉類不用),然後統計的時候用數組索引即可
很多人還是完全擺脫不了C語言的思維方式,且資料結構基本功幾乎為零
很多人對工程性之類的事情全無認識,認為程式能運作即可
然而,靜态數組實際上有很緻命的缺陷:
資料量較小的時候,空間浪費相當嚴重。
資料量較大的時候,會不可避免的數組越界導緻crash。實際上,筆者至今為止,已經至少有抓住3個送上門的bug是因為被測試者使用靜态數組造成的(此外,筆者現在每次查程式之前,都喜歡用正規表達式+<code>grep</code>指令将對方程式裡頭的靜态數組一口氣揪出來,隻要能找到,基本上很快就能開開心心的拿下這次的一血。這招一抓一個準,屢試不爽,而且基本是抓住的都是crash,一般人我不告訴他23333)
靜态數組這樣的東西隻在極少數特定場合下稍微友善些,然而帶來的卻是很多性能和工程性上的不可控,可謂得不償失。
建議使用<code>Java</code>内置的資料結構,諸如<code>List</code>、<code>Vector</code>、<code>ArrayList</code>類,這些類均進行過有效的代碼封裝和性能優化,各方面性能均有保證,且不會很容易的出現錯誤。
從第七次作業開始,引入了一些代碼規範相關的考察。個人覺得,其實這是一件很好的事情,畢竟真正的工程永遠離不開維護,也很難離開teamwork。
然而,據筆者觀察,似乎很多人對這件事頗為反感與不解,諸如以下的論調:
為什麼我們的程式能運作了,還要在意這些麻煩的事情?
這個東西卡的很嚴格嘛?如果不是很嚴格那我這12分直接不要了
這個東西有明确的标準嘛?如果沒有的話撕逼怎麼辦?算了。。這12分我還是不要了得了
是的,上述的想法可以說非常普遍,筆者在第七次作業正式釋出後的客服群裡,基本每天都能看到這樣的論調。感覺相當多的人覺得這個要求很不合理。
首先,關于代碼規範的重要性,筆者在上次部落格作業已經有說過,不想再重複唠叨一遍(或者說,唠叨了估計也沒人愛聽。。。)。
不過這樣估計說服不了任何人,那容筆者來舉幾個親自遇到的案例吧。
這個圖,來自于第六次作業筆者測試的這位同學的<code>summary.txt</code>
恩,沒錯,這就是<code>summary.txt</code>。為了防止各位看了一臉懵逼,我還可以告訴你們,冒号前的<code>0</code>、<code>1</code>、<code>2</code>、<code>3</code>表示的是四種不同的事件。
那麼,請你現在告訴我,這個<code>summary.txt</code>是在表達什麼?
是的,沒錯,看不懂的不止你一個,因為筆者當時看到這個的時候也還是一臉懵逼(即便猜到了前面的數字表示的是各個事件類型)。
于是,筆者隻好開始研究他的源代碼。然後很驚喜的發現,這位老哥的所有代碼全都寫在了一個檔案裡頭,而且右邊滾動條上還密密麻麻的都是各種warning。
終于,功夫不負有心人,筆者終于找到了一絲線索:
恩,就是這裡
就是這句
我們來研究下這個超長的三元表達式在表達什麼(emmm,筆者作為多年的老碼農,表示愣是一眼沒看懂):
如果是<code>renamed</code>,傳回<code>0</code>,否則繼續
如果是<code>Modified</code>,傳回<code>1</code>,否則繼續
如果是<code>path-changed</code>,傳回<code>2</code>,否則繼續
傳回<code>3</code>
到這裡,筆者費盡千辛萬苦,終于看明白這個檔案了。
想到這裡,假如,我不是一個測試人員,而是這位老哥的teammate,想要一起開發一個項目。
如果,需要對接的時候要是遇到了這樣的情況,得費多大的勁才能搞清楚?
試想想,如果你每次開發項目,都要花一堆的時間在這種無謂的事情上,你覺得值得麼?有何效率可言?
如果,輸出的不是
而是
如果,這個程式能夠滿足我們所規定的:
懂我原則 讓人一眼就看懂意思,不用再一點一點去翻源代碼
顯示表達原則 這樣的東西封裝成enum然後再用數組啥的搞搞也比一直傳字元串然後弄那麼一個又臭又長的三元表達式強啊
這麼一來可以節省多少的時間。
在第七次作業中,筆者配置設定到的測試程式,依然存在和上面類似的情況。
當筆者一次性輸入多個請求的時候,等待3秒後,出現了一片的報錯:
筆者當時瞬間就懵了,到底哪些指令執行了,哪些指令配置設定失敗了?
然後對<code>detail.txt</code>仔細研究了好半天後,才終于确認程式運作的是對的。
其實吧,在這種時候順帶輸出下錯誤的詳細情況(甚至不用太詳細,輸出一下哪條指令出錯也是好的),對于程式設計者而言真的就是幾秒鐘的事情。
然而如果不加,不僅給别人會帶來很大的困擾,你們自己debug的時候,也會處于完全摸不着頭腦的狀态——因為無論哪裡錯了,輸出的都一樣。
說了以上這些,其實我隻想說明一點:
這些規則,每一條都是有原因的,都是實實在在幫助你們寫出更好的程式提高團隊協作效率的
當然,可能很多人還是無法了解,這也正常。等有一天你們真正參與項目維護(尤其是多人團隊項目)的時候,你們就會明白這些事情的重要性了。
筆者在之前的多次程式作業中,發現每次都要花上好半天的時間搭建程式架構,而且做得基本都是重複工作。
作為一個聰明的懶人,筆者于是自己寫了一個簡單的的工程代碼模闆。Git倉庫,歡迎star
這樣的一個架構能較好的符合筆者本人每次寫代碼的工程結構需要。同時對于一些常見需求也都進行了以行為邏輯為主的封裝,可以通過類繼承等方式快速建構功能子產品(尤其是多線程功能子產品)。
這個庫将會不斷地維護和更新,希望可以幫助到大家。
筆者作為一個寫了很多年代碼(至今已有10年有餘),且實際維護過不止一個工程項目的程式猿,每當想在群裡分享一些個人對于程式、對于代碼規範、對于工程的了解和看法時,永遠會有一些人站出來針鋒相對。
他們的主要邏輯如下:
你說這些有什麼用,我們就是想完成作業啊!
你說這些有什麼用,我的程式是不能運作了還是怎麼着了?
你說這些有什麼用,你說的再多代碼規範啥的一樣會被鑽牛角尖啊!
其實,筆者對于這樣的想法還是表示可以了解的。畢竟每個人站的角度不同,格局自然也有天壤之别(俗稱:屁股決定腦袋)。
不過,筆者還是希望各位能好好想想你們是為何而學習的。僅僅就是為了趕快畢業拿文憑?
當然了,如果這就是你的全部想法,而且以後不想從事這方面的工作的話,那的确随意,隻能說你和咱們技術發燒友(或者最起碼是打算靠這個吃飯的人)不是一路的人。
如果不是這樣,那麼你就該站在更高的格局上想問題:
我究竟能從中收獲到什麼?
結論很簡單,能有所收獲的,就是對的;能收獲更大的,就是更好的。
接下來我來逐個回應下這三個常見邏輯:
<code>我們就是想完成作業啊</code> 請想一想僅僅就是完成一個作業的話,你能學到的東西有多少。。。
<code>我的程式是不能運作了還是怎麼着了</code> 請想想,程式能運作但是毫無維護性和可合作性,這種代碼除了糊弄一下作業有任何價值麼。。。
<code>你說的再多代碼規範啥的一樣會被鑽牛角尖啊</code> 請相信我們的助教團,他們會給你公道的。你隻管做好自己就是了。
另外,可能有些人(甚至包括一些著名大佬)受到知乎上一些所謂的6系人的影響,認為北航的OO課程就是一無是處毫無收獲的。對于這樣的無腦黑,我隻能對您表示深深的同情和憐憫,因為您在用您的未來前途消費,而目的,僅僅隻是為了證明一個文章,和一些前人片面的話語的正确性。
前方高能。接下來的章節可能會引起部分人的不适,請非戰鬥人員迅速撤離。
時間過得真快,一不小心又過去了三次作業。不過這其中自然也有些不爽的事情發生。
雖然呢,筆者很清楚,這樣的東西寫進自己的技術部落格實在是非常不雅,簡直可以說弄髒了筆者的部落格(事實上這也是筆者沒在上面說這件事的原因)。但是有些事情嘛。。。還是不吐不快。
是以接下來說件事,請大家自行評判。
筆者在第五次作業截止後的一個晚上,突然被告知,自己被無效了???
然後,到群裡問了下助教原因,原因是,我在<code>readme.md</code>的指導書url連結中包含了"個人資訊"
連結位址全文如下:
當時,懵逼了。然而再仔細一想,發現事情并不簡單。
首先,這個url位址是在markdown中以連結的形式存在的
其次,這個連結裡頭僅僅隻是個部落格園的檔案位址,僅僅隻是包含了一個叫做HansBug的名字
再其次,這人是怎麼通過HansBug這麼快知道是我的,筆者在北航這個圈子很少以HansBug的名字示人。
越想越覺得不對勁。于是筆者事後仔細一琢磨,可以推測出這個人的邏輯流程圖:
我的天啊,老哥诶,您老人家為了不測試别人的程式為了讓自己睡大覺,可真是煞費苦心啊。走了這麼多步終于找到了我,我佩服你那為了偷懶不怕艱難險阻過五關斬六将的精神,是在下輸了。
或者,我們甚至還可以在這個的基礎上進一步擴充下:
也許可能各位還有點疑惑,甚至覺得我是在用惡意揣測别人。很明顯,有如此耐心曆經那麼多個環節,隻是為了找别人的無效作業痕迹的人,我并不相信他有可能一上來就是想好好測試的。
然而這樣的人物,一個對學術毫無敬畏之心隻想着偷懶萬歲的人,居然還能和筆者分到了相近的段位,筆者隻能哀歎——“知人知面不知心”啊。
綜上,我隻想對這人說一句:<b>你有種給我站出來,别玩陰的!!!</b>
不過,再一想想,人家如何如何,關我何事。筆者還是想認真的對學術和工程負責到底的,以及,無法帶來任何實質性改變的怒火是毫無意義的。
正如上文所言,這類人挖地三尺的一般性動機,就是在于一旦把對方無效了,自己就可以不用測試了。
事實上這次事情的後續進展也表明筆者的猜測完全正确——截至互測時間結束,筆者這份被無效的作業依然一個點都沒有進行測試(包括公測)。最後還是在筆者的一再要求下,課程組的助教們幫筆者完成了測試(在此感謝默默支援的老師和助教們,真的非常感謝)。
至此,這人的動機可以說是非常明顯了。如果他隻是一個按照規則辦事且對學術和工程品質負責的人,那如何解釋到最後都一個點都沒測試的情況?
說到這裡,筆者對于課程有個改進的思路,以遏制這種表面矯枉過正實則惡意滿滿的行為:
規定隻要對于有測試價值的程式(至少具備最基本的功能),即便是無效作業,也必須認真測試
理由其實也非常簡單:
作為一個認真完成作業的人,即便因為各種原因無意中暴露個人資訊,也有權知道自己的勞動成果到底怎麼樣。
這是課程,目的是學到知識和技能,目的是有所收獲。對于無效作業這樣一刀切的做法顯然是在剝奪很多認真寫作業的人有所收獲的權利。
如果不這樣要求,必然導緻有些心術不正之人,不花心思在好好測試上,同樣于有所收獲這一目标背道而馳。(雖然筆者很清楚,這種事情防君子不防小人,不過能防得住幾個僞君子也是好的)
以上是我的看法。
非常感謝各位默默支援我的老師、助教和同學
對為了使OO課程更好,為了讓大家更能有所收獲而不斷努力的前輩們,報以崇高的敬意
對于對筆者提出善意批評和提出意見的人,筆者也表示很歡迎
對于帶着滿滿惡意的人,無論是對于筆者本人還是這門課程,筆者隻能******(請自行腦補)