Skip to main content

Applying Rational tools to a simple J2EE-based project Part 6: Early development

Steven Franklin, Software Design and Process Specialist, Software Design and Process Specialist
Steven Franklin has an extensive background in software design, architecture, and engineering process, which he usually applies to large, distributed information management and command and control systems. He's been using Rational tools since 1997, and his primary areas of interest include XML, J2EE, wireless, and software engineering methodologies. Steven can be reached via e-mail.

Summary:  This installment focuses on putting a development approach in place and using Rational tools during early development. Here, Rose is used for reverse engineering to keep the design and code in sync. Purify and Quantify then track memory use and performance.

Date:  04 Dec 2003
Level:  Introductory
Activity:  334 views

This is the sixth installment of a multiple-part article (as outlined below) that demonstrates using Rational's tools in a distributed, J2EE-based project.

  • Part 1: project introduction; high-level planning
  • Part 2: detailed planning; risk management; requirements management
  • Part 3: Rational Rose model creation and access control; requirements analysis
  • Part 4: use-case refinement; report generation; tool and technology selection
  • Part 5: architecture and design
  • Part 6: detailed design; early development; round-trip engineering; early unit tests
  • Part 7: continued development; early builds; demonstrations
  • Part 8: strategies for unit testing; function tests; GUI test scripts
  • Part 9: system builds and testing; defect tracking; product acceptance
  • Part 10: project results; conclusions; future work

The fictional premise of the article is that we're a software company, Lookoff Technologies Incorporated, and our customer, Audiophile Speaker Design, Inc. (ASDI), has hired us to meet their burgeoning IT requirements. For a more detailed introduction to the project, see Part 1.

This installment discusses the team's progressing into implementation, and hence into the RUP's construction phase. We'd sorted out most of the technologies that would be involved in Phase 1 of the ASDI project. The design was in fairly good shape, although the package structure and design discussed in Part 5 continued to evolve over the next week or two. For instance, portions of the package structure were reworked to reflect the anticipated Java package-naming convention.

Part 6 Snapshot

Tools and technologies demonstrated in Part 6:

  • Rational Rose Enterprise v2001A -- For round-trip engineering
  • Rational Purify v2001A -- For inspecting Java memory use
  • Rational Quantify v2001A -- For understanding performance bottlenecks
  • J2SE (Java 2 Platform, Standard Edition) 1.3 -- Sun's Java reference implementation
  • Jikes -- IBM's high-speed compiler (replacement for javac from Sun)
  • Castor -- Data-binding framework from the ExoLab Group, for binding XML to Java and vice versa

Artifacts created or updated:

  • Design model (Rational Rose) -- Updated as the code progressed
  • Java code -- Created for the command gateway and other subsystems

Paving the Way

Before development could get underway, we had to accomplish the following at the management and team lead level:

  • Set up guidelines and informal training sessions so that the engineering team would all be on the same page with respect to coding and design conventions.
  • Update the original team structure (shown in Part 2) to reflect the different needs of implementation as compared to design.
  • Set up the development strategy and environment such that our developers could collaborate efficiently, work on their part of system without impeding others, and easily test their code.
  • Have tight tracking in place to ensure that tasks were being completed on schedule and satisfying their objectives.

Guidelines and Standards

The RUP emphasizes the importance of peer reviews as a product is being constructed; we'll look at this in more detail later. The team has to agree on the criteria for peer reviews, to avoid going to either of two extremes: lightweight reviews that add very little value, or overly rigorous reviews that yield lots of comments along the lines of "This works, but here's how I'd do it."

For our Java code, we created a coding standards document based heavily on the AmbySoft Inc. Java coding standards. These standards proved invaluable as they were enforced during our peer reviews. Not only did they result in a more consistent and higher-quality deliverable for the customer, but they allowed us to move team members between subsystems (and projects) more easily. We found that developers integrated much more quickly into the team if the code style and construction were familiar to them. By avoiding obscure naming practices, inadequate commenting, and poor coding style, they created code that was much easier for another developer to take over.

Training

As a general rule, the engineers at Lookoff tried to stay ahead of the technology curve as needed to remain competitive in the business; however, some projects introduced new technologies that required team training. We weren't placed in this situation on the ASDI project, because the architecture and technologies were familiar to us. Our training for this project was instead on the use of Rational tools, UML, Java coding standards, and J2EE design patterns. Although we had some excellent knowledge in all of these areas, much of it was in the head of the team lead. Consequently, the training consisted of informal lunchtime and afternoon sessions put on by the team lead. We found these sessions, which lasted from one hour to half a day, to be very cost-effective (but of course they only work if you have a sufficiently knowledgeable team member with good communication skills).

Because the topics were relevant throughout the company, we encouraged other technical staff at Lookoff to attend these training sessions. We found that having a larger technical audience resulted in an even more valuable exchange of ideas. At the very least, we scheduled the sessions such that they could be attended by all engineers on the ASDI project (whether involved in analysis, design, implementation, or in some cases even testing).

Team Structure Evolution

The team structure evolved from what it had been during the analysis of the system, to meet the different needs during implementation. As shown in Table 1, most of the time commitments had changed, and five new positions were added.

  Role During analysis During implementation
Project management Project manager50%25%
Accounting support15%25%
QA10% 25%
Project engineering Project engineer50%25%
Team lead/senior analyst100%75%
Engineering support, other than configuration management (CM)20% 10%
Engineering support: CM20%40%
Support and review team10%5%
Senior developer100%100%
Junior developer100%100%
Database architect25%25%
Senior developer (remote) --100%
Intermediate-level developer (remote) --100%
Junior developer (remote) --100%
Integration and test (I&T) lead --50%
I&T junior member --100%
Table 1: Evolution of team structure

The changes and the reasons behind them can be summarized as follows:

  • Project management decreased, focusing on the customer interface and budget tracking.
  • Accounting support increased, as we aimed for more accurate and lower-granularity reports on progress against each task.
  • QA increased. We needed this role to confirm that code reviews were taking place, engineering notebooks were being maintained by developers, and so on.
  • Project engineering decreased, and the senior analyst role that had been coupled with the team lead role disappeared. Consequently, project engineering and team leadership (down to 25% and 75%, respectively) were consolidated into one full-time position.
  • Except for CM, engineering support decreased, since most of the infrastructure (that is, computer hardware) was in place by now. CM increased to allow for participation in builds with I&T and to support the CM repository for version control.
  • Support and review team effort decreased, since we only pulled them in for big issues. Most code reviews now took place within the team through peer reviews.

These positions were added:

  • Senior, intermediate, and junior developers, to support the increased development effort. These team members did remote development from the head office, providing "back-end systems" expertise. (We'd originally planned to move management to the head office as well, but the current arrangement was working so well that it was agreed we'd hold onto the bulk of the coordination.)
  • An I&T team consisting of a lead and a junior member. The lead member drafted preliminary test specifications, wrote the high-level test plan, and mentored the junior member, who provided support in the form of generating test data, writing test scripts, and fleshing out test documents.

In hindsight, our team structure may have been overkill, since we were only working toward a proof of concept in Phase 1. We probably could have trimmed back on some of the build and QA formality without too much harm and still met our Phase 1 objectives. In the end, however, we built a very high-quality proof of concept that provided more reuse for Phase 2 than we'd originally expected.

Development Approach

Some earlier projects had forced us to work in a shared development environment, and it was always a source of headaches. Developers working on common code frequently broke other pieces of software in the process. We sometimes were forced to work in a shared environment because of architectural or licensing constraints, but wherever possible we aimed for having an independent environment on each developer's machine. We scheduled integration builds to piece developer components together on a regular basis.

On the ASDI project, it would be easy to provide independent development environments, even for our remote offices. The only shared aspect would be the DB2 database, but we were able to set up an independent schema for each developer, removing any potential for problems. Furthermore, we set up our engineering team such that each class was "owned" by a single developer. We found that this greatly reduced our merging and modification effort. We'd never believed in the CVS (Concurrent Versioning System) philosophy of parallel development on a source file, because changes in one method could have a subtle yet significant impact on another method. We felt that the safest approach was to assign responsibility for a given class's implementation to a single team member.

Regarding our specific development environment, we found that the Orion Application Server, Rational Suite DevelopmentStudio, the J2SE JDK, and the DB2 client software easily fit on a P-III 500 with 256 MB of RAM. Orion's wonderfully small footprint and efficient design were major factors in enabling this small minimum hardware configuration.

The basic development cycle was as shown in Figure 1 (which borrows heavily from the RUP).

Basic development cycle
Figure 1: Development cycle

Each developer worked primarily from the baseline design specification. The first iteration of development involved generating a code skeleton out of Rational Rose as a starting point. A number of iterations (including frequent mini-builds) followed from there. The developer very informally unit-tested early iterations and also consulted with the team leadon any deviations from the design. Small design changes were communicated via e-mail, whereas more significant changes required one-on-one discussion to ensure that the change was appropriate and wouldn't have a negative impact on other aspects of the system. Obviously, any changes to interfaces (even public methods) required extra scrutiny and impact analysis. The design was periodically updated through reverse engineering, incorporating any changes back into the Rose model to maintain an up-to-date picture of the system.

Looking back, we wish we'd invested more effort into scenarios. If our scenarios had demonstrated greater coverage of the system, we could have used reports in Rose to show detailed dependencies between classes. This would have enabled us to make more educated guesses regarding the impact of specific changes. Instead, we had to write scripts that would do text searches against configuration-managed code to determine who might be relying on specific methods of a given class.

As complex issues or problems were encountered, they were raised to the team lead. Usually the team lead either personally assisted in the problem, left the developer to battle the problem, or engaged help from another team or company member. On occasion, we encountered technical issues that required discussion with the customer and subsequent updating of the requirements themselves. For example, some of our security requirements changed for compatibility with the JSSE (Java Secure Socket Extension) API.

Once the code was fleshed out, the developer compiled a set of unit tests, and the I&T team a set of component tests, that were designed to test performance as well as functional and reliability requirements. Upon completing the code and the unit tests, the developer assembled a review package for the peer review process (described later) and awaited feedback. The review process sometimes resulted in design modifications and other times simply identified a few bugs or needed enhancements.

Tracking Progress

Because we had just started with implementation, we weren't ready to use defect statistics from Rational ClearQuest as part of measuring our progress. Instead, we relied on two major sources of information: task reports and mini-milestones.

Task reports were submitted by developers on a weekly basis. These would identify the work accomplished on the task and the budget expended on it since the last report, and would estimate the effort remaining on the task. Any impediments that were hindering the task's progress were also reported in this weekly summary.

Mini-milestones were even more crucial, since they sometimes revealed significant problems. The team lead often requested mini-builds, informal Friday afternoon demonstrations, code walkthroughs, or even on-the-spot code reviews. If we found that a team or team member was unable to meet the deadline with a suitable product, it sometimes meant there was a problem that required assistance.


Ensuring System Quality

Software engineering has the goal of producing high-quality software, on schedule and on budget. The exact definition of quality varies from team to team and from project to project. The quality-related goals for our engineering team included:

  • easily maintainable code
  • assurance that all requirements were addressed
  • reliable operation
  • adequate performance
  • clear documentation
  • an extensible design
  • adherence to schedule and budget

We found that the Rational tools helped us meet many of these requirements. To illustrate one area where they helped, this section will focus on the command gateway part of the customer interface. As noted in Part 5, this gateway was a B2B (business-to-business) interface that would allow large companies to query ASDI's parts availability, submit orders, update their customer information, and query shipping or account status.

Updating the Design: Round-Trip Engineering

The design of the command gateway had gone through a number of iterations, leading to the mature design shown in Part 5; however, a situation arose in which the remote senior developer got out of sync with that design. She came up with some excellent ideas on her own, and we were able to incorporate them thanks to round-trip engineering -- that is, by reverse-engineering her changes into our Rose model. This easy synchronization of the design with late code changes was important to maintaining the quality of our system, since so much centers around the design model.

The command gateway was being developed remotely (at Lookoff's head office) because they had extensive experience with Java, XML, and JSSE. We sent the senior developer the latest design on a Friday, and planned to meet through a teleconference early the following week to discuss it. However, the developer was out sick that Friday and never received the design; in fact, she wasn't aware of any of the progress we'd made since our first design, which was much less detailed. She proceeded to work over the weekend on the project from her laptop at home, not realizing she was out of sync.

In the teleconference the following week, the senior developer talked at length about her improvements to the design, her introduction of new technologies, and the great head start she'd made on the overall development. This came as a surprise to the team lead, and the developer was of course surprised to hear about the updated design. We agreed to walk through both the latest design and the developer's efforts, to see which approach we should pursue.

As it turned out, the developer's improvements were significant, and were better thought-out than our previous efforts. She had uncovered a product, Castor, that would encapsulate the mapping of XML data to Java objects, and she had incorporated some design decisions that were more elegant than our proposed solution. Consequently, we agreed to update the design to reflect her insightful approach.

Because she had started from scratch with her code, we needed to back her design into our model. This was fairly easy to do: we simply provided the developer with our latest *.cat file for the command gateway, and she reverse-engineered her code into the model. In later parts of the project, similar circumstances arose in which reverse engineering was a big help.

The Reverse-Engineering Process

The first step we followed when we did reverse engineering was to set the CLASSPATH environment variable from within Windows. The location of this variable depends on the version of Windows, but it's typically found through the system control panel. (In Windows 2000, look for the Advanced tab of that panel.) If the CLASSPATH environment variable isn't set properly, Rose will have trouble evaluating relationships between the code and externally referenced classes, often causing the parsing of a class to fail. In our case, we had to set this variable to

D:\jdk1.3.1\jre\lib\rt.jar;j:\usr\local\lib\xerces\xerces.jar; 
j:\usr\local\lib\castor\castor-0.9.3-xml.jar 

This value pointed to the runtime libraries for core J2SE classes and the Castor XML-binding classes that would map between Java objects and XML data.

We then defined the project specification, using the Tools > Java > Project Specification option in Rose (which brings up the dialog box shown in Figure 4). We confirmed that all paths were found, and we pointed Rose at the root of our code base.

project specification in Rose
Figure 2: Defining the project specification in Rose

Next, we chose the Tools > Java > Reverse Engineer option, which presented a dialog box (shown in Figure 3) prompting us to select source files to be analyzed. We selected the package of interest -- the root asdi class, to bring in all of the senior developer's code -- and clicked the Add Recursive button. We then selected all the listed files and click Reverse to reverse-engineer them.

Dialog box
Figure 3: Reverse-engineering in Rose

During the first few tries, we realized we'd made mistakes in setting our CLASSPATH variable, causing errors in the log files. (It was important not to ignore these errors, which sometimes indicated that parsing of the file had failed completely.)

The Results of Reverse Engineering

Once the reverse engineering was successfully completed, we found a root package named asdi under Logical View and Component View in our model (see Figures 4 and 5).

Logical view
Figure 4: Reverse-engineered classes (Logical View)

Component View
Figure 5: Reverse-engineered components (Component View)

The reverse engineering was fairly effective at parsing out relationships between classes. It was more reliable at finding ownership relationships when the variables were declared as member variables of the class. Some relationships weren't correctly captured (for example, relationships created through local-scope instantiated variables in our Java code), so a bit of follow-up inspection was required.

Rose doesn't create diagrams for the code, understandably. With hundreds of classes, Rose would have no way of knowing how to logically group classes to properly express the architecture and design of the system. However, with all the relationships between classes already in place, generating design and component diagrams was relatively easy. The diagram in Figure 8 shows the revised gateway design after reverse engineering.

gateway design
Figure 6: Revised (reverse-engineered) gateway design

The major change in the design as illustrated in Figure 6 was the introduction of Castor's XML-binding interface. We didn't have to do our own parsing (using Xerces-J or XML4J) to translate XML messages to objects, because Castor provided this mapping capability transparently. The Talker class encapsulated the JSSE functionality, and subclassed java.util.Vector to provide easy management of incoming messages. Vectors make for very simple first-in-first-out (FIFO) queues through add(...) and remove(0) calls. Normally we'd choose ArrayList over Vector, but because the queue had to be shared across threads, we agreed to keep things simple. (Vector is synchronized but ArrayList isn't, requiring Collections.synchronizedList() to be used.)

Profiling

One risk associated with the new command gateway approach was an uncertainty regarding the performance of the Castor serialization API. Having already tested the XML parsers at great length, we knew that their memory use and performance would be adequate under peak loading conditions. We needed to assess the Castor product to make sure it met our system's performance requirements.

To speed up this process, we decided to use Rational Purify and Rational Quantify to observe Castor's behavior. These tools allowed us to closely inspect the resource requirements and behavior of Castor at run time. For expediency, rather than bother to implement the full JSSE client and server code, we decided to stub the JSSE functionality (the Talker class in Figure 6) to supply dummy XML messages.

Inspecting Java Memory Use

We wanted to understand the level of resources required by the Castor engine. Using this open-source product was a bit of a risk for the project, so we needed be sure it was bulletproof and wouldn't hog resources under heavy use. We designed some unit tests that would run overnight to identify any heap or stability problems. Rational Purify had recently added some Java memory analysis functionality, so we decided to give this a try.

On C or C++ projects, we always made it mandatory to run Purify on components to prevent memory access violations from making their way into production code. With Java, problems such as null pointer reads, memory leaks, and array overruns weren't an issue; however, Purify still provided us with some features that were very useful in our analysis of Castor.

To run Purify, we first had to set preferences configuring it to use the correct JDK. We used the default settings for our JDK version, except that we checked the "Pause JVM console after exit" option so that we could see any errors or closing results of our application when the Purify test was complete (see Figure 7).

Configuring the JVM
Figure 7: Configuring the JVM for Purify

To run the Purify test, we chose File > Run and set the program name to the Main.class file by browsing to it. This set up default options as shown in Figure 8. The only change we had to make (not visible in this figure, due to truncation of the display) was to update the command-line arguments to run asdi.exchange.command.Main, since Purify's default was Main with no package scope.

Running Java test
Figure 8: Running a Purify Java test

Interestingly, we first ran into problems with class format exception errors. We had seen these in the past when moving between JDK 1.1 and 1.3, where *.class validation rules had changed. For some reason we were running into this problem again, but only within Purify. It went away if we compiled the *.class files with J2SE's javac.exe instead of jikes.exe (IBM's high-speed compiler). The results of the Purify analysis are shown in Figure 9.

results of the Purify  analysis
Figure 9: Purify output for the command gateway
(click here to enlarge)

We ran this test for several hours to make sure it was repeatable and predictable. No problems were noted, with the exception of very chatty garbage collection. Although memory use never crept up, our application forced significant garbage collection when processing and mapping 20 commands per second. For now, we didn't see this as a performance concern, since the CPU load never become stressed at any point in the test.

Profiling Code

Rational Quantify had always been a favorite tool of ours on C or C++ projects. We typically used it to track down performance problems and to ensure that no areas of code were wasting CPU or real-time cycles.

Quantify was similar in appearance and configuration to Purify, and setup of the JVM was accomplished in the same fashion. Quantify was very useful for understanding how CPU- and time-intensive Castor would be, and it also helped us see where most of Castor's effort was going. Figure 10 shows a sample screenshot of the Quantify environment during its profiling of our command gateway code.

Quantify environment
Figure 10: Quantify output for command gateway code
(click here to enlarge)

One point that became clear to us was that Xerces (Castor's underlying XML parser) was using a fair amount of the CPU while Castor was running. We would obviously run into the same problem, since we'd still have to parse the XML messages to extract the content. Quantify enabled us to understand the maximum and minimum times for execution at each step in the call stack, the time consumed by descendents, and other useful pieces of information. In the end, we felt comfortable including Castor in our system, since it had demonstrated robustness, a lean implementation, and a good feature set.

Unit Tests

Unit tests were a vital part of our development effort. Most developers did some form of unit testing even without being asked; however, we found tremendous value in formalizing the unit test process to ensure consistent rigor and quality. The developers often focused on error conditions in their tests, whereas unit tests should test several aspects of software. Some resources that provided useful information for the team in defining the role and appearance of unit test specifications are listed later under "References and Related Resources."

The developers always defined their own unit test specifications, since these tests were at a very low level of white- and black-box testing that would be too detailed for the I&T team to understand. To enforce consistent detail in the unit test specifications, we included them in the peer review process.

Peer Reviews

We instituted peer reviews to help identify bugs before they hit production, and we observed something very interesting: few bugs were being identified during the reviews. At first this seemed to indicate a lack of value in the code reviews, so the project engineer looked into things a little more carefully. Here's what he discovered:

  • Peer reviews appeared to be raising the quality of the software simply because developers knew their code was going to be scrutinized.
  • Added process in the form of standards, guidelines, walkthroughs, and better training was reducing the number of bugs reaching the code.
  • The addition of formal unit testing was giving developers a chance to catch bugs for themselves. On earlier projects where we hadn't scheduled this additional unit-testing effort, developers felt terribly pressured and rushed to get their code into the integration plan.

Peer reviews also improved overall team capability through cross-pollination of skills and approaches. The developers built up a good portion of their design patterns and coding idioms through looking at each other's ideas. Code reviews allowed plenty of time for valuable discussion of pros and cons for various coding strategies; consequently, we usually tried to have at least one junior developer present for learning purposes.

Our coding standards addressed not only simple style matters but also comment conventions, coding practices, and performance issues. The standards were presented to the team over three lunch hours, along with guidelines for the review process.

The steps of the review process were outlined as follows:

  1. Upon completing the code and the unit tests, the developer creates a review package consisting of design specifications, code, unit test specifications, and unit test results.
  2. The review package is distributed to the reviewers -- that is, the team lead and up to two other developers, depending on code complexity.
  3. The developer performs a 1- to 3-hour walkthrough of the code for the reviewers.
  4. The reviewers individually review and mark up the code, and the markups are returned to the developer.
  5. The developer looks over the reviewers' comments.
  6. The developer performs a 1- to 2-hour walkthrough of the comments with the reviewers and reaches consensus on an action plan for each comment.

At first there was serious concern that this review process would take too much time. However, we found it to be extremely valuable, provided that:

  • Everyone was well prepared for each of the stages.
  • Simple, "been there, done that" code had very few reviewers -- sometimes only the team lead.
  • The final walkthrough meeting wasn't rushed, since it provided much of the cross-pollination, agreement on solutions, and discussion of impact and pros and cons.

Summary

Having paved the way with guidelines, adjustments to the team structure, and a well thought-out development approach, we found that development (including refinements to the design) was progressing well. The engineering team was starting to see the power in the Rational Suite DevelopmentStudio tools. The learning curve for the tools had been nontrivial, but by this time we were quite comfortable with them. In particular, we benefited greatly by using Rational Rose for round-trip engineering, Rational Purify for inspecting Java memory use, and Rational Quantify for profiling our code. Using these tools, along with instituting unit tests and peer reviews, we were well on our way to meeting our quality goals for the ASDI system.

Looking Ahead

The sooner we could get the team into the habit of mini-builds, the better. We were contemplating having a build cycle every Friday for subsystems, and every second Friday for subsystem integration (for pieces that were available). Assembling the team for these mini-builds would be valuable, and it would be a good morale booster for the team to see things coming together.

The next few weeks would be filled with early demonstrations, both internally and externally. We'd soon be pulling together user interface screens for an external demonstration. This would also be a good opportunity for us to get additional requirements feedback.

Major Risks

Even at this early stage of development, the challenges of remote development were starting to hit us, and we knew it would become rougher as we started to integrate components and subsystems. Early "practice builds" would need to start soon so that we could smooth out the integration process and work out early problems.

Remote development would be a challenge for us throughout the project. Although we'd done remote development before, we never figured out how to seamlessly spread work across geographically isolated teams. We learned that Rational tools wouldn't entirely eliminate the remote development problem, but they could at least ease the pain of it. We couldn't, for example, have prevented the senior developer's divergence from the command gateway design, but reverse engineering helped us assess and integrate her changes with minimal effort.

To meet our tight deadlines, development had to continue at an efficient pace. The customer was eager to see some progress, as it had been a while since we'd given them the software architecture document. It would be important to provide integrated demonstrations as soon as possible.


References and Related Resources


About the author

Steven Franklin has an extensive background in software design, architecture, and engineering process, which he usually applies to large, distributed information management and command and control systems. He's been using Rational tools since 1997, and his primary areas of interest include XML, J2EE, wireless, and software engineering methodologies. Steven can be reached via e-mail.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Rational
ArticleID=297
ArticleTitle=Applying Rational tools to a simple J2EE-based project Part 6: Early development
publish-date=12042003
author1-email=
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers