1.代碼倉庫地址:https://git.coding.net/mafx8859/ArithWeb.git
遠程服務器測試路徑(直接點擊測試):http://47.93.197.5:8080/ArithmeticWeb1.0/
2.PSP表格:
PSP | 任務內容 | 計划共完成需要的時間 | 實際完成需要的時間 |
Planning | 計划 | 一周 | 一周 |
Estimate | 估計這個任務需要多少時間,並規划大致工作步驟 | 一周 | 一周 |
Development | 開發 | 4天 | 4天 |
Analysis | 需求分析 (包括學習新技術) | 3.5(h) | 3(h) |
Design Spec | 生成設計文檔 | 2(h) | 2(h) |
Design Review | 設計復審 (和同事審核設計文檔) | 1(h) | 1(h) |
Coding Standard | 代碼規范 (為目前的開發制定合適的規范) | 1(h) | 40min |
Design | 具體設計 | 1h | 35min |
Coding | 具體編碼 | 2天 | 2天 |
Code Review | 代碼復審 | 1(h) | 1(h) |
Test | 測試(自我測試,修改代碼,提交修改) | 2(h) | 2(h) |
Reporting | 報告 | 2h | 1.5h |
Test Report | 測試報告 | 1.5h | 1h |
Size Measurement | 計算工作量 | 30min | 30min |
Postmortem & Process Improvement Plan | 事后總結, 並提出過程改進計划 | 30min | 20min |
3.
(1)Information Hiding:在出題模塊和計算模塊的設計過程中尤其體現出了Information Hiding,在出題模塊中對於訪問者來說,存儲題目的容器list、運算數的上下界、存儲運算符的數組等都是不可隨意訪問修改的,運用java的private進行將其私有化,向外提供訪問的方法即可。在計算模塊,計算運用到的棧、判斷運算符優先級的map等均是向外隱藏的,同樣運用private關鍵字將其向外隱藏。如下:
private Stack<String> s1=new Stack<String>(); private Stack<Integer> s2=new Stack<Integer>(); private Map<String,Integer> map=new HashMap<String,Integer>(); private int maxDigitNum=6; private int minDigitNum=4; private int[] digitArray; private String[] operatorArray; private List<String> list=new ArrayList<String>();
同時在web頁面程序開發中,運用到的實體類中的屬性均運用private修飾,向外提供geter和seter方法,增強了信息的保護。
(2)Interface Design:運用接口編程,對出題模塊和計算模塊設計接口增強了程序的可擴展性,可維護性。
(3)Loose Coupling:在程序設計中將出題模塊、計算模塊、運算符判斷模塊等均封裝到不同的方法中,降低程序的耦合度。
4.計算模塊接口的設計與實現過程:
在計算模塊,由於計算模塊中所設計到的操作有運算符的優先級判斷以及堆棧,因此放在同一個類中足以實現,包含的函數有運算符優先級判斷函數、運算數和運算符的判斷函數、中綴表達式轉后綴表達式函數等。在計算模塊中算法的關鍵是中綴表達式轉后追表達式和計算結果時的堆棧算法,其中中綴表達式轉后綴表達式算思路大致為:從左到右遍歷中綴表達式的每個數字和符號,若是數字就輸出,即成為后綴表達式的一部分;若是符號,則判斷其與棧頂符號的優先級,是右括號或優先級不高於棧頂符號則棧頂元素一次出棧並輸出,並將當前符號進棧,一直到最終輸出后綴表達式為止,計算是的堆棧算法思路大致為:從左到右遍歷后綴表達式的每個數字和字符,遇到是數字就進棧,遇到是符號,就將處於棧頂兩個數字出棧進行運算,運算結果進棧,一直到最終獲得結果。
5.計算模塊接口部分的性能改進:
在性能改進中大致時間表如下:
項目 | 用時 |
使用JProfiler工具分析調試 | 2(h) |
查找影響性能的程序模塊 | 1(h) |
性能改進 | 2(h) |
改進調試思路:首先進行內存資源監控,當程序剛進入運行時,對當前狀態進行Mark,觀察不同類的內存變化,一段時間后按下F4進行資源回收,此時發現在自己的向本地文件寫入模塊中有資源無法回收,經過進一步調試發現是對IO資源沒有close,進而調用close()對IO資源進行關閉。同時在資源監測過程中發現出題模塊對資源的占有較多,以及耗時較大,這里所改進的思路是將原來通過循環產生合法的運算式的方式改進成一次性輸出合法運算式。性能分析圖如下:
Mark:
再次回收:
內存分析:
6.計算模塊部分單元測試展示:
該項目中的部分單元測試代碼如下:
import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Test;
public class getResultTest {
DealAtith da=new DealAtith();
@Test
public void test1() {
assertEquals(17,da.getResult("6+3-2+10", true));
assertEquals(17,da.getResult("6+3-2+10", false));
}
@Test
public void test2() {
assertEquals(18,da.getResult("(6+4)÷2+10", true));
assertEquals(18,da.getResult("6+4÷2+10", false));
}
@Test
public void test3() {
assertEquals(260,da.getResult("(6+4)÷2*50+10", true));
assertEquals(260,da.getResult("(6+4)÷2*50+10", false));
}
@Test
public void test4() {
da.creatAtith(10, 4, 1, 100, true, true);
da.creatAtith(10, 4, 1, 100, false, false);
da.getBl("9+6*(2+10)");
da.getBl("9+6*(2+10)-(10÷2-2)");
try {
da.printOperForm();
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("打印函數拋出異常");
}
}
}
覆蓋率截圖:
在計算模塊中設計到對個條件的判斷分支,其中分支主要存在於,對運算符優先級的判斷、對括號的判斷等,同樣在由中綴綴表達式獲取后綴表達式的方法中同樣存在以上分支的判斷,因此為了增加測試的覆蓋率,首先從簡單的加減法運算數據入手,接着再加入乘除法,最后引入帶有括號的運算數據。這樣逐漸提高了測試的覆蓋率。
7.計算模塊部分異常處理說明
在計算模塊主要涉及到異常處理問題有參數合法性和運算結果的正確性,其中參數合法性包括對生成運算式個數的參數的合法性判斷以及異常處理、運算符個數參數合法性判斷以及異常處理、運算數范圍參數合法性判斷以及異常處理等
(1)對-m、-n參數的整體為空值是的測試,測試其為空時,程序對異常處理的友好性。
@Test public void testcommand1() { String[] args={}; Command.main(args); }
(2)對運算數范圍參數-m的合法性異常處理的JUNit測試代碼以及參數構造思路為:
①選擇合理的參數范圍測試其在參數合理的條件下程序的正確性:
@Test public void testcommand3() { String[] args={"-m","1","100","-n","10"}; Command.main(args); }
②構造不合理參數進行測試,測試其在出現異常時友好的異常處理功能:
@Test public void testcommand3() { String[] args={"-m","1","40","-n","10"}; Command.main(args); }
(3)對生成運算式個數參數-n的合法性異常處理的JUNit測試代碼以及參數構造思路為:
①構造用戶傳入的-n參數是合法的,用於測試在參數合法的條件下程序的正確性。
@Test public void testcommand4() { String[] args={"-m","1","40","-n","10"}; Command.main(args); }
②構造不合理的參數用於測試當參數不合法是,程序對異常處理的友好性。
@Test public void testcommand3() { String[] args={"-m","1","100","-n","20000"}; Command.main(args); }
(3)對計算模塊運算結果的測試,其參數構造思路是從簡單的運算式開始入手,逐漸構造叫復雜的運算式,測試計算程序的運行結果的正確性:
DealAtith da=new DealAtith(); @Test public void test1() { assertEquals(17,da.getResult("6+3-2+10", true)); assertEquals(17,da.getResult("6+3-2+10", false)); } @Test public void test2() { assertEquals(18,da.getResult("(6+4)÷2+10", true)); assertEquals(18,da.getResult("6+4÷2+10", false)); } @Test public void test3() { assertEquals(410,da.getResult("(6+4)÷2*50+10", true)); assertEquals(410,da.getResult("(6+4)÷2*50+10", false)); } @Test public void test4() { da.creatAtith(10, 4, 1, 100, true, true); da.creatAtith(10, 4, 1, 100, false, false); da.getBl("9+6*(2+10)"); da.getBl("9+6*(2+10)-(10÷2-2)"); try { da.printOperForm(); } catch (IOException e) {
System.out.println("打印函數拋出異常"); } }
8.界面模塊的詳細設計過程
在界面設計過程中花費較多時間,為了增強界面的交互友好性,首先我們以草圖的形式設計出了界面的大致布局與初級的樣式,同時為了增強兩人合作的工作效率初步擬定運用前后台分離的方式進行小系統的開發,前台運用ajax實現數據填充,后台給前台返回json格式的數據。在初步的界面布局設計號以后着手於代碼的編寫,其中初期重要頁面部分代碼如下:
<button onclick=timedCount()>開始答題</button> <button onclick=getGradpm()>成績排名</button>
<form action="AtithControlle?flag=getGrad" method="post">
<input type="hidden" name="filename" id="filename_id"/>
<input type="hidden" name="userid" id="user_id"/>
<table id="atithList">
<tr><th>題目</th><th>填寫答案</th></tr>
</table>
<input type="submit" value="提交答案"/>計時:<input type="text" name="time" id="time_id"/>
</form>
<div style="width:500px;background-color:yellow"> 本套試題成績排名(點擊成績排名可獲取): <table id="grad_id">
</table>
</div>
<script type="text/javascript"> $(function(){ $.ajax({ url:"AtithControlle",/*請求的地址*/ data:"flag=makeques&fileName="+"<%=request.getParameter("filename")%>",/*數據攜帶*/ type:"get",/*請求的方式*/ dataType:"json", success:function(result){/*請求后得到的結果*/ console.log(result); buildList(result); } }); }); function buildList(result){ $.each(result,function(index,item){ var i=0; if(i==0){ document.getElementById("filename_id").value=item.filename; document.getElementById("user_id").value=item.zcm; } var td1="<td>"+item.atith+"</td>"; var td2="<td><input type='hidden' name='userSolve'/><input type='hidden' name='rightSolve' value='"+item.result+"'/></td>";
$("<tr></tr>").append(td1).append(td2) .appendTo("#atithList"); }); } </script>
</body>
初期的界面實現了大部分交互功能,但是在用戶的交互友好性上很欠缺,於是我們有進一步對界面進行的美化,添加了css樣式和js動態效果,同時也進一步完善了ajax請求與數據處理程序,同時對功能做了進一步實現,部分代碼如下:
<body>
<form method="post" name="chuti" action="AtithControlle?flag=chuti" onsubmit="return checkform()">
<div class="detail">
<label>
<span class="form-group tishi" style="letter-spacing: 4px;">題 目 數 量</span>
<input type="text" name="count" id="count" placeholder="必須為1-10000整數" required />
</label>
<b id="countb"></b>
</div>
<div class="detail">
<label>
<span class="form-group tishi" style="letter-spacing: 2px;">算式數值范圍</span>
<input type="text" name="rangeLow" id="rangeLow" required/>
<span>——</span>
<input type="text" name="rangeHigh" id="rangeHigh" required/>
</label>
<b id="rangebL"></b>
<b id="rangebH"></b>
</div>
<div id="js-example-change-value" class="detail">
<span class="tishi">運算符的最大數目</span>
<input type="range" min="1" max="10" value="1" data-rangeslider name="opeMax">
<output></output>
</div>
<div class="detail selediv">
<span class="tishi" style="letter-spacing: 1px;">是否包含乘除法</span>
<select name="if_multiply" >
<option value="no">否</option>
<option value="yes">是</option>
</select>
</div>
<div class="detail selediv">
<span class="tishi" style="letter-spacing:1px;">是否包含括號</span>
<select name="if_bracket">
<option value="no">否</option>
<option value="yes">是</option>
</select>
</div>
<div class="detail ">
<div class="detailsub">
<div class="radius"></div>
<input type="submit" value="開始出題" class="submit" name="submit" />
</div>
</div>
</form>
<script src="js/jquery.min.js"></script>
<script src="js/rangeslider.min.js"></script>
<script type="text/javascript" src="js/main.js"></script>
<script type="text/javascript"> $(function() { var $document = $(document); var selector = '[data-rangeslider]'; var $inputRange = $(selector);
function valueOutput(element) { var value = element.value; var output = element.parentNode.getElementsByTagName('output')[0]; output.innerHTML = value; }
for (var i = $inputRange.length - 1; i >= 0; i--) { valueOutput($inputRange[i]); };
$document.on('input', selector, function(e) { valueOutput(e.target); });
$inputRange.rangeslider({ polyfill: false });
$document.on('click', '#js-example-change-value button', function(e) { var $inputRange = $('input[type="range"]', e.target.parentNode); var value = $('input[type="number"]', e.target.parentNode)[0].value; $inputRange .val(value) .change(); }); }); </script>
</body>
通過較長時間的設計與開發,開發出了交互較友好,功能全面的圖形界面。
注:由於界面程序含有大量css和HTML等程序,不易在博客展示,詳細代碼請參考代碼倉庫。
9.界面模塊與計算模塊的對接
在界面與計算模塊的鏈接中,前台向后台主要發送ajax請求,后台由Servlet接受前台請求並且向前台返回json格式的數據,功能展示如下:
初始頁面,可點擊選擇不同模式:
出題界面:
出題成功以后,支持題目下載:
做題界面,用戶可以自己上傳題目,也可以選擇已經上傳的題目進行練習:
在用戶做題過程中可顯示計時:
10.結對的過程
11.結對編程優缺點都是存在着的,首先優點在於:
(1)程序員互相幫助,互相教對方,可能得到能力上的互補。
(2)可以讓編程環境有效地貫徹Design。
(3)增強代碼和產品質量,並有效的減少BUG。
(4)降低學習成本。一邊編程,一邊共享知識和經驗,有效地在實踐中進行學習。
(5)在編程中,相互討論,可能更快更有效地解決問題。
缺點在於:
(1)對於有不同習慣的編程人員,可以在起工作會產生麻煩,甚至矛盾。
(2)有時候,程序員們會對一個問題各執己見(代碼風格可能會是引發技術人員口水戰的地方),爭吵不休,反而產生重大內耗。
(3)兩個人在一起工作可能會出現工作精力不能集中的情況。程序員可能會交談一些與工作無關的事情,反而分散注意力,導致效率比單人更為低下。
(4)結對編程可能讓程序員們相互學習得更快。有些時候,學習對方的長處,可能會和程序員們在起滋生不良氣氛一樣快。比如,合伙應付工作,敷衍項目。
(5)面對新手,有經驗的老手可能會覺得非常的煩躁。不合適的溝通會導到團隊的不和諧。
(6)新手在面對有經驗的老手時會顯得非常的緊張和不安,甚至出現害怕焦慮的的精神狀態,從而總是出現低級錯誤,而老手站在他們后面不停地指責他們導致他們更加緊張,出現惡性循環。最終導致項目進展效率低下,並且團隊貌合神離。
(7)有經驗的人更喜歡單兵作戰,找個人來站在他背后看着他可能會讓他感到非常的不爽,最終導致編程時受到情緒影響,反而出現反作用。
團隊成員優缺點分析:
(1)馬福孝
優點:①擅長后台程序開發 ②擅長系統設計 ③有較強好的的解決程序bug能力
缺點:不太擅長交流,對部分前端技術不夠熟悉
(2)吳建瑜
優點:①擅長前端頁面的設計以及動態效果的實現②擅長交流與分析③對實際問題有較強的分析解決能力
缺點:對后端部分技術不夠熟悉
12.實際花費時間記錄: