【做業3.0】HansBug的第三次博客規格總結

轉眼間第三次做業了,彷佛須要說點啥,那就說點。java

規格&工業

說到這個,不得不提一下軟件開發的發展史。git

歷史的進程

早在上世紀50年代,就已經有早期的編程語言出現,也開始有一些程序編寫者出現(多爲資深電子工程師,和半路出家的數學家)。程序員

然而那個時代,軟件開發基本侷限於本身或本身部門內部的使用,需求並無不少,也並不複雜(或者說人們並無意識到有那麼多事情能夠經過軟件解決)。因此基本都是靠早期的程序猿們的自由開發,也並無現代代碼規範的概念。github

然而等到了60到70年代,隨着硬件技術和工業界思想的進步,軟件層面上的需求愈來愈多,愈來愈雜,且再也不侷限於本身的使用,開始有了各種外包的需求(早期的軟件做坊、外包公司)。這時候,人們發現代碼規模一上來,工程質量將再也不那麼可控。不只開發成本隨規模急劇上升,且開發過程當中的人員與工程管理也出現了很大的麻煩。失敗的案例不在少數,工期拖延數月甚至數年的也經常發生,並且還頗有可能沒法知足用戶的需求或者可靠性極差。軟件工程迎來了一個動亂的年代正則表達式

1968年,北大西洋公約組織的計算機科學家在聯邦德國召開的國際學術會議上第一次提出了「軟件危機」(software crisis)這個名詞。算法

歸納來講,軟件危機包含兩方面問題:編程

  • 如何開發軟件,怎樣知足對軟件日益增加的需求
  • 如何維護數量不斷膨脹的已有軟件

1968年秋季,NATO的科技委員會召集了近50名一流的編程人員、計算機科學家和工業界巨頭,討論和制定擺脫「軟件危機」的對策。在那次會議上第一次提出了軟件工程(software engineering)這個概念。軟件工程正式被列爲工程的一種,並開始走向專業化系統化,以全新的面貌從新步入工業界。數組

現代的軟件工程是一門研究如何用系統化、規範化、數量化等工程原則和方法去進行軟件的開發和維護的學科。經過前人的不斷努力,人們逐漸解決了軟件危機,並認識到規格化設計的重要性,在此期間,一些重要的文檔格式的標準被肯定下來,包括變量、符號的命名規則以及源代碼的規範式。後來隨着發展,這些規範逐漸造成了軟件開發中的規格化設計,而且因爲其高效性與高可靠性,愈來愈受到軟件開發人員的重視。架構

我的的奮鬥

結合我我的嘛,其實也是能說上一些的。因爲筆者在早年長期處於自由成長階段,因此其實不少發展歷程,和歷史的進程十分類似。編程語言

筆者從2年級初學編程(2005年,豆腐塊+win2000的年代),最初寫的都是一些很小的程序(基本不存在超過100行的狀況),用的是面向過程語言和原始的面嚮對象語言。(Pascal、VB6,後來進階VB.NET)

說實話,筆者之因此喜歡編程,喜歡計算機,很大程度上喜歡的是創造的快感,尤爲是計算機這種低成本高回報即刻見效的創造。因而呢,筆者逐漸在試着編寫規模更大程序,來知足一些更加實際的需求。在那個階段,筆者的開發徹底是怎麼順手怎麼來,畢竟急於得到那種看到成果的快感,且尚未造成工程的思惟(和不少同窗現階段的狀態相似)。

然而,筆者在初中那會就發現了一件很頭疼的事情——但凡程序超過500行,不管再簡單的需求,再明確的目的,本身都會開始控制不住局面。具體的表現爲,只要規模一上去,哪怕本來早就想清楚了一切,在debug的時候仍是不是這裏出錯就是那裏出錯,甚至自覺得改好了一邊,而後另外一邊又被帶出毛病的狀況也時有發生。

那個階段,能夠說,筆者本身軟件開發的投入成本隨代碼量上升而上升的幅度是指數級別的。

筆者曾經被這個問題困擾了很是久,一直處於這樣的一個瓶頸期,難以突破。

直到高中,接觸了github,上去看了一些各個語言的開源代碼以後,才恍然大悟。筆者發現:

  • 不少的開源代碼,都配備了相關的說明文檔,並且格式整齊內容齊全,查找相關信息至關的方便。
  • 點開代碼以後,發現不少地方都有註釋(甚至註釋行數和代碼行數比例已經接近1:1),說明相關位置的功能與需求。(相似於規格的requires和effects)
  • 不只如此,連類、方法,甚至局部變量的命名,格式都十分整齊。(求讀者別笑,筆者曾經一切數組命名均爲abbd,其餘變量都亂用單個字母)
  • 各個類、方法,各司其職,或者說誰都自掃門前雪,無論他人瓦上霜。

因而,解決方案就很是明顯了——代碼規範化。由於,多花這些時間作好這些工做,對於全局而言,實際上並不下降效率,正所謂磨刀不誤砍柴工。

當筆者得到進一步能力提高以後,就開始開發更大規模的程序。

然而,當正式步入工業界時,另外一個很現實的問題產生了——對於上層的工程師或架構師,該如何對全局化系統化地設計一個系統

親手碼代碼顯然速度太慢,且只能一我的幹,不具有可合做性,沒法發揮並行優點。然而設計不實現好的話,又該如何描述設計?

答曰——規格。架構師只須要將各個部分的規格設計好,規定好出入口條件等信息,由下位程序猿進行完成便可。既準確描述需求又提供了測試根據,一箭雙鵰。

規格與bug相關性分析

規格錯誤

筆者未被報過規格錯誤。

bug分析

筆者

在第十一次做業中,被友善好心素質優良情商天下第一的測試者找到了bug,分別是:

  • 未過濾map.txt內的空白字符
  • 未過濾lights.txt內的空白字符
  • 在直路或者斷頭路加上紅綠燈後未輸出錯誤信息

很明顯,這三個均不是內部功能性上的錯誤。

能夠說是筆者的需求分析失誤。(前兩個隱藏在指導書上的一個角落中,後一個隱藏在第十次做業的issue區。)

相關性分析

因爲筆者未被報過規格錯誤,且bug均爲需求研究層面上的疏漏,故不存在相關性。

規格舉例

筆者認爲,實際上,只要搞清楚規格的做用與意義,不少問題就應該迎刃而解,無需舉過多的例子

反面教材

說到規格的一些不太好的用法,其實最典型的有如下幾種

過分使用天然語言

字面意思,有些很好用布爾表達式表達的卻恰恰用了天然語言

/**
 * @requires: true;
 * @modifies: None;
 * @effects: result will be the equation between a and b;
 */

應該改成

/**
 * @requires: true;
 * @modifies: None;
 * @effects: \result == (a == b);
 */

使用具體算法表示規格

規格,講究的是個對於局部抽象功能的描述。說白了,它只關心這個方法或者類應該實現什麼樣的一個功能,而不關內心頭具體是怎麼實現的,同時,給出的規格條件必須具有可斷定性

例如程序(GenericPair爲泛型二元對類):

public static GenericPair<Integer, Integer> whatCanYouSee(int a, int b) {
    int c = a + b;
    b = c - b;
    a = c - a;
    return new GenericPair<>(a, b);
}

仔細看的話,應該不難發現其實功能是交換了ab的順序後存入了GenericPair內。

然而規格很容易被寫成以下的形式:

/**
 * @requires: true;
 * @modifies: None;
 * @effects: 
 *                 c == (\old(a) + \old(b));
 *                 b == (c - \old(b));
 *                 a == (c - \old(a));
 *                 result will be new GenericPair<>(a, b);
 */

而正確的應該是改成先後置約束條件。

/**
 * @requires: true;
 * @modifies: None;
 * @effects: (\result.first == b) && (\result.second == a);
 */

方法內局部變量寫入modifies

實際上,筆者見過一些同窗,在初學階段把局部變量的修改也寫入了modifies。相似這樣:

/**
 * @requires: true;
 * @modifies: z;
 * @effects:
 *                 z = x * y;
 *                 \result == (z + x + y);
 *                 
 */
public static void privateVariableSample(int x, int y) {
    int z = x * y;
    return z + x + y;
}

不過,仍是那句話——規格只關心這個方法或者類應該實現什麼樣的一個功能,而不關內心頭具體是怎麼實現的

局部變量徹底是屬於方法內部的東西,並不屬於外部設計者須要關心的範疇。因此,不該寫在modifies內,與之相關的表達式在effects關鍵字中也應該展開表達。

/**
 * @requires: true;
 * @modifies: None;
 * @effects:
 *                 \result == (x * y + x + y);
 */
public static void privateVariableSample(int x, int y) {
    int z = x * y;
    return z + x + y;
}

不符合javadoc基本格式規則

其實,這一點是ppt上的錯誤示範致使的。筆者在第十次做業報了對方一個這樣的JSF錯誤,然而鑑於對方認爲ppt上有相似的格式,因此筆者只好先選擇了仲裁。

實際上,JSF這樣的東西,從一設計,就是要面向自動化的,同時繼承了doclet(筆者有幸閱讀過JSF源代碼),就是爲了完美兼容和擴展javadoc。而違反javadoc基本格式規範的行爲,顯然與這一設計初衷不符。建議課程組看到以後對相關部分進行全面的修改。

錯誤示範一(第九次PPT,P16):

javadoc基本格式中間行開頭都是須要*的,且首行(兩個*的行)不要寫東西。開頭的*也最好嚴格對齊。

錯誤示範二(第十次PPT,P9):

理由同上

相似這樣的錯誤示範還有很是多

此外,其實關於javadoc的格式,在idea(或者說jetbrains系列IDE)中,直接鍵入/**並回車便可生成正確規範的格式。

感想

關於規格

其實,根據筆者的瞭解,嚴格工程開發是這樣的一個流程:

能夠看出,規格、不變式在開發、測試環節中扮演了至關重要的角色

  • 爲開發組提供了實現程序內部具體代碼的需求依據
  • 爲測試組提供了編寫單元測試的需求依據
  • 爲架構師提供了架構依據,和嚴格論證正確性的依據(在航空航天等對軟件質量有極高要求的行業內,這一點尤爲重要)

固然,實際上,在一些非高度嚴格的工程代碼中,甚至不寫規格也是很常見的。例如筆者參與過的創業公司內的開發,多爲敏捷開發,且攻城獅開發經驗均較爲老道,徹底有能力緊緊掌握全局

不過,敏捷開發對攻城獅自身素養要求是很高的。而若是想普遍地擴大生產力,則這樣子成本無疑太高。

這時候,強類型面嚮對象語言、代碼規範、文檔規範、規格就得以體現其做用:

  • 對底層開發者而言,開發只須要嚴格按照規格需求,便可撰寫程序和文檔。程序員工做技能門檻變得很低,有利於普遍招募廉價生產力,創造更多效益
  • 嚴格約束底層開發者的開發行爲,而且能夠進行嚴格的量化考覈,管理起來很方便
  • 對於上層的攻城獅和架構師,其編程行爲即爲規格編寫,再也不須要具體地去實現每個內部的細節(或者說只要規格需求能知足,內部實現細節並不那麼重要)。工程師工做效率得以提升

生產力決定生產關係,生產力量變引起社會質變,這樣的結論在計算機行業同樣適用。由於,工業界,其終極目標永遠只有一個——創造更多價值

關於JSF

JSF根據筆者瞭解,彷佛是之前的某位學姐的畢業論文。以及,彷佛課程組對這樣一個東西情有獨鍾。

咱們先來看看JSF爲人稱道的地方:

  • 採用布爾表達式,便於自動化生成單元測試*(的確,有了require、effects條件,就徹底具有單元測試的基本屬性了)
  • 輕量級,繼承自doclet,可擴展進javadoc

看似,的確是個好東西,並且理論上確實如此。然而,理論和實際老是存在着不可忽視的差距的:

  • 採用布爾表達式,因而不少東西變得再也不有正常表達的可能(例如,正則表達式斷定,難道使用者還須要把整個正則表達式龐大的邏輯像寫verilog似的表達出來?)
  • 對override,繼承的支持至關貧乏(這意味着,若是想要徹底完整的表達表達式,在繼承層數較多的狀況下,表達式規模將無限膨脹,友好性極差)
  • 容錯性將是另外一個很棘手的問題。用布爾表達式爲了什麼?很明顯最終目的是實現自動化。然而用戶只要寫的稍有欠缺(哪怕小到徹底不影響人工編程和人工測試的地步),單元測試的生成都將出現巨大問題。
  • 不只如此,對於一些沒法表達的東西怎麼辦?
    • 用天然語言?那麼還打算怎麼自動化?自動化生成一小部分而後人工再寫?這樣高不成低不就的解決方案用戶體驗並很差
    • 進一步擴大語法?咱們暫且先認爲存在這種完備的語法設計,就算全都能用布爾表達式表達了,那麼這樣一個東西輕量化的優勢將不復存在。同時,你也會發現,這種完備的表達式,已經和直接寫單元測試差很少少了。那麼自動化難道就是幫人近似的抄一遍程序?很抱歉,這樣的自動化毫無心義,工程師們不可能買帳的。與其這樣還不如直接寫單元測試,而後用腳本將單元測試程序拷貝到對應的方法註釋上。

這麼看下來,彷佛惟一還能夠的地方就是javadoc的兼容性設計了。

JSF的設計宗旨是爲自動化提供可能,而且具有輕量級特性。然而就目前的JSF而言,能夠說是很是尷尬的存在——本是追求自動化的,但是自動化卻作得侷限這麼大,作得這麼不到位,並且實際寫起來對用戶要求還極高,和天然語言比起來體驗只差很差。

綜上,筆者以爲,若是JSF不良好的解決自動化問題,或者從新對這種工具進行需求定位的話,這樣的東西將不存在實際應用到工業界的可能性。(筆者也對這種東西的前景持消極態度)

關於某位大佬

emmm。。。說在前面,若是讀者您看不懂這段話在說啥的話,那說明不是寫給您的,您能夠直接跳至下一個段落,感激涕零

我相信您老人家此次必定又在看個人博客。嘛。。。本菜的博客有您這樣的粉絲,實屬蓬蓽生輝。

以前已經給您寫了一些話,我已經深入沉痛深切地檢討了個人過錯,還望大佬您海涵。

做爲本菜對友善好心素質優良情商天下第一的大佬您的賠禮道歉,我爲大佬送上一句大佬本身說出來的金句——「對了,情商是個好東西」

emmm。。。筆者認爲,對於這樣的大佬這一句還不夠,那麼,再來兩句——「種瓜得瓜種豆得豆」「己所不欲勿施於人」

其餘更多的話,本菜坐臥不安,不敢多言。由於您這樣神通常的大佬哪裏是我這樣的人能夠教育的了的呢。

好的,可愛的筆者抽風完畢。接下來正文繼續。

關於規格制度設計上的我的意見

其實,規格的意義與重要性,筆者在上面均已經進行了論述。這一點絲絕不值得懷疑。

可是,這樣的制度直接照搬進了一個面向小白的OO課程,並且還如此草率地歸入互測考覈,真的合適麼?

筆者給出的答案是否認的。

首先,在目前這樣的課程制度設計下,徹底不能體現規格的重要性。最典型的一點,就是先寫程序後寫規格。這顯然是錯誤的作法,然而,這樣作的不只僅是大部分同窗們,還包括課程的設計——出租車做業第一次並不要求規格,從第二次纔開始要求。這意味着什麼?這意味着你們第二次出租車做業將花費大量的時間補第一次的規格(甚至花在這上面的時間遠遠多於正確使用規格的時間)。給第一次接觸規格的同窗們上來就是這樣的徹底錯誤的引導,顯然是不合適的。

其次,JSF的各類槽點,上面已經吐槽過了,用戶體驗至關差,此處再也不贅述。並且當JSF歸入考覈以後,因爲不得不使用部分天然語言,而致使你們都使用天然語言描述的狀況不斷地發生,然後課程組還給出了require必須布爾表達式的要求,然而根據筆者的調查和了解,並無起到預期的效果。能夠說,JSF的強行推廣是至關失敗的

不只如此,咱們來回想一下,JSF互測,評判者都是些什麼人——同樣還沒有造成工程思惟,同樣不熟悉規格設計的小白同窗。把這樣的東西的評價權力直接交給自顧不暇的初學者,或者說得更直接點,讓不懂工程的人強行評判工程的好壞,這樣的作法顯然很荒唐。這樣只會致使測試者無從下手(甚至乾脆選擇不講道理亂扣分),而被測試者的公平與利益毫無保障

不一樣於BUG互測(實際上筆者支持保留BUG的互測),JSF這東西不少同窗都是第一次接觸,工程思惟不少同窗都尚未造成。也許對於職業攻城獅和其餘從業人員而言,他們內心都一把評判的尺子,也具有最最基本的職業道德和職業素養。可是對於初學階段,各方面水準參差不齊的學生而言,這樣的作法顯然太過於理想化了。

此外,課程組還彷佛單純的想依靠高傷害和仲裁機制來保證你們的重視與制度的公平性。可是,在目前這樣雙方都一臉迷茫的情況下,這樣是毫無效果的(甚至能夠說弊遠遠大於利)。盲目的高傷害只會致使你們愈來愈沒有努力的動力(由於再努力再踏實也沒有有些良心歷來不會痛的投機分子過得舒服,本身的努力在高傷害面前一文不值),而滯後至關嚴重的仲裁製度更是致使你們再也不那麼相信正義的存在,可謂雪上加霜(遲來的正義,經常和沒來沒有區別)。

然而,據筆者所知,課程組彷佛在根據經過這樣收集到的數據來進行數據分析,並且彷佛還分析了與bug的相關性,不只如此,甚至還得出了同窗們不夠重視JSF的結論。對此,我只想說,這樣的數據,與其說是JSF評判的最終結果,倒不如說是博弈的最終結果,公平性真實性根本保證不了。用了個錯誤的前提條件,獲取了所謂預期的分析結果,是毫無心義的

綜上,筆者以爲不該該在使用互測制度來考覈JSF,而應該將評價權交給更加專業的人士。一方面保證同窗們能受到正確的引導,另外一方面也保證制度的公平與合理,此外,也保證數據收集工做真正的客觀性與有效性

相關文章
相關標籤/搜索