1、实验内容
1. XP基础
2. XP核心实践
3. 相关工具
2、实验步骤
(一)敏捷开发与XP
软件工程是把系统的、有序的、可量化的方法应用到软件的开发、运营和维护上的过程。软件工程包括下列领域:软件需求分析、软件设计、软件构建、软件测试和软件维护。 人们在开发、运营、维护软件的过程当中有不少技术、作法、习惯和思想体系。软件工程把这些相关的技术和过程统一到一个体系中,叫“软件开发流程”。软件开发流程的目的是为了提升软件开发、运营、维护的效率,并提升软件的质量、用户满意度、可靠性和软件的可维护性。 光有各类流程的思想是不够的,咱们还要有一系列的工具来保证这些思想可以在实践中有效率地运做。软件开发很重要的一点不是看你能对多少理论讲的头头是道,还要看你对相关工具应用的如何,好比Java中单元测试要和JUnit的应用结合起来,建模要和Umbrello或StarUML的应用结合起来。编程学习是一个习而学
的过程。 常见的开发流程有:php
- RUP(Rational Unified Process)
- PSP(Personal Software Process )
- TSP(Team Software Process )
- Agile Process
- ……
敏捷开发包括不少模式:html
其中,极限编程(eXtreme Programming,XP)是是一种全新而快捷的软件开发方法。XP团队使用现场客户、特殊计划方法和持续测试来提供快速的反馈和全面的交流:java
- XP是以开发符合客户须要的软件为目标而产生的一种方法论
- XP是一种以实践为基础的软件工程过程和思想
- XP认为代码质量的重要程度超出人们通常所认为的程度
- XP特别适合于小型的有责任心的、自觉自励的团队开发需求不肯定或者迅速变化的软件
XP软件开发是什么样的
经过 XP准则来表达:linux
- 沟通 :XP认为项目成员之间的沟通是项目成功的关键,并把沟通看做项目中间协调与合做的主要推进因素。
- 简单 :XP假定将来不能可靠地预测,在如今考虑它从经济上是不明智的,因此不该该过多考虑将来的问题而是应该集中力量解决燃眉之急。
- 反馈 :XP认为系统自己及其代码是报告系统开发进度和状态的可靠依据。系统开发状态的反馈能够做为一种肯定系统开发进度和决定系统下一步开发方向的手段。
- 勇气:表明了XP认为人是软件开发中最重要的一个方面的观点。在一个软件产品的开发中人的参与贯穿其整个生命周期,是人的勇气来排除困境,让团队把局部的最优抛之脑后,达到更重大的目标。代表了XP对“人让项目取得成功”的基本信任态度。
一项实践在XP环境中成功使用的依据经过XP的法则
呈现,包括:快速反馈、假设简单性、递增更改、提倡更改、优质工做。git
XP软件开发的基石是XP的活动
,包括:编码、测试、倾听、设计。程序员
以测试为核心的开发流程:github
(二)编码标准
编写代码一个重要的认识是“程序大多时候是给人看的”,编程标准使代码更容易阅读和理解,甚至能够保证其中的错误更少。编程标准包含:具备说明性的名字、清晰的表达式、直截了当的控制流、可读的代码和注释,以及在追求这些内容时一致地使用某些规则和惯用法的重要性。算法
这个问题在Eclipse中比较容易解决,咱们单击Eclipse菜单中的source
->Format
或用快捷键Ctrl+Shift+F
就能够按Eclipse规定的规范缩进,效果以下:express
代码标准中很重要的一项是如何给包、类、变量、方法等标识符命名,能很好的命名可让本身的代码立立刻升一个档次。Java中的通常的命名规则有:编程
- 要体现各自的含义
- 包、类、变量用名词
- 方法名用动宾
- 包名所有小写,如:io,awt
- 类名第一个字母要大写,如:HelloWorldApp
- 变量名第一个字母要小写,如:userName
- 方法名第一个字母要小写:setName
- ...
有一些公司好比Google公开了本身的编码标准,能够做为学习不错的参考,你们参考一下范飞龙老师写的代码规范&代码风格,有兴趣的能够尝试如何在Eclipse中实践Google Java Style(中文版),也就是说如何作到“按一下快捷键Ctrl+Shift+F
就可让本身的代码符合Google Java Style(中文版)的要求”,完成后单独写一篇Blog,有加分的。
(三)结对编程
结对编程是XP中的重要实践。在结对编程模式下,一对程序员肩并肩、平等地、互补地进行开发工做。他们并排坐在一台电脑前,面对同一个显示器,使用同一个键盘、同一个鼠标一块儿工做。他们一块儿分析,一块儿设计,一块儿写测试用例,一块儿编码,一块儿作单元测试,一块儿作集成测试,一块儿写文档等。 结对编程中有两个角色:
- 驾驶员(Driver)是控制键盘输入的人。
- 领航员(Navigator)起到领航、提醒的做用。
结对编程和两人合做的重点是:
- 驾驶员:写设计文档,进行编码和单元测试等XP开发流程。
- 领航员:审阅驾驶员的文档、驾驶员对编码等开发流程的执行;考虑单元测试的覆盖率;思考是否须要和如何重构;帮助驾驶员解决具体的技术问题。
- 驾驶员和领航员不断轮换角色,不要连续工做超过一小时,每工做一小时休息15分钟。领航员要控制时间。
- 主动参与。任何一个任务都首先是两我的的责任,也是全部人的责任。没有“个人代码”、“你的代码”或“他/她的代码”,只有“咱们的代码”。
- 只有水平上的差距,没有级别上的差别。两人结对,尽管可能你们的级别资历不一样,但无论在分析、设计或编码上,双方都拥有平等的决策权利。
(四)版本控制
XP的集体全部制意味着每一个人都对全部的代码负责;这一点,反过来又意味着每一个人均可以更改代码的任意部分。结对编程
对这一实践贡献良多:借由在不一样的结对中工做,全部的程序员都能看到彻底的代码。集体全部制的一个主要优点是提高了开发程序的速度,由于一旦代码中出现错误,任何程序员都能修正它。 这意味着代码要放到一个你们都能方便获取的地方,咱们叫代码仓库。这引出另一个话题叫版本控制(Version Control)。
不管是对于团队仍是个体,版本控制都提供了不少好处。
- 版本控制提供项目级的 undo(撤销) 功能: 没有什么事情是终结版本, 任何错误必须很容易回滚。 假设你在使用世界上最复杂的文字处理系统。 它具有了全部的能想到的功能,就是没有支持 DELETE(删除) 键。想象你打字的时候得多么的谨慎和缓慢吧, 特别是一篇超大的文档的快临近末尾的时候, 一个不当心就要重头再来(试想你选中全部的文字, 不当心按了 DELETE 键, 由于没有撤销功能,只好从新录入)。编辑文字和版本控制相同,任什么时候候都须要回滚,不管是一个小时, 一天, 仍是一周, 这让你的团队工做自由快速的工做, 并且对于修正错误也很是自信。
- 版本控制容许多人在同一代码上工做, 只要遵照必定的控制原则就行。 不再会发生诸如一我的覆盖了另外一我的编辑的代码,致使那我的的修改无效这样的状况。
- 版本控制系统保存了过去所做的修改的历史记录。若是你遭遇到一些惊讶的代码,经过版本控制系统能够很容易找出是谁干的, 修改了什么, 修改的时间, 若是幸运的话,还能找出缘由。
- 版本控制系统还支持在主线上开发的同时发布多个软件版本。在软件发布的时候也不须要整个团队的中止工做,不须要冻结代码。
- 版本控制也是项目级的时间机器,你能够选择任何一个时间, 精确地查看项目在当时的状况。 这对研究很是有用, 也是重现之前某个有问题的发布版本的基础。
流行的版本控制工具备CVS,SVN,Git等。Git是Linus除了Linux操做系统外的另一个重要发明。
实验楼上线个人代码库功能,为你们提供实验环境内置的公开的git服务。学习的课程会自动建立一个公开的代码仓库,命名为shiyanlou_cs[课程ID]
,好比本课程的代码库命名shiyanlou_cs212
,为启动实验时会在环境中自动执行git pull
,获取课程仓库最新代码,存放在/home/shiyanlou/Code
目录。git push
操做须要手动完成,请务必在中止实验前push所有修改,不然代码就丢了。
好比个人专属用户名是pianogirl,则个人代码库连接为:http://git.shiyanlou.com/pianogirl, 《Java 程序设计》课程的代码仓库连接为:http://git.shiyanlou.com/pianogirl/shiyanlou_cs212,该课程实验环境中代码路径为:/home/shiyanlou/Code/shiyanlou_cs212.
使用方法以下:
- 若是对Git不熟悉,推荐先学习Git课程
- 开始实验时,若是您已经有了该课程的代码仓库则会自动同步(git pull)到实验环境中/home/shiyanlou/Code目录,若是尚未建立过则会自动建立并同步
- 进入到实验环境中修改代码,完成后须要依次执行下述命令便可提交:
$ cd /home/shiyanlou/Code/shiyanlou_cs212 # 修改代码文件 # 添加修改文件 $ git add 全部修改的文件 # 提交到环境中本地代码仓库 $ git commit -m '本次修改的描述' # push到git.shiyanlou.com,无需输入密码 $ git push
克隆其余用户代码仓库只须要知道对方的仓库连接,咱们鼓励在别人代码基础上修改:
$ git clone http://git.shiyanlou.com/[对方的专属用户名]/[课程代码仓库名]
咱们给一个HelloWorld
的例子: 首先进入Code
目录,你会发现有了shiyanlou_cs212
目录,进入shiyanlou_cs212
,以下图所示:
建立HelloWorld
目录,以下图所示:
建立并编辑HelloWorld.java
文件,以下图所示:
注意一点,往代码库提交的代码必定编译、运行、测试都没有问题的代码,咱们上面测试代码没有问题了,就能够提交了:
如图:咱们能够先用git status
查看一下代码状态,显示有未跟踪的代码,并建议用git add <file>...
添加,咱们使用git add HelloWorld.*
把要提交的文件的信息添加到索引库中。当咱们使用git commit
时,git将依据索引库中的内容来进行文件的提交。这只是在本地操做,关闭实验环境,会删除代码的,若是想把代码保存到远程托管服务器中,须要使用git push
,实验完成前,必定不要忘了使用git push
,不然就是至关于你在Word中编辑了半天文件最后却没有保存。 咱们能够修改HelloWorld.java
,以下图所示:
编译、运行、测试没有问题后进行提交,这儿使用的是git commit -a
:
咱们能够经过git log
查看代码提交记录:
有个问题是HelloWorld.class
是不该该保存在代码库中的,咱们只要有HelloWorld.java
就好了,这怎么办?经过搜索引擎解决一下。
固然,Git不是只有程序员才用到,全部须要"Undo"的场合,版本控制都能帮助你。参考一下Git for Non-Programmers(中文版)。
更进一步的学习,参考Git使用、工具、原理、进阶的几个连接
(五)重构
咱们先看看重构的概念:
重构(Refactor),就是在不改变软件外部行为的基础上,改变软件内部的结构,使其更加易于阅读、易于维护和易于变动 。
重构中一个很是关键的前提就是“不改变软件外部行为”,它保证了咱们在重构原有系统的同时,不会为原系统带来新的BUG,以确保重构的安全。如何保证不改变软件外部行为?重构后的代码要能经过单元测试。如何使其更加易于阅读、易于维护和易于变动 ?设计模式给出了重构的目标。
重构重要吗?你看看Eclipse菜单中有个refactor
菜单就知道了,重构几乎是现代IDE的标配了:
咱们在编码标准
中说“给标识符命名”是程序员一项重要技能,之前没有这个意识,如今知道了怎么办?没问题,上图中重构的第一项功能就是Rename
,能够给类、包、方法、变量更名字。 例如这有个ABC
类:
这个类,类名,方法名和方法的参数名都有问题,没有注释的话是没法理解代码的。咱们可使用Eclipse中的重构功能来更名。修改方法是,用鼠标单击要改的名字,选择Eclipse中菜单中的Refactor
->Rename...
:
重构完的效果以下:
功能不变,代码水平立立刻了一个档次,体会到命名的威力了吧?
学过C语言的学生学Java时常犯的毛病是不会封装,该用类的地方都用告终构体。好比要定义一个类Student
,会出现这样的代码:
Eclipse中菜单中的Refactor
->Encapsulate Field...
,以下图:
注意分析一下重构先后的代码变化:
一样能够封装id
和age
两个成员变量,结果以下:
上面第33行仍是有问题的,每次打印学生信息都这么写代码违反了DRY原则,形成代码重复,正常的重构可使用Eclipse中的Extract Method...
,以下图:
因为Java中全部的类都有个专门的toString方法,咱们使用Eclipse中Source
->Generate toString()...
给Student
类产生一个toString
方法
修改main的代码,结果以下:
你们想想,这样重构后有什么好处?重构有什么问题吗?
咱们要修改软件,万变不离其宗,无非就是四种动机:
- 增长新功能;
- 原有功能有BUG;
- 改善原有程序的结构;
- 优化原有系统的性能 。
第一种和第二种动机,都是源于客户的功能需求,而第四种是源于客户的非功能需求。软件的外部质量,其衡量的标准就是客户对软件功能需求与非功能需求的满意度。它涉及到一个企业、一个软件的信誉度与生命力,所以为全部软件企业所高度重视。要提升软件内部质量,毫无疑问就是软件修改的第三个动机:改善原有程序的结构。它的价值是隐性的,并不体如今某一次或两次开发中,而是逐渐体如今往后长期维护的软件过程当中。 高质量的软件,能够保证开发人员(即便是新手)可以轻易看懂软件代码,可以保证往后的每一次软件维护均可以轻易地完成(不论软件经历了多少次变动,维护了多少年),可以保证往后的每一次需求变动都可以轻易地进行(而不是伤筋动骨地大动)。要作到这几点其实并不容易,它须要咱们持续不断地对系统内部质量进行优化与改进。这,就是系统重构的价值。 下面一个重要问题是哪些地方须要重构?有臭味道(Bad Smell)的代码。 什么是臭味道?想象一下你打开冰箱门,出来一股臭味道你就知道冰箱里有东西腐坏了,要清除了。代码同样有臭味道:
臭味行列中首当其冲的就是Duplicated Code(重复的代码)。若是你在一个以上的地点看到相同的程序结构,那么当可确定:设法将它们合而为一,程序会变得更好。
- 最单纯的
Duplicated Code
就是[同一个class内的两个方法含有相同表达式(expression)]。这时候你须要作的就是采用Extract Method
提炼出重复的代码,而后让这两个地点都调用被提炼出来的那一段代码。 - 另外一种常见状况就是[两个互为兄弟(sibling)的subclasses内含有相同表达式]。要避免这种状况,只须要对两个classes都使用
Extract Method
,而后再对被提炼出的代码使用Pull Up Method
,将它推入superclass内。 - 若是代码之间只是相似,并不是彻底相同,那么就得运用
Extract Method
将类似部分和差别部分割开,构成单独一个方法。而后你可能发现或许能够运用Form Template Method
得到一个Template Method
设计模式。 - 若是有些方法以不一样的算法作相同的事,你能够择定其中较清晰的一个,并使用
Substitute Algorithm
将其它方法的算法替换掉。 - 若是两个绝不相关的classes内出现
Duplicaded Code
,你应该考虑对其中一个使用Extract Class
,将重复代码提炼到一个独立class中,而后在另外一个class内使用这个新class。可是,重复代码所在的方法也可能的确只应该属于某个class,另外一个class只能调用它,抑或这个方法可能属于第三个class,而另两个classes应该引用这第三个class。你必须决定这个方法放在哪儿最合适,并确保它被安置后就不会再在其它任何地方出现。
其余Bad Smell
与相应的重构手法以下表所示:
Eclipse中Refactor
菜单中的重构手法的应用时机以下图所示:
更完整的手法能够参考《重构》做者Martin Fowler的博客。Eclipse中基本手法的使用你们能够参考任何人均可以重构来进行学习实践。
一个完整的重构流程包括:
- 从版本控制系统代码库中Check out code
- 读懂代码(包括测试代码)
- 发现bad smell
- Refactoring
- 运行全部的Unit Tests
- 往代码库中Check in code
咱们结合Git给出一个比较完整的例子。
(六)实践项目
1. 以结对编程的方式编写一个软件,Blog中要给出结对同窗的Blog网址,能够拍照展示结对编程状况,能够参考一下其余学校的做业
队友blog网址:http://home.cnblogs.com/u/christyalaa/
2.代码
基本计算器
3.GUI界面
//面板容器类file name:CalculatorPanelClass.java
package Game.Calculator;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CalculatorPanelClass extends JPanel
{
private JLabel display;
private JPanel panel;
private double result;
private String lastCommand;
private boolean start;
public CalculatorPanelClass()
{
setLayout(new BorderLayout());
result = 0;
lastCommand = "=";
start = true;;
display = new JLabel("0",SwingConstants.RIGHT);
display.setForeground(Color.black); //设置前景颜色
display.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.black),
BorderFactory.createEmptyBorder(5,5,5,5)));
add(display, BorderLayout.NORTH);
ActionListener insert = new InsertAction();
ActionListener command = new CommandAction();
panel = new JPanel();
panel.setLayout(new GridLayout(4,4));//计算器按钮
addButton("7",insert);
addButton("8",insert);
addButton("9",insert);
addButton("/",command);
addButton("4",insert);
addButton("5",insert);
addButton("6",insert);
addButton("*",command);
addButton("1",insert);
addButton("2",insert);
addButton("3",insert);
addButton("-",command);
addButton("0",insert);
addButton(".",insert);
addButton("=",command);
addButton("+",command);
add(panel,BorderLayout.CENTER);
}
//在面板容器中添加按钮组件
private void addButton(String label,ActionListener listener)
{
JButton button = new JButton(label);
button.addActionListener(listener);
panel.add(button);
}
//处理单击数字按钮事件的监听器类
private class InsertAction implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
String input = event.getActionCommand();
if (start)
{
display.setText("");
start = false;
}
display.setText(display.getText() + input);
}
}
//处理单击命令按钮事件的监听器类
private class CommandAction implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
String command = evt.getActionCommand();
if(start)
{
lastCommand = command;
}
else
{
calculate(Double.parseDouble(display.getText()));
lastCommand = command;
start = true;
}
}
}
public void calculate(double x)
{
if (lastCommand.equals("+"))
{
result += x;
}else if (lastCommand.equals("-"))
{
result -= x;
}else if (lastCommand.equals("*"))
{
result *= x;
}else if (lastCommand.equals("/"))
{
result /= x;
}else if (lastCommand.equals("="))
{
result = x;
}
display.setText("" +result);
}
}
//定义外层窗口类CalculatorFrameClass
//file name:CalculatorFrameClass.java
package Game.Calculator;
import java.awt.*;
import javax.swing.*;
public class CalculatorFrameClass extends JFrame//外层窗口类
{
public CalculatorFrameClass()
{
setTitle("Calculator");
Container contentPane = getContentPane();
CalculatorPanelClass panel = new CalculatorPanelClass();
contentPane.add(panel);
setSize(400,400);
setVisible(true);
setResizable(false);
}
}
//测试类TestCalculatorClass.java
package Game.Calculator;
import javax.swing.*;
public class TestCalculatorClass
{
public static void main(String[] args)
{
CalculatorFrameClass frame = new CalculatorFrameClass();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
4.实验报告中统计本身的PSP(Personal Software Process)时间
步骤 | 耗时 | 百分比 |
---|---|---|
需求分析 | 半天 | 20% |
设计 | 半天 | 20% |
代码实现 | 一天 | 40% |
测试 | 半天 | 20% |
分析总结 |
3、实验中遇到的问题
1.vim的使用
(1)保存及其余方法
第一级
当你安装好一个编辑器后,你必定会想在其中输入点什么东西,而后看看这个编辑器是什么样子。但vim不是这样的,按照下面的命令操做:
- 启 动Vim后,vim在 Normal 模式下。
- 让咱们进入 Insert 模式,请按下键 i 。(陈皓注:你会看到vim左下角有一个–insert–字样,表示,你能够以插入的方式输入了)
- 此时,你能够输入文本了,就像你用“记事本”同样。
- 若是你想返回 Normal 模式,请按
ESC
键。
如今,知道如何在 Insert 和 Normal 模式下切换了。下面是一些命令:
i
→ Insert 模式,按ESC
回到 Normal 模式.x
→ 删当前光标所在的一个字符。:wq
→ 存盘 + 退出 (:w
存盘,:q
退出) (陈皓注::w 后能够跟文件名)dd
→ 删除当前行,并把删除的行存到剪贴板里p
→ 粘贴剪贴板推荐:
hjkl
(强例推荐使用其移动光标,但没必要需) →你也可使用光标键 (←↓↑→). 注:j
就像下箭头。:help <command>
→ 显示相关命令的帮助。你也能够就输入:help
而不跟命令。(陈皓注:退出帮助须要输入:q)
你能在vim幸存下来只须要上述的那5个命令,你就能够编辑文本了,你必定要把这些命令练成一种下意识的状态。因而你就能够开始进阶到第二级了。
当是,在你进入第二级时,须要再说一下 Normal 模式。在通常的编辑器下,当你须要copy一段文字的时候,你须要使用 Ctrl
键,好比:Ctrl-C
。也就是说,Ctrl键就好像功能键同样,当你按下了功能键Ctrl后,C就不在是C了,并且就是一个命令或是一个快键键了,在VIM的Normal模式下,全部的键就是功能键了。这个你须要知道。
标记:
- 下面的文字中,若是是
Ctrl-λ
我会写成<C-λ>
. - 以
:
开始的命令你须要输入<enter>
回车,例如 — 若是我写成:q
也就是说你要输入:q<enter>
.
第二级
上面的那些命令只能让你存活下来,如今是时候学习一些更多的命令了,下面是个人建议:(陈皓注:全部的命令都须要在Normal模式下使用,若是你不知道如今在什么样的模式,你就狂按几回ESC键)
- 各类插入模式
a
→ 在光标后插入o
→ 在当前行后插入一个新行O
→ 在当前行前插入一个新行cw
→ 替换从光标所在位置后到一个单词结尾的字符
- 简单的移动光标
0
→ 数字零,到行头^
→ 到本行第一个不是blank字符的位置(所谓blank字符就是空格,tab,换行,回车等)$
→ 到本行行尾g_
→ 到本行最后一个不是blank字符的位置。/pattern
→ 搜索pattern
的字符串(陈皓注:若是搜索出多个匹配,可按n键到下一个)
- 拷贝/粘贴 (陈皓注:p/P均可以,p是表示在当前位置以后,P表示在当前位置以前)
P
→ 粘贴yy
→ 拷贝当前行当行于ddP
- Undo/Redo
u
→ undo<C-r>
→ redo
- 打开/保存/退出/改变文件(Buffer)
:e <path/to/file>
→ 打开一个文件:w
→ 存盘:saveas <path/to/file>
→ 另存为<path/to/file>
:x
,ZZ
或:wq
→ 保存并退出 (:x
表示仅在须要时保存,ZZ不须要输入冒号并回车):q!
→ 退出不保存:qa!
强行退出全部的正在编辑的文件,就算别的文件有更改。:bn
和:bp
→ 你能够同时打开不少文件,使用这两个命令来切换下一个或上一个文件。(陈皓注:我喜欢使用:n到下一个文件)
花点时间熟悉一下上面的命令,一旦你掌握他们了,你就几乎能够干其它编辑器都能干的事了。可是到如今为止,你仍是以为使用vim仍是有点笨拙,不过不要紧,你能够进阶到第三级了。
(2)建立文件时注意的问题
在学会vim的使用方法后发现仍找不到文件,如图
才知道建立时命名错误。
4、实验总结
一开始不懂vim使用,浪费了好多时间。之后要作好准备工做。