天天看點

軟工實踐寒假作業(2/2)

這個作業屬于哪個課程 <2021春軟體工程實踐|S班>
這個作業要求在哪裡 <作業要求>
這個作業的目标

1.重讀《建構之法》并提問

2.學習github和git的使用

3.編寫詞頻統計程式

4.學習并進行單元測試

其他參考文獻

1.正規表達式的學習

2.git和github的學習

3.鄒欣:關于單元測試和回歸測試

4.IDEA中使用JUnit4

目錄
  • 作業一 閱讀《建構之法》并提問
    • 問題1:“足夠好”的軟體
    • 問題2:注釋及可移植性
    • 問題3:代碼複審
    • 問題4:創新思維
    • 問題5:提高商品競争力
    • 附加題:軟體工程發展的過程中有什麼你覺得有趣的冷知識和故事?
  • 任務二 WordCount程式設計
    • 0.作業描述
    • 1.Github項目位址
    • 2.PSP表格
    • 3.解題思路描述
    • 4.代碼規範制定連結
    • 5.設計與實作過程
    • 6.性能改進與測試
    • 7.單元測試
    • 8.異常處理說明
    • 9.心路曆程與收獲

在課本P15中寫着:一些同學認為,所謂好軟體,就是軟體沒有缺陷(Bug),所謂軟體工程,就是把軟體中的Bug都消滅掉的過程。P17中寫着:“足夠好”的軟體不是期末前兩天由兩三個同學熬通宵趕出來的急就章,而是經曆了一定的軟體流程,通過全體團隊成員的努力,在一個長期階段内逐漸完成的。

一個軟體的好壞應該更主要由什麼來評價,評價标準是怎樣呢?通過搜集資料發現軟體的好壞得到的大多是來自于使用者的評價。我的想法:我覺得評價應該注重的是使用者評價,看軟體的閱聽人是什麼,将自己代入閱聽人的角度去體驗軟體,如果舒适度便捷度等都合理,那麼軟體應該就挺好的。

在課本P74中寫着:注釋應該隻用ASCII字元,不要用中文或其他特殊字元,否則會極大地影響程式的可移植性。

像在于現階段,我對于很多注釋還是采取使用中文的方式,此時的我的認知中并無法體會到這之中的影響。我想知道在之後的工作中是否每個人的注釋基本都采用英語,或者是什麼樣的情況。再對于文中提及的可移植性。注釋對于每個函數都有必要添加嗎,比如一些工具類的小函數,還是應該怎麼選擇需要注釋的地方。

在課本P79中寫着:軟體工程中最基本的複審手段,就是同伴複審。

當局者迷,旁觀者清。我了解了同伴複審能夠看到更多自己看不到的錯誤或者遺漏,這有利于效率的提高。但就大學裡所遇到的來說,我對于别人的代碼常常會遇到看不懂的情況,或者代碼風格差異較大的情況,我們對于同伴的選擇是否優先考慮水準接近,代碼風格接近。對于以後進入公司後我想大多應該是團隊任務,在那裡對于代碼複審的情況又是如何呢?

在課本第16章“IT行業的創新”中寫着:最近幾年,我們整個社會對創新都很感興趣,媒體上充斥着創新型的人才、創新型的學校、創新型的公司、創新型的社會等名詞,有些城市還把創新當做城市精神之一,還有城市要 批量生産上千名頂級創新人才。

現在國内對于創新十分重視,由“中國制造”轉向“中國創造”。IT行業對于創新思維的要求相對會更高,那麼在平常中該如何去提高這種思維方式。我的了解是從需求中出發進行創新,還有别的方法嗎?我認為對于創新的誕生,主要還是從需求出發,因為有需求,為了滿足這種需求而創造出更便捷的方式。還有就是平常生活中要多關注客觀事物的不同性與特殊性。

在課本P373的魔方的創新故事中,果凍從其他地方帶來魔方,這是創造了一個原本這個地方沒有的事物;小飛影印了魔方口訣表來提高自己的競争力,大牛通過改變遊戲規則來先做到别人不能做到的事,但最後都是因為同學們對魔方的興趣漸漸失去而失去了市場。

這三位同學的行為也對應了不同的選擇:1.去封閉的地方賣魔方,那裡的人不知道外面的世界。2.依靠自己别的優勢或壟斷。3.開發有差異化的新東西,展現獨特的價值。對于一個事物大衆化的過程中(很多人都能夠實作),還有什麼方法能夠提高它的競争力。

一次,馮·諾伊曼在晚會上,女主人勇敢地向他提出一個謎題:兩列火車在同一軌道上以每小時 30 英裡的速度相對而行,且相距 1 英裡,這時栖在一列火車前面的一隻蒼蠅以每小時 60 英裡的速度朝着另一列火車飛去。當它飛到另一列火車時,它又迅速地飛回來。它一直這樣飛過去飛回來,直到兩列火車不可避免地發生碰撞。問這隻蒼蠅共飛了多少英裡?幾乎在女主人剛解釋完問題的同時,馮·諾伊曼就答道:“1 英裡。”“太讓我驚訝了,你這麼快就算出來了。” 她說道。“大多數數學家都沒能看出這裡面的技巧,而是用無窮級數去計算,這花費了他們很長時間。”“什麼技巧?我也是用無窮級數算的。” 馮·諾伊曼回答道。參考來源

這個故事有着很多版本,馮·諾伊曼從小就被寄予厚望,他也為計算機行業做了許多貢獻。

在大資料環境下,搜尋引擎,電商系統,服務平台,社交軟體等,都會根據使用者的輸入來判斷最近搜尋最多的詞語,進而分析目前熱點,優化自己的服務。首先當然是統計出哪些詞語被搜尋的頻率最高啦,請設計一個程式,能夠滿足一些詞頻統計的需求。

作業倉庫:PersonalProject-Java

個人github項目位址:https://github.com/camocd/PersonalProject-Java

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 30 40
• Estimate • 估計這個任務需要多少時間
Development 開發 600 755
• Analysis • 需求分析 (包括學習新技術) 120 200
• Design Spec • 生成設計文檔 25
• Design Review • 設計複審 10
• Coding Standard • 代碼規範 (為目前的開發制定合适的規範) 15
• Design • 具體設計 50 60
• Coding • 具體編碼 300 360
• Code Review • 代碼複審 20
• Test • 測試(自我測試,修改代碼,送出修改) 70
Reporting 報告 135 145
• Test Repor • 測試報告 90 100
• Size Measurement • 計算工作量
• Postmortem & Process Improvement Plan • 事後總結, 并提出過程改進計劃 35
合計 765 940

  • 剛開始看到題目的時候,對于github和git的使用是比較少的,這也給我帶來了一些困擾,不過通過查找一些資料後,也漸漸會使用了,也感受到了其中的便利。
  • 程式設計作業,首先從題目中提取重要資訊
    1. 輸入、輸出檔案以指令行參數傳入
    2. 輸入檔案隻考慮Ascii碼,不考慮漢字
    3. 空格,水準制表符,換行符,均算字元
    4. 任何包含非空白字元的行,都需要統計
    5. 隻輸出頻率最高的10個單詞,形式均為小寫格式
    6. 輸出時冒号後面包含一個空格
  • 對程式設計任務進行分解
    1. 讀取input檔案中的資料
    2. 統計字元數
    3. 統計單詞數
    4. 統計行數
    5. 統計各單詞的出現次數
    6. 将各種結果輸出到output檔案中
  • 在程式設計設計的時候考慮到的問題
    1. 應該用什麼讀取檔案中的資料
    2. 單詞可以用String類的split拆分
    3. 應用什麼來判斷分解出來的字元串是一個單詞
    4. 該怎麼判斷行
    5. 單詞及其頻數用什麼存儲可以友善輸出(Map類)

221801230的代碼規範

隻有兩個類,WordCount類和Lib類,用WordCount類來執行Main函數,指令行參數傳入檔案名,對于傳入檔案後的統計和輸出的處理都在Lib類裡寫。Lib裡主要包含

readFile

writeFile

charNumCount

wordNumCount

lineNumCount

幾個函數

  1. 讀取檔案
public String readFile() {
        StringBuilder builder = new StringBuilder();
        try {
            BufferedReader reader = new BufferedReader(new FileReader(inputFile));
            int ch;
            while ((ch = reader.read()) != -1){
                builder.append((char)ch);
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return builder.toString();
    }
           

讀檔案是選擇采用BufferReader類的read方法,存入StringBuilder對象擷取整個檔案後再做處理

String str = readFile();
charNumber = str.length();
           

直接由字元串的length函數獲得

3.統計行數

String[] lines = str.split("\n");
        lineNumber = lines.length;
        Pattern linePattern = Pattern.compile("\\s*");
        for(String line : lines){
            Matcher matcher = linePattern.matcher(line);
            if (matcher.matches()){
                lineNumber--;
            }
        }
           

先通過

split("\n")

将檔案分成多行,再通過正規表達式

\\s*

去掉那些隻含有空白字元的行,得到需要的值。

String[] words = str.split("[^a-zA-Z0-9]");
        Pattern wordPattern = Pattern.compile("([a-zA-Z]{4}[a-zA-Z0-9]*)");
        for (String word:words){
            Matcher matcher = wordPattern.matcher(word);
            if(matcher.matches()){
                wordNumber++;
                String w = word.toLowerCase();
                Integer count = wordsMap.get(w);
                if(count == null){
                    count = 0;
                }
                wordsMap.put(w,count+1);
            }
        }
           

通過正規表達式

[^a-zA-Z0-9]

将檔案分成一個個詞,在通過正規表達式

([a-zA-Z]{4}[a-zA-Z0-9]*)

判斷是否為滿足條件的單詞。若為單詞,将單詞存入Map裡,進行統計。

  1. 在統計單詞數的時候已經将單詞及出現次數存在Map裡,但是輸出時要滿足一定的順序,通過查資料知道所用HashMap是無序的,則需要進行排序處理
list = new ArrayList<Map.Entry<String, Integer>>(wordsMap.entrySet());
        Collections.sort(list,new Comparator<Map.Entry<String,Integer>>(){
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                if(o1.getValue() == o2.getValue()){
                    return o1.getKey().compareTo(o2.getKey());
                }
                    return o2.getValue().compareTo(o1.getValue());
            }
        });
           

通過重寫compare方法來對Map進行排序

  1. 輸出檔案

    用BufferWriter類的write方法進行輸出

  • 讀寫檔案的時候對比采用BufferReader和BufferWriter類

    帶有緩存的讀寫類能夠減少作業系統通路檔案的次數,加快程式的運作速度。

    輸入測試input.txt

    軟工實踐寒假作業(2/2)
    相應輸出結果ouput.txt
    軟工實踐寒假作業(2/2)
    運作時間
    軟工實踐寒假作業(2/2)

  1. 對字元計數進行測試
@Test
    public void getCharNumber() throws IOException {
        BufferedWriter writer = new BufferedWriter(new FileWriter("x.txt"));
        String text= "ads54\n\t\rdasd,";
        writer.write(text);
        writer.flush();
        writer.close();
        Lib lib = new Lib(  "x.txt ", "y.txt");
        lib.writeFile();
        Assert.assertEquals(lib.getCharNumber(),13);
    }
           
  1. 對單詞計數進行測試
@Test
    public void getWordNumber() throws IOException {
        BufferedWriter writer = new BufferedWriter(new FileWriter("x.txt"));
        String text= "hello1,2hello2,hello3,123jki2,iii\ndasd,156ads";
        writer.write(text);
        writer.flush();
        writer.close();
        Lib lib = new Lib(  "x.txt ", "y.txt");
        lib.writeFile();
        Assert.assertEquals(lib.getWordNumber(),3);
    }
           
  1. 對行數計數進行測試
@Test
    public void getLineNumber() throws IOException {
        BufferedWriter writer = new BufferedWriter(new FileWriter("x.txt"));
        String text = "124\n12312\n\n\n\n3123\n\n ";
        writer.write(text);
        writer.flush();
        writer.close();
        Lib lib = new Lib(  "x.txt ", "y.txt");
        lib.writeFile();
        Assert.assertEquals(lib.getLineNumber(),3);
    }
           
  1. 覆寫率截圖
    軟工實踐寒假作業(2/2)
    覆寫率未滿為trycatch異常處理

主要是對于文檔打開操作的異常處理

try {
    BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile));
} catch (IOException e) {
    System.out.println("檔案打開失敗");
    e.printStackTrace();
}
           
  1. 指令行參數數量不正确的處理
if (args.length != 2){
    System.out.println("指令行參數應該為兩個");
    return;
}
           

  • 剛看到作業的時候,心情是很忐忑的,因為這次作業的内容需要通過github和git來完成,對于之前,也隻是偶爾從github上下載下傳東西,對于使用倒是一竅不通,還好通過學習,現在已經會使用一些了,也能夠體會到git的友善。還有就是對單元測試的學習,基本算是會運用了。
  • 而且一段時間較少使用Java程式設計了,通過這次作業,也重新溫習了一些運用,也加深了對Map類的運用。
  • 也逐漸地認識到了自己的代碼規範,好的代碼規範可便于程式設計,有利于程式設計。
  • 還有就是對于時間的規劃,我對于時間的規劃還存在一定的問題,對時間有規劃也能夠提高自己的效率,會不斷學習提高自己。
  • 複習了正規表達式,這次作業也讓我對于正規表達式有了更多的運用,使用起來也更加熟練