天天看點

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

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

這個作業屬于哪個課程 2021春軟體工程實踐|S班
這個作業要求在哪裡
這個作業的目标 閱讀《建構之法》并提出問題、學習git、實作WordCount
其他參考文獻 部落格園,CSDN

目錄

  • 閱讀《建構之法》并提問
    • 1.創新者與先行者
    • 2.事後諸葛亮會議
    • 3.qa和test
    • 4.結對程式設計
    • 5.典型使用者
  • WordCount程式設計
    • Github項目位址
    • PSP表格
    • 解題思路描述
    • 代碼規範制定連結
    • 計算子產品接口的設計與實作過程
    • 計算子產品接口部分的性能改進
    • 計算子產品部分單元測試展示
    • 計算子產品部分異常處理說明
    • 心路曆程與收獲

p351頁寫到:

大家聽了很多創新者的故事,有些人想,他們真了不起,第一個想出了這些美妙的想法,要是我早生幾十年,也第一個實作那些想法就好了。其實,大部分成功的創新者都不是先行者,例如搜尋引擎,Google是很晚才進入這個領域的。又如 Apple的音樂播放器iPod,釋出于2001年10月23日,在它之前市面上已經有很多同類産品了.

論及市場競争時,人們喜歡用下面這樣一些詞彙:。

先行者( First Mover )、先發優勢(First Mover Advantage,FMA )·

後起者( Second Mover ),後發優勢( Second Mover Advantage,SMA)

這是sma的定義:後動優勢(late-mover advantage;Second-mover advantage;又稱為次動優勢、後發優勢、先動劣勢)是指相對于行業的先進入企業,後進入者由于較晚進入行業而獲得的較先動企業不具有的競争優勢,通過觀察先動者的行動及效果來減少自身面臨的不确定性而采取相應行動,獲得更多的市場佔有率。

實際上,搜尋了一下SMA的定義後,我覺得一些成功的後發者憑借的并不是後發優勢,如微信打敗米聊更多的是因為QQ龐大的使用者基數可以使微信迅速發展使用者流量罷了.同樣ie超過mosaic更多的應該是商業政策的原因.

p339頁:

一個裡程碑結束了,接下來怎麼辦?團隊有什麼經驗教訓?産品怎麼才能做得更好?我們常說“軟體的生命周期”—這個軟體開發的周期結束了,生命也結束了。我們能不能像醫學的屍體解剖一樣,把這個軟體開發的流程解剖一下?解剖的過程可以叫:Postmortem,Retrospective",Review,事後諸葛亮會議,等等……大多數學校裡的軟體工程項目結束後大家一哄而散,一些諾言像“我一定會補上文檔的”、“我們還會繼續開發的”……成了撤退時的疑兵之計,等煙塵散去,同學們早跑沒影了。

産品釋出了,大家松了一口氣。阿超建議大家開一個總結會議,就是事後諸葛亮會議。會議請公司的秘書小芳主持并作記錄。為了讓大家能暢所欲言,阿超和大牛沒有參加會議。為了活躍氣氛,小芳還買了零食、飲料、河曲啤酒等。

事後諸葛亮會議是對整個項目的回顧,總結經驗教訓,但是一些公司裡人員流動大,去去留留一個項目能換幾茬人,那麼事後諸葛亮會議還有意義嗎?會不會變成甩鍋大會呢?

思考以後覺得個人對參與項目的自我反思還是相當重要的,事後諸葛亮會議要不要成為團隊的常設項目還是要因具體情況而定吧

p316頁:

從上面的叙述中不難看出,軟體的品質保障(QA)和軟體測試(Test)是有很大差別的。然而,目前IT業界經常混用QA和Test這兩個名詞,很多團隊的QA/Test工作是在較低水準上重複。一位曾在微軟和雅虎工作過的程式員,有這麼一個論斷:大多數的開發團隊并不需要一個獨立的測試角色°。這引起了中國IT業界的熱烈讨論,其中一篇影響較大的文章是“我們需要專職的QA嗎?”

我了解了QA與TEST的具體資訊與差別

相同點 不同點
QA TEST
保證和提高産品品質 關注過程SQA 重點是對軟體開發過程進行監督管理、控制 關注産品TESTER 重點是對軟體開發的成果進行檢查、控制
以組織标準過程和項目已定義過程為依據 以産品需求為依據
以評審和審計為主要手段 以模拟各種場景的實際使用為手段
重在發現和提出過程存在的問題 重在發現産品存在的缺陷
重在預防 重在發現和糾正

我的了解是test就是QA的子集,軟體測試隻是QA的一部分,QA的權限也比test大許多,對于大部分公司來說,職位并不是嚴格的,很多人可能是一職多能,即是QA也是開發.看了一些回答把國内的測試稱作頂着QA頭銜的test

p85:在結對程式設計模式下,一對程式員肩并肩、平等地、互補地進行開發工作。他們并排坐在一台電腦前,面對同一個顯示器,使用同一個鍵盤、同一個滑鼠一起工作。他們一起分析,一起設計,一起寫測試用例,一起編碼,一起做單元測試,一起做內建測試,一起寫文檔,等等。

結對程式設計的好處書中已經較長的描述了,那結對程式設計的不足之處呢?結對程式設計在現實生活中國内的公司似乎很少采用,是有什麼局限嗎?

我發現知乎有一個相似的提問:國内為何很少有人做結對程式設計呢?是确實不好還是屬于中國特色

閱讀了他們的回答以後,我總結了一些看法:

1、一些内向的程式員不太喜歡在程式設計中與他人頻繁交流

2、管理者懷疑結對程式設計的産出比不上兩個人以傳統方式進行開發

3、有些工作不适合結對,結對的人有明顯的思維趨同性,可能範一樣的錯誤

實際上,到目前為止,我的感受就是互相溝通一起完成工作确實會比單幹少放錯、進度快,但是會快多少就不清楚了。

下面還刷到了周筠老師的回答-------

p218:

定義了最初的典型使用者之後,是不是就可以開始寫程式了?不,典型使用者隻是我們的設想,這些都是紙上談兵,我們還要和這些典型使用者的代表交流,了解使用者,了解他們的工作方式和需要。然後再修改,細化典型使用者。于是,移山公司的員工和實習生花了幾天時間,做了不少使用者調查,搞了不少頭腦風暴,畫了無數草圖。

小李:(回來報告)除了進一步了解使用者的需求,細化了一些功能的設想外,我們還有一個重大發現,我們的第一個典型使用者,吳石頭,好像不喜歡上網,他事實上不太會用電腦,也搞不懂如何上傳照片。凡是和網絡相關的事情,都交給了他的兒子。是以我們不得不把吳石頭從典型使用者中删除。

典型使用者是指,按不同次元來區分使用者的過程中,在每個次元中能代表目标使用者的那類群體。比如,按人數多少來劃分的,能代表最多使用者特征的群體;按盈利來劃分,能代表帶來最多盈利價值特征的群體。

但是典型使用者的定義和删除讓我覺得非常奇怪,典型使用者在何種情況下需要進行删除呢?

https://github.com/hh-afk/PersonalProject-C

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

最開始拿到題目後,想法就是将其拆分成4-5個部分,一部分實作一個功能,編寫countchar,countline,countword分别解決,然後詞頻通過數組存儲冒泡排序進行統計。(後面看來在最開始的思考方面應該多花些時間而不是急匆匆的編碼)

最後詞頻統計是用map存儲,使用了Merge Sort

analysisFlie類中包含有成員函數countChar、countWord、countLine 進行分析處理,getChars()、getWords()、getLines()進行傳回類内私有變量chars、words、lines,countWord同時将統計資料存入map,通過sort函數排序後得到詞頻。

代碼規範

計算字元數:

思路就是一個個讀字元,然後累加。但是最開始沒有使用noskipws,無法讀入空格,之後也遇到了'\r'讀不出來的情況,以二進制打開file後解決.

while (!file1.eof())
    {
        file1 >> c;
        if (file1.eof())
        {
            break;
        }
        i++;
    }
           

計算行數

思路與上面讀字元類似,用getline一行一行讀,如果遇到空行就不加。

string d;
    while (!file1.eof())
    {
        getline(file1, d);
        if (file1.eof())
            break;
        if (d.empty()) 
        {
            i--;
        }

        i++;
    }
           

計算詞數将所有大寫字元轉換為小寫後操作,先判斷是否前四個都是字元 ,是的話将單詞存入map

for (i = 0; i < n; i++)
    {
        if (!isChar(b.text[i])) //如果不屬于0-9及a-z跳過繼續循環
            continue;
        else
        {
            for (j = 0; j < 4 && i < n; j++) //計算存儲合适的字元串
            {
                if (!isChar(b.text[i]))
                    break;
                store[j] = b.text[i++];
            }
            if (j == 4)
            {
                for (m = 0; m < 4; m++) //如果不是字母開頭則不符合要求
                {
                    if (store[m] < 97 || store[m]>122)
                    {
                        sym = 1;
                        break;
                    }
                }
                if (sym == 0) //符合要求的話将單詞存入w,再存入map
                {
                    char* w = new char[1000];
                    b.sums++;
                    for (m = 0; m < 4; m++)
                    {
                        w[k++] = store[m];
                    }
                    while (isChar(b.text[i]) && i < n)
                    {
                        w[k++] = b.text[i++];
                    }
                    w[k] = '\0';
                    load(w);
                    isWord++;
                    delete[]w;
                    k = 0;
                }
                else
                {
                    sym = 0;
                    j = 0;
                }
            }
        }
    }
           

最開始詞頻方面我是用冒泡排序解決的,與同學交流後得知用map存儲的話排序可以友善快速,因為思考的時候沒有考慮周到是以最後還是用了歸并排序,但是也提高了處理速度.

void merge(Words* a, Words* b, int left, int mid, int right) {
    int i = left, j = mid + 1, m = 1;
    while (i <= mid && j <= right) {
        if (a[i].count < a[j].count) b[m++] = a[j++];
        else b[m++] = a[i++];
    }
    while (i <= mid) b[m++] = a[i++];
    while (j <= right) b[m++] = a[j++];
    for (int n = 1; n <= right - left + 1; n++)
        a[left + n - 1] = b[n];
}

void sort(Words* a, Words* b, int left, int right) {
    if (left < right) {
        int mid = (left + right) / 2;
        sort(a, b, left, mid);
        sort(a, b, mid + 1, right);
        merge(a, b, left, mid, right);
    }
}
           

歸并排序參考自https://blog.csdn.net/qq_43337263/article/details/105218460

另外我發現各個函數實作功能的時候都會對整個檔案讀取周遊所有字元,計算單詞數的函數還不止周遊了一遍

一開始因為沒有接觸過單元測試,是以還是先對程式功能進行手動測試,跑出結果後用NOTEPAD++編輯器手動統計字元,行數,詞頻等,後面學習了單元測試的相關知識,就改用單元測試了

編寫的單元測試例子如下:

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

運作單元測試時出現了一些平時跑程式時沒有的問題,花了一些時間來解決問題。單元測試比起手動測試統計來說還是友善了不少,簡化了繁瑣的重複操作。

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

main函數内沒有覆寫到,其他都測試到了

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

我發現同一個文本在性能分析報告中跑的速度會比直接運作慢好多,并且會生成一個很大的檔案,是以後來選了一個小一些的檔案來跑進行分析

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

如果打不開需要分析的檔案,就會輸出File open failed

if (!file1.is_open())
    {
        cout << "File open failed" << endl;
    }
           

如果打不開需要寫入結果的檔案,就會輸出無法寫出結果

if (!file2.is_open())
    {
        cout << "無法寫出結果" << endl;
    }
           

1、事後想來再進行需求分析,設計複審,具體設計的時候應該多花些時間,在具體編碼之前沒有仔細審慎的工作,前面節省的一些時間都在後頭的編碼與測試中成倍的還回來了。進行編碼前還是要考慮好設計好,邏輯混亂、想到哪寫到哪導緻程式中好幾個函數沒用過(根本用不到的功能),對\t等的處理又沒有考慮到。

2、開發時因為沒有配置好.gitignore導緻代碼都是在本地vs上的一個項目内寫好,再拷貝到github目錄下commit,代碼搬來搬去的不僅容易亂還出了一堆錯誤,比如兩個編輯器的代碼規範配置不一樣導緻代碼規範一改再改,比如拷貝的時候拷錯了地方,下次應該先配置好.gitignore再編寫。

3、合理命名變量,及時編寫注釋是相當重要的,像統計次數的功能中用了一堆i,j,m,k之類的沒有好好命名的變量,又沒有及時編寫注釋,第二天就看不懂寫了啥了。變量亂七八糟,沒有好好命名的代碼是shithole,再缺少注釋就爛到無法形容了。

4、大學中應該積極的自我學習,像github是很早以前就注冊過了,然而直到這次作業才比較實際的使用它,而不是把它當成永遠在将要學習的計劃裡的一門技術。vs中的單元測試和性能探查也是,一直沒有實際的應用,隻是知道而已。

5、與同伴一起程式設計一起交流比起一個人埋頭悶幹要順的多,比如行數統計和字元統計中遇到\r以及中文等會出問題的情況就是同伴告訴我比較快捷的解決方法的,在優化代碼方面幾個人一起讨論也比較容易發現自己的不足,比如用通配符實作字元串的比對就會簡潔易懂的多,還有排序可以直接用map進行,速度快很多。

6、性能分析中的檢測會生成一份非常大的報告并且速度極其慢,2e6的資料跑了半個小時還沒有結束,并且占滿了我的c盤,或許可能是我的使用方法出了錯誤。

7、代碼規範十分重要,最好在規定好代碼規範後配置好ide,再進行編寫,并且要按照完全按照規範來,我的代碼規範确定好後在程式設計過程中因為ide配置不一樣、規範和個人編寫習慣有所差别導緻中途更改了規範,完成後又重新審查一遍以符合規範。