首页 > 技术文章 > 软件工程导论结对项目

chenyyxx 2018-04-10 07:18 原文

小学四则运算结对项目

.项目地址

https://git.coding.net/chenxin1998/Arithmetic.git

结对成员:马乐平,地址:https://git.coding.net/maleping/Amerithic.git

.预计完成项目时间(PSP

PSP2.1

任务内容

计划共完成需要的时间(h)

实际完成需要的时间(h)

Planning

计划

15

17

·       Estimate

·  估计这个任务需要多少时间,并规划大致工作步骤

18

20

Development

开发

98

100

··       Analysis

  需求分析 (包括学习新技术)

52

54

·       Design Spec

·  生成设计文档

22

24

·       Design Review

·  设计复审 (和同事审核设计文档)

18

20

·       Coding Standard

  代码规范 (为目前的开发制定合适的规范)

12

16

·       Design

  具体设计

26

28

·       Coding

  具体编码

48

56

·       Code Review

·  代码复审

7

9

·       Test

·  测试(自我测试,修改代码,提交修改)

18

24

Reporting

报告

9

6

··       Test Report

·  测试报告

3

2

·       Size Measurement

  计算工作量

2

1

·       Postmortem & Process Improvement Plan

·  事后总结 ,并提出过程改进计划

3

3

 

 

.如何进行接口设计*

在进行接口设计之前,我们认真阅读了教材中的相应章节,以及相关的博客,以下是一些介绍接口设计的优秀博客:

https://blog.csdn.net/yu870646595/article/details/51900478

https://blog.csdn.net/blueangle17/article/details/54965597

首先要想好是给什么业务提供的接口,比如是给旅游业务提供的接口,可以叫做TravelService,意思就是说需要根据业务给项目起名字。

信息隐藏:信息隐藏是指在设计和确定模块时,使得一个模块内包含的特定信息(过程或数据),对于不需要这些信息的其他模块来说,是不可访问的。因此,我们在最初设计时决定运用java的private进行将其私有化,向外提供访问的方法。

松耦合:降低耦合度的过程就是模块化编程的过程。我们在设计的过程中,决定采用前后端分离的模式,运算模块,与界面模块相对独立,以此来降低耦合度。

接口设计:面向接口编程是软件工程领域常用的设计手段。

四.计算模块接口的设计与实现过程*

在计算模块,实现小学四则运算的这部分代码中,主要分为三个类,其中RandomArithmetic类负责开启程序运行的入口,CreateProblem主要用于处理运算式,WriteResult用于文件写入,整个程序由这三个类块构成,实现了功能的模块化。

关键函数:

其中在CreateProblem类中又分离出了private Stack<Integer> stackOfNum=new Stack<Integer>();//计算结果所用栈;private Stack<Character> suffix=new Stack<Character>();//后缀表达式private Stack<Character> stackOfOperation=new Stack<Character>();//计算后缀表达式所用栈;这样设计使得各功能再次模块化,使得程序更加的便于维护和扩展。

独到之处:

1.用两个Character栈存储数字和符号,然后用两个栈分别用作转换的缓冲栈和计算结果的缓冲栈

2. 一般Character里面的编码是ascii,但我没有那样做,就是一种新的编码,用ascii0-99表达0-99,而符号和数字冲突,所以符号是100-105

 

 

 

 

 

 

五.计算模块接口部分的性能改进

(记录在改进计算模块性能上所花费的时间,描述你改进的思路,并展示一张性能分析图,并展示你程序中消耗最大的函数。)

 

用时

使用JProfiler工具分析调试

3(h)

查找影响性能的程序模块

3(h)

性能改进

6(h)

我们在性能分析的过程中花费了比较多的时间。

性能优化涉及面很广。一般而言,性能优化指降低响应时间和提高系统吞吐量两个方面,但在流量高峰时候,性能问题往往会表现为服务可用性下降,所以性能优化也可以包括提高服务可用性。在某些情况下,降低响应时间、提高系统吞吐量和提高服务可用性三者相互矛盾,不可兼得。

一开始的时候,我们用了比较多的正则表达式,发现:正则表达式给人的印象是快捷简便。但是在 N.O.P.E 分支中使用正则表达式将是最糟糕的决定。如果万不得已非要在计算密集型代码中使用正则表达式的话,至少要将Pattern缓存下来,避免反复编译Pattern。最好还是用普通的 char[] 数组或者是基于索引的操作。还有就是使用了大量的泛型,导致的结果是使用了 byte、 short、 int 和 long 的包装类,当我们处于 N.O.P.E. 分支的深处时,应该极力避免使用包装类。这样做的坏处是给GC带来了很大的压力。GC将会为清除包装类生成的对象而忙得不可开交。所以最后优化方法是使用基本数据类型、定长数组,并用一系列分割变量来标识对象在数组中所处的位置。

 

以下是一些JAVA性能优化的办法:http://www.importnew.com/16181.html

性能分析图:

 

六. 计算模块部分单元测试展示

部分单元测试代码如下:

package cn.bravedawn.airthmeticwebappse;


import org.junit.Test;

import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.test.context.junit4.SpringRunner;


@RunWith(SpringRunner.class)
@SpringBootTest
public class AirthmeticwebappseApplicationTests {

	@Test
	public void contextLoads() {
	}

}

 部分函数代码如下:

package cn.bravedawn.airthmeticwebappse.common.util;
public class CalculateUtil {

    public static void main(String[] args) {
        System.out.println(compute(1, 2, "+"));
    }

    public static Integer compute(int firstNum, int secNum, String operator) {

        switch (operator) {
            case Const.Operator.add: {
                return firstNum + secNum;
            }
            case Const.Operator.subtraction: {
                return firstNum - secNum;
            }
            case Const.Operator.multiplication: {
                return firstNum * secNum;
            }
            case Const.Operator.division: {
                return firstNum / secNum;
            }
            default: {
                return null;
            }
        }
    }
}

 

package cn.bravedawn.airthmeticwebappse.common.util;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class CookiesUtil {

    /**
     * 添加cookie
     *
     * @param response
     * @param name
     * @param value
     */
    public static void addCookie(HttpServletResponse response, String name, String value, int time) {
        Cookie cookie = new Cookie(name.trim(), value.trim());
        cookie.setMaxAge(time);// 设置为30min  
        cookie.setPath("/");
        System.out.println("已添加===============");
        response.addCookie(cookie);
    }

    /**
     * 修改cookie
     *
     * @param request
     * @param response
     * @param name
     * @param value    注意一、修改、删除Cookie时,新建的Cookie除value、maxAge之外的所有属性,例如name、path、domain等,都要与原Cookie完全一样。否则,浏览器将视为两个不同的Cookie不予覆盖,导致修改、删除失败。
     */
    public void editCookie(HttpServletRequest request, HttpServletResponse response, String name, String value) {
        Cookie[] cookies = request.getCookies();
        if (null == cookies) {
            System.out.println("没有cookie==============");
        } else {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(name)) {
                    System.out.println("原值为:" + cookie.getValue());
                    cookie.setValue(value);
                    cookie.setPath("/");
                    cookie.setMaxAge(60 * 60 * 7);// 设置为30min  
                    System.out.println("被修改的cookie名字为:" + cookie.getName() + ",新值为:" + cookie.getValue());
                    response.addCookie(cookie);
                    break;
                }
            }
        }
    }

    /**
     * 删除cookie
     *
     * @param request
     * @param response
     * @param name
     */
    public void delCookie(HttpServletRequest request, HttpServletResponse response, String name) {
        Cookie[] cookies = request.getCookies();
        if (null == cookies) {
            System.out.println("没有cookie==============");
        } else {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(name)) {
                    cookie.setValue(null);
                    cookie.setMaxAge(0);// 立即销毁cookie  
                    cookie.setPath("/");
                    System.out.println("被删除的cookie名字为:" + cookie.getName());
                    response.addCookie(cookie);
                    break;
                }
            }
        }
    }

    /**
     * 根据名字获取cookie
     *
     * @param request
     * @param name    cookie名字
     * @return
     */
    public static Cookie getCookieByName(HttpServletRequest request, String name) {
        Map<String, Cookie> cookieMap = ReadCookieMap(request);
        if (cookieMap.containsKey(name)) {
            Cookie cookie = (Cookie) cookieMap.get(name);
            return cookie;
        } else {
            return null;
        }
    }


    /**
     * 将cookie封装到Map里面
     *
     * @param request
     * @return
     */
    private static Map<String, Cookie> ReadCookieMap(HttpServletRequest request) {
        Map<String, Cookie> cookieMap = new HashMap<String, Cookie>();
        Cookie[] cookies = request.getCookies();
        if (null != cookies) {
            for (Cookie cookie : cookies) {
                cookieMap.put(cookie.getName(), cookie);
            }
        }
        return cookieMap;
    }
}

 

单元测试覆盖率:

七. 计算模块部分异常处理说明

异常处理代码如下:

package cn.bravedawn.airthmeticwebappse;


import org.junit.Test;

import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.test.context.junit4.SpringRunner;


@RunWith(SpringRunner.class)
@SpringBootTest
public class AirthmeticwebappseApplicationTests {

	@Test
	public void contextLoads() {
	}

}

 

八.界面模块的详细设计过程*

首先,为了提高完成项目的效率,我们采用了前后端分离的方式进行项目开发。在最初的界面设计中,考虑到我们的目标用户中有小学生、家长、以及教师,因此界面的适用性比较重要。所以我们现在Photoshop上规划出页面的大体格局及初步界面样式。我们分了三个界面,分别是进入界面,答题界面,和结果界面。在编程过程中,页面实现采用了html+css+js+jquery进行编码。

初步重要代码如下:

! function(a, b) {
	var c = "function" == typeof define,
		d = "undefined" != typeof module && module.exports;
	c ? define(a, b) : d ? module.exports = b() : this[a] = b()
}("Calculagraph", function() {
	function a() {
		this.time = 0, this.isRunning = !1, this._callback = null, this._interval = 0, this.last = 0
	}
	return a.prototype.increase = function(a, b, c, d) {
		var e = this;
		return e._curry(0)(a, b, c, d), e
	}, a.prototype.decrease = function(a, b, c, d) {
		var e = this;
		return e._curry(1)(a, b, c, d), e
	}, a.prototype._curry = function(a) {
		var b = this;
		return a && (b._set = b.time),
			function(c, d, e, f) {
				if(b.isRunning) return !1;
				b.isRunning = !0, b._callback = c, b._interval = d, b._tick = e || 1e3, b._finish = f || function() {}, b.last = a;
				var g = +new Date;
				! function h() {
					var f = +new Date,
						i = parseInt((f - g) / 1e3);
					return c(b.time / 1e3), a ? b.time -= e : b.time += e, b.time < 0 || d && i >= d ? (b.stop(), void b._finish()) : void(b.times = setTimeout(function() {
						h()
					}, e))
				}()
			}
	}, a.prototype.set = function(a) {
		var b = this;
		return b.isRunning ? !1 : (b.time = 1e3 * a, void(b._time = b.time))
	}, a.prototype.stop = function() {
		var a = this;
		clearTimeout(a.times), a.time = null, a.isRunning = !1
	}, a.prototype.parse = function() {
		var a = this;
		clearTimeout(a.times), a.isRunning = !1
	}, a.prototype.restore = function() {
		var a = this;
		a.last ? a.decrease(a._callback, a._interval, a._tick, a._finish) : a.increase(a._callback, a._interval, a._tick, a._finish)
	}, a.prototype.restart = function() {
		var a = this;
		a.stop(), a._time && (a.time = a._time), a.restore()
	}, a
});

 

九.界面模块与计算模块的对接*

UI模块设计过程:我们分为三个页面:用户进入页面,做题页面,结果分析页面。

用户进入页面:前台使用form表单把用户输入的信息传到后台进行出题。这部分对用户输入信息的各种情况的判断,由前台的js判断并实现。

做题界面:打开做题页面,页面上可以呈现出所有题目。通过js对答案对错进行判断。后台把所有题目和所有题目答案放在list里传递到前台,答题者完成题目后,可以进行检查。检查无误后,答题情况即可提交到后台。

结果界面:答题者提交答题后,由后台JSP页面返回结果。

十.描述结对的过程

十一.结对编程的优点和缺点

同时指出结对的每一个人的优点和缺点在哪里 (要列出至少三个优点和一个缺点)。

通过这次结对项目,我觉得结对编程能够带来1+1>2的效果。

结对编程有以下优点:

1.之前一个人做的时候,遇到不懂得问题时,就会陷入迷茫。当两个人一起编程时,有不懂的可以一起讨论,说出自己的意见,也为整个编程过程节约了时间。

2.除此之外,两个人一起合作时就会产生更多更好的想法,可以更好的优化整个项目的设计,遇到问题时可以相互帮助解决问题,效率也比较高。

3.两个人合作还可以发现多方身上的优点,找出自己身上的不足,并能相互监督让彼此变得更好,还可以彼此分享好的学习经验。综上所述,我们认为两个人合作的效率远远大于一个人。

要说结对编程的缺点:

1.我觉得主要在完成项目的过程中,会产生分歧。每个人有每个人自己的想法,如果不能及时解决分歧,达成一致,很有可能演化成矛盾,进而使合作关系破裂,无法完成项目。

2.对于一个有经验的编程人员来说,更习惯于一个人编程。毕竟,在编程的过程中有别人在看的感觉有些奇怪。

小组成员互评:

马乐平:优点:认真细心,勤奋好问,善于思考;

              缺点:理解能力欠佳,不善沟通

陈逸璇:优点:对学习充满热情,不怕困难,善于沟通;

              缺点:技术还有待提高

 

 

十二.实际完成项目时间(PSP

PSP2.1

任务内容

计划共完成需要的时间(h)

实际完成需要的时间(h)

Planning

计划

15

17

·       Estimate

·  估计这个任务需要多少时间,并规划大致工作步骤

18

20

Development

开发

98

100

··       Analysis

  需求分析 (包括学习新技术)

52

54

·       Design Spec

·  生成设计文档

22

24

·       Design Review

·  设计复审 (和同事审核设计文档)

18

20

·       Coding Standard

  代码规范 (为目前的开发制定合适的规范)

12

16

·       Design

  具体设计

26

28

·       Coding

  具体编码

48

56

·       Code Review

·  代码复审

7

9

·       Test

·  测试(自我测试,修改代码,提交修改)

18

24

Reporting

报告

9

6

··       Test Report

·  测试报告

3

2

·       Size Measurement

  计算工作量

2

1

·       Postmortem & Process Improvement Plan

·  事后总结 ,并提出过程改进计划

3

             3

 总结:经过此次结对项目,让我感受到结对编程的优点及乐趣。同时,经过此次项目的锻炼,让我对后端的学习更急深入,同时培养了我的许多能力,如:如何与别人沟通,如何合作等等。总之,此次作业中收获很大。

 

推荐阅读