項目 | 內容 |
---|---|
課程班級博客鏈接 | https://edu.cnblogs.com/campus/xbsf/nwnu2020SE |
作業要求鏈接 | https://www.cnblogs.com/nwnu-daizh/p/12521474.html |
我的課程學習目標 | (1)體驗軟件項目開發中的兩人合作,練習結對編程。(2)掌握Github協作開發程序的操作方法。 |
這個作業作業在哪些方面幫助我實現學習目標 | 兩人合作練習結對編程、掌握Github協作開發程序的操作方法以及運用學習工具 |
結對方學號-姓名 | 201771010136-楊野 |
結對方本次博客作業鏈接 | https://www.cnblogs.com/2017xinghui/p/12554158.html |
本項目Github的倉庫鏈接地址 | https://github.com/yy202901582/DieaseSubmitSystem |
任務1:閱讀《現代軟件工程—構建之法》第3-4章內容,理解並掌握代碼風格規范、代碼設計規范、代碼復審、結對編程概念;
已閱讀完,相關概念如下:
1、代碼風格規范
(1)代碼風格的原則是:簡明,易讀,無二義性。
(2)縮進:4個空格,不用Tab鍵是因為在不同的情況下顯示的長度可能不一樣。
(3)行寬:限定為100字符。
(4)括號:在復雜的條件表達式中,可以清晰地表示邏輯優先級。
(5)斷行與空白的{}行:斷行在程序調試時可以清晰的表達變量的變化情況,{}來判斷程序的結構。
(6)分行:不要把多個變量定義在一行上。
(7)命名:
①在變量名中不要提到類型或其他語法方面的描述。
②避免過多的描述。
③如果信息可以從上下文中得到,那么此類信息就不必寫在變量名中。
④避免可要可不要的修飾詞。
(8)下划線:用來分割變量名字中的作用域標注和變量的語義。
(9)大小寫:
①所有類型/類/函數名都用Pascal形式(所有單詞第一個字母都大寫)。
②所有變量都用Camel形式(第一個單詞全部小寫,隨后單詞用Pascal形式)。
③類/類型/變量:名詞或組合名詞。
④函數則用動詞或動賓組合詞來表示。
(10)注釋:注釋是為了解釋程序做什么(What),為什么這樣做(Why)以及要特別注意的地方。
2、代碼設計規范
(1)概念:代碼設計規范不光是程序書寫的格式問題,而且涉及到程序設計、模塊之間的關系、設計模式等方方面面,又有不少內容與具體程序設計語言息息相關(如C,C++,JAVA,C#),但是也有通用的原則。
(2)函數:原則:只做一件事,並且要做好。
(3)goto:函數最好有單一出口,為了達到這一目的,可以使用goto。
(4)錯誤處理:
①參數處理:在Debug版本中,所有的參數都要驗證其正確性,在正式版本中,對從外部(用戶或別的模塊)傳遞過來的參數,要驗證其正確性。
②斷言:驗證正確性就要用斷言。
(5)如何處理C++中的類
①類:
a.使用類來封裝面向對象的概念和多態。
b.避免傳遞類型實體的值,應該用指針傳遞。換句話說,對於簡單的數據類型,沒有必要要用類來實現。
c.對於有顯示的構造和析構的類,不要建立全局的實體,因為不知道它們在何時創建和消除。
d.僅在有必要時,才是用“類”。
②class vs.struct:如果只是數據的封裝,用struct即可。
③公共/保護/私有成員:按照這樣的次序來說明類中的成員。
④數據成員:
a.數據類型的成員用m_name說明。
b.不要使用公共的數據成員,要用inline訪問函數,這樣可兼顧封裝和效率。
⑤虛函數
a.使用虛函數來實現多態。
b.僅在很有必要時,才使用虛函數。
c.如果一個類型要實現多態,在基類中的析構函數應該是虛函數。
⑥構造函數
a.不要在構造函數中做復雜的操作,簡單初始化所有成員即可。
b.構造函數不應該返回錯誤。
⑦析構函數
a.把所有的清理工作都放在析構函數中。如果有些析構函數在之前就釋放了,要重置這些成員為0或NULL。
b.析構函數也不應該出錯。
⑧new和delete
a.如果可能,實現自己的new/delete,這樣可以方便地加上自己的跟蹤和管理機制。自己的new/delete可以包裝系統提供的new/delete。
b.檢查new的返回值。new不一定都成功。
c.釋放指針時不用檢查NULL。
⑨運算符
a.在理想情況下,我們定義的類不需要自定義操作符。確有必要時,才會自定義操作符。
b.運算符不要做標准語義之外的任何動作。
c.運算符的實現必須非常有效率,如果有復雜的操作,應定義一個單獨的函數。
d.當拿不定注意時,用成員函數,不要用運算符。
⑩異常
a.不要用異常作為邏輯控制來處理程序的主要流程。
b.當使用異常時,要注意在什么地方清理數據。
c.異常不能跨過DLL或進程的邊界來傳遞消息,所以異常不是萬能的。
⑪類型繼承
a.僅在有必要時,才使用類型繼承。
b.用const標注只讀的參數。
c.用const標注不改變數據的函數。
3、代碼復審:看代碼是否在代碼規范的框架內正確的解決了問題。代碼復審的形式包括:自我復審、同伴復審、團隊復審。
4、結對編程:結對編程中有兩個角色:領航員和駕駛員。在個人編寫的過程中,很多人喜歡根據個人喜好來規定代碼規范,而且存在的bug自己難以發現,因此,在結對編程時,我們可以互換角色,在開始寫代碼之前,規定兩個人都認可的一套代碼規范,並且不間斷地進行復審,以減少軟件中存在的問題,修復bug,提高軟件質量。
任務2:兩兩自由結對,對結對方《實驗二 軟件工程個人項目》的項目成果進行評價,具體要求如下:
對項目博文作業進行閱讀並進行評論,評論要點包括:博文結構、博文內容、博文結構與PSP中“任務內容”列的關系、PSP中“計划共完成需要的時間”與“實際完成需要的時間”兩列數據的差異化分析與原因探究,將以上評論內容發布到博客評論區。
結對伙伴:
結對方博客鏈接
https://www.cnblogs.com/2017xinghui/p/12452438.html
結對方Github項目倉庫鏈接
https://github.com/yy202901582/DieaseSubmitSystem
克隆結對方項目源碼到本地機器,閱讀並測試運行代碼,參照《現代軟件工程—構建之法》4.4.3節核查表復審同伴項目代碼並記錄。
1、概要部分
(1)代碼符合需求和規格說明么?
答:部分符合需求與規格。
(2)代碼設計是否有周全考慮?
答:基本周全,改動的地方很少。
(3)代碼可讀性如何?
答:可讀性好。
(4)代碼容易維護么?
答:較易。
(5)代碼的每一行都執行並檢查過了嗎?
答:是的,檢查過。
2、設計規范部分
(1)設計是否遵從已知的設計模式或項目中常用的模式?
答:部分遵從。
(2)有沒有硬編碼或字符串/數字等存在?
答:有一部分。
(3)代碼有沒有依賴於某一平台,是否會影響將來的移植(如Win32到Win64)
答:沒有依賴,不會影響移植。
(4)開發者新寫的代碼能否用已有的Library/SDK/Framework中的功能實現?在本項目中是否存在類似的功能可以調用而不用全部重新實現?
答:可以實現,存在,調用了一部分。
(5)有沒有無用的代碼可以清除?(很多人想保留盡可能多的代碼,因為以后可能會用上,這樣導致程序文件中有很多注釋掉的代碼,這些代碼都可以刪除,因為源代碼控制已經保存了原來的老代碼。)
答:有,基本清除完畢。
3、代碼規范部分
(1)修改的部分符合代碼標准和風格么(詳細條文略)?
答:大部分代碼符合,不符合的已修改。
4、具體代碼部分
(1)有沒有對錯誤進行處理?對於調用的外部函數,是否檢查了返回值或處理了異常?
答:對錯誤進行了處理,檢查了返回值,並處理了異常。
(2)參數傳遞有無錯誤,字符串的長度是字節的長度還是字符(可能是單/雙字節)的長度,是以0開始計數還是以1開始計數?
答:無錯誤,字符串的長度是字節的長度,是以0開始計數。
(3)邊界條件是如何處理的?Switch語句的Default是如何處理的?循環有沒有可能出現死循環?
答:結對伙伴未用到Switch語句,沒有出現死循環,循環語句正確。
(4)有沒有使用斷言(Assert)來保證我們認為不變的條件真的滿足?
答:沒有使用。
(5)對資源的利用,是在哪里申請,在哪里釋放的?有沒有可能導致資源泄露(內存、文件、各種GUI資源、數據庫訪問的連接,等等)?有沒有可能優化?
答:是隨機生成的,不會導致資源泄漏,有可能優化。
(6)數據結構中是否有無用的元素?
答:沒有。
5、效能
(1)代碼的效能(Performance)如何?最壞的情況是怎樣的?
答:代碼正確,程序運行正常。
(2)代碼中,特別是循環中是否有明顯可優化的部分(C++中反復創建類,C#中 string 的操作是否能用StringBuilder 來優化)?
答:沒有可優化地方,比較優化。
(3)對於系統和網絡調用是否會超時?如何處理?
答:不會超時。
6、可讀性
代碼可讀性如何?有沒有足夠的注釋?
答:代碼不是很復雜,有足夠的注釋。
7、可測試性
代碼是否需要更新或創建新的單元測試?還可以有針對特定領域開發(如數據庫、網頁、多線程等)的核查表。
答:不需要。
結對方的項目倉庫原本Fork、Clone、Push、Pull request、Merge pull request日志數據如下。
使用git命令clone結對方倉庫到本地便於查看修改
對代碼的一些更改操作
作出回應,並關閉
任務3:采用兩人結對編程方式,結合我校師生疫情每日上報系統使用體驗,設計開發一款符合我校疫情防控工作需求的信息系統,使之具有以下功能:
(1)可采集全校各類師生員工疫情信息;
(2)各二級部門疫情防控工作負責人可查看本部門人員疫情匯總,並提供高級查詢功能進行多屬性組合查詢和可視化統計功能;
(3)學校防控辦指定負責人登錄《西北師范大學疫情防控信息統計》子系統,可瀏覽所有人員填報匯總數據清單,利用【高級查詢】可進行數據組合篩選,系統以圖形化方式展示各學院已填報和未填報學生統計情況和關鍵疫情數據統計情況,可【導出】查詢列表的EXCEL文件;
(4)人機交互界面要求GUI界面(WEB頁面、APP頁面都可);
(5)附加分功能:定時填報提醒
1、需求分析陳述。
就(1)而言,要求能采集全校學生/教職工的疫情信息。我們將用戶填寫的數據保存在txt文件中,作為數據便於后續使用。
就(2)而言,要求各二級部門疫情防控工作負責人可查看本部門人員疫情匯總,並能夠進行多屬性組合查詢和可視化統計功能。我們做了學院查詢,姓名查詢以及地區查詢和是否感染查詢等多種組合查詢,並用餅狀圖直觀地表示查詢到結果的信息。
就(3)而言,要求學校負責人登錄子系統,可瀏覽所有人員填報匯總數據清單,可進行數據組合篩選查詢,以圖形化方式展示各學院已填報和未填報學生統計情況和關鍵疫情數據統計情況,可【導出】查詢列表的EXCEL文件。我們將用戶填寫的信息保存在txt文件中,方便查閱。
就(4)而言,我們采用了GUI界面,並在之前討論了界面的大致樣子,並繪圖,如下圖所示:
就(5)而言,我們采用了彈出框的形式來提示用戶,詢問用戶是否填寫,若用戶填寫,則不再提醒。否則每隔10分鍾提醒一次
2、.軟件設計說明。
(1)軟件界面設計
包括搜索菜單,圖標功能,提醒功能和填報功能,在界面設計上,采用簡單明了,易於操作的原則,凸顯出了要求功能。
(2)工程項目圖:
其中writetxt生成txt文件。
(3)主要的功能:
1)師生可登錄系統進行疫情信息的填報;
2)二級防疫部門人員可進行疫情信息的填報;
3)二級防疫部門負責人可可根據姓名進行模糊查詢,根據姓名、學院、感染情況進行准確查詢,可查看感染情況的統計數據(用柱狀圖來表示)。
3、軟件實現及核心功能代碼展示:軟件包括哪些類,這些類分別負責什么功能,他們之間的關系怎樣?類內有哪些重要的方法,關鍵的方法是否需要畫出流程圖?
工程結構說明:
。chart:存放生成的圖表
。img:存放系統圖標
。src:存放具體代碼
。Text.txt:存放數據
src說明:
。Frame.java
繪制界面內容,與事件的監聽處理
。MenuTnput.java
其中有initializeGragh方法,主要用於初始化內容,包括數據計數和生成graph
。ProduceChart.java
生成數據統計圖,借用了插件JFreeChart Java圖表庫。里面有ProduceChart,ProduceChartC2,生成柱狀圖和扇形圖的方法,生成的在chart文件中。
。Search.java
增加方法BuildGragh(),生成圖表的包裝函數,一次執行完生成圖表。
。SthFunction.java
其中有采集數據的方法:Insert_Message,會在action事件中被調用
。listMain.java
主函數,運行入口,其中實例化了MenuTnput,ReadFile進行初始化工作,再通過frame生成swing界面
。writetxt.java
生成Text.txt中數據信息
4、程序運行:程序運行時每個功能界面截圖。擴展功能實現可得附加分5分。
二級防疫部門負責人可輸入各自學院篩選查看:
查詢某個人的狀況:
所在地查詢:
是否感染查詢:
圖標可視化,可以根據出現的字段生成相應的圖表:
學院,餅狀圖和柱狀圖顯示:
師生比:
所在地:
感染情況:
填報信息:
定時提醒
數據文件展示
5、核心功能代碼展示
import java.awt.Font;
import java.io.File;
import java.io.IOException;
import org.jfree.chart.*;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DatasetUtilities;
import org.jfree.data.general.DefaultPieDataset;
/**
* Created by IntelliJ IDEA.
* User: YANG
*/
public class ProduceChart {
/**
* 生成扇形統計圖
*
*/
public void ProduceChartC(String[][] GraphList,int[][] ListCount){
String[] list = new String[]{"college","place","ID","timeM","timeD","situation"};
Font font = new Font("宋體", Font.BOLD, 20);
try {
for (int j = 0; j < 6; j++) {
DefaultPieDataset dataset = new DefaultPieDataset();
for (int i = 0; i < GraphList[0].length; i++) {
if (GraphList[j][i]!=null){
double count = ListCount[j][i];
String Gcount = GraphList[j][i]+ListCount[j][i];
dataset.setValue(Gcount,count);
}
}
//創建圖
JFreeChart chart = ChartFactory.createPieChart(
list[j], // chart title
dataset, // data
true, // include legend
true,
false);
int width = 1000;
int height = 800;
//設置字體
chart.getTitle().setFont(font);
chart.getLegend().setItemFont(font);
PiePlot piePlot = (PiePlot) chart.getPlot();
piePlot.setLabelFont(font);
chart.getLegend().setItemFont(font);
// 改樣式
chart.setTextAntiAlias(true);
chart.setBackgroundPaint(ChartColor.WHITE);
piePlot.setBackgroundPaint(ChartColor.WHITE);
// 關閉片區外廓
piePlot.setSectionOutlinesVisible(false);
// 生成jpeg
String pathname = "chart//"+list[j]+".jpeg";
File pieChart = new File(pathname);
ChartUtilities.saveChartAsJPEG( pieChart , chart , width , height );
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 生成柱統計圖
*
*/
public void ProduceChartC2(String[][] GraphList,int[][] ListCount){
String[] list = new String[]{"college","place","ID","timeM","timeD","situation"};
Font font = new Font("宋體", Font.BOLD, 20);
try {
for (int j = 0; j < 6; j++) {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
for (int i = 0; i < GraphList[0].length; i++) {
if (GraphList[j][i]!=null){
double count = ListCount[j][i];
String str = GraphList[j][i]+ListCount[j][i];
dataset.addValue(count,str,list[j]);
}
}
//創建圖
JFreeChart chart = ChartFactory.createBarChart(
list[j], //標題
"x", //x軸名稱
"y", //y軸名稱
dataset,//數據集
PlotOrientation.VERTICAL,//使用垂直柱狀圖
true,//是否使用legend
false,//是否使用tooltip
false); //是否使用url
int width = 1000;
int height = 800;
//設置字體
chart.getTitle().setFont(font);
chart.getLegend().setItemFont(font);
chart.getLegend().setItemFont(font);
// 改樣式
chart.setTextAntiAlias(false);
chart.setBackgroundPaint(ChartColor.WHITE);
// 生成jpeg
String pathname = "chart//"+list[j]+"1.jpeg";
File pieChart = new File(pathname);
ChartUtilities.saveChartAsJPEG( pieChart , chart , width , height );
// 生成png
String pathname2 = "chart//"+list[j]+"1.png";
File pieChart2 = new File(pathname2);
ChartUtilities.saveChartAsPNG( pieChart2, chart , width , height );
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
6、描述結對的過程,提供兩人在討論、細化和編程時的微信或QQ截圖(截圖要完整,能夠顯示結對雙方姓名)
7、提供此次結對作業的PSP
PSP | 任務內容 | 計划共完成需要的時間(min) | 實際完成需要的時間(min) |
---|---|---|---|
Estimate | 計划 | 30 | 30 |
Estimate | 估計這個任務需要多少時間,並規划大致工作步驟 | 30 | 30 |
Development | 開發 | 2585 | 1705 |
Analysis | 需求分析 (包括學習新技術) | 20 | 20 |
Design Spec | 生成設計文檔 | 30 | 30 |
Design Review | 設計復審(和同事審核設計文檔) | 10 | 10 |
Coding Standard | 代碼規范 (為目前的開發制定合適的規范) | 5 | 5 |
Design | 具體設計 | 900 | 500 |
Coding | 具體編碼 | 1440 | 960 |
Code Review | 代碼復審 | 180 | 180 |
Test | 測試(自我測試,修改代碼,提交修改) | 120 | 120 |
Reporting | 報告 | 30 | 30 |
Test Report | 測試報告 | 10 | 10 |
Size Measurement | 計算工作量 | 10 | 10 |
Postmortem & Process Improvement Plan | 事后總結 ,並提出過程改進計划 | 30 | 30 |
8、小結感受:兩人合作真的能夠帶來1+1>2的效果嗎?通過這次結對合作,請談談你的感受和體會。
通過本次合作我覺得兩個人合作做項目比一個人獨自做效果要好很多。在項目完成方面,結對編程會帶來1+1>2的效果,在編寫程序遇到問題時,可以及時的向同伴求助,特別感謝我這次的結對編程伙伴楊野同學。我在寫程序時遇到好幾個問題都是他幫我解決的。通過這次合作我真真體會到了結對編程的樂趣和互相督促的進步。結對編程還可以找出自己代碼的不足之處,以及版本的兼容問題。比如在我的的電腦上字體顯示正常,結果到編程伙伴的電腦上出現亂碼,通過這種相互測試,可以更好的優化自己的程序。再次特別感謝楊野同學。