天天看點

寒假作業2/2

這個作業屬于哪個課程 <班級的連結>
這個作業要求在哪裡 <作業要求的連結>
這個作業的目标 學習Python文法和基礎API,自主完成項目,形成文法規範,對于《建構之法》的再思考
作業正文 項目的開發到結束的詳細流程和文檔,閱讀《建構之法》提出問題并思考
其他參考文獻 《建構之法》 《騰訊Cplusplus編碼規範》 《Python PEP8》

目錄:

  • 關于《建構之法》的思考和提問
    • Question One:團隊中的人員能力參差不齊,在一個團隊中如何安排才能使每個人在團隊中發揮出最大作用?
    • Question Two:在項目合作中總是會出現個别人躺赢的情況,不管是團隊項目還是結對程式設計,特别是作業項目,如何處理好這個情況?
    • Question Three:代碼重構和重寫的差別是什麼?
    • Question Four:關于Bug,有些時候bug存在緻命性,但我們又無法修複他,隻能推倒重做,如何在開發過程中避免這種情況?
    • Question Five:關于PM,在小型開發中是否需要PM?
  • 附加題
  • WordCount程式設計
    • GitHub項目位址
    • PSP表格
    • 解題思路描述
    • 代碼規範制定連結
    • 設計與實作過程
    • 性能改進
    • 單元測試
    • 異常處理說明
    • 心路曆程與收獲

1. 關于《建構之法》的思考和提問

寒假作業2/2

  • 《建構之法》P151頁

    在第四章中講述了“結對合作”,雖然文中講述了代碼規範,代碼複審,兩人合作的技巧等......,但是我有一個疑惑點,在團隊開發中每個人的代碼水準都不盡相同,那麼在團隊中應該如何較好地協調安排每個人的工作?我查找了一些資料,對于3-5小型的項目由于團隊規模較小,能夠及時溝通,是以有什麼事情能夠較好得溝通,但是對于大團隊來說,必須要有一系列的說明文檔來提供相應的支援,團隊通過篩選人員進入公司,并安排有項目經驗的人來管理安排人員,但是具體在小型項目中如何安排人員配置設定依舊沒有相應的答案,希望能夠給予具體的解答。

  • 盡管文中提及如何結對程式設計,如何團隊開發,但是依然可能出現問題中的這個情況。在網上搜尋回答,給出的回答是在元件團隊的初期應該能夠篩選隊友,對于一些不靠譜的隊友不予考慮,俗稱“混子”,但是根據以往經驗,一開始項目時,并沒有辦法分别是否這個隊友靠譜,隻有在項目進行到一定的階段時,才能分辨出來,而在這個時候基于人情考慮,還是沒法直接點破将在之提出隊伍,在項目開發中,如果出互相這個情況如何解決,懇求給予解答。

  • 《建構之法》P407頁

    文中“小飛對照設計文檔和代碼指南進行自我複審,重構代碼。”對于“代碼重構”不是很清楚,查找了一些資料,重構代碼就是通過調整程式代碼,但并不改變程式的功能特征,達到改善軟體的品質、性能,使程式的設計模式和架構更趨合理,更容易被了解,提高軟體的擴充性和維護性。資料中都在強調重構的好處,重構在“軟體系統的過程, 它不會改變代碼的外部行為, 同時改善其内部結構。 這是一種嚴格的清理代碼的方法, 它可以最大限度地減少引入錯誤的可能性。 本質上, 當重構代碼時, 是在編寫代碼之後改進它的設計”。而重寫時将代碼全部重寫。但是具體如何選擇重構還是重寫我還是不太明白,何時重構何時重寫,可以舉例說明嗎?

  • 《建構之法》P61頁

    文中對bug的定義時影響軟體使用效率的缺陷,文中也對如何做出足夠好的軟體做出了相應的解釋,比如做到寫文檔說明,進行壓力測試等等...但是對于一些隐藏的bug人為觀察并不容易發現,并且對于一些關鍵代碼,可能出現一些無法修複的bug,到後期無法修複,那應該如何避免這種情況?資料中查找到依舊時列出完整的文檔,協調好各個流程,并且考慮周全,但是由于個人原因可能會出現遺漏的情況,那麼在具體項目中應該如何考慮,才能盡量不出現這種情況呢?

  • 《建構之法》第五章

文中對PM有一個專門的章節進行講述,但是對于目前來說,接觸的都是一些小型的項目,沒有接觸到大的項目,所做的項目也并不能夠發表,在沒有專門PM的指導下,做技術的人員通過什麼樣的方式,才能較為有效地避免後期項目PM的加入并不沖突?并且PM真的不用懂技術嗎?查找資料得知,PM可以不用懂技術,但是一定得有所了解,不能說明都不懂,能夠從技術轉型學習PM是最優選擇。既懂得技術又懂得産品的人員更會明白開發人員的難處。小型項目可以沒有PM,但是一定得有一個明确的文檔,代碼規範應該形成,有明白的說明文檔。對于了解開發人員的難處确實不懂技術的PM無法體會到開發人員的實作難度,更容易導緻争吵(是以建議來幾個小姐姐)。具體程式如何快速在生活中PM技能,希望能夠給予一定的建議。

2.5附加題

馮·諾伊曼的故事

一次,馮·諾伊曼在晚會上,女主人勇敢地向他提出一個謎題:兩列火車在同一軌道上以每小時 30 英裡的速度相對而行,且相距 1 英裡,這時栖在一列火車前面的一隻蒼蠅以每小時 60 英裡的速度朝着另一列火車飛去。當它飛到另一列火車時,它又迅速地飛回來。它一直這樣飛過去飛回來,直到兩列火車不可避免地發生碰撞。問這隻蒼蠅共飛了多少英裡?

幾乎在女主人剛解釋完問題的同時,馮·諾伊曼就答道:“1 英裡。”

“太讓我驚訝了,你這麼快就算出來了。” 她說道。“大多數數學家都沒能看出這裡面的技巧,而是用無窮級數去計算,這花費了他們很長時間。”

“什麼技巧?我也是用無窮級數算的。” 馮·諾伊曼回答道。

事實上,這個笑話 (嚴格講應該叫轶事) 見于 Norman Macrae 所作的馮·諾伊曼傳記 John von Neumann

Norman Macrae

作者最後寫道:“值得一提的是,後來當别人拿這件事開他玩笑時,Johnny 說,‘其實當時他們給我的數字可沒這麼簡單’”。

2.WordCount程式設計

1.Github項目位址

項目位址

2.PSP表格

PSP Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 20min 25min
• Estimate • 估計這個任務需要多少時間
Development • 開發 9h20min 10h30min
• Analysis • 需求分析 (包括學習新技術) 3h 4h
• Design Spec • 生成設計文檔 30min 1h
• Design Review • 設計複審
• Coding Standard • 代碼規範 (為目前的開發制定合适的規範) 1h30min
• Design • 具體設計
• Coding • 具體編碼
• Code Review • 代碼複審 10min
• Test • 測試(自我測試,修改代碼,送出修改) 2h
Reporting 報告 2h10min 2h50min
• Test Repor • 測試報告
• Size Measurement • 計算工作量
• Postmortem & Process Improvement Plan • 事後總結, 并提出過程改進計劃 1h20min
合計 12h 13h45min

3.解題思路描述

拿到題目後,我首先學習了Python的基礎文法,而浏覽了一遍題目,明白了題目重點要求IO操作,正規表達式,單元測試。

其中對檔案的讀寫對于IO操作,對單詞的搜尋對于正規表達式,對結果的測試對于單元測試。

于是我首先重點學習了IO類的相關操作,正規表達式和如何進行單元測試,在了解了這三方面的知識後大體上就能夠完成本次作業的内容,在作業完成過程中有時候會遇到一些自身無法解決的問題,我會進行google或百度都能找到答案

4.代碼規範制定連結

5.計算子產品接口的設計與實作過程

子產品接口:

# WordCount接口 由于這次作業的類隻有一個就實際代碼沒有封裝了
class IWordCount
    # 統計字元數
    @abstractmethod
    def count_char(filename)
    # 統計單詞數
    @abstractmethod
    def count_word(filename)
    # 統計行數
    @abstractmethod
    def count_row(filename)
    # 統計最多的10個單詞及其詞頻
    @abstractmethod
    def count_fword(filename)
           

總體思路:将檔案的每行讀出,并進行處理

統計字元數關鍵代碼:使用

len

函數讀取每行字元個數

with open(dir, "r", encoding="utf-8") as f:
        for line in f:
            count += len(line)
           

統計單詞數關鍵代碼:應用正規表達式

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

表示比對一個以4個字母開頭的字元串

with open(dir, "r", encoding="utf-8") as f:
    for line in f:
        lis = re.split(r"[^a-zA-Z0-9]", line)
        new_lis = [x for x in lis if x != ""]
        for item in new_lis:
            if not re.match(r"^[a-zA-Z]{4}[a-zA-Z0-9]*", item) == None:
                count += 1
           

統計行數關鍵代碼:由于使用每行讀取的方法每讀取一行如果還有下一行的話那麼每行讀取的字元串最後一個字元就是

\n

,我們使用

strip('\n')

去掉後再使用re.sub('\s',"",new_line)去掉字元串中的空白字元如果最後這個字元串不為空那麼則此行不是空行,即計數

with open(dir, "r", encoding="utf-8") as f:
        for line in f:
            new_line = line.strip('\n')
            new_line=re.sub('\s',"",new_line)
            if new_line != "":
                count += 1
           

統計最多的10個單詞及其詞頻關鍵代碼:通過字典存儲單詞,并計數,首先使用正規表達式

[^a-zA-Z0-9]

對一行的字元串進行分隔,得到一個

List

字元串數組,而後去掉

List

數組中的空字元串,把其中的字母轉為小寫,對于每個符合要求的單詞檢查是否在字元串數組中,如存在則計數加

1

,不存在則在字典中添加該單詞

key

,并将

value

設定為

1

最後使用

sorted

方法對得到字典進行排序,使用

lambda

表達式表示

key

lambda

表達式表示先按照

valua

的負數按照升序排序(即

value

的正數的降序排列),而後按照

key

鍵的升序排列,并取最終結果的前

10

個數構成字典

dict = {}
with open(dir, "r", encoding="utf-8") as f:
        for line in f:
            lis = re.split(r"[^a-zA-Z0-9]", line)
            new_lis = [x for x in lis if x != ""]
            for item in new_lis:
                new_item = item.lower()
                if not re.match(r"^[a-zA-Z]{4}[a-zA-Z0-9]*", new_item) == None:
                    if dict.__contains__(new_item):
                        dict[new_item] += 1
                    else:
                        dict[new_item] = 1
#排序           
sorted(dict.items(), key=lambda x: (-x[1], x[0]))[:10]
           

獨到之處:使用Python來書寫代碼能夠快速解決許多其他語言需要寫多行代碼才能解決的事情,使用正規表達式來比對字元串快速判斷出了單詞的正确性,使用sorted函數快速進行排序并得到最後要求的結果

6.計算子產品接口部分的性能改進

10條資料 0.001s

寒假作業2/2

100條資料 0.002s

寒假作業2/2

1000條資料 0.008s

寒假作業2/2

10000條資料 0.065s

寒假作業2/2

100000條資料 0.628s

寒假作業2/2

1000000條資料 6.71s

寒假作業2/2

...

資料測試大緻呈現線性增長

改進計算子產品性能上所花費的時間:1h

思路:通過使用正規表達式能夠快速比對單詞,使用内置函數排序能使得按照一定順序輸出,使用按照字典

value

的負數輸出能夠使得排序結果降序輸出

7.計算子產品部分單元測試展示

由于單元測試函數有十多個,一一列舉的話篇幅過多,這裡僅列舉較為重要的幾個測試函數

對于統計特殊字元數測試的測試:

#對于特殊的字元進行測試如:/t  /r等等
def test_count_char1(self):
        """
        統計特殊字元數測試(轉義字元)
        """
        filename = "test_count_char1.txt"
        dir = os.getcwd() + "/" + filename
        str="1\r\n2\n3\'\t4\"5\f\a"
        with open(dir, "w", encoding="utf-8") as f:
           f.write(str)
        WordCount.file_read_out(filename, "testout_count_char1")
           

對于統計單詞數測試:

#特殊單詞進行測試 如:12file  fil等等
def test_count_word2(self):
    """
    統計單詞數測試(判斷是不是單詞情況)
    """
    filename = "test_count_word2.txt"
    dir = os.getcwd() + "/" + filename
    with open(dir, "w", encoding="utf-8") as f:
        str = "123file;wwww;wWwW,file123;file;fil,\n"
        i = 0
        while i < 100:
            f.write(str)
            i += 1
    WordCount.file_read_out(filename, "testout_count_word2")
           
#空白字元進行測試如:\r  \n  \t等等
 def test_count_row1(self):
    """
    行數測試(有空行包括非空白字元)
    """
    str = "whuihu\n\t\n     \nwww"
    filename = "test_count_row1.txt"
    dir = os.getcwd() + "/" + filename
    with open(dir, "w", encoding="utf-8") as f:
        f.write(str)
    WordCount.file_read_out(filename, "testout_count_row1")
           

對于統計最多的10個單詞及其詞頻測試:

#測試大小寫和優先輸出
def test_count_fword2(self):
    """
    統計最多的10個單詞及其詞頻測試(頻率相同的單詞,優先輸出字典序靠前的單詞)
    """
    str = ('windows95 windows95 windows98 windows96 '
            'windows2000\n')
    filename = "test_count_fword2.txt"
    dir = os.getcwd() + "/" + filename
    with open(dir, "w", encoding="utf-8") as f:
        i = 0
        while i < 20:
            f.write(str)
            i += 1
    WordCount.file_read_out(filename, "testout_count_fword2")
           

使用Coverage計算測試覆寫率:

寒假作業2/2

如何優化覆寫率:

由于我采用正規表達式比對,并未使用判斷,是以覆寫率基本是100%,少了的那些覆寫率是因為對于輸入檔案名的正确性判斷和主函數是以暫時無法更好優化,除非将主函數獨立出來,就可将覆寫率再提升,但我個人認為這樣做意義不大

8.計算子產品部分異常處理說明

由于題目要求的是不會有中文輸入,是以中文輸入可能存在錯誤,但是在實際統計過程中,因為是正則比對又會将不是因為字元和數字的删除,是以最後漢字不記錄統計,将漢字作為特殊字元看待。

控制台輸入參數錯誤異常

9.心路曆程與收獲

學習了Python基礎文法,相關IO操作,學習了如何進行單元測試和如何生成覆寫率文檔,學習了如何使用正規表達式,對Python基本的API調用有了大緻的了解,對IO操作進行了熟悉.學會了如何使用Python文法完成一個較為完整的項目