這個作業屬於哪個課程 | 2021春軟件工程實踐|W班(福州大學) |
---|---|
這個作業要求在哪里 | 寒假作業2/2 |
這個作業的目標 |
1、閱讀《構建之法》並再提出五個問題2、完成詞頻統計個人作業
|
其他參考文獻 | 《構建之法》 |
閱讀《構建之法並提出五個問題》
問題一:我認為要實現一個項目不只是需要能創新就夠了,這其中和資金、人才以及機遇也有很大的關系。一個好的點子能否實現,和點子由誰想出、點子由誰實現和點子產生的時代背景密不可分。文中區分了“創新者”和“先行者”,實際上“創新者”並可能不是第一個想出那些好點子的人,既然如此,這還能叫做創新嗎?
原文:......大家聽了很多創新者的故事,有些人想,他們真了不起,第一個想出了這些美妙的想法,要是我早生幾十年,也第一個實現那些想法就好了。其實,大部分成功的創新者都不是先行者,例如搜索引擎,Google是很晚才進入這個領域的。又如Apple的音樂播放器iPod,發布於2001年10月23日,在它之前市面上已經有很多同類產品了......
問題二:在中國知識產權一直不受人重視,這一段的上文中的魔方創新也是如此,果凍沒能保護好關於魔方的專利,使得技術被他人魔方學走(雖然這篇短文想告訴我們的應該不是這個道理),在中國這樣一個大環境之下,我們應該怎么樣合理地維護創新成果?結合上一個問題,人們是否可以為了自己的私欲,把沒有把握實現的創新想法藏在心中不讓他人知道?
原文:......這些對“小作坊”睜一只眼閉一只眼的經理,值得表揚。這些好的作坊,都有這些核心特性:從小事做起,重質量,講信用,對產品負責,對工作自豪。作坊這么好,那中國的許多作坊為什么不能興旺?大家經常提到的一個原因,就是“環境對知識產權的尊重和保護不夠”,其實哪里都有盜版,哪里都有抄襲,哪里都有競爭。有能力的作坊,往往能找到合適的渠道和空間,實現自己的價值。那些想開作坊的人,你們對知識產權又是如何尊重和保護的呢?你心里“熱愛技術”么?你是否發現了自家作坊的獨特價值?你能放棄貌似免費的看熱鬧的機會,在網上斗嘴的爽快,倒賣繪圖儀的短期收益,吹噓自己要寫一個平台的風光,先練好內功?作坊就在那里,你是裝作路過沒看見,還是走進去?......
問題三:每個團隊中大伙兒的負擔都是不同的,有的人可能為了團隊會舍棄很多,有的人可能在工作中付出了相對於別人來說不重要但是最他自己十分重要的東西,每個人的負擔與付出可以說因為個體的原因,沒有一個很好的度量方法,既然如此,在分配資源和收益的時候應該根據這些負擔去考慮分配嗎?如果負擔不同但是任務相同呢?還是說應該在組建團隊之初就商量好所有人都平均分配?這樣又是否會打擊到隊友的積極性?具體應該怎么實現會比價合理。
原文:......豬: 提供豬肉,做熏肉。雞: 提供雞蛋,做煎蛋。鸚鵡:提供咨詢,每天閱讀大量博客,給其他團隊成員提供建議,例如業界最新趨勢、最新術語、SaaS、N-層架構、創業明星當年的軼事,等等。這次創業對三個動物的負擔是一樣的么?它們又該各占多少股份?一旦創業失敗,豬、雞和鸚鵡各自會失去什么?在一個團隊中,不同的成員來自五湖四海,為了一個共同的目標,走到一起來了(至少表面上是這樣)。
問題四:團隊在談及分配利益的時候每個人都不希望自己拿不到屬於自己的那一份,但是每個人所做的工作方向不同,內容不同,效率不同,擅長的領域也更不相同,每個人對他人的付出或許都會有不同的評價,有沒有一套相對來說比較客觀的評判標准,能具體不抽象地反應出團隊里每個隊員做出的貢獻呢?
原文:......有人建議按照角色來定位,例如有豬、雞和鸚鵡等,問題是大多數鸚鵡都說自己是雞,剩下的都認為自己是豬,而且分量很重!有人建議根據工作時間來衡量,這規定一宣布,大家都開始比誰走得晚,另外,我周末一直在想工作上的事,這算工作時間么?
比資歷?
軟件行業的競爭有“贏者通吃”的規律,一個快要被市場淘汰的產品不能說:我們是最先進入這一市場的,理應繼續占有足夠份額!軟件團隊成員也不能說:我來得早,所以我的報酬就應該多!
大鍋飯?
所有人都評“優”,大家平分錢,好么?優秀的人會離開,最后會剩下平庸的人在過平均主義——也許整個團隊都被淘汰了。同一團隊的成員報酬能差別多大?我們看看職業籃球的一個例子:1997—1998賽季,邁克爾·喬丹掙了8000萬美元,而他的隊友喬·克萊恩(JoeKleine)當年掙了27萬美元。兩者相差將近300倍!如果兩人掙錢平均分,誰會離開?球隊因此變強還是變弱?
比效率?
我們也知道軟件開發人員的效率有很大的差別,一流程序員的效率是普通程序員的10倍;有些效率的差別還有正負之分。一個心不在焉的程序員可以一天寫2000行代碼,然后測試人員和其他開發人員要花很多時間來修復其中的缺陷,這些同事原本要做的任務就被耽誤了。同時,一個非常用心的程序員發現可以重用以前的穩定模塊,他花很多時間重構和測試,最后只修改了500行代碼,缺陷特別少,這樣無形中節約了其他同事的大量時間。曾有研究[注釋5]衡量不同水平的程序員(從接受編程培訓的學生,到有7年經驗的工程師)的效率和質量,他們在解決復雜問題時,最低效的程序員所花的時間是最高效的程序員的20倍。不僅如此,低效的程序員所寫的程序在質量上也有明顯的差距。如果你的團隊失去了最高效的程序員,那么即使你能馬上找到20個菜鳥(最初級的程序員),也無法產生同樣質量的軟件,更不用說20個菜鳥程序員在交流時所產生的眾多問題和生產力的損失。
背靠背評比?
根據所有其他人的評價來決定某個人的績效?這樣會發生小團體抱團,以及劣幣驅逐良幣的現象。做游戲的工程師一定聽說過維爾福公司(Valve[注釋6],開發有半條命、反恐精英等游戲),這家公司的員工手冊[注釋7]很有意思,大家不妨看看。根據手冊的描述,維爾福的員工可以自由支配100%的工作時間,做什么項目、在哪兒工作等,員工可以自己做主。但是在績效評估上,他們用了隊友評估這一機制,得出下列四個值:1. 技術等級/技術能力2. 勞動生產力/結果3. 對團隊的貢獻(做一些工具讓大家的工作更容易,幫助招人)4. 對產品的貢獻(除本職工作外,對產品有幫助的活動,比如找Bug、預測用戶的反饋、產品推廣等)
比不犯錯誤?
軟件項目的進展不是一帆風順的,總會有問題發生,出了問題,就一定會記在相關人員的賬上,以便總結提高。但是一定會作為績效評估的依據?那倒不一定。如果成員的行為只影響己,或者是探索式的行動,則不是壞事。例如有些成員自行探索最新的技術,但是最后決定不采用此技術。如果團隊成員的行為影響整個團隊,例如構建中斷(Build Break)導致每日構建(DailyBuild)失敗,則要注意。在一個里程碑中,可以統計誰導致這種錯誤最多。對此可以采取本書前面提到的“構建大師”方法處理。如何區別對待?......
問題五:在一個團隊中,我認為蘿卜和白菜都是必不可少的角色,蘿卜能夠保證代碼的產出效率,白菜則是能夠保證程序整體的穩定性和質量,這兩類人面對不同的項目中具體應該占的比例應該是什么樣的?或者說什么樣的項目更需要蘿卜多一些,什么樣的項目更需要白菜多一些?
原文:......阿超:我有一個故事,假設團隊里來了兩位年輕人,嗯,就叫“蘿卜”和“白菜”。蘿卜做事很快,是“蘿卜快了不洗泥”類型;白菜是“慢工出細活”類型。分配了任務后,蘿卜很快就說做好了!白菜還在吭哧吭哧地跟項目經理和測試人員討論。領導很高興,讓蘿卜去做更多的事。開發階段結束了,蘿卜比白菜多做了不少功能。穩定階段開始了。大家發現蘿卜負責的功能出了很多問題,白菜的模塊倒是比較穩定。然而蘿卜在團隊中的曝光率很高,很多問題都在等着他解決,從統計數據上看,他也修復了不少小強。白菜搞定了自己負責的模塊,開始幫助其他人,由於不熟悉其他人的模塊,白菜修復的缺陷不多。由於蘿卜的設計有缺陷,導致模塊非常復雜,蘿卜也成了唯一了解其模塊的開發人員。項目最后階段,幾乎都是蘿卜工作得最晚,把最后幾個缺陷給修復了。領導們說:有問題,找蘿卜!項目結束了,開始了績效考核,領導A認為白菜績效不錯,模塊按時完成,沒有大多問題,然后還能幫助其他成員;領導B認為蘿卜是超級明星:第一個完成模塊,修復的缺陷最多,而且掌握了最復雜的模塊,離開他不行,工作得也很晚,有突出貢獻。至於白菜,領導B沒感覺他做了啥,僅僅是按要求完成任務
了。蘿卜白菜,各有所愛。那蘿卜和白菜誰該得到獎勵,誰該得到批評呢?假如領導B的評價方式占了上風,蘿卜得到獎勵,白菜離開了團隊,你覺得下一個版本會出現什么情況......
附加題:
在早期許多學者都認為下圖的鍵盤比上圖的鍵盤更好,因為元音字母都在中間一行能提高打字的速度。然后由於但是制作方式和材質的原因,如果把常用的元音字母都放在同一行,會使得鍵盤的磨損加快,因此廠商還是選擇按上圖的方式制造鍵盤。久而久之,即使現在能夠從制作方式和材質上減少常用字符放在同一行帶來的磨損,人們也已經習慣了上圖的鍵盤模式。
程序作業
作業描述
在大數據環境下,搜索引擎,電商系統,服務平台,社交軟件等,都會根據用戶的輸入來判斷最近搜索最多的詞語,從而分析當前熱點,優化自己的服務。首先當然是統計出哪些詞語被搜索的頻率最高啦,請設計一個程序,能夠滿足一些詞頻統計的需求。
項目地址
PSP表格
PSP2.1 | Personal Software Process Stages | 預估耗時(分鍾) | 實際耗時(分鍾) |
---|---|---|---|
Planning | 計划 | 20 | 15 |
• Estimate | • 估計這個任務需要多少時間 | 20 | 15 |
Development | 開發 | 600 | 959 |
• Analysis | • 需求分析 (包括學習新技術) | 30 | 67 |
• Design Spec | • 生成設計文檔 | 30 | 15 |
• Design Review | • 設計復審 | 10 | 5 |
• Coding Standard | • 代碼規范 (為目前的開發制定合適的規范) | 20 | 30 |
• Design | • 具體設計 | 60 | 40 |
• Coding | • 具體編碼 | 420 | 732 |
• Code Review | • 代碼復審 | 30 | 40 |
• Test | • 測試(自我測試,修改代碼,提交修改) | 20 | 40 |
Reporting | 報告 | 60 | 98 |
• Test Repor | • 測試報告 | 20 | 78 |
• Size Measurement | • 計算工作量 | 15 | 10 |
• Postmortem & Process Improvement Plan | • 事后總結, 並提出過程改進計划 | 25 | 10 |
合計 | 680 | 1072 |
解題思路
先把任務主要分成了讀寫文件、統計行數、統計字符數量、統計單詞數量和統計頻率這個幾個部分。最開始想的是一行一行地讀取文件同時記錄行的數量,然后再把接收的每一行拼接成一個大的字符串去統計字符數量那些的。然后在實際做的過程中發現做出來的效果和題目的要求不相符合,如果要這樣做恐怕會比較麻煩,於是把讀入的全部加入到字符串中再去判斷。在統計詞頻的過程中原本想的是用兩個數組分別記錄下單詞和詞頻,寫的過程中感覺很麻煩,后來在找資料的過程中發現之前學過的map可以很好地實現想法就直接用上了。
代碼規范
實現過程
1.文件讀寫
讀取文件代碼:先判斷文件是否存在如果不存在就返回文件不存在異常,如果存在就打開輸入流用BufferedReader來讀取文件內容,讀取失敗會返回讀取失敗異常,用StringBuilder接收后轉成String返回。
InputStreamReader read = new InputStreamReader(new FileInputStream(file),
"UTF-8");
BufferedReader bufferedReader = new BufferedReader(read);
int x;
while((x=bufferedReader.read()) != -1) {
Text.append((char)x);
}
read.close();
寫文件的代碼:這段是把統計結果合並成一個String后用輸出流進行輸出寫入目標文本filePath(如果目標文本不存在會自動創建),如果輸出失敗會提示異常。
FileOutputStream p;
try {
p = new FileOutputStream(filePath);
p.write(str.getBytes());
p.close();
}
2.統計行數
因為不會記錄空白行,所以直接按\s把從intput讀來的字符串進行分割放入String數組並統計這個數組長度,遍歷String數組如果有空的就讓剛剛統計的長度-1。
String[] LINE = str.split("\\s"); //把可能換行的地方分割出來
int lines = LINE.length;
for(int i = 0;i < LINE.length; i++ ) { //減去空白行
if(LINE[i].isEmpty()) lines-- ;
}
3.統計字符數量
這個直接把接收的字符串轉成char數組,遍歷數組統計能用ASCII碼表示的字符數量。
public static int countChars(String str) { //統計字符數量
int sum = 0;
char[] cs = str.toCharArray();
for(int i = 0;i < cs.length; i++ ) {
if(cs[i] >= 0 && cs[i] < 128) sum++ ;
}
return sum;
}
4.統計單詞數量
這里也是用到了split來分割,因為單詞內部不可能有除了字母和數字以外的字符,所以把讀取的字符串按除了字母數字以外的符號分割放入String數組,再對這個數組里面的每個元素進行判斷是否符合單詞的要求,如果符合就讓計數器+1,最后返回計數器結果。
......
//把可能是單詞的字符串切割出來
int words = 0;
for(int i = 0;i < strArray.length; i++ ) {
if(strArray[i].length() < 4)continue;
else {
String temp=strArray[i].substring(0,4); //檢測是否符合規則
if(temp.matches("[a-z]*")) {
words++;
}
}
}
5.統計單詞出現頻率
這段代碼先是做了和上面一段一樣的事,不過不是符合單詞規則就讓計數器加1而是把符合規則的記錄下在一個String數組中,之后遍歷數組,用Map來記錄單詞以及它出現的頻率,key是單詞的字符串,value是出現的頻率,之后再遍歷Map找value最大的,如果value的值相同就比較key值,遍歷一次就得到一個結果,把結果加入到要輸出的StringBuilder里,並在Map中把那個結果刪除,這樣遍歷10次或者直到Map中沒有元素,最后把Stringbuilder轉成String返回。
public String countTimes(String str) { //統計單詞出現次數
......
//前面先是是用了一個List來存儲所有符合條件的單詞(相同的單詞也會被重復apend,然后把List里面的內容存入Map)
StringBuilder finalstr=new StringBuilder();
while(!map.isEmpty()) {
int i = 0,maxvalue = 0;
String maxstr = " ";
for(String s:key) {
......
//遍歷map,比較出value值最大的key,如果value的值相同就比較key的ASCII碼
}
finalstr.append(maxstr + ":" + maxvalue + "\n");
map.remove(maxstr);
if(i == 9)break; //如果finalstr中的單詞數量已經有10個了就退出循環
}
性能測試
(測試文本中包含空白行、不符合單詞規則的字符串、出現次數相同但是不完全相同的單詞)
10000個字符串
100000個字符串
不是很會分析。。。
單元測試
測試文本與結果
測試文本中包含空白行、不符合單詞規則的字符串、出現次數相同但是不完全相同的單詞
覆蓋率截圖
提高覆蓋率的辦法
簡化邏輯,減少不必要的判斷,消除重復代碼。
異常處理
當要求讀取的文件不存在時會報錯
心路歷程
這次作業學習由於寒假期間在電影院兼職所以拖得比較遲才開始,剛開始啟動這個作業的時候在github上花了很多時間,因為是第一次使用這個網站又是全英文,即使是翻譯完也不是很能理解每個模塊的功能。在寫代碼的階段剛開始想的比較簡單,但是隨着群里同學們提出的問題也發現了自己的代碼和題目的要求其實有很多不相符的地方,進行了一些修改。在最后統計單詞出現頻率的地方收獲比較大,Map<object,object>雖然是之前學過的知識但是這次編碼的時候沒有第一時間想起,通過這次實踐讓我對它加深了印象。感覺以后寫程序不能光在腦子里想想,有時想的過於簡單,有些關鍵的地方想起來或許容易,但是用代碼表達起來就比較復雜。在寫這篇博客的過程中也有很多第一次接觸的東西,也都通過百度和問別的同學盡量學習了,收獲還是很大的。