201971010138-湯可意 實驗三 結對專案—《{0-1}KP 例項資料集演算法實驗平臺》專案報告
【keyi21】軟體工程準備報告[實驗三]
201971010139-湯可意 實驗三 結對專案—《{0-1}KP 例項資料集演算法實驗平臺》專案報告
專案 | 內容 |
---|---|
課程班級部落格連結 | https://edu.cnblogs.com/campus/xbsf/2019nwnucs |
作業要求連結 | https://edu.cnblogs.com/campus/xbsf/2019nwnucs/homework/12560 |
我的課程學習目標 | 1.體驗軟體專案開發中的兩人合作,練習結對程式設計; 2. 掌握Github協作開發程式的操作方法; 3.閱讀《現代軟體工程—構建之法》學習程式碼規範等知識。 |
這個作業在哪些方面幫助我實現學習目標 | 1.熟悉了軟體工程結對程式設計; 2.掌握Github克隆結對方專案; 3.學習了程式碼風格規範、程式碼設計規範、程式碼複審等知識; |
結對方學號-姓名 | 201971010142-王玉慧 |
結對方本次部落格作業連結 | 201971010142-王玉慧 |
本專案Github的倉庫連結地址 | 201971010138-keyi21 |
·任務一 閱讀《現代軟體工程—構建之法》第3-4章內容,理解並掌握程式碼風格規範、程式碼設計規範、程式碼複審、結對程式設計概念;
1.程式碼風格規範:
程式碼風格規範包括命名規範,程式碼展示風格的規範(縮排、空格、換行),控制語句的規範以及程式碼註釋的規範,好的程式碼風格規範可以讓其他人更好的理解。它的原則是:簡明
- 四個空格的縮排
- 每個{}獨佔一行
- 不要把多個變數定義在一行上
- 一個型別的成員變數用同一型別命名
- 所有的型別/類/函式名
- 註釋是為了解釋程式做什麼(What),為什麼這麼做(Why),以及要特別注意的地方,只用ASCII字元,不要用中文
2.程式碼設計規範:
- 函式:只做一件事,並且要做好
- 單一出口
- 不要在建構函式中做複雜的操作,簡單初始化所有的資料成員即可
3.程式碼複審:
看程式碼是否在程式碼規範的框架內正確地解決了問題、長遠的問題;
- 修改之後,有沒有別的功能會受影響;
- 專案中還有別的地方需要類似的修改嗎;
- 有沒有留下足夠的說明,讓將來維護程式碼時不會出現問題;
- 對於修改,是否需要告知成員;
- 導致問題的根本原因是什麼?以後如何能自動避免這樣的情況再次出現;
4.結對程式設計
結對程式設計是一種敏捷軟體開發的方法,兩個程式設計師在一個計算機上共同工作。一個人輸入程式碼,而另一個人審查他輸入的每一行程式碼。輸入程式碼的人稱作駕駛員,審查程式碼的人稱作觀察員。兩個程式設計師經常互換角色。
在結對程式設計中,觀察員同時考慮工作的戰略性方向,提出改進的意見,或將來可能出現的問題以便處理。這樣使得駕駛者可以集中全部注意力在完成當前任務的“戰術”方面。觀察員當作安全網和指南。結對程式設計對開發程式有很多好處。比如增加紀律性,寫出更好的程式碼等。
結對程式設計是極端程式設計的組成部分。
·任務2:兩兩自由結對,對結對方《實驗二 軟體工程個人專案》的專案成果進行評價
1.專案要求:
- 對專案博文作業進行閱讀並進行評論,評論要點包括:博文結構、博文內容、博文結構與PSP中“任務內容”列的關係、PSP中“計劃共完成需要的時間”與“實際完成需要的時間”兩列資料的差異化分析與原因探究,將以上評論內容釋出到部落格評論區。
- 克隆結對方專案原始碼到本地機器,閱讀並測試執行程式碼,參照《現代軟體工程—構建之法》4.4.3節核查表複審同伴專案程式碼並記錄。
- 依據複審結果嘗試利用github的Fork、Clone、Push、Pull request、Merge pull request等操作對同伴個人專案倉庫的原始碼進行合作修改。
2.專案完成:
- 結對方部落格連結:包鳳梅的部落格
- 結對方Github專案倉庫連結:王玉慧Github專案倉庫連結
- 部落格評論:
評論地址:201971010142-王玉慧
評論內容:
- 程式碼核查表
專案 | 內容 |
---|---|
概要部分 | a.程式碼書寫符合需求和規格說明; b.程式碼設計沒有考慮周全,有很多程式碼使用的很不合適; c.程式碼可讀性還性吧,不過有的還存在很多問題; d.程式碼比較容易維護; e.對結對方程式碼進行了逐行檢查與執行。 |
設計規範部分 | a.程式碼遵循了已知的設計模式和在專案中的常用模式, 學習了很多知識。 b.我程式碼設計中有字串和數字的存在。 c.程式程式碼沒有依賴於某一平臺,從Win32移植到Win64上沒有出現很大的問題。 d.在本程式中類似的功能差不多都可以呼叫而不用全部重新來實現。 e.有無用的程式碼可以刪除,在我的抽籤程式中,我對於按組抽籤中的新增人員姓名進行了編碼,實際上是不需要的,因為一個學號就做夠啦,而且還有窗體控制元件的功能實現。 |
程式碼規範部分 | a.修改的部分有很多地方是符合程式碼標準和風格的,但是有也有程式碼是沒有符合標準和風格的。 |
具體程式碼部分 | a.在抽籤程式中對錯誤進行了處理,在實現號碼滾動的程式碼上出現了錯誤,只能實現程式碼中的數字,而不能隨機的進行輸入數字。對於呼叫的外部函式,檢查了返回值。 b.引數傳遞無錯誤,字串的長度是位元組的長度,是雙位元組,是以1開始計數 c.Switch語句的用的很好,沒有出現死迴圈 d.沒有使用斷言(Assert)來保證我們認為不變的條件真的滿足 f.對資源的利用,是在C#書上借鑑的,記憶體、檔案、各種GUI資源、資料庫訪問的連線沒有可能導致資源洩露,有可能優化 e.資料結構中有很的元素是沒有用到的。 |
效能 | a.程式碼中,特別是迴圈中沒有明顯可優化的部分。 b.對於系統和網路呼叫會超時,可以等待一會。 |
可讀性 | 程式碼可讀性很易懂,沒有足夠的註釋,程式碼量很少。 |
可測試性 | 程式碼需要更新和建立新的單元測試。 可以針對部分功能的實現對程式碼進行進一步改進或建立新的單元測試。 |
3.依據複審結果嘗試利用github的Fork、Clone、Push、Pull request、Merge pull request等操作對同伴個人專案倉庫的原始碼進行合作修改。
GitHub部分操作介紹:
- Fork:從別人釋出的專案上覆制一個過來,相當於一個分支;專案複製到自己的個github中,於是本地就有了一個倉庫,假設名字為A;
- Clone:從自己的github上把fork過來的複製到本地,這樣本地就有了一個專案A1;
- Push:當你在A1中進行修改進行開發後,最後同步到你的github上的倉庫中;
- Pull request:你把自己github中的已經修改的內容申請同步到最初那個開發者的專案中;
·任務3:兩兩採用兩人結對程式設計方式,設計開發一款D{0-1}KP 例項資料集演算法實驗平臺
1.功能要求:
- 平臺基礎功能:實驗二 任務3;
- {0-1}KP 例項資料集需儲存在資料庫;
- 平臺可動態嵌入任何一個有效的{0-1}KP 例項求解演算法,並儲存演算法實驗日誌資料;
- 人機互動介面要求為GUI介面(WEB頁面、APP頁面都可);
- 查閱資料,設計遺傳演算法求解{0-1}KP,並利用此演算法測試要求(3);
- 附加功能:除(1)-(5)外的任意有效平臺功能實現。
2.功能分析:
- 可讀取實驗資料,有效呈現所有資料;
- 用讀取的資料繪製出以重量為橫軸、價值為縱軸的資料散點圖;
- 將資料按項集第三項的價值:重量比進行非遞增排序;
- 使用者能夠自主選擇動態規劃演算法、回溯演算法求解資料的最優解和求解時間;
- 資料的最優解、求解時間和解向量可儲存為txt檔案
3.軟體設計
本次結對程式設計專案採用C/S結構進行,專案分兩部分,一部分是客戶端的編寫,客戶端主要處理本地讀取的資料和傳輸資料到伺服器和資料庫,還有從伺服器讀取資料庫中儲存的結果,一部分是伺服器端的編寫,主要是連線資料庫,接收資訊,返回資訊。客戶端和伺服器端雙方通過tcp連結,並且在此基礎上自定義協議進行通訊和操作。同時本次專案採用了.net core平臺作為開發平臺,它具有跨平臺、易開發等多種特點,在本次開發中儘量減少在重複工作上的工作量。
具體實現專案:
- D{0-1}KP 例項資料集需儲存在資料庫;
- 平臺可動態嵌入任何一個有效的D{0-1}KP 例項求解演算法,並儲存演算法實驗日誌資料;
- 人機互動介面要求為GUI介面;
- 查閱資料,設計遺傳演算法求解D{0-1}KP,並利用此演算法測試要求(3);
4.軟體實現及核心功能程式碼展示
-
DatabaseController(請求資料庫操作)
package com.chm.bag_system.controller; public class DatabaseController { @Resource DataService dataService; @Resource CapacityService capacityService; @GetMapping("/save/data/database") public String insert(){ int count = capacityService.count(null); if (count>0){ return "redirect:/database"; } // 儲存所有檔名的列表 ArrayList<String> files=new ArrayList<>(); files.add("idkp1-10.txt"); files.add("sdkp1-10.txt"); files.add("udkp1-10.txt"); files.add("wdkp1-10.txt"); for (String file : files) { ReadFile rf = new ReadFile(); try { rf.clearData(file); } catch (IOException e) { e.printStackTrace(); } rf.replaceCharacter(); rf.separateVolume(); Result result = rf.resultData(); insertDataBase(result); } return "database"; } /** * 將資料插入到資料庫 * @param result */ private void insertDataBase(Result result) { for (String profit : result.getProfits()) { Data fileData = new Data(); fileData.setContent(profit); fileData.setType("價值"); fileData.setTeam(result.getProfits().indexOf(profit)+1); fileData.setFile(result.getFileName()); dataService.save(fileData); } for (String weight : result.getWeights()) { Data fileData = new Data(); fileData.setContent(weight); fileData.setType("重量"); fileData.setTeam(result.getWeights().indexOf(weight)+1); fileData.setFile(result.getFileName()); dataService.save(fileData); } for (String volume : result.getVolumes()) { Capacity volume1 = new Capacity(); volume1.setSize(Integer.parseInt(volume)); volume1.setTeam(result.getVolumes().indexOf(volume)+1); volume1.setFile(result.getFileName()); capacityService.save(volume1); } } }
-
ScatterController(散點圖繪製)
package com.chm.bag_system.controller; @Controller public class ScatterController { @Resource DataService dataService; // 存放當前組價值的整型列表 private static ArrayList<Integer> profitList=new ArrayList<>(); // 存放當前組重量的整型列表 private static ArrayList<Integer> weightList=new ArrayList<>(); // 存放當前散點圖資料的列表 private static ArrayList<ArrayList<Integer>> scatterData=new ArrayList<ArrayList<Integer>>(); @PostMapping("/scatter/query") public String queryData(Scatter scatter, Model model){ if(scatter.getFileName().equals("")||scatter.getGroup().equals("")){ model.addAttribute("data",null); return "scatter"; } profitList.clear(); weightList.clear(); scatterData.clear(); QueryWrapper<Data> wrapper = new QueryWrapper<Data>(); wrapper.eq("file",scatter.getFileName()); wrapper.eq("team",scatter.getGroup()); List<Data> list = dataService.list(wrapper); HandleData handleData = new HandleData(); for (Data data : list) { if (data.getType().equals("價值")) { handleData.splitDataIntoInteger(profitList,data.getContent()); } if (data.getType().equals("重量")) { handleData.splitDataIntoInteger(weightList,data.getContent()); } } for (int i = 0; i < weightList.size(); i++) { ArrayList<Integer> integers = new ArrayList<>(); integers.add(weightList.get(i)); integers.add(profitList.get(i)); scatterData.add(integers); } model.addAttribute("data",scatterData); return "scatter"; } }
-
往資料庫裡面儲存資料
- 對選定的某個資料夾中的某一組繪製散點圖
- 選擇將要排序的具體組數
- 對某一組組資料項集按第三項價效比進行排序
- 用回溯演算法求最優解
- 用動態規劃演算法求最優解
- 資料庫中按組數儲存的資料
- 資料庫中每一項資料的價值與重量
- 有關遺傳演算法的使用
遺傳演算法(Genetic>遺傳演算法(Genetic Algorithm,GA)是進化計算的一部分,是模擬達爾文的遺傳選擇和自然淘汰的生物進化過程的計算模型,是一種通過模擬自然進化過程搜尋最優解的方法。該演算法簡單、通用,魯棒性強,適於並行處理。
遺傳演算法基本流程:- 通過隨機方式產生若干由確定長度(長度與待求解問題的精度有關)編碼的初始群體;
- 通過適應度函式對每個個體進行評價,選擇適應度值高的個體參與遺傳操作,適應度低的個體被淘汰;
- 經遺傳操作(複製、交叉、變異)的個體集合形成新一代種群,直到滿足停止準則(進化代數GEN>=?);
- 將後代中變現最好的個體作為遺傳演算法的執行結果。
其中,GEN是當前代數;M是種群規模,i代表種群數量。
5.描述結對的過程,提供兩人在討論、細化和程式設計時的結對照片(非擺拍)。
6.本次結對實驗PSP
PSP3.1 | 任務內容 | 計劃共完成需要的時間(min) | 實際完成需要的時間(min) |
---|---|---|---|
Planning | 計劃 | 6 | 8 |
- Estimate | - 估計這個任務需要多少時間,並規劃大致工作步驟 | 6 | 8 |
Development | 開發 | 510 | 600 |
- Analysis | - 需求分析(包括學習新技術) | 10 | 6 |
- Design Spec | - 生產設計文件 | 10 | 8 |
- Design Review | - 設計複審(和同事稽核設計文件) | 5 | 6 |
- Coding Standard | - 程式碼規範(為目前的開發指定合適的規範) | 10 | 20 |
- Design | - 具體設計 | 25 | 30 |
- Coding | - 具體編碼 | 500 | 600 |
- Code Review | - 程式碼複審 | 30 | 30 |
- Test | - 測試(自我測試,修改程式碼,提交修改) | 120 | 200 |
Reporting | 報告 | 60 | 62 |
- Test Report | - 測試報告 | 30 | 25 |
- Size Measurement | - 計算工作量 | 10 | 13 |
- Postmortem & Process Improvement Plan | - 事後總結,並提出過程改進計劃 | 20 | 24 |
7.小結感受:兩人合作真的能夠帶來1+1>2的效果嗎?通過這次結對合作,請談談你的感受和體會