实验三 敏捷开发与XP实践
实验内容
1. XP基础
2. XP核心实践
3. 相关工具
实验要求
1.没有Linux基础的同学建议先学习《Linux基础入门(新版)》《Vim编辑器》 课程
2.完成实验、撰写实验报告,实验报告以博客方式发表在博客园,注意实验报告重点是运行结果,遇到的问题(工具查找,安装,使用,程序的编辑,调试,运行等)、解决办法(空洞的方法如“查网络”、“问同学”、“看书”等一律得0分)以及分析(从中可以得到什么启示,有什么收获,教训等)。报告可以参考范飞龙老师的指导
3. 严禁抄袭,有该行为者实验成绩归零,并附加其他惩罚措施。
实验步骤
(一)敏捷开发与XP
- XP是以开发符合客户需要的软件为目标而产生的一种方法论
- XP是一种以实践为基础的软件工程过程和思想
- XP认为代码质量的重要程度超出人们一般所认为的程度
- XP特别适合于小型的有责任心的、自觉自励的团队开发需求不确定或者迅速变化的软件
(二)编码标准
编写代码一个重要的认识是“程序大多时候是给人看的”,编程标准使代码更容易阅读和理解,甚至可以保证其中的错误更少。编程标准包含:具有说明性的名字、清晰的表达式、直截了当的控制流、可读的代码和注释,以及在追求这些内容时一致地使用某些规则和惯用法的重要性。
代码标准中很重要的一项是如何给包、类、变量、方法等标识符命名,能很好的命名可以让自己的代码立马上升一个档次。Java中的一般的命名规则有:
- 要体现各自的含义
- 包、类、变量用名词
- 方法名用动宾
- 包名全部小写,如:io,awt
- 类名第一个字母要大写,如:HelloWorldApp
(三)结对编程
结对编程是XP中的重要实践。在结对编程模式下,一对程序员肩并肩、平等地、互补地进行开发工作。他们并排坐在一台电脑前,面对同一个显示器,使用同一个键盘、同一个鼠标一起工作。他们一起分析,一起设计,一起写测试用例,一起编码,一起做单元测试,一起做集成测试,一起写文档等。 结对编程中有两个角色:
- 驾驶员(Driver)是控制键盘输入的人。
- 领航员(Navigator)起到领航、提醒的作用。
如何结对编程,为何要结对编程,大家参考一下结对编程和两人合作 ,重点是:
- 驾驶员:写设计文档,进行编码和单元测试等XP开发流程。
- 领航员:审阅驾驶员的文档、驾驶员对编码等开发流程的执行;考虑单元测试的覆盖率;思考是否需要和如何重构;帮助驾驶员解决具体的技术问题。
- 驾驶员和领航员不断轮换角色,不要连续工作超过一小时,每工作一小时休息15分钟。领航员要控制时间。
- 主动参与。任何一个任务都首先是两个人的责任,也是所有人的责任。没有“我的代码”、“你的代码”或“他/她的代码”,只有“我们的代码”。
- 只有水平上的差距,没有级别上的差异。两人结对,尽管可能大家的级别资历不同,但不管在分析、设计或编码上,双方都拥有平等的决策权利。
团队精神是好多地方都强调的一个精神,最小的团队就是一对一的二人团队了,培养团队精神从结对编程开始吧。社会生活中人与人相处最重要的是诚信,有同理心,互利。结对编程中大家会出现分歧,如何更有效地合作要做到对事不对人,掌握这些是可以终生受益的,如何影响小伙伴,大家参考一下两人合作:要会做汉堡包。
(四)版本控制
XP的集体所有制意味着每个人都对所有的代码负责;这一点,反过来又意味着每个人都可以更改代码的任意部分。结对编程对这一实践贡献良多:借由在不同的结对中工作,所有的程序员都能看到完全的代码。集体所有制的一个主要优势是提升了开发程序的速度,因为一旦代码中出现错误,任何程序员都能修正它。 这意味着代码要放到一个大家都能方便获取的地方,我们叫代码仓库。这引出另外一个话题叫版本控制(Version Control)。
不论是对于团队还是个体,版本控制都提供了很多好处。
(五)重构
我们先看看重构的概念:
重构(Refactor),就是在不改变软件外部行为的基础上,改变软件内部的结构,使其更加易于阅读、易于维护和易于变更 。
学过C语言的学生学Java时常犯的毛病是不会封装,该用类的地方都用了结构体。比如要定义一个类Student,会出现这样的代码:
- 增加新功能;
- 原有功能有BUG;
- 改善原有程序的结构
- 优化原有系统的性能
一个完整的重构流程包括:
- 从版本控制系统代码库中Check out code
- 读懂代码(包括测试代码)
- 发现bad smell
- Refactoring
- 运行所有的Unit Tests
- 往代码库中Check in code
(六)实践项目
1. 以结对编程的方式编写一个软件,Blog中要给出结对同学的Blog网址,可以拍照展现结对编程情况,可以参考一下其他学校的作业
2.记录TDD和重构的过程,测试代码不要少于业务代码,Eclipse中refactor菜单下的重构技能不要少于5个
3.团队代码要使用git在实验楼中托管,要使用结对同学中的一个同学的账号托管。
4. 程序要有GUI界面,参考用户界面和用户体验
5.程序功能从豌豆荚游戏中选择一款用Java实现,注意:团队之间项目不能有重复,课代表协调一下。
高级计算器:代码
package caculater;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Calc extends MouseAdapter {
JFrame list;
// Container con;
JTextField show;
JButton[] jbNum = new JButton[10];
JPanel jpMain; // 主面板
JPanel jpRight; // 右子面板主要用于存放运算符和等号
JPanel jpLight; // 左子面板用于存放数字,符号, “.”
JButton dight; // 小数点
JButton sign; // 正负号
JButton add; // 加号
JButton sub; // 减号
JButton multiply; // 乘号
JButton divide; // 除号
JButton power; // 求幂
JButton cos; // cos
JButton sin; // sin
JButton ln; // ln
JButton ce; // 清除
JButton equal; // 等于
JButton mod; // 取余
JButton sqrt; // sqrt
double sum = 0; // 临时结果
boolean b = false; // 监控运算符是否被点击,错误是否出现,用于实现下一次点击按钮时清空
operator i = operator.un; // 记录等号符点击前某一运算符点击次数,用于实现连加或者连减等
int op; // 记录操作符
// 操作符一包括+-*/%^
enum operator {
add, sub, mul, div, mod, pow, sin, cos, sqrt, ln, un
}
void display() {
// 创建主窗口,添加一个Text框,
list = new JFrame("计算器");
list.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
list.setSize(360, 230);
list.setLocation(400, 300);
list.setBackground(Color.LIGHT_GRAY); // 设置窗口背景颜色
list.setResizable(false);
list.setLayout(new FlowLayout(FlowLayout.CENTER));
show = new JTextField(31);
show.setHorizontalAlignment(JTextField.RIGHT); // 文本框内文字右对齐
show.setEditable(false); // 文本框不可编辑
list.add(show);
// 创建面板并设置布局
jpMain = new JPanel();
jpRight = new JPanel();
jpLight = new JPanel();
jpMain.setLayout(new GridLayout(1, 2));
jpRight.setLayout(new GridLayout(4, 3, 3, 3));
jpLight.setLayout(new GridLayout(4, 3, 3, 3));
list.add(jpMain);
jpMain.add(jpLight);
jpMain.add(jpRight);
// 创建0~9按钮对象
for (int i = 9; i >= 0; i--) {
jbNum[i] = new JButton(String.valueOf(i));
jbNum[i].setForeground(Color.BLUE);
jpLight.add(jbNum[i]);
jbNum[i].addMouseListener(this);
}
add = new JButton("+");
sub = new JButton("-");
multiply = new JButton("*");
divide = new JButton("/");
power = new JButton("x^y");
sin = new JButton("sin");
cos = new JButton("cos");
ln = new JButton("ln");
ce = new JButton("CE");
equal = new JButton("=");
mod = new JButton("%");
sqrt = new JButton("sqrt");
jpRight.add(divide);
jpRight.add(sqrt);
jpRight.add(ln);
jpRight.add(multiply);
jpRight.add(sin);
jpRight.add(mod);
jpRight.add(sub);
jpRight.add(cos);
jpRight.add(ce);
jpRight.add(add);
jpRight.add(power);
jpRight.add(equal);
// 给所有按钮注册监听器
dight = new JButton(".");
sign = new JButton("±");
jpLight.add(sign);
jpLight.add(dight);
add.addMouseListener(this);
sub.addMouseListener(this);
multiply.addMouseListener(this);
divide.addMouseListener(this);
power.addMouseListener(this);
sin.addMouseListener(this);
cos.addMouseListener(this);
ln.addMouseListener(this);
ce.addMouseListener(this);
equal.addMouseListener(this);
mod.addMouseListener(this);
sqrt.addMouseListener(this);
dight.addMouseListener(this);
sign.addMouseListener(this);
list.setVisible(true);
}
public void mouseClicked(MouseEvent e) {
// 0~9的输入
if (e.getSource() == jbNum[0]) {
input(0, e);
}
if (e.getSource() == jbNum[1]) {
input(1, e);
}
if (e.getSource() == jbNum[2]) {
input(2, e);
}
if (e.getSource() == jbNum[3]) {
input(3, e);
}
if (e.getSource() == jbNum[4]) {
input(4, e);
}
if (e.getSource() == jbNum[5]) {
input(5, e);
}
if (e.getSource() == jbNum[6]) {
input(6, e);
}
if (e.getSource() == jbNum[7]) {
input(7, e);
}
if (e.getSource() == jbNum[8]) {
input(8, e);
}
if (e.getSource() == jbNum[9]) {
input(9, e);
}
// 小数点,正负号,CE,等号
if (e.getSource() == dight) {
if (show.getText().indexOf('.') == -1) {
show.setText(show.getText() + ".");
}
}
if (e.getSource() == sign) {
if (show.getText().indexOf("-") == -1) {
show.setText("-" + show.getText());
} else {
show.setText(show.getText().replace('-', ' '));
}
}
if (e.getSource() == ce) {
show.setText("0");
sum = 0;
i = operator.un;
b = false;
}
outer: if (e.getSource() == equal) {
try {
if (i == operator.un) {
b = true;
} else {
if (i == operator.add) {
sum += Double.parseDouble(show.getText());
}
if (i == operator.sub) {
sum -= Double.parseDouble(show.getText());
}
if (i == operator.mul) {
sum *= Double.parseDouble(show.getText());
}
if (i == operator.div) {
if (Double.parseDouble(show.getText()) != 0) {
sum /= Double.parseDouble(show.getText());
} else {
show.setText("ERROR");
b = true;
sum = 0;
break outer; // 不执行trimIn()方法 屏幕显示错误
}
}
if (i == operator.mod) {
sum %= Double.parseDouble(show.getText());
}
if (i == operator.pow) {
sum = Math.pow(sum, Double.parseDouble(show.getText()));
}
trimIn(sum);
}
} catch (Exception ex) {
show.setText("ERROR");
b = true;
sum = 0;
}
sum = 0;
i = operator.un;
b = true;
}
// 加减乘除//幂指函数//取余
if (e.getSource() == add) {
cal(i);
i = operator.add;
b = true;
}
if (e.getSource() == sub) {
cal(i);
i = operator.sub;
b = true;
}
if (e.getSource() == multiply) {
cal(i);
i = operator.mul;
b = true;
}
if (e.getSource() == divide) {
cal(i);
i = operator.div;
b = true;
}
if (e.getSource() == mod) {
cal(i);
i = operator.mod;
b = true;
}
if (e.getSource() == power) {
cal(i);
i = operator.pow;
b = true;
}
// sqrt,sin,cos,ln
try {
if (show.getText() != "ERROR") {
if (e.getSource() == sqrt) {
sum = Math.sqrt(Double.parseDouble(show.getText()));
trimIn(sum);
b = true;
}
if (e.getSource() == sin) {
sum = Math.sin(Double.parseDouble(show.getText()));
trimIn(sum);
b = true;
}
if (e.getSource() == cos) {
sum = Math.cos(Double.parseDouble(show.getText()));
trimIn(sum);
b = true;
}
if (e.getSource() == ln) {
sum = Math.log(Double.parseDouble(show.getText()));
trimIn(sum);
b = true;
}
}
} catch (Exception ex) {
show.setText("ERROR");
b = true;
}
}
// 用以四则运算和求幂和取模的方法
public void cal(operator i) {
try {
if (show.getText() != "ERROR") {
if (i == operator.un) {
sum = Double.parseDouble(show.getText());
}
if (i == operator.add) {
sum += Double.parseDouble(show.getText());
trimIn(sum);
}
if (i == operator.sub) {
sum -= Double.parseDouble(show.getText());
trimIn(sum);
}
if (i == operator.mul) {
sum *= Double.parseDouble(show.getText());
trimIn(sum);
}
if (i == operator.div) {
if (Double.parseDouble(show.getText()) != 0) {
sum /= Double.parseDouble(show.getText());
trimIn(sum);
} else {
//出现0后,把一切数据重置
show.setText("ERROR");
sum = 0;
b = true;
i=operator.un;
}
}
//取余
if (i == operator.mod) {
sum %= Double.parseDouble(show.getText());
trimIn(sum);
}
//幂指函数
if (i == operator.pow) {
sum = Math.pow(sum, Double.parseDouble(show.getText()));
trimIn(sum);
}
}
} catch (Exception ex) {
show.setText("ERROR");
b = true;
}
}
// 点击数字输入
public void input(int i, MouseEvent e) {
if (b == true) {
show.setText(String.valueOf(i));
b = false;
} else {
//判断0和.来清除整数时后面的点
if (show.getText().indexOf('0') == 0 && e.getSource() != dight) {
show.setText(String.valueOf(i));
} else {
show.setText(show.getText() + String.valueOf(i));
}
}
}
// sum的显示,整数的去掉小数点和0
public void trimIn(double sum) {
// if (show.getText().indexOf('.') != -1 &&
// show.getText().endsWith("0")) {
// show.setText((String.valueOf(sum).substring(0, String.valueOf(sum)
// .indexOf('.'))));
// } else
if (String.valueOf(sum).indexOf('.') != -1
&& String.valueOf(sum).endsWith("0")) {
show.setText((String.valueOf(sum).substring(0, String.valueOf(sum)
.indexOf('.'))));
} else if (Double.isNaN(sum)) {
show.setText("ERROR"); //不 是数字时 屏幕显示错误,并把sum置于0 运算符置UN
b = true;
sum = 0;
i = operator.un;
} else if (Double.isInfinite(sum)) {
show.setText("ERROR"); //出现infinite(无限大)时显示错误SUM置0运算符置UN
b = true;
sum = 0;
i = operator.un;
} else {
show.setText(String.valueOf(sum));
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Calc c = new Calc();
c.display();
}
}
产品测试:
遇到的一个问题
6.实验报告中统计自己的PSP(Personal Software Process)时间
步骤 |
耗时 |
百分比 |
需求分析 |
1小时 |
14.28% |
设计 |
30分钟 |
7.14% |
代码实现 |
4小时 |
57.14% |
测试 |
1小时 |
14.28% |
分析总结 |
30分钟 |
7.14% |
!!!partner的地址:http://www.cnblogs.com/20135202yjx/