201971010101-阿麗米拉 實驗三 結對專案—《{0-1}KP 例項資料集演算法實驗平臺》專案
專案 | 內容 |
---|---|
課程班級部落格連結 | 2019級卓越班 |
作業要求連結 | 實驗三 |
我的課程學習目標 | 體驗軟體專案開發中的兩人合作,練習結對程式設計;掌握Github協作開發程式的操作。 |
這個作業在哪些方面幫助我實現學習目標 | 學習如何與同學高效的分配並完成小組合作任務,幫我複習瞭如何使用python寫圖形使用者介面,並讓我瞭解熟悉了遺傳演算法。 |
結對方學號-姓名 | 201971010160-謝家俊 |
結對方本次部落格作業連結 | 謝家俊 |
本專案Github的倉庫連結地址 | Github的倉庫 |
實驗內容
任務一:閱讀《現代軟體工程—構建之法》第3-4章內容,理解並掌握程式碼風格規範、程式碼設計規範、程式碼複審、結對程式設計概念;
-
程式碼風格規範:簡明、易讀、無二義性。
-
縮排:4個空格。
-
行寬:可以限定100字元。
-
括號:在複雜的條件表示式中,用括號清楚地表達邏輯優先順序。
-
斷行與空白的{}行:格式D:每個“{”和“}”都獨佔一行。
-
分行:不要把多條語句放在一行上。
-
命名:在變數名中不要提到型別或者其他語法方面的描述。避免過多的描述。如果資訊可以從上下文中得到,那麼此類資訊就不必寫在變數名中。避免可要不可要的修飾詞。
-
下劃線:下劃線用來分隔名字中作用域標註和變數的語義。
-
大小寫:由多個單片語成的變數名,如果全部都是小寫,很不易讀,一個簡單的解決方案就是用大小寫區分它們。
-
註釋:註釋是為了解釋程式做什麼(what),為什麼這樣做(why)。
-
-
程式碼設計規範:
- 函式:最重要的原則:只做一件事,並且要最好。
- goto:函式最好有單一的出口,為達到這一目的,可以使用goto。只要有助於程式邏輯的清晰體現,什麼方法都可以使用,包括goto。
- 錯誤處理:當程式的主要功能實現後,給程式碼加一些錯誤處理。
1、引數處理:在debug版本中,所有的引數都要驗證其正確性。在正式版本中,對從外部(使用者或別的模組)傳遞過來的引數,要驗證其正確性。
2、 斷言:使用斷言來驗證正確性。- 如何處理c++中的類:
1、類:
使用類來封裝面向物件的概念和多型( Polymorphism)。
避免傳遞型別實體的值,應該用指標傳遞。換句話說,對於簡單的資料型別,沒有必要用類來實現。
對於有顯式的構造和解構函式的類,不要建立全域性的實體,因為你不知道它們在何時建立和消除。
僅在必要時,才使用“類”。
2、class vs.struct
如果只是資料的封裝,用struct即可。
3、公共/保護/私有成員( public. protected和private )
按照這樣的次序來說明類中的成員: public、 protected. private。
4、資料成員
資料型別的成員用m_ name說明。
不要使用公共的資料成員,要用inline訪問函式,這樣可兼顧封裝和效率。
5、虛擬函式 ( Virtual Function )
使用虛擬函式來實現多型( Polymorphism)。
僅在很有必要時,才使用虛擬函式。
如果一個型別要實現多型,在基類( Base Class )中的解構函式應該是虛擬函式。
6、建構函式( Constructors )
不要在建構函式中做複雜的操作,簡單初始化所有資料成員即可。
建構函式不應該返回錯誤(事實上也無法返回)。把可能出錯的操作放到HrInit()或FInit()中。
7、解構函式 ( Destructor )
把所有的清理工作都放在解構函式中。如果有些資源在解構函式之前就釋放了,記住要重置這些成員為0或NULL。
解構函式也不應該出錯。
8、new 和delete
如果可能,實現自已的new/delete,這樣可以方便地加上自已的跟蹤和管理機制。自已的new/delete可以包裝系統提供的new/delete。
檢查new的返回值。new 不一定都成功。
釋放指標時不用檢查NULL。
9、運算子 ( Operators )
在理想狀態下,我們定義的類不需要自定義操作符。確有必要時,才會自定義操作符。
運算子不要做標準語義之外的任何動作。例如.“==”的判斷不能改變被比較實體的狀態。
運算子的實現必須非常有效率,如果有複雜的操作,應定義一個單獨的函式。
當你拿不定主意的時候,用成員函式.不要用運算子。
10、異常( Exceptions )
異常是在“異乎尋常”的情況下出現的,它的設定和處理都要花費“異乎尋常”的開銷,所以不要用異常作為邏輯控制來處理程式的主要流程。
瞭解異常及處理異常的花銷,在C++語言中,這是不可忽視的開銷。
當使用異常時,要注意在什麼地方清理資料。
異常不能跨過DLL或程序的邊界來傳遞資訊,所以異常不是萬能的。
11、型別繼承( Class Inheritance )
僅在必要時,才使用型別繼承。
用const標註只讀的引數(引數指向的資料是隻讀的,而不是引數本身)。
用const標註不改變資料的函式。 -
程式碼複審:看按程式碼是否在程式碼規範的框架內正確地解決了問題。
名稱 | 形式 | 目的 |
---|---|---|
自我複審 | 自己vs.自己 | 用同伴複審的標準來要求自己。不一定最有效,因為開發者對自己總是過於自信。如果能持之以恆,則對個人有很大好處 |
同伴複審 | 複審者 vs. 開發者 | 簡便易行 |
團隊複審 | 團隊 vs. 開發者 | 有比較嚴格的規定和流程,用於關鍵的程式碼,以及複審後不再更新的程式碼。 覆蓋率高——有很多雙眼睛盯著程式。但是有可能效率不高(全體人員都要到會) |
- 程式碼複審的目的在於:
1、找出程式碼的錯誤。
2、發現邏輯錯誤, 程式可以編譯通過,但是程式碼的邏輯是錯的。
3、發現演算法錯誤, 比如使用的演算法不夠優化,邊界條件沒有處理好等。
4、發現潛在的錯誤 和迴歸性錯誤——當前的修改導致以前修復的缺陷又重新出現
5、發現可能需要改進的地方
6、教育(互相教育)開發人員,傳授經驗,讓更多的成員熟悉專案各部分的程式碼,同時熟悉和應用領域相關的實際知識 - 結對程式設計概念:
是一種敏捷軟體開發的方法,兩個程式設計師在一個計算機上共同工作。一個人輸入程式碼,而另一個人審查他輸入的每一行程式碼。輸入程式碼的人稱作駕駛員,審查程式碼的人稱作觀察員(或導航員)。兩個程式設計師經常互換角色。 和現實生活中的例子類似,一個人負責具體的執行(駕駛,用鍵盤編寫程式等),另一人負責導航、檢查、掩護等。
任務二:兩兩自由結對,對結對方《實驗二 軟體工程個人專案》的專案成果進行評價,具體要求如下:
(1)對專案博文作業進行閱讀並進行評論,評論要點包括:博文結構、博文內容、博文結構與PSP中“任務內容”列的關係、PSP中“計劃共完成需要的時間”與“實際完成需要的時間”兩列資料的差異化分析與原因探究,將以上評論內容釋出到部落格評論區。
專案 | 內容 |
---|---|
結對方部落格評論連結 | 201971010160-謝家俊 |
結對方Github專案倉庫連結 | Github |
(2)克隆結對方專案原始碼到本地機器,閱讀並測試執行程式碼,參照《現代軟體工程—構建之法》4.4.3節核查表複審同伴專案程式碼並記錄。
(3)依據複審結果嘗試利用github的Fork、Clone、Push、Pull request、Merge pull request等操作對同伴個人專案倉庫的原始碼進行合作修改。
- 克隆結對方專案原始碼到本地機器並測試執行程式碼
- 程式碼核查表
專案部分 | 完成情況 |
---|---|
概要部分 | |
程式碼能符合需求和規格說明麼? | 程式碼完成了部分需求,程式碼編寫基本規範 |
程式碼設計是否有周全的考慮? | 是 |
程式碼的可讀性? | 簡單易讀 |
程式碼是否容易維護? | 易維護 |
程式碼的每一行是否都執行並檢查過? | 是 |
設計規範部分 | |
設計是否遵從已知的設計模式或專案中常用的模式? | 是 |
有沒有硬編碼或字串/數字等存在? | 沒有 |
程式碼有沒有依賴於某一平臺,是否會影響將來的移植? | 否 |
開發者新寫的程式碼是否用已有的Library/SDK/Framework中的功能實現?在本專案中是否存在類似的功能可以通過呼叫而不用全部重新實現? | 否 |
有沒有無用的程式碼可以清除? | 否 |
程式碼規範部分 | |
修改的部分符合程式碼標準和風格麼? | 符合 |
具體程式碼部分 | |
有沒有對錯誤進行處理?對於呼叫的外部函式,是否檢查了返回值或處理了異常? | 已處理 |
引數傳遞有無錯誤,字串的長度是位元組的長度還是字元的長度,是從0開始計數還是從1開始計數 | 無錯誤 |
邊界條件是如何處理的?switch語句和default分支是如何處理的?迴圈有沒有可能出現死迴圈? | 沒有出現死迴圈 |
有沒有使用斷言來保證我們認為不變的條件真的得到滿足? | 否 |
資料結構中有沒有用不到的元素? | 否 |
效能 | |
程式碼的效能如何?最壞的情況是怎麼樣的? | 效能一般 |
程式碼中,特別是迴圈中是否有明顯可優化的部分? | 有 |
對於系統和網路的呼叫是否會超時?如何處理? | 否 |
可讀性 | |
程式碼可讀性如何?有沒有足夠的註釋? | 程式碼有較好的可讀性 |
可測試性 | |
程式碼是否需要更新或建立新的單元測試? | 否 |
任務三: 採用兩人結對程式設計方式,設計開發一款{0-1}KP 例項資料集演算法實驗平臺,使之具有以下功能:
1、基本功能設計
- 平臺基礎功能:實驗二 任務3;
- 可正確讀入實驗資料檔案的有效{0-1}KP資料;
- 能夠繪製任意一組{0-1}KP資料以價值重量為橫軸、價值為縱軸的資料散點圖;
- 能夠對一組{0-1}KP資料按重量比進行非遞增排序;
- 使用者能夠自主選擇貪心演算法、動態規劃演算法、回溯演算法求解指定{0-1} KP資料的最優解和求解時間(以秒為單位);
- 任意一組{0-1} KP資料的最優解、求解時間和解向量可儲存為txt檔案或匯出EXCEL檔案。
- {0-1}KP 例項資料集需儲存在資料庫;
- 平臺可動態嵌入任何一個有效的{0-1}KP 例項求解演算法,並儲存演算法實驗日誌資料;
- 人機互動介面要求為GUI介面(WEB頁面、APP頁面都可);
- 查閱資料,設計遺傳演算法求解{0-1}KP,並利用此演算法測試要求(3);
2、需求分析
D{0-1}KP問題可以採用動態規劃演算法,回溯演算法以及遺傳演算法等多種演算法來解決,每一種演算法解決D{0-1}KP問題所消耗的時間和空間都有所不同,為了方便使用者快速的選擇某種演算法來解決D{0-1}KP問題並且比較每一種演算法執行時所消耗的時間和空間,所以我們試圖開發一個D{0-1}KP例項資料集演算法實驗平臺,以便使用者能夠快速的選擇某種演算法來解決D{0-1}KP問題並且比較出哪種演算法更高效。
3、軟體設計說明
- 在實驗二-個人專案的基礎上進行開發;
- 人機互動介面通過python來編寫GUI介面;
- 將D{0-1}KP例項資料集儲存在資料庫,在GUI介面可進行資料的查詢;
- 輸入需要繪製散點圖或者需要排序的資料集以及資料項後進行散點圖的繪製或者資料的排序;
- 平臺動態嵌入有效的{0-1}KP例項求解演算法。
4、程式執行圖
-
資料庫
-
GUI介面設計
-
散點圖
-
排序
-
演算法模組
5、核心程式碼
- 散點圖繪製
def paint(list11=[],list22=[]):
import numpy as np
import matplotlib.pyplot as plt
plt.scatter(list11,list22)
plt.show()
- 資料排序
def sort(list11=[],list22=[]):
win1 = tkinter.Toplevel()
win1.title('資料排序')
win1.geometry('500x300')
sw = win1.winfo_screenwidth()
sh = win1.winfo_screenheight()
win1.geometry('+%d+%d' % ((sw - 500) / 2, (sh - 300) / 2))
list4=[]
for i in range(2,len(list11)+1):
if i%3==0:
list4.append(round(int(list11[i-1])/int(list22[i-1]),3))
list4.sort(reverse=True)
tkinter.messagebox.showinfo("按照價效比的非遞增排序",list4)
win1.destroy()
- GUI介面佈局
win = tkinter.Tk()
win.title('D{0-1}揹包問題')
win.geometry('500x300')
win.configure(bg='Linen')
sw = win.winfo_screenwidth()
sh = win.winfo_screenheight()
win.geometry('+%d+%d' % ((sw - 500) / 2, (sh - 300) / 2))
l = tkinter.Label(win, text='{0-1}KP例項資料集演算法實驗平臺', font=('華文行楷', 24), fg='black')
l.place(relx=0.5, rely=0.1, anchor='center')
Lname = tkinter.Label(win, text='資料集檔名', font=('華文行楷', 19), fg='black')
Lname.place(relx=0.45, rely=0.3, anchor='center')
nu = tkinter.StringVar()
name = tkinter.Entry(win, textvariable=nu)
name.place(relx=0.51, rely=0.29, width=95)
choose = [('1.進行資料的查詢', 1), ('2.繪製資料散點圖', 2), ('3.對資料進行排序', 3), ('4.選擇演算法來求解', 4)]
v = tkinter.IntVar()
v.set(1)
x, y = 0.5, 0.5,
for a, b in choose:
cc = tkinter.Radiobutton(win, text=a, variable=v, value=b, font=('華文行楷', 20), fg='black')
cc.place(relx=x, rely=y, anchor='center')
y += 0.1
b = tkinter.Button(win, text='確定', width=10, height=3, bg='gray', command=secondMain)
b.place(relx=0, rely=1, anchor='sw')
b2 = tkinter.Button(win, text='退出', width=10, height=3, bg='gray', command=win.quit)
b2.place(relx=1, rely=1, anchor='se')
6、展示psp
PSP2.1 | 任務內容 | 計劃共完成需要的時間(min) | 實際完成需要的時間(min) |
---|---|---|---|
Planning | 計劃 | 30 | 25 |
Estimate | 估計這個任務需要多少時間,並規劃大致工作步驟 | 30 | 25 |
Development | 開發 | 1120 | 953 |
Analysis | 需求分析(包括學習新的技術) | 310 | 260 |
Design Spec | 生成設計文件 | 90 | 60 |
Design Review | 設計複審 | 30 | 25 |
Coding Standard | 程式碼規範(為開發制定合適的規範) | 10 | 8 |
Design | 具體設計 | 60 | 40 |
Coding | 具體編碼 | 500 | 520 |
Code Review | 程式碼複審 | 60 | 40 |
Test | 測試(自我測試,修改程式碼,提交修改) | 60 | 30 |
Reporting | 報告 | 100 | 70 |
Test Report | 測試報告 | 60 | 30 |
Size Measurement | 計算工作量 | 10 | 10 |
Postmortem & Process Improvement Plan | 事後總結 ,並提出過程改進計劃 | 30 | 30 |
7、實驗總結描述結對的過程,提供兩人在討論、細化和程式設計時的結對照片(非擺拍)
8、實驗總結
- 本次實驗採用了結對程式設計的思想以及做法,通過本次實驗我覺得結對程式設計有它的好處也有不好的地方。首先,在設計以及編碼的過程中兩個人的思路是不同的,尤其在編碼過程中,很好的避免了因為一個小問題而去鑽牛角尖的問題,同時在設計方面也不再很單調,兩個人的想法會多一點,對題目的理解也會有所不同,能讓我們更好的理解和完成實驗。但是結對程式設計需要兩個人不斷地去討論,很多問題面對面的解決會更有效,但是兩人的時間會有一定的差異,這樣有些問題就需要通過社交媒體來交流,這樣不利於解決問題,有時對一個問題還會產生理解上的偏差,容易在編碼時出現錯誤。但總的來說,結對程式設計是利大於弊的,現在出現的問題很大程度上是所處環境造成的,但幫助是很大的,通過本次實驗,我從結對夥伴身上學到了很多值得學習的品質與精神。
任務四: 完成結對專案報告博文作業
- 已完成博文作業