201971010216-李斌 實驗三 結對專案——《{0-1}KP 例項資料集演算法實驗平臺》專案報告
實驗三 軟體工程結對專案
專案 | 內容 |
---|---|
課程班級部落格的連結 | 2019級卓越工程師班 |
作業要求連結 | 實驗三 結對專案 |
課程學習目標 | 1.體驗軟體專案開發中的兩人合作,練習結對程式設計。2.掌握Github協作開發軟體的操作方法。 |
結對對方學號和姓名 | 201971010237-尚潔 |
結對方部落格連結 | [實驗三 軟體工程](https://www.cnblogs.com/sj3191/p/16061576.html) |
專案倉庫連結 | 實驗三 倉庫 |
任務1
閱讀《現代軟體工程—構建之法》第3-4章內容,理解並掌握程式碼風格規範、程式碼設計規範、程式碼複審、結對程式設計概念;
-
IC在團隊中的流程
- 通過交流、實驗、快速原型等方法,理解問題、需求或任務
- 提出多種解決辦法並估計工作量其中包括尋找以前的解決方案,因為很多工作是重複性的
- 與相關角色交流解決問題的提案,決定一個可行的方案
- 執行,把想法變成實際中能工作的程式碼,同時驗證方案的可行性和其他特性
- 和團隊的其他角色合作,在測試環境中測試實現方案,修復缺陷(Bug )。如果此方案有嚴重的問題,那麼就考慮其他方案
在解決方案發布出去之後,對結果負責
-
程式碼設計規範
- 概念:程式碼設計規範不光是程式書寫的格式問題,而且涉及到程式設計、模組之間的關係、設計模式等方方面面,又有不少內容與
具體程式設計語言息息相關(如C,C++,JAVA,C#),但是也有通用的原則。 - 函式:原則:只做一件事,並且要做好。
- goto:函式最好有單一出口,為了達到這一目的,可以使用goto。
-
錯誤處理:
- 引數處理:在Debug版本中,所有的引數都要驗證其正確性,在正式版本中,對從外部(使用者或別的模組)傳遞過來的引數,要驗證其正確性。
- 斷言:驗證正確性就要用斷言。
- 概念:程式碼設計規範不光是程式書寫的格式問題,而且涉及到程式設計、模組之間的關係、設計模式等方方面面,又有不少內容與
-
結對程式設計:
- 在結對程式設計模式下,一對程式設計師肩並肩地、平等地、互補地進行開發工作。兩個程式設計師並排坐在一臺電腦前,面對同一個
顯示器,使用同一個鍵盤,同一個滑鼠一起工作。他們一起分析,一起設計,一起寫測試用例,一起編碼,一起單元測試,
一起整合測試,一起寫文件等。
- 在結對程式設計模式下,一對程式設計師肩並肩地、平等地、互補地進行開發工作。兩個程式設計師並排坐在一臺電腦前,面對同一個
-
角色
- 駕駛員(Driver ) :控制鍵盤輸入。
- 領航員(Navigator ) :起到領航、提醒的作用。
-
優點
- 在開發層次,結對程式設計能提供更好的設計質量和程式碼質量,兩人合作解決問題的能力更強。兩人合作,還有相互激勵的作用,
工程師看到別人的思路和技能,得到實時的講解,受到激勵,從而努力提高自己的水平,提出更多創意。 - 對開發人員自身來說,結對工作能帶來更多的信心,高質量的產出能帶來更高的滿足感。
- 在企業管理層次上,結對能更有效地交流,相互學習和傳遞經驗,分享知識,能更好地應對人員流動。
- 在開發層次,結對程式設計能提供更好的設計質量和程式碼質量,兩人合作解決問題的能力更強。兩人合作,還有相互激勵的作用,
-
如何結對程式設計
- 駕駛員:寫設計文件,進行編碼和單元測試等XP開發流程。
- 領航員:審閱駕駛員的文件;監督駕駛員對編碼等開發流程的執行;考慮單元測試的覆蓋率;思考是否需要和如何重構;
幫助駕駛員解決具體的技術問題。 領航員也可以設計TDD中的測試用例。 - 駕駛員和領航員不斷輪換角色,不要連續工作超過一小時,每工作一小時休息15分鐘。領航員要控制時間。
- 主動參與。任何一個任務都首先是兩個人的責任,也是所有人的責任。
- 只有水平上的差距,沒有級別上的差異。兩人結對,儘管可能大家的級別資歷不同,但不管在分析、設計或編碼上,
雙方都擁有平等的決策權利。 - 設定好結對程式設計的環境,座位、顯示器、桌面等都要能允許兩個人舒適地討論和工作。如果是通過遠端結對程式設計,
那麼網路、語音通訊和螢幕共享程式要設定好。
任務2:
兩兩自由結對,對結對方《實驗二 軟體工程個人專案》的專案成果進行評價
專案 | 內容 |
---|---|
結對方 | 尚潔(201971010237) |
實驗二連結 | 實驗二 軟體工程 |
實驗二倉庫 | 倉庫 |
部落格評論
-
博文結構:
- 整體結構較為簡練,條目清晰,但在排版上存在一定的欠缺。
-
博文內容:
- 總體上完成了要求的內容,以各任務為中心構成行文路線。但對於專案描述的詳細程度有所不足,但是總體而言還是很不錯。
-
博文結構與PSP中“任務內容”列的關係:
- 博文結構與“內容任務”列並非完全對應。博文結構主要應用“從面至點”的思路,由整體開發思路到詳細編碼內容。
-
PSP中“計劃共完成需要的時間”與“實際完成需要的時間”兩列資料的差異化分析與原因探究:
- 實際完成需要的時間比計劃共完成需要的時間更長,作者提到其自身編碼能力很好,使用Java進行程式設計,各個功能實現完整,實驗整體非常成功。
Git操作
將專案匯入進行測試
專案 | 內容 |
---|---|
概要部分 |
|
程式碼符合需求和規格說明麼? | 完成全部功能 |
程式碼設計是否考慮周全? | 是 |
程式碼可讀性如何? | 較好 |
程式碼容易維護麼? | 易維護 |
程式碼的每一行都執行並檢查過了嗎? | 是 |
```設計規範部分```` | |
設計是否遵從已知的設計模式或專案中常用的模式? | 是 |
有沒有硬編碼或字串/數字等存在? | 有 |
程式碼有沒有依賴於某一平臺,是否會影響將來的移植? | 對移植影響較小 |
開發者新寫的程式碼是否用已有的Library/SDK/Framework中的功能實現? | 是 |
在本專案中是否存在類似的功能可以通過呼叫而不用全部重新實現? | 是,程式碼中使用了Matplotlib庫 |
有沒有無用的程式碼可以清除? | 沒有 |
程式碼規範部分 |
|
修改的部分符合程式碼標準和風格麼? | 符合 |
具體程式碼部分 |
|
有沒有對錯誤進行處理?對於呼叫的外部函式,是否檢查了返回值或處理了異常? | 已處理 |
引數傳遞有無錯誤,字串的長度是位元組的長度還是字元的長度,是從0開始計數還是從1開始計數 | 無錯誤;字元的長度;從0開始 |
邊界條件是如何處理的?switch語句和default分支是如何處理的?迴圈有沒有可能出現死迴圈? | 前提分析推導邊界條件;可能 |
有沒有使用斷言來保證我們認為不變的條件真的得到滿足? | 否 |
對資源的利用,是在哪裡申請,在哪裡釋放的?有無可能存在資源洩露?有沒有優化的空間? | 有對應的申請、釋放語句;不存在;有 |
資料結構中有沒有用不到的元素? | 有 |
效能 |
|
程式碼的效能如何?最壞的情況是怎麼樣的? | 效能一般;最壞情況下回溯演算法將在極長的一段時間無法給出結果 |
程式碼中,特別是迴圈中是否有明顯可優化的部分? | 有,如動態規劃可優化為一維 |
對於系統和網路的呼叫是否會超時?如何處理? | 否 |
可讀性 |
|
程式碼可讀性如何?有沒有足夠的註釋? | 沒有足夠的註釋,但程式碼較為清晰,故可讀性較好 |
可測試性 |
|
程式碼是否需要更新或建立新的單元測試? | 是 |
結對方專案倉庫中的日誌資料 | |
Commits資料:如圖所示,幫助結對方完成了揹包資料讀取與選擇的功能,並上傳至Github。 | |
Forks資料:如圖所示,對結對方的專案進行了Fork操作和將修改提交到指定一方的倉庫中
將修改提交到指定一方的倉庫中
任務3:
採用兩人結對程式設計方式,設計開發一款{0-1}KP例項資料集演算法實驗平臺
-
專案背景:
- {0-1}揹包問題:有N件物品和一個容量為M的揹包。第i件物品所佔空間是w[i],價值是v[i]。求解將哪些物品裝入揹包可使價值總和最大,對於每件物品,僅有取與不取兩個狀態。
-
需求分析:
- 通過需求文件,使用“3W”模型進行分析:
- Who-為誰設計,使用者是誰?
- 為需要使用不同的方法求出0-1揹包問題的最優解、提高多組資料處理效率的使用者。
- What-要解決哪些問題?
- GUI頁面:
- 採用java圖形使用者介面的方式實現GUI。
- 資料讀入與處理:
- 正確讀入實驗資料檔案的有效{0-1}KP資料,並將其處理為便於後續操作的資料形式。
- 資料展示(拓展):
- 選擇任意一組已經讀入的資料並展示。
- 散點圖繪製:
- 繪製任意一組{0-1}KP資料以價值重量為橫軸、價值為縱軸的資料散點圖。
- 排序:
- 對任一組{0-1}KP資料按重量比進行非遞增排序。
- 貪心演算法:
- 採用貪心演算法求解不超過揹包容量的最大價值和解向量。
- 動態規劃演算法:
- 採用動態規劃演算法求解不超過揹包容量的最大價值和解向量。
- 回溯演算法:
- 採用回溯演算法求解不超過揹包容量的最大價值和解向量。
- 遺傳演算法:
- 採用遺傳演算法求解不超過揹包容量的最大價值和解向量。
- 檔案儲存:
- 將求解時間,最大價值,解向量儲存至檔案中。
- 資料庫儲存:
- 將資料集、日誌資料存入資料庫。
- Why-為什麼要解決這些問題?
- 根據給出的任務要求,結合使用系統時的實際需求,在該專案的實現中我們需要實解決上述的問題。
軟體設計
- 1、D{0-1}KP 例項資料集需儲存在資料庫;
- 2、平臺可動態嵌入任何一個有效的D{0-1}KP 例項求解演算法,並儲存演算法實驗日誌資料;
- 3、人機互動介面要求為GUI介面;
- 4、查閱資料,設計遺傳演算法求解D{0-1}KP,並利用此演算法測試要求(3);
遺傳演算法
-
遺傳演算法(Genetic>遺傳演算法(Genetic Algorithm,GA)是進化計算的一部分,是模擬達爾文的遺傳選擇和自然淘汰的生物進化過程的計算模型,是一種通過模擬自然進化過程搜尋最優解的方法。該演算法簡單、通用,魯棒性強,適於並行處理。
-
遺傳演算法的基本步驟是:
- (1)初始化:設定進化代數計數器t=0,設定最大進化代數T,隨機生成M個個體作為初始群體P(0)。
- (2)個體評價:計算群體P(t)中各個個體的適應度。
- (3)選擇運算:將選擇運算元作用於群體。選擇的目的是把優化的個體直接遺傳到下一代或通過配對交叉產生新的個體再遺傳到下一代。選擇操作是建立在群體中個體的適應度評估基礎上的。
- (4)交叉運算:將交叉運算元作用於群體。遺傳演算法中起核心作用的就是交叉運算元。
- (5)變異運算:將變異運算元作用於群體。即是對群體中的個體串的某些基因座上的基因值作變動。群體P(t)經過選擇、交叉、變異運算之後得到下一代群體P(t+1)。
- (6)終止條件判斷:若t=T,則以進化過程中所得到的具有最大適應度個體作為最優解輸出,終止計算。
參考文獻:
- [1]吳聰聰,賀毅朝,趙建立.求解折扣{0-1}揹包問題的新遺傳演算法[J].計算機工程與應用,2020,56(07):57-66.
- [2]楊洋,潘大志,劉益,譚代倫.折扣{0-1}揹包問題的簡化新模型及遺傳演算法求解[J].計算機應用,2019,39(03):656-662.
遺傳演算法虛擬碼,如下圖所示。 -
軟體實現及核心功能程式碼展示
實現圖形使用者介面功能:
public static void main(String[] args){
ArrayList<GradeFrame> GradeFrame = new ArrayList<GradeFrame>();
int arr[] = {1,1,1,1,1,1,1,1,1,1};
JPanel p = new JPanel();
p.setPreferredSize(new Dimension(200, 180));
JFrame f = new JFrame("0/1揹包管理系統");
f.setSize(400, 300);
JButton b1 = new JButton("輸入題目要求");
JButton b2 = new JButton("輸出實驗結果");
JButton b3 = new JButton("輸出散點圖");
b1.addActionListener(new ActionListener(){
//單擊輸入執行的方法
public void actionPerformed(ActionEvent e) {
JPanel jp12=new JPanel();
JPanel jp13=new JPanel();
JTextField jt11=new JTextField(10);
JTextField jt12=new JTextField(10);
JDialog jd = new JDialog();
jd.setLayout(new GridLayout(10, 1));
jd.setTitle("請輸入");
jd.setSize(400, 850);
jp13.add(new JLabel("所使用的演算法"));
jp13.add(jt12);
jd.add(jp12);
jd.add(jp13);
JPanel jp1=new JPanel();
JPanel jp11=new JPanel();
JButton jb1,jb2;
JTextField jt1=new JTextField(10);
jb1=new JButton("確定");
jb2=new JButton("取消");
jb2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
jd.dispose();
}
});
jp1.add(new JLabel("揹包資料數"));
jp1.add(jt1);
jp11.add(jb1);
jp11.add(jb2);
jd.add(jp1);
jd.add(jp11);
jb1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
String num;
for(int i=0;i<10;i++) {
if(i==0) {
num = jt1.getText();
int x = Integer.parseInt(num);
arr[i]= x;
}
}
}
});
jd.setLocationRelativeTo(null);
jd.setModal(true);
jd.setVisible(true);
}
});
b2.addActionListener(new ActionListener(){
//單擊輸出執行的方法
public void actionPerformed(ActionEvent e) {
JDialog jd = new JDialog();
jd.setTitle("實驗結果");
jd.setSize(300, 500);
JTextArea jt = new JTextArea();
jt.setLayout(null);
jt.setSize(300, 500);
for (bag.GradeFrame d :GradeFrame)
{
jt.append(d.toString()+"\r\n");
}
jd.add(jt);
jd.setLocationRelativeTo(null);
jd.setModal(true);
jd.setVisible(true);
}
});
b2.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
});
p.add(b1);
p.add(b2);
p.add(b3);
f.add(p, BorderLayout.SOUTH);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//介面關閉後程序結束
f.setLocationRelativeTo(null);
f.setVisible(true);
}
測試執行:
首頁:
-
資料輸入:
執行結果:1
執行結果:2
資料庫:1
資料庫:2
散點圖:
結對過程記錄:
此次結對實驗的PSP
PSP2.1 | 任務內容 | 計劃共完成需要的時間(min) | 實際完成需要的時間(min) |
---|---|---|---|
Planning | 計劃 | 10 | 13 |
Estimate | 估計這個任務需要多少時間,並規劃大致工作步驟 | 10 | 12 |
Development | 開發 | 400 | 580 |
Analysis | 需求分析(包括學習新技術) | 30 | 45 |
Design Spec | 生成設計文件 | 15 | 25 |
Design Review | 設計複審(和同事稽核設計文件) | 15 | 24 |
Coding Standard | 程式碼規範(為目前的開發制定合適的規範) | 10 | 18 |
Design | 具體設計 | 140 | 160 |
Coding | 具體編碼 | 40 | 80 |
Code Review | 程式碼複審 | 30 | 40 |
Test | 測試(自我測試,修改程式碼, 提交修改) | 30 | 38 |
Reporting | 報告 | 50 | 70 |
Test Report | 測試報告 | 20 | 24 |
Size Measurement | 計算工作量 | 16 | 24 |
Postmortem & Process Improvement Plan | 事後總結,並提出過程改進計劃 | 10 | 15 |
實驗總結:
-
對於此次結對程式設計實驗,我有如下感受及體會:
第一次接觸結對程式設計,對於結對程式設計的整體感受總的來說是利大於弊的,即有1+1>2的效果。我認為或許結對程式設計並不適用於簡單的寫程式碼的工作,結對程式設計更適用於解決一些方向性的問題,因為在程式設計時,每個人的思想不同可能用到的方法及語句也就不同,所以難免會產生分歧與不一致,但是,兩個人的思想可能會碰撞出新的火花,有時候還可以找到更適合、更節省空間與時間的方法與演算法。在結對程式設計中,雙方的互動目的在於開啟思路,避免單獨程式設計時思維容易阻塞的情況,有時候一個人在寫程式碼時,難免會陷入僵局出不來,而兩個人合作缺可以解決不這個問題,有時候對方的一句話可以啟發自己換一種思考方式,從而高效地解決問題。
在自己程式設計過程時不難發現,程式設計耗時最多的方面就是debug。在我們得出設計思路,並將它們初次轉化成程式碼後,程式設計之路其實才走了一小段。由於個人的疏忽,輸入的錯誤,以及設計思路的偏差,往往會讓我們的程式陷入無止盡的bug泥潭中,難以掙脫,這會消耗我們大量的時間。 而結對程式設計的好處就在於此。由於身邊有個領航員角色的存在,在編寫程式碼時,一旦出現輸入錯誤,就會有人及時的提醒。並且,在設計程式碼時,有個同伴可以一起討論,融合兩個人不同的見解和觀點,我們往往可以得出更加準確且更加高效的設計思路。這一切都為我們在完成程式碼後的debug過程省去了大量的時間。
總體來說,結對程式設計可以很大程度上提高程式設計效率,而且兩人輪流程式設計,不會太過疲憊,因此十分適合敏捷開發。如果未來我們從事軟體開發的工作,我們會十分樂於進行結對程式設計,因為這會極大的改善我們的程式設計體驗,是程式設計不再那麼枯燥,debug之路也不會那麼恐怖。