敏捷开发与XP实践

北京电子科技学院(BESTI)

实  验  报  告

 课程: Java        班级:1352          姓名:朱国庆         学号:20135237

 成绩:               指导教师:娄嘉鹏    实验日期:2015.6.2

实验密级:         预习程度:             实验时间:15:30~18:00

仪器组次:37         必修/选修:选修       实验序号:(三)

实验名称:敏捷开发与XP实践

实验目的:

1.XP基础

2.XP核心实践

3.相关工具

实验要求:

1.没有Linux基础的同学建议先学习《Linux基础入门(新版)》《Vim编辑器》 课程

2.完成实验、撰写实验报告,实验报告以博客方式发表在博客园,注意实验报告重点是运行结果,遇到的问题(工具查找,安装,使用,程序的编辑,调试,运行等)、解决办法(空洞的方法如“查网络”、“问同学”、“看书”等一律得0分)以及分析(从中可以得到什么启示,有什么收获,教训等)。报告可以参考范飞龙老师的指导

3. 严禁抄袭,有该行为者实验成绩归零,并附加其他惩罚措施。

实验步骤:

(一)敏捷开发与XP

  1、软件工程

软件工程是把系统的、有序的、可量化的方法应用到软件的开发、运营和维护上的过程。

软件开发流程的目的是为了提高软件开发、运营、维护的效率,并提高软件的质量、用户满意度、可靠性和软件的可维护性。软件开发很重要的一点不是看你能对多少理论讲的头头是道,还要看你对相关工具应用的如何,比如Java中单元测试要和JUnit的应用结合起来,建模要和Umbrello或StarUML的应用结合起来。编程学习是一个习而学的过程。 一个常见的公式是:软件工程=开发流程+工具 邹欣老师给出的两个公式:软件=程序+软件工程和软件企业=软件+商业模式

2、极限编程(eXtreme Programming,XP)

是一种全新而快捷的软件开发方法。XP团队使用现场客户、特殊计划方法和持续测试来提供快速的反馈和全面的交流:

  • XP是以开发符合客户需要的软件为目标而产生的一种方法论
  • XP是一种以实践为基础的软件工程过程和思想
  • XP认为代码质量的重要程度超出人们一般所认为的程度
  • XP特别适合于小型的有责任心的、自觉自励的团队开发需求不确定或者迅速变化的软件

XP软件开发是什么样的通过 XP准则来表达:

  • 沟通 :XP认为项目成员之间的沟通是项目成功的关键,并把沟通看作项目中间协调与合作的主要推动因素。
  • 简单 :XP假定未来不能可靠地预测,在现在考虑它从经济上是不明智的,所以不应该过多考虑未来的问题而是应该集中力量解决燃眉之急。
  • 反馈 :XP认为系统本身及其代码是报告系统开发进度和状态的可靠依据。系统开发状态的反馈可以作为一种确定系统开发进度和决定系统下一步开发方向的手段。
  • 勇气:代表了XP认为人是软件开发中最重要的一个方面的观点。在一个软件产品的开发中人的参与贯穿其整个生命周期,是人的勇气来排除困境,让团队把局部的最优抛之脑后,达到更重大的目标。表明了XP对“人让项目取得成功”的基本信任态度。

一项实践在XP环境中成功使用的依据通过XP的法则呈现,包括:快速反馈、假设简单性、递增更改、提倡更改、优质工作。

XP软件开发的基石是XP的活动,包括:编码、测试、倾听、设计。

(二)编码标准

编写代码一个重要的认识是“程序大多时候是给人看的”,编程标准使代码更容易阅读和理解,甚至可以保证其中的错误更少。编程标准包含:具有说明性的名字、清晰的表达式、直截了当的控制流、可读的代码和注释,以及在追求这些内容时一致地使用某些规则和惯用法的重要性。

下面来看一个例子:

 

程序没有最基本的缩进,让人读起来很费劲,这个问题在Eclipse中比较容易解决,我们单击Eclipse菜单中的source(源码)->Format(格式) 或用快捷键Ctrl+Shift+F就可

以按Eclipse规定的规范缩进,效果如下: 

代码标准中很重要的一项是如何给包、类、变量、方法等标识符命名,能很好的命名可以让自己的代码立马上升一个档次。Java中的一般的命名规则有:

l         要体现各自的含义

l         包、类、变量用名词

l         方法名用动宾

l         包名全部小写,如:io,awt

l         类名第一个字母要大写,如:HelloWorldApp

l         变量名第一个字母要小写,如:userName

l         方法名第一个字母要小写:setName

l         ...

标识符名字应当直观且可以拼读,可望文知意,不必进行“解码”,一般采用英文单词或其组合,便于记忆和阅读,切忌使用汉语拼音来命名,用词要准确。

标识符的长度“min-length && max-information”的原则,比如:maxVal 比maxValueUntilOverflow要好些,可以通过去元音法把变量名变短,如returnValue->rtnVal ,message->msg;一般全局变量用具有说明性的名字,局部变量用短名字:单字符的名字,常见的如i,j,k等用作局部变量。

其他的可以参考邹欣老师写的代码规范与代码复审.

关于代码标准,可以遵循以下原则:

有一些公司比如Google公开了自己的编码标准,可以作为学习不错的参考,大家参考一下范飞龙老师写的代码规范&代码风格,有兴趣的可以尝试如何在Eclipse中实践Google Java Style(中文版),也就是说如何做到“按一下快捷键Ctrl+Shift+F就可以让自己的代码符合Google Java Style(中文版)的要求”,完成后单独写一篇Blog,有加分的

(三)结对编程

结对编程是XP中的重要实践。在结对编程模式下,一对程序员肩并肩、平等地、互补地进行开发工作。他们并排坐在一台电脑前,面对同一个显示器,使用同一个键盘、同一个鼠标一起工作。他们一起分析,一起设计,一起写测试用例,一起编码,一起做单元测试,一起做集成测试,一起写文档等。 结对编程中有两个角色:

l         驾驶员(Driver)是控制键盘输入的人。

l        领航员(Navigator)起到领航、提醒的作用。

重点是:

 

l         驾驶员:写设计文档,进行编码和单元测试等XP开发流程。

l         领航员:审阅驾驶员的文档、驾驶员对编码等开发流程的执行;考虑单元测试的覆盖率;思考是否需要和如何重构;帮助驾驶员解决具体的技术问题。

l         驾驶员和领航员不断轮换角色,不要连续工作超过一小时,每工作一小时休息15分钟。领航员要控制时间。

l         主动参与。任何一个任务都首先是两个人的责任,也是所有人的责任。没有“我的代码”、“你的代码”或“他/她的代码”,只有“我们的代码”。

l         只有水平上的差距,没有级别上的差异。两人结对,尽管可能大家的级别资历不同,但不管在分析、设计或编码上,双方都拥有平等的决策权利。。

(四)版本控制

XP的集体所有制意味着每个人都对所有的代码负责;这一点,反过来又意味着每个人都可以更改代码的任意部分。结对编程对这一实践贡献良多:借由在不同的结对中工作,所有的程序员都能看到完全的代码。集体所有制的一个主要优势是提升了开发程序的速度,因为一旦代码中出现错误,任何程序员都能修正它。 这意味着代码要放到一个大家都能方便获取的地方,我们叫代码仓库。这引出另外一个话题叫版本控制(Version Control)。

不论是对于团队还是个体,版本控制都提供了很多好处。

l         版本控制提供项目级的 undo(撤销) 功能: 没有什么事情是终结版本, 任何错误必须很容易回滚。 假设你在使用世界上最复杂的文字处理系统。 它具备了所有的能想到的功能,就是没有支持 DELETE(删除) 键。想象你打字的时候得多么的谨慎和缓慢吧, 特别是一篇超大的文档的快临近末尾的时候, 一个不小心就要重头再来(试想你选中所有的文字, 不小心按了 DELETE 键, 因为没有撤销功能,只好重新录入)。编辑文字和版本控制相同,任何时候都需要回滚,无论是一个小时, 一天, 还是一周, 这让你的团队工作自由快速的工作, 而且对于修正错误也非常自信。

l         版本控制允许多人在同一代码上工作, 只要遵守一定的控制原则就行。 再也不会发生诸如一个人覆盖了另一个人编辑的代码,导致那个人的修改无效这样的情况。

l         版本控制系统保存了过去所作的修改的历史记录。如果你遭遇到一些惊讶的代码,通过版本控制系统可以很容易找出是谁干的, 修改了什么, 修改的时间, 如果幸运的话,还能找出原因。

l         版本控制系统还支持在主线上开发的同时发布多个软件版本。在软件发布的时候也不需要整个团队的停止工作,不需要冻结代码。

l         版本控制也是项目级的时间机器,你可以选择任何一个时间, 精确地查看项目在当时的情况。 这对研究非常有用, 也是重现以前某个有问题的发布版本的基础。

l        流行的版本控制工具有CVS,SVN,Git等,更多的可以参考这里。Git是Linus除了Linux操作系统外的另外一个重要发明。

 

克隆其他用户代码仓库只需要知道对方的仓库链接:$ git clone http://git.shiyanlou.com/[对方的专属用户名]/[课程代码仓库名]

以HelloWorld的例子:

$ cd /home/shiyanlou/Code/shiyanlou_cs212

 

l         修改代码文件

l         添加修改文件

l         $ git add 所有修改的文件

l         提交到环境中本地代码仓库

l         $ git commit -m '本次修改的描述'

l         # push到git.shiyanlou.com,无需输入密码

l         $ git push

 

(五)重构

1. 概念

重构(Refactor),就是在不改变软件外部行为的基础上,改变软件内部的结构,使其更加易于阅读、易于维护和易于变更。

2. eclipse中Refactor

重新命名:Rename

封装成员变量:Encapsulate Field...

抽象方法:Extract Method...

这个类,类名,方法名和方法的参数名都有问题,没有注释的话是无法理解代码的。我们可以使用Eclipse中的重构功能来改名。修改方法是,用鼠标单击要改的名字,选择Eclipse中菜单中的Refactor->Rename...: 重构完的效果如下:

3.实用的方法

 

4. 完整的重构流程包括:

从版本控制系统代码库中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实现,注意:团队之间项目不能有重复,课代表协调一下。

6.实验报告中统计自己的PSP(Personal Software Process)时间

产品代码及截图如下:

 

package dj;

import java.awt.*;
import java.awt.event.*;
import java.io.*;

import javax.swing.*;


public class mainFrm extends JFrame implements KeyListener, Runnable{
 Button btn_start=new Button();
 int moveDir=0;
 int i=0;
 int x=100;
 int y=400;
 public int dr=1;
 int btm=0;
 int base=200;
 boolean isLive=true;
 JMenuBar mb=new JMenuBar();
 JMenu jm=new JMenu("菜单");
 JMenuItem jm1=new JMenuItem("开始");
 JMenuItem jm2=new JMenuItem("暂停");
 JMenuItem jm3=new JMenuItem("得分记录");
 JMenuItem jm4=new JMenuItem("退出");
 boolean isStart=false;
 Board bd[]=new Board[10];
 JLabel lbl_score=new JLabel("score:");
 JLabel lbl_level=new JLabel("level:");
 int level=1;
 int score=0;

 boolean moveBg=false;
 JLabel lbl_img=new JLabel(new ImageIcon("man.jpg"));
 JLabel lbl_bd1=new JLabel(new ImageIcon("board.jpg"));
 JLabel lbl_bd2=new JLabel(new ImageIcon("board.jpg"));
 JLabel lbl_bd3=new JLabel(new ImageIcon("board.jpg"));
 JLabel lbl_bd4=new JLabel(new ImageIcon("board.jpg"));
 JLabel lbl_bd5=new JLabel(new ImageIcon("board.jpg"));
 JLabel lbl_bd6=new JLabel(new ImageIcon("board.jpg"));
 JLabel lbl_bd7=new JLabel(new ImageIcon("board.jpg"));
 JLabel lbl_bd8=new JLabel(new ImageIcon("board.jpg"));
 JLabel lbl_bd9=new JLabel(new ImageIcon("board.jpg"));
 JLabel lbl_bd0=new JLabel(new ImageIcon("board.jpg"));
 mainFrm(){
  jm.add(jm1);
  jm.add(jm2);
  //jm.add(jm3);
  jm.add(jm4);
  setJMenuBar(mb);
  mb.add(jm);  
  setTitle("DoodleJump");
  setSize(350,600);
  setLocation(300,100);
  setBackground(Color.white);
  setVisible(true);
  setLayout(null);
  addWindowListener(new WindowAdapter(){
   public void windowClosing(WindowEvent e){
    System.exit(0);}});  
  jm3.addActionListener(new ActionListener(){
   public void actionPerformed (ActionEvent e){
   }
  });
  jm4.addActionListener(new ActionListener(){
   public void actionPerformed(ActionEvent e) {
    System.exit(0);}});
  jm1.addActionListener(new ActionListener(){
   public void actionPerformed(ActionEvent e) {
    isStart=true;}});
  jm2.addActionListener(new ActionListener(){
   public void actionPerformed(ActionEvent e) { 
    isStart=false;}});
  lbl_score.setSize(100,30);
  lbl_score.setLocation(250, 0);
  lbl_level.setSize(100,30);
  lbl_level.setLocation(20, 0);
  bd[0]=new Board(100);
  bd[1]=new Board(120);
  bd[2]=new Board(170);
  bd[3]=new Board(230);
  bd[4]=new Board(280);
  bd[5]=new Board(330);
  bd[6]=new Board(370);
  bd[7]=new Board(400);
  bd[8]=new Board(440);
  bd[9]=new Board(480);
  btn_start.setLocation(350, 50);
  btn_start.setSize(100, 30);
  btn_start.addKeyListener(this);
  
  lbl_img.setLocation(0, 0);
  lbl_img.setSize(64, 60);
  
  lbl_bd1.setLocation(bd[1].x, bd[1].y);
  lbl_bd1.setSize(63, 19);
  lbl_bd2.setLocation(bd[2].x, bd[2].y);
  lbl_bd2.setSize(63, 19);
  lbl_bd3.setLocation(bd[3].x, bd[3].y);
  lbl_bd3.setSize(63, 19);
  lbl_bd4.setLocation(bd[4].x, bd[4].y);
  lbl_bd4.setSize(63, 19);
  lbl_bd5.setLocation(bd[5].x, bd[5].y);
  lbl_bd5.setSize(63, 19);
  lbl_bd6.setLocation(bd[6].x, bd[6].y);
  lbl_bd6.setSize(63, 19);
  lbl_bd7.setLocation(bd[7].x, bd[7].y);
  lbl_bd7.setSize(63, 19);
  lbl_bd8.setLocation(bd[8].x, bd[8].y);
  lbl_bd8.setSize(63, 19);
  lbl_bd9.setLocation(bd[9].x, bd[9].y);
  lbl_bd9.setSize(63, 19);
  
  lbl_bd0.setSize(63, 19);
  lbl_bd0.setLocation(bd[0].x, bd[0].y);
 
  add(btn_start);
  addKeyListener(this);
  add(lbl_img);
  add(lbl_bd1);
  add(lbl_bd2);
  add(lbl_bd3);
  add(lbl_bd4);
  add(lbl_bd5);
  add(lbl_bd6);
  add(lbl_bd7);
  add(lbl_bd8);
  add(lbl_bd9);
  add(lbl_bd0);
  add(lbl_score);
  add(lbl_level);
  repaint();
    }


 public static void main(String[] args) {
  mainFrm mf=new mainFrm();
  Thread t1=new Thread(mf);
  t1.start(); 
  
 }

 public int funT(int x){
  return x*x/50;
 }
 int r=1;
 int t=0;
 int bd_base[]=new int[10];
 
 public void run() { 
  for(int i=0;i<10;i++){
   bd_base[i]=bd[i].y;
  }
  int score_dr=10000;
  lbl_level.setText("level:"+level);
  
  while(true){
   if(isStart==true)
   {
   dis();
   ifJump();
   t+=r;
   if(kp==true){//按键则左右移动。
    x+=dr;
   }
   if(x<-30)
    x=300;
   if(x>300)
    x=-30;
   if(moveBg==false){//人物 跳跃
    y=base+funT(t);
    if(score>score_dr){
     level++;
     score_dr+=10000;
     lbl_level.setText("level:"+level);
    }
   }
   else{
    int aaa=200-(200+base-y)-funT(t);
    for(int i=0;i<10;i++){
     bd[i].y=bd_base[i]+aaa;
    score++;
    
    lbl_score.setText("Score:"+score/10);
    }
   }
   ifIsDead();
   lbl_img.setLocation(x, y);//刷新屏幕 
   lbl_bd1.setLocation(bd[1].x, bd[1].y);
   lbl_bd2.setLocation(bd[2].x, bd[2].y);
   lbl_bd3.setLocation(bd[3].x, bd[3].y);
   lbl_bd4.setLocation(bd[4].x, bd[4].y);
   lbl_bd5.setLocation(bd[5].x, bd[5].y);
   lbl_bd6.setLocation(bd[6].x, bd[6].y);
   lbl_bd7.setLocation(bd[7].x, bd[7].y);
   lbl_bd8.setLocation(bd[8].x, bd[8].y);
   lbl_bd9.setLocation(bd[9].x, bd[9].y);
   lbl_bd0.setLocation(bd[0].x, bd[0].y);
   
   try {//停顿 20ms
    Thread.sleep(7);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   if(t<=-100){//t小于-100 t++
    r=-r;
    }
   if(t<0)moveDir=0;//t小于 0 跳棋状态 反之 下降状态。
   else {
    moveDir=1;
   }
   if(y<199&&moveDir==0&&moveBg==false){//y小于一定程度的时候背景开始动,任务则在y的位置停止 
    moveBg=true;
   }
   else if(t==0&&moveBg==true)
    {
     moveBg=false;
     base=200;
     for(int i=0;i<10;i++){
      bd_base[i]=bd[i].y;
     }
    }
   }
  }
 }

 boolean kp = false;
 boolean isMove = false;
 
 
 public void keyPressed(KeyEvent e) {
  // TODO Auto-generated method stub 
  
  if(isMove==false){
   switch(e.getKeyCode())
   {
    case KeyEvent.VK_LEFT:{
     dr=-2;
       break;
    }
    case KeyEvent.VK_RIGHT:{
     dr=2;
       break;}
    case KeyEvent.VK_UP:{
     if(moveDir==1){
     dr=0;
     t=-100;
     r=-1; 
     btm=base+200-y;
     base=base-btm;
         }
     break;
    }
   }
  }
  kp=true;
  isMove=true;
 }

 public int findMix(){
  int min=bd[0].y;
  for(int i=1;i<10;i++){
   if(bd[i].y<min)
    min=bd[i].y;
  }
  System.out.println(min);
  return min;
 }
 public void dis(){
  for(int i=0;i<10;i++){
   if(bd[i].y>500)
   {
    bd[i].newPosition(findMix()-170-level);
    bd_base[i]=bd[i].y;
    System.out.println("-----------  "+i);
   }
  }
 }
 public void ifIsDead(){
  if(y>600&&isLive==true){
   isStart=false;
   System.out.print("dead");
   isLive=false;
   JOptionPane.showMessageDialog(null,"game over","结束",JOptionPane.ERROR_MESSAGE);
   bd[0]=new Board(100);
   bd[1]=new Board(120);
   bd[2]=new Board(170);
   bd[3]=new Board(230);
   bd[4]=new Board(280);
   bd[5]=new Board(330);
   bd[6]=new Board(370);
   bd[7]=new Board(400);
   bd[8]=new Board(440);
   bd[9]=new Board(480);
   bd[8].x=bd[9].x;
   for(int i=0;i<10;i++){
    bd_base[i]=bd[i].y;
   }
   x=bd[9].x;
   y=400;
   isStart=true;
   isLive=true;
   
  }
 }
 public void ifJump(){
  int width=45;
  int height=10;
  for(int i=0;i<10;i++){
   if(moveDir==1&&(x>bd[i].x-width-5&&x<bd[i].x+width-10&&y>bd[i].y-height-40&&y<bd[i].y+height-40)){
    moveDir=0;
    t=-100;
    r=1; 
    btm=base+200-y;
    base=base-btm;
   }
  }
 }
 
 public void keyReleased(KeyEvent e) {
  // TODO Auto-generated method stub
 // System.out.println(e.getKeyChar());    
  kp = false; 
  isMove=false;
  
 }
 @Override
 public void keyTyped(KeyEvent e) {
  // TODO Auto-generated method stub   
 }
}

游戏运行结果截图如下图:

游戏运行结果截图如下图:

PSP时间统计

步骤

耗时

百分比

需求分析

25min

8.2%

设计

80min

26.2%

代码实现

120min

39.3%

测试

50min

18%

分析总结

25min

8.2%

7.实验总结

通过本次试验我对Java有了更深的认识,了解了它的许多功能都非常实用,在以后的练习中将多加练习。通过Java编写的小程序让我对Java更加“佩服”,由于自己的

水平太有限,所以从网上参考了许多,让我了解到学习课本的知识是远远不足,所以在今后的任然需要努力。

结对同学blog地址:http://www.cnblogs.com/lv-20135229/p/4553600.html

http://www.cnblogs.com/lv-20135229/p/4553600.html

posted on 2015-06-06 16:34  20135237朱国庆  阅读(242)  评论(0编辑  收藏  举报