201971010157-張穎 實驗三 結對專案-《{0-1}KP例項資料集演算法實驗平臺》
專案 | 內容 |
課程班級部落格連結 | 2019級卓越班 |
這個作業要求連結 | 實驗三 軟體工程結對專案 |
我的課程學習目標 |
|
這個作業在哪些方面幫助我實現學習目標 |
|
結對方學號-姓名 | 201971010106-陳玉英 |
結對方本次部落格作業連結 | 201971010106-陳玉英 實驗三 結對專案-《{0-1}KP例項資料集演算法實驗平臺》專案報告 |
本專案Github的倉庫連結地址 | https://github.com/xiaokaxi08042/text2 |
任務1:閱讀《現代軟體工程—構建之法》第3-4章內容,理解並掌握程式碼風格規範、程式碼設計規範、程式碼複審、結對程式設計概念
程式碼規範-
- 程式碼規範可以分為兩個部分:
- 程式碼風格規範-主要是文字上的規定、看似表面文章,實際上非常重要
- 程式碼設計規範-牽扯到程式設計、模組之間的關係、設計模式等方方面面的通用規則
程式碼風格規範-
- 程式碼風格的原則是:簡明,易讀,無二義性
- 縮排:4個空格比tab鍵更好,tab鍵在不同的情況下會顯示不同的長度,嚴重干擾閱讀體驗,4個空格的距離從可讀性來說,正好。
- 行寬:行寬必須限制,以前有些文件規定的80字元行寬太小,現在可以先定為100字元
- 括號:在複雜的條件表示式中,用括號清楚地表示邏輯優先順序
- 斷行與空白的{}行:每個“{”和“}”都獨佔一行
- 分行:不要把多條語句放在一行上,更嚴格的說,不要把多個變數定義在一行上
- 命名:(1)在變數名中不要提到型別或其他語法方面的描述(2)避免過多的描述(3)如果資訊可以從上下文中得到,那麼此類資訊就不必寫在變數名中(4)避免可要不可要的修飾詞
- 下劃線:用來分隔變數名字中的作用域標註和變數的語義
- 大小寫:所有單詞的第一個字母都大寫(Pascal);第一個單詞全部小寫,隨後單詞隨Pascal形式
- 註釋:(1)解釋程式做什麼,為什麼這樣做,以及要特別注意的地方(2)複雜的註釋應該放在函式頭(3)註釋要隨著程式的修改而不斷更新(4)註釋應該只用ASCII字元,不要用中文或其他特殊字元
代碼設計規範-
- 程式碼設計規範不光是程式書寫的格式問題,而且牽扯到程式設計、模組之間的關係、設計模式等方方面面,這裡又有不少內容與具體程式設計語言息息相關,但是也有通用的規則,主要有——
- 函式:現代程式設計語言中的絕大部分功能,都在程式 的函式中實現
- goto:函式最好有單一的出口,為了達到這一目的,可以使用goto
- 錯誤處理:(1)引數處理(2)斷言
- 處理c++中的類
程式碼複審-
- 定義:看程式碼是否在程式碼規範的框架內正確的解決了問題
- 形式:
名稱 |
形式 |
目的 |
自我複審 |
自己vs.自己 |
用同伴複審的標準來要求自己。不一定最有效,因為開發者對自己總是過於自信。如果能持之以恆,則對個人有很大好處 |
同伴複審 |
複審者vs.開發者 |
簡單易行 |
團隊複審 |
團隊vs.開發者 |
有比較嚴格的規定和流程,適用於關鍵的程式碼,以及複審後不再更新的程式碼覆蓋率高——有很多雙眼睛盯著程式,但效率可能不高 |
- 目的:
- 找出程式碼的錯誤
- 發現邏輯錯誤
- 發現演算法錯誤
- 發現潛在的錯誤和迴歸性錯誤
- 發現可能需要改進的地方
- 互相教育開發人員,傳授經驗
- 步驟:
- 程式碼必須成功地編譯
- 程式設計師必須測試過程式碼
- 程式設計師必須提供新的程式碼,以及檔案差異分析工具
- 在面對面的複審中,一般是開發者控制流程,講述修改的前因後果。但是複審者有權在任何時候打斷敘述,提出自己的意見。
- 複審者必須逐一提供反饋意見。
- 開發者必須負責讓所有的問題都得到滿意的解釋或解答,或者在TFS中建立愛你新的工作項以確保這些問題會得到處理。
- 對於複審的結果,雙方必須達成一致的意見
- 程式碼複審的核查表:
概要部分 |
|
設計規範部分 |
|
程式碼規範部分 |
修改的部分符合程式碼標準和風格麼? |
具體程式碼部分 |
|
效能 |
|
可讀性 |
程式碼可讀性如何?有沒有足夠的註釋? |
可測試性 |
程式碼是否需要更新或建立新的單元測試?針對特定領域的開發(如資料庫、網頁、多執行緒等),可以整理專門的核查表。 |
結對程式設計-
- 結程式設計是一個相互學習、相互磨合的漸進過程。
- 優點:
- 在開發層次,結對程式設計能提供更好的設計質量和程式碼質量,良人合作解決問題的能力更強。兩人合作,還有相互激勵的作用,工程師看到別人的思路和技能,得到實時的講解,受到激勵,從而努力的提高自己的水平,提出更多的創意。
- 對開發人員來說,就地工作能帶來更多的信心,高質量的產出能帶來更高的滿足感。
- 在企業管理層次上,就地能更有效地交流,相互學習和傳遞經驗、分享知識,能更好地應對人員流動。
- 兩人合作的不同階段和技巧:
- 萌芽階段
- 磨合階段
- 規範階段
- 創造階段
- 解體階段
- 影響他人的幾種方式:
- 斷言
- 橋樑
- 說服
- 吸引
- 評論別人的三種層次:
- 最外層:行為和後果
- 中間層:習慣與動機
- 最內層:本質和固有屬性
- 如何正確地給予反饋:“三明治”辦法
- 先來一片面包,做好鋪墊:強調雙方的共同點,從團隊共同的願景講起,讓對方覺得處於一個安全的環境。
- 再把肉放上:這時就可以把建設性的意見加工好,加上生菜、佐料等。怎麼準備這塊肉也有講究,在提供反饋時,不宜完全沉溺於過去的陳年穀子爛芝麻,給別人做評價,下結論。這樣會造成一種“你就是做得不好,我恨你”的情緒。不妨換個角度,展望將來的結果,強調“過去你做得不夠,但是我們以後可以做得更好”。在技術團隊裡,我們的反饋還是要著重於“行為和後果”這一層面,不要貿然深入到“習慣和動機”、“本質”除非情況非常嚴峻,需要觸動別人內心深處,讓別人懸崖勒馬。
- 再來一片面包:呼應開頭,鼓勵對方把工作做好。
任務2:兩兩自由結對,對結對方《實驗二 軟體工程個人專案》的專案成果進行評價
- 結對方部落格連結:201971010106-陳玉英 實驗二 個人專案 —《{0-1}揹包問題》專案報告
- 結對方Github專案倉庫連結:https://github.com/15294140835
- 符合(1)要求的部落格評論:
- 符合(2)要求的程式碼審查表:
概要部分 | |
程式碼符合需求和規格說明麼? | 符合 |
程式碼設計是否考慮周全? | 考慮的不是很周全 |
程式碼可讀性如何? | 可讀性好,有註釋 |
程式碼容易維護麼? | 層次清晰,模組化不錯,遵從基於介面而非實現程式設計的原則,容易維護 |
程式碼的每一行都執行並檢查過了嗎? | 是 |
設計規範部分 | |
設計是否遵從已知的設計模式或專案中常用的模式? | 是 |
有沒有硬編碼或字串/數字等存在? | 沒有直接將資料嵌入到程式中,沒有硬編碼存在 |
程式碼有沒有依賴於某一平臺,是否會影響將來的移植(如Win32到 Win64 ) ? | 沒有依賴於某一平臺 |
開發者新寫的程式碼能否用已有的 Library/SDK/Framework 中的功能實現?在本專案中是否存在類似的功能可以呼叫而不用全部重新實現? | 沒有用其功能實現 |
有沒有無用的程式碼可以清除? | 有 |
程式碼規範部分 | |
修改的部分符合程式碼標準和風格麼? | 符合 |
具體程式碼部分 | |
有沒有對錯誤進行處理?對於呼叫的外部函式,是否檢查了返回值或處理了異常? | 有對錯誤進行處理,對於呼叫的外部函式,檢查了返回值沒有發現錯誤 |
引數傳遞有無錯誤,字串的長度是位元組的長度還是字元(可能是單/雙位元組)的長度,是以0開始計數還是以1開始計數? | 引數傳遞沒有錯誤,字串的長度是字元的個數,ASCII碼下也是位元組數,是以0開始計數 |
邊界條件是如何處理的? switch語句的default分支是如何處理的?迴圈有沒有可能出現死迴圈? | 沒有用到switch語句,沒有出現死迴圈 |
有沒有使用斷言(Assert)來保證我們認為不變的條件真的得到滿足? | 沒有使用斷言 |
對資源的利用,是在哪裡申請,在哪裡釋放的?有無可能存在資源洩漏(記憶體、檔案、各種GUI資源、資料庫訪問的連線等等)?有沒有優化的空間? | 因程式功能較為簡單,沒有使用到GUI資源、資料庫等 |
資料結構中有沒有用不到的元素? | 沒有用不到的元素 |
效能 | |
程式碼的效能(Performance)如何?最壞的情況是怎樣的? | 效能一般,在資料量很大時會執行較長時間 |
程式碼中,特別是迴圈中是否有明顯可優化的部分? | 沒有明顯可優化的部分 |
可讀性 | |
程式碼可讀性如何?有沒有足夠的註釋? | 可讀性很好,註釋足夠 |
可測試性 | |
程式碼是否需要更新或建立新的單元測試?針對特定領域的開發(如資料庫、網頁、多執行緒等),可以整理專門的核查表。 | 實驗二的程式碼沒有使用到資料庫、網頁等的開發 |
- 結對方專案倉庫中的Fork、Clone、Push、Pull request、Merge pull request日誌資料
Fork 是 Github 上的常用操作之一,不同於 Star,Fork 會將進行 Fork 操作那一刻的倉庫程式碼完全複製到自己的倉庫下。Fork 之後,可能會為原倉庫新增一個 Feature,之後發起 Pull Request
克隆:
執行:
fork:
任務3:採用兩人結對程式設計方式,設計開發一款{0-1}KP 例項資料集演算法實驗平臺
- 需求分析陳述——採用“3W”分析法
-
- what:需求是什麼
-
- 採用動態規劃法、貪心演算法和回溯演算法求解不超過揹包容量的最大價值和解向量
- 繪製價值重量為橫軸,價值為縱軸的資料散點圖
- 輸出的最優解和求解時間可儲存為txt檔案
- 例項資料集儲存在資料庫
- 平臺可動態嵌入任何一個有效的{0-1}KP 例項求解演算法,並儲存演算法實驗日誌資料;
- 人機互動介面為GUI介面
- 設計遺傳演算法求解{0-1}KP,並利用此演算法測試要求
-
- why:為什麼會產生這樣的需求
-
- 用多種演算法解決0-1揹包問題
- 更好的儲存和管理資料
- 增加使用者的體驗感
-
- how:如何將需求轉化為產品進行後續的價值分析
- 軟體設計說明
- 軟體實現及核心功能程式碼展示:軟體包括哪些類,這些類分別負責什麼功能,他們之間的關係怎樣?類內有哪些重要的方法,關鍵的方法是否需要畫出流程圖?
遺傳演算法:遺傳演算法類似於自然進化,通過作用於染色體上基因尋找好染色體來求解問題。及自然界相似,遺傳演算法對求解問題本身一無所知,它所需要僅是對演算法所產生每個染色體進行評價,並基於適應值來選擇染色體,使適應性好染色體有更多繁殖機會。在遺傳演算法中,通過隨機方式產生若干個所求解問題數字編碼,即染色體,形成初始群體;通過適應度函式給每個個體一個數值評價,淘汰低適應度個體,選擇高適應度個體參加遺傳操作,經過遺傳操作後個體集合形成下一代新種群。對這個新種群進行下一輪進化。
演算法流程圖:
-
- 遺傳演算法-GAType類
class GAType(): # 種群
def __init__(self, obj_count):
self.gene = [0 for x in range(0, obj_count, 1)] # 序列編碼 0 / 1
self.fitness = 0 # 適應度
self.cho_feq = 0 # choose 選擇概率
self.cum_feq = 0 # cumulative 累積概率
class genetic():
def __init__(self, value, weight, max_weight):
self.value = value
self.weight = weight
self.max_weight = max_weight
self.obj_count = len(weight)
self._gatype = [GAType(self.obj_count) for x in range(0, population_size, 1)]
self.total_fitness = 0
Back_pack類:(部分功能程式碼)
def draw(self): # 畫散點圖
nums_pro = self.str_profit[0:len(self.str_profit)]
nums_wei = self.str_weight[0:len(self.str_weight)]
nums_pro = [int(i) for i in nums_pro]
nums_wei = [int(i) for i in nums_wei]
df = pd.DataFrame({'profit': nums_pro, 'weight': nums_wei})
df.plot(kind="scatter", x="weight", y="profit")
plt.show()
def DP(self): # 動態規劃演算法
dp = [[[0 for k in range(self.cubage + 5)] for i in range(4)] for j in range(self.size + 5)] # 三維dp陣列
for k in range(1, self.size + 1):
for i in range(1, 4):
for v in range(self.cubage + 1):
for j in range(1, 4):
dp[k][i][v] = max(dp[k][i][v], dp[k - 1][j][v])
if v >= self.items[k - 1].pack[i - 1].weight:
dp[k][i][v] = max(dp[k][i][v],dp[k - 1][j][v - self.items[k - 1].pack[i - 1].weight]+self.items[k - 1].pack[i - 1].profit)
self.max_val = max(self.max_val, dp[k][i][v])
資料庫-sql
config = {
'host': 'localhost',
'port': 3306,
'user': 'root',
'password': 'root',
'db': 'dk',
'charset': 'utf8',
'cursorclass': pymysql.cursors.DictCursor,
}
- 程式執行:程式執行時每個功能介面截圖。
主頁面(GUI介面):
繪製散點圖:
-
- 資料庫儲存的資料:
遺傳演算法:
匯出結果檔案:
- 描述結對的過程,提供兩人在討論、細化和程式設計時的結對照片(非擺拍)。
理解了領航員和駕駛員兩種角色關係:兩人都必須參與編碼工作,在結對程式設計中兩個人輪流做對方的角色。
採用了漢堡包法實施專案結對中兩個人的溝通:
討論的步驟總結:
- 提交原始碼到Github專案倉庫中,編撰兩人合作開發遵守共同認可的編碼規範,提交專案程式碼規範文件到Github專案倉庫根目錄下
- 提供此次結對作業的PSP。
PSP2.1 | 任務內容 | 計劃完成需要的時間(h) | 實際完成需要的時間(h) |
Planning | 計劃 | 1 | 1 |
Estimate | 估計這個任務需要多少時間,並規劃大致工作步驟 | 1 | 1 |
Development | 開發 | 16.5 | 21.5 |
Analysis | 需求分析(包括學習新技術) | 5 | 7 |
Design Spec | 生成設計文件 | 0.5 | 0.5 |
Design Review | 設計複審 | 0.5 | 0.5 |
Coding Standard | 程式碼規範 | 0.5 | 0.5 |
Design | 具體設計 | 1 | 1 |
Coding | 具體編碼 | 5 | 5 |
Code Review | 程式碼複審 | 1 | 2 |
Test | 測試 | 3 | 5 |
Reporting | 報告 | 6.3 | 9.8 |
Test Report | 測試報告 | 5 | 8 |
Size Measurement | 計算工作量 | 0.3 | 0.3 |
Postmortem &Process Improvement Plan | 事後總結,並提出過程改進計劃 | 1 | 1.5 |
- 小結感受:兩人合作真的能夠帶來1+1>2的效果嗎?通過這次結對合作,請談談你的感受和體會。
通過這次結對實驗合作,讓我覺得1+1真的大於2,我們兩個人在彼此溝通的過程中,都能發現對方沒有注意到的問題,這是一個人需要經過很長時間才能意識到的。三人行,必有我師。也就是說每個人都有自己的優劣點以及自己獨創的想法。結對完成專案有助於產生不同種想法,從而有助於在決策的時候可以集思廣益而產生一種比較好的方案。人無完人,一個人的力量有限,若是個人單打獨鬥難以把全部事情都做盡做全。但是兩人分工合作的話,就會有監督有分工,還能提高自身的效率。
任務4:完成結對專案報告博文作業