 | Level: Introductory Roy Miller (rmiller@rolemodelsoft.com), Software Developer, RoleModel Software, Inc.
27 May 2003 Teams that want to give XP a try often don't know where to start. Typically, they have lots of questions about the XP practices. But what comes after technique? This month, Roy Miller puts the theory into practice as he discusses what tools you should use and how you should use them.
When it comes to the tools you need to implement XP, the bad news is that there is usually a bit of a learning curve. The good news is that there are embarrassingly few tools you need in the first place. You do not need lots of document authoring tools and design tools to make great software. In the end, you need a few non-technical supplies, a couple pieces of software, and some dedicated team members. Remember that XP is all about doing the simplest thing that could possibly work. That applies to design, code, process, and tools.
I've written software and managed projects for ten years. During that time, I've used a good number of tools for managing and coding. Having done that, I feel comfortable saying that people rely on tools too much. Tools have their place, but there's no substitute for skill and experience.
I recommend that you and your teams start -- and perhaps remain -- with relatively simple tools that offer lots of power and capability in exchange for a non-trivial learning curve. Assuming you're working with the Java language (this is the Java technology zone, after all), consider the following tools for use on your projects:
-
Eclipse as your primary team-friendly development environment
- Your favorite source code control tool (I've used CVS for as long I've used Eclipse)
- JUnit for programmer tests, and possibly as an engine for customer tests
- HttpUnit for testing Web applications
- Ant for building your application every day
- Shams for stubbing out components you haven't built yet, in tests that need those components to exist
We'll be focusing our efforts in this article on using Eclipse, JUnit, and Ant effectively. (HttpUnit is the subject of an upcoming article, and we covered shams last time in "Test-driven programming".)
Getting started with Eclipse
I've used several IDEs in my career as a programmer. When I first started using VisualAge for Java (VAJ), the learning curve seemed overwhelming, but after two or three weeks I wondered how anybody ever wrote Java software without VAJ. It was the most amazing IDE I had ever worked with. Still, Eclipse is better -- and it's free (really).
Eclipse is based on a simple premise: there ought to be a truly integrated development environment for teams. The entire application is written in the Java language for developing in the Java language. If you want to see rich, well-factored code, take a look at the source for Eclipse. The application is really a framework for building applications, based on a plug-in architecture. Pretty much everything in Eclipse is a plug-in -- even the support for Java language development. There's a core platform that everything else plugs into. There are lots of articles on the Eclipse site and here at developerWorks (see Resources) about how to get started, so I'll only give a quick overview of how to use the tool.
Installation is simple. Go to the Eclipse downloads page, pick a mirror site, and download the latest stable build or the latest release (2.1). Don't feel like you have to wait for a new release to upgrade Eclipse -- the folks on the Eclipse team are definitely test-first, and they make available their entire suite of tests so you can check to make sure a stable build is, well, stable.
Once you've downloaded the release, complete the following steps to install and run it (assuming you use some flavor of Windows):
- Install JDK 1.4 (see Resources for information on downloading it if you don't have it already).
- Extract the Eclipse zip file to C:\eclipse.
- Create a separate directory on your hard drive called
C:\EclipseWorkspaces.
- Create a shortcut on your Start menu to
C:\eclipse\eclipse.exe -data C:\EclipseWorkspaces\<your workspace name> that starts in C:\eclipse.
- Double-click your new shortcut. Eclipse will create a subdirectory for your workspace in
C:\EclipseWorkspaces.
When Eclipse starts up the first time, you'll see something like Figure 1:
Figure 1. Eclipse Welcome screen
The Welcome screen is part of the Resource perspective of the Eclipse Workspace. This perspective gives you a view of all the files in your workspace. The list shows up in the Navigator view at the upper-left corner. Eclipse is completely customizable, and you can move views around anywhere you want. For now, we'll leave them alone and go to the Java Browsing perspective. You can see which perspectives are available by selecting Window >Open Perspective. Select the Java Browsing perspective, which is shown in Figure 2:
Figure 2. The Java Browsing perspective
The Java Browsing perspective has four views at the top and an editor at the bottom. The four views, from left to right, show Projects, Packages, Types, and Members. Packages, Types, and Members are all Java language constructs you should be familiar with. Projects are Eclipse meta containers for Java packages. This perspective is where you'll do most of your development, although the Resource perspective comes in handy for dealing with files other than source and class files.
To get started developing, complete the following steps to create a Java project called Sample:
- Click Window >Preferences >Java >New Project.
- Click the Folder radio button, then click OK.
- Click File >New >Project.
- Select Java Project, then click Next.
- Enter Sample for the project name, then click Finish.
You should now see the Sample project in the Projects view. At this point, click the Create a Java Package button on the toolbar and create a package called com.sample. Select that package. Now you're ready to create your first Java class and see how Eclipse helps the XP development flow.
JUnit
The single biggest impact to my software development career in the past ten years has been XP. As a programmer, the practice (XP or otherwise) that has had the biggest impact is writing tests before I write code. As I said last month, writing just enough code to make a test pass keeps code simpler and keeps me focused on the task at hand. I talked about some of the mechanics of using JUnit last month, but I'll go into a little more detail here.
JUnit comes with Eclipse, so you don't have to download it. If you're not using Eclipse, you can download JUnit (see Resources). To use JUnit, you must first put the JUnit JAR on your project's build path, and create a test class. Complete the following steps to put JUnit on the project's build path:
- Right-click the
Sample project and select Properties at the bottom of the context menu.
- Select Java Build Path.
- Select the Libraries tab.
- Click the Add Variable button.
- Click the New button and enter JUNIT_LIB as the variable name.
- Edit that variable and point to a file in
C:\eclipse\plugins\org.junit_3.8.1 (JUnit is an Eclipse plug-in).
- Select the src folder in your Sample project again.
Now you have JUnit on your build path. You could have added an external JAR to the path directly, but using variables makes it easier to set up workspaces on other machines (the variable is a meta name that can point to a machine-specific location). The next step is to create a test class:
- Click the drop-down arrow to the right of the Create a Java Class button on the toolbar and select Test Case.
- Enter TC_Account as the test name.
- Select the setUp() and tearDown() check boxes.
- Click Finish.
You should now see a screen that looks similar to Figure 3:
Figure 3. Open test case
You now have the TC_Account class listed in the Types view, and you can see the methods on that class in the Members view. You also have an editor open on the TC_Account class, with lots of generated code and comments in it. I prefer to set up my preferences to prevent all the generated comments from showing up, which you can do by selecting Window >Preferences >Java >Code Generation.
What will the Account class do? Let's start with being able to add money to the account. That would require a method something like this:
public void deposit(int amount)
|
Add a method to TestCase that will test the deposit method on Account. The test class should now look like Listing 1:
Listing 1. JUnit test
package com.sample;
import junit.framework.TestCase;
public class TC_Account extends TestCase {
public TC_Account(String arg0) {
super(arg0);
}
protected void setUp() throws Exception {
super.setUp();
}
public void testDeposit() {
Account account = new Account();
assertEquals("Account should start with no
funds.", 0, account.balance());
}
protected void tearDown() throws Exception {
super.tearDown();
}
}
|
In English, you're checking that account.balance() returns 0. Note that the test doesn't even compile, because the Account class doesn't exist yet. Figure 4 shows what the workspace looks like when the test doesn't compile:
Figure 4. Test case that doesn't compile
The Tasks view at the bottom of the screen shows the compile errors. Clicking on any of the errors takes you to that exact spot in the code, which is very handy, indeed. In fact, Eclipse has lots of little conveniences like this. For example, notice that there are multiple ways to see that you have a compile problem. The Tasks view shows it, the editor has a red X circle at the left, and all of the views at the top of the workspace show a red X. If you hover over the red X at the left of the editor (next to the line with the error), the hover text gives you the error message.
Feel free to hover over things, click on things, and do other experiments to find "hidden" features. They're all over the place. But back to the task at hand -- the test doesn't compile. So, write just enough code to get the test to compile, run, and fail. Remember, we're trying to take baby steps and keep things as simple as possible for as long as possible. Create the Account class by selecting the com.sample project, clicking the Create Java Class button on the toolbar, entering Account as the name for the class, then clicking Finish. You now should have an editor open on the Account class, which should have no methods at all. Add the balance() method. The class should now look like Listing 2:
Listing 2. Account class
package com.sample;
public class Account {
public int balance() {
return 0;
}
}
|
To run the test, select the TC_Account type, click the drop-down arrow next to the "running man" icon on the toolbar, and select Run As >JUnit Test. The test will run and will show up as a view at the bottom of the screen. I prefer to make JUnit a Fast view by dragging it to the left side of the workspace until Eclipse lets me drop the JUnit view on the Fast view bar. At this point, select Window >Preferences >Java >JUnit and check the Show the JUnit results view only when a failure or error occurs check box. That will keep the JUnit Fast view hidden unless there's an error or failure. If everything went well, it will show a green check in the lower-left corner of the icon. It's less obtrusive that way.
Writing just enough code to get the test to compile gave you a passing test this time, but not for long. Now add another assertion to the test case to test the new balance after somebody calls the deposit() method. The testDeposit() method should now look like Listing 3:
Listing 3. JUnit test for deposit() method
public void testDeposit() {
Account account = new Account();
assertEquals("Account should start with
no funds.", 0, account.balance());
account.deposit(5);
assertEquals("Account should reflect
deposit.", 5, account.balance());
}
|
Write just enough code to make the test compile. In this case, that means adding the do-nothing deposit() method to Account. The class should now look like Listing 4:
Listing 4. Account with empty deposit() method
package com.sample;
public class Account {
protected int balance;
public int balance() {
return balance;
}
public void deposit(int amount) {
}
}
|
Rerun the tests by clicking on the running man icon again. The JUnit Fast View expands and you see a failure with the "Account should reflect deposit" message. Now you have a failing test that tells you exactly what code to write. Write just enough to get the test to pass. Having the deposit() method add the deposit amount to balance should be enough. When you rerun the tests, they should pass.
This "write a test, write just enough code to get it to pass, rerun the test" approach is the XP development flow that you should experience every day. With JUnit being integrated into Eclipse, everything you need to concentrate on coding is right there. Running tests is as easy as breathing. Creating them is easier as well, because Eclipse saves you lots of mundane typing by generating code. You still have to think, but only about the important things. Your Account class should now look like Listing 5:
Listing 5. Account with implemented deposit() method
package com.sample;
public class Account {
protected int balance;
public int balance() {
return balance;
}
public void deposit(int amount) {
balance += amount;
}
}
|
Being able to deposit money is good, but people probably want to take it out as well. Write a test for the withdraw() method on Account. Your test should now look like Listing 6:
Listing 6. Updated test for Account
package com.sample;
import junit.framework.TestCase;
public class TC_Account extends TestCase {
public TC_Account(String arg0) {
super(arg0);
}
protected void setUp() throws Exception {
super.setUp();
}
public void testDeposit() {
Account account = new Account();
assertEquals("Account should start with
no funds.", 0, account.balance());
account.deposit(5);
assertEquals("Account should reflect
deposit.", 5, account.balance());
}
public void testWithdraw() {
Account account = new Account();
account.balance = 5;
account.withdraw(3);
assertEquals("Account should reflect
withdrawal.", 2, account.balance());
}
protected void tearDown() throws Exception {
super.tearDown();
}
}
|
Get the test to compile by adding the do-nothing withdraw() method to Account, then rerun the tests. They should fail. Now implement the withdraw method. The Account class should look like Listing 7:
Listing 7. Account with implemented withdraw() method
package com.sample;
public class Account {
protected int balance;
public int balance() {
return balance;
}
public void deposit(int amount) {
balance += amount;
}
public void withdraw(int amount) {
balance -= amount;
}
}
|
All the tests should pass. Now it's time to integrate. Huh? You'll recall that "Continuous Integration" is an important practice in XP. Anytime all the tests pass, you can integrate code into the system. You should do so early and often. Eclipse makes this outrageously easy.
Integrate, integrate, integrate
To prepare your Eclipse workspace for integration, complete the following steps; you'll need to have CVS set up for this process:
- Select Window >Open Perspective >Other >CVS Repository Exploring to open the CVS perspective.
- Right-click and select New Repository Location. Enter all the parameters specific to your particular setup, then click Finish. You should end up with a repository location in the list in the CVS Repositories view. Expand it and you'll see a HEAD stream, a Branches entry, and a Versions entry. The HEAD stream is the main code stream that users should be integrating to (if they want to branch off on their own and then merge with the HEAD stream later, that's fine).
- Close the CVS perspective window.
To integrate your code into the system, complete the following steps:
- Right-click the
Sample project.
- Select Team >Share Project. You're "sharing" a project that hasn't been integrated before. You usually only have to do this once.
- When prompted, select the repository location you want, then click Finish.
Now the XP flow goes like this: "write a test, write just enough code to make the test pass, rerun the test, integrate."
Now, take a look at TC_Account. Notice any code duplication there? Both test methods instantiate an Account. The JUnit framework runs the setUp() method before each test method, so that's the logical place to do any set up that every test needs. Instantiating the Account object qualifies.
That's a simple refactoring, but Eclipse makes it even easier:
- Go to the editor for
TC_Account.
- Right-click the
account local variable in testDeposit(), then select Refactor >Convert Local Variable to Field.
- Enter "account" as the name for the field, select the
protected access qualifier, then click OK. Your test class now has a protected field called account, and the test method initializes it.
- Move the line that initializes
account from the test method to setUp(), then delete the declaration and initialization from the other test method. Your test class should now look like Listing 8:
Listing 8. Refactored TC_Account
package com.sample;
import junit.framework.TestCase;
public class TC_Account extends TestCase {
protected Account account;
public TC_Account(String arg0) {
super(arg0);
}
protected void setUp() throws Exception {
super.setUp();
account = new Account();
}
public void testDeposit() {
assertEquals("Account should start with
no funds.", 0, account.balance());
account.deposit(5);
assertEquals("Account should reflect
deposit.", 5, account.balance());
}
public void testWithdraw() {
account.balance = 5;
account.withdraw(3);
assertEquals("Account should reflect
withdrawal.", 2, account.balance());
}
protected void tearDown() throws Exception {
super.tearDown();
}
}
|
You still had to do some work, but Eclipse saved you at least some of the more tedious typing. After a while, those savings pile up. Check out the other refactorings available on the context menu. Some are quite powerful and can save you lots of time:
- Go to the editor for
Account, then right-click the balance() method name.
- Select Refactor >Rename, then enter "getBalance" as the new name.
- Make sure "Update references to the renamed element" is checked, then click OK.
That simple exercise renamed the accessor method on Account and updated all references to it. Rerun the tests to make sure everything still works. That easily saved a minute or more of typing for just one class. Imagine you've got a huge system and multiple classes call getBalance. Feel free to dance in the streets. And the best thing is that refactorings are undoable. If you fat-finger the new name and type "getbalancew," just undo. Better yet, since it's so easy, just refactor again and change the name.
Time to integrate again. Remember the flow? We changed some code and reran the tests:
- Right-click the
Sample project, then select Team >Synchronize with Repository to open the Synchronize view at the bottom of the screen. Double-click the blue title bar to expand it.
- Click the Incoming/Outgoing Mode button on the right side of the toolbar. This view shows you all the incoming and outgoing changes. In other words, Eclipse interfaces with CVS to show you deltas between what's in your workspace and what's in CVS.
- Since you've never committed anything before, right-click the
Sample project in the Structure Compare view, then select Commit.
To see what would happen if there were a delta, go back to the Account class, right-click the amount parameter to the deposit() method, then select Refactor >Rename. Change the name to "anAmount." Voila! It's changed. Rerun the tests. Everything should pass. Now right-click the project and synchronize again. You should see a screen similar to Figure 5. If you double-click the Account class, you'll see the delta you just created. Because you want to keep it, right-click the project and select Commit.
Figure 5. The Synchronize view
Building with Ant
As soon as possible after a project starts, every XP team ought to build their entire system at the end of every day. That allows the team to give a running system to anybody who needs to see it (the Customer, for example). It also provides a checkpoint for the team. If something goes terribly wrong, they can always go back to the running system from yesterday. Nothing like a safety net to make the team more confident.
The Ant project from Jakarta is a nice build tool. You write your build scripts in XML. I find the XML "targets" a bit cryptic, but that fades with time as you get more familiar with what's going on. I must confess, though, if I don't use Ant for a while, I have to go back and look up a lot of the information just to do basic things. In any case, Eclipse comes with an Ant plug-in that works very well. The integration is almost seamless.
Let's create a sample build for our project that copies the files to a deployment directory on the hard drive somewhere (in real life, this might be a network drive or some other drive):
- Select the
Sample project in the workspace.
- Select File >New >Other.
- Select Simple, then select File.
- Name the new file build.xml. Eclipse creates the file and opens an editor on it (notice that the icon in the title bar is a nice Ant icon). Your build script should look like Listing 9:
Listing 9. The Build script
<project name="Sample" default="build" basedir=".">
<property name="project" value="${basedir}"/>
<property name="tempDirectory" value="${project}/temp"/>
<property name="runtimeClasses"
location="${project}/lib/runtime.jar"/>
<property name="deployDirectory" location="c:/deploy"/>
<patternset id="non.test.classes" >
<include name="**/*.class"/>
<exclude name="**/TC_*.class"/>
</patternset>
<target name="build">
<antcall target="clean"/>
<antcall target="init"/>
<antcall target="build.Sample"/>
<antcall target="clean"/>
</target>
<target name="init">
<mkdir dir="${tempDirectory}"/>
<mkdir dir="${deployDirectory}"/>
</target>
<target name="build.Sample">
<javac srcdir="${project}/src"
destdir="${tempDirectory}"
>
<exclude name="**/TC_*.java"/>
</javac>
<jar destfile="${deployDirectory}/sample.jar">
<fileset dir="${tempDirectory}"></fileset>
</jar>
</target>
<target name="clean">
<delete dir="${tempDirectory}"/>
</target>
</project>
|
Ant is based on targets, which describe units of work for Ant to run. In this case, you have three targets. The first is the main target, called build. The default attribute of the project tag identifies build as the default target. That target calls three others: clean, init, and build.Sample. If this were Java code, you might describe the default target as a delegator method -- it calls the other targets in the right order (in a sense, it's an implementation of the Template Method pattern). This main target first calls clean to make sure things start fresh, then init to set up necessary directories. Next, it calls build.Sample and then clean again. The build.Sample target is where the action is. With build.Sample, you can:
- Create a deployment directory on the local hard drive
- Compile all of your
Sample project source, excluding test cases (no need to deploy those), to a temporary directory
- JAR up the compiled classes in the temporary directory and put them in the deployment directory
To run the Ant script, go to the Resource perspective, right-click build.xml, and select Run Ant. That brings up a dialog with the default target already selected. Click Run. If there's a failure, Eclipse will show the Ant Console at the bottom of the screen. This is my biggest gripe about Ant: if something goes wrong, debugging can be a bear. Fortunately, the Echo Ant target gives you the equivalent of System.out.println(). If something goes wrong in your script, stick <echo>some helpful message</echo> in there to help you figure out what's going on. In the current case, the error is a tricky one. Ant complains that it can't find tools.jar. You need to tell Ant where to find the Java classes necessary to compile stuff. To do that, follow these steps:
- Select the
Sample project.
- Select File >Import, then select File System.
- Browse to the
lib directory in your installed JDK.
- Select the
tools.jar file, then click Finish.
Completing this series of steps creates a lib directory in the Sample project and puts tools.jar in it. Now tell Ant how to find it:
- Select Preferences >Ant >Runtime. "Additional classpath entries:" should be at the bottom.
- Click the Add JARs... button, then select Sample/lib/tools.jar. Now Ant knows how to find your compiler.
- Right-click
build.xml and rerun Ant. There should be no errors, and you should end up with sample.jar in c:\deploy.
The benefit of tools
You'll notice that there aren't many tools on the "must have" list. There may be other Eclipse plug-ins that you'll want to get, perhaps, and you probably need some extra Java language libraries to support your particular project, but you don't need the pile of tools that lots of project teams assume they need. If you're using XP, the only management tools you need are some note cards and maybe a spreadsheet. Everything else is a developer tool, and the list of those should remain small. I think you should resist adding more unless they make life easier. When they do, by all means use them. Good tools can make the difference between an ugly project and an enjoyable one. Eclipse, JUnit (as well as other test helpers like shams and HttpUnit), and Ant are at the top of my list. And if you need an application server, use Tomcat until somebody says you're not allowed to.
Resources - Participate in the discussion forum.
- Are you joining this column late in the game? See where it all started, with the first article co-written with Chris Collins, "XP distilled" (developerWorks, March 2001). Then, take a look at the complete set of articles from this column.
- Read Java Tools for Extreme Programming by Richard Hightower and Nicholas Lesiecki for a book-length description of various Java tools that support XP, including JUnit and Ant.
- Erik Hatcher shows you how he modified the popular Ant 1.3 and the JUnit test framework for complete, customized automation of the build and test process (developerWorks, August 2001).
- One of the most powerful features in Eclipse is a set of automated refactorings, as described in this article by Daniel Steinberg (developerWorks, November 2001).
- Download Eclipse and read some of the many excellent technical articles available at eclipse.org.
- The developerWorks Open source projects offers a wealth of information on Eclipse.
- JUnit is a great tool for writing programmer tests in the Java language. This site has links to lots of papers and tools.
- Find out why VisualAge for Java is a great tool for XP teams in "Extreme Programming with IBM VisualAge for Java" (developerWorks, April 2001).
- You'll find hundreds of articles about every aspect of Java programming in the
developerWorks Java technology zone.
About the author  | |  | Roy W. Miller has been a software developer and technology consultant for almost ten years, first with Andersen Consulting (now Accenture) and currently with RoleModel Software, Inc. in North Carolina. He has used heavyweight methods and agile ones, including XP. He co-authored a book in the Addison-Wesley XP Series (Extreme Programming Applied: Playing to Win) and is currently writing a book about complexity, emergence, and software development (the working title is Growing Software: Debunking the Myth of Prediction and Control). Contact Roy at rmiller@rolemodelsoft.com. or roy@roywmiller.com.. You can also visit his personal Web site at www.roywmiller.com. |
Rate this page
|  |