這個作業屬於哪個課程 | <班級的鏈接> |
---|---|
這個作業要求在哪里 | <作業要求的鏈接> |
這個作業的目標 | 學習Python語法和基礎API,自主完成項目,形成語法規范,對於《構建之法》的再思考 |
作業正文 | 項目的開發到結束的詳細流程和文檔,閱讀《構建之法》提出問題並思考 |
其他參考文獻 | 《構建之法》 《騰訊Cplusplus編碼規范》 《Python PEP8》 |
目錄:
1. 關於《構建之法》的思考和提問
Question One:團隊中的人員能力參差不齊,在一個團隊中如何安排才能使每個人在團隊中發揮出最大作用?
- 《構建之法》P151頁
在第四章中講述了“結對合作”,雖然文中講述了代碼規范,代碼復審,兩人合作的技巧等......,但是我有一個疑惑點,在團隊開發中每個人的代碼水平都不盡相同,那么在團隊中應該如何較好地協調安排每個人的工作?我查找了一些資料,對於3-5小型的項目由於團隊規模較小,能夠及時溝通,所以有什么事情能夠較好得溝通,但是對於大團隊來說,必須要有一系列的說明文檔來提供相應的支持,團隊通過篩選人員進入公司,並安排有項目經驗的人來管理安排人員,但是具體在小型項目中如何安排人員分配依舊沒有相應的答案,希望能夠給予具體的解答。
Question Two:在項目合作中總是會出現個別人躺贏的情況,不管是團隊項目還是結對編程,特別是作業項目,如何處理好這個情況?
- 《構建之法》P151頁
盡管文中提及如何結對編程,如何團隊開發,但是依然可能出現問題中的這個情況。在網上搜索回答,給出的回答是在組件團隊的初期應該能夠篩選隊友,對於一些不靠譜的隊友不予考慮,俗稱“混子”,但是根據以往經驗,一開始項目時,並沒有辦法分別是否這個隊友靠譜,只有在項目進行到一定的階段時,才能分辨出來,而在這個時候基於人情考慮,還是沒法直接點破將在之提出隊伍,在項目開發中,如果出相互這個情況如何解決,懇求給予解答。
Question Three:代碼重構和重寫的區別是什么?
- 《構建之法》P407頁
文中“小飛對照設計文檔和代碼指南進行自我復審,重構代碼。”對於“代碼重構”不是很清楚,查找了一些資料,重構代碼就是通過調整程序代碼,但並不改變程序的功能特征,達到改善軟件的質量、性能,使程序的設計模式和架構更趨合理,更容易被理解,提高軟件的擴展性和維護性。資料中都在強調重構的好處,重構在“軟件系統的過程, 它不會改變代碼的外部行為, 同時改善其內部結構。 這是一種嚴格的清理代碼的方法, 它可以最大限度地減少引入錯誤的可能性。 本質上, 當重構代碼時, 是在編寫代碼之后改進它的設計”。而重寫時將代碼全部重寫。但是具體如何選擇重構還是重寫我還是不太明白,何時重構何時重寫,可以舉例說明嗎?
Question Four:關於Bug,有些時候bug存在致命性,但我們又無法修復他,只能推倒重做,如何在開發過程中避免這種情況?
- 《構建之法》P61頁
文中對bug的定義時影響軟件使用效率的缺陷,文中也對如何做出足夠好的軟件做出了相應的解釋,比如做到寫文檔說明,進行壓力測試等等...但是對於一些隱藏的bug人為觀察並不容易發現,並且對於一些關鍵代碼,可能出現一些無法修復的bug,到后期無法修復,那應該如何避免這種情況?資料中查找到依舊時列出完整的文檔,協調好各個流程,並且考慮周全,但是由於個人原因可能會出現遺漏的情況,那么在具體項目中應該如何考慮,才能盡量不出現這種情況呢?
Question Five:關於PM,在小型開發中是否需要PM?
- 《構建之法》第五章
文中對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 | • 估計這個任務需要多少時間 | 20min | 25min |
Development | • 開發 | 9h20min | 10h30min |
• Analysis | • 需求分析 (包括學習新技術) | 3h | 4h |
• Design Spec | • 生成設計文檔 | 30min | 1h |
• Design Review | • 設計復審 | 30min | 20min |
• Coding Standard | • 代碼規范 (為目前的開發制定合適的規范) | 1h | 1h30min |
• Design | • 具體設計 | 1h | 1h |
• Coding | • 具體編碼 | 1h | 1h |
• Code Review | • 代碼復審 | 20min | 10min |
• Test | • 測試(自我測試,修改代碼,提交修改) | 2h | 1h30min |
Reporting | 報告 | 2h10min | 2h50min |
• Test Repor | • 測試報告 | 1h | 1h |
• Size Measurement | • 計算工作量 | 10min | 20min |
• Postmortem & Process Improvement Plan | • 事后總結, 並提出過程改進計划 | 1h20min | 1h30min |
合計 | 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
100條數據 0.002s
1000條數據 0.008s
100條數據 0.002s
10000條數據 0.065s
100000條數據 0.628s
1000000條數據 6.71s
...
數據測試大致呈現線性增長
改進計算模塊性能上所花費的時間: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計算測試覆蓋率:
如何優化覆蓋率:
由於我采用正則表達式匹配,並未使用判斷,所以覆蓋率基本是100%,少了的那些覆蓋率是因為對於輸入文件名的正確性判斷和主函數所以暫時無法更好優化,除非將主函數獨立出來,就可將覆蓋率再提升,但我個人認為這樣做意義不大
8.計算模塊部分異常處理說明
由於題目要求的是不會有中文輸入,所以中文輸入可能存在錯誤,但是在實際統計過程中,因為是正則匹配又會將不是因為字符和數字的刪除,所以最后漢字不記錄統計,將漢字作為特殊字符看待。
9.心路歷程與收獲
學習了Python基礎語法,相關IO操作,學習了如何進行單元測試和如何生成覆蓋率文檔,學習了如何使用正則表達式,對Python基本的API調用有了大致的了解,對IO操作進行了熟悉.學會了如何使用Python語法完成一個較為完整的項目