Skip to main content

Applying Rational tools to a simple J2EE-based project Part 5: Architecture and design

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 ongoing example of applying the RUP and other Rational tools to a J2EE project moves into a more technical stage, as it migrates from use cases to architecture and design (including data modeling, and prototyping to test design assumptions).

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

This is the fifth 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 Part 5 installment first reviews the project to date and then elaborates on the next stage, as we move forward into architecture, design, data modeling, and prototyping.

Part 5 Snapshot

Tools and technologies demonstrated in Part 5:

  • Rational Rose Enterprise v2001A -- For creating the design model (including data modeling done with Rose's data modeler)
  • Rational RequisitePro v2001A -- For adding or refining requirements

Artifacts created or updated:

  • Design model (Rational Rose) -- Created to add architecture and design information (including the database schema)
  • RequisitePro database -- Updated to add or refine requirements based on architecture and design exploration

The Project to Date

Before launching into the details of the architecture and design efforts, let's review the overall progress of the ASDI project. As you may recall from Part 1, this multiple-part article covers Phase 1 of the project: a proof of concept resulting in a set of requirements, a reference architecture, and (ideally reusable) code. By now, we were roughly one-third of the way through the budget for Phase 1, but close to halfway through the schedule. This was in line with our expectations, since we'd fully intended to ramp up slowly. Analysis and planning activities always move at a slower pace, and the team should build gradually at the start of a project.

Because Phase 1 required a relatively structured and formal proof of concept, we were treating it as a mini-project, complete with testing and QA (peer review) on the evolving product. The RUP has some mechanisms for developing a proof of concept, primarily in the Perform Architectural Synthesis activity of the analysis and design workflow. We were taking the proof of concept a step further, to a usable beta version of the product. The more functionality, risk mitigation, and maturity we could put into this phase, the happier the customer would be, and the more skills and knowledge we'd take into the production version of the system.

This next set of tasks would be more technical than our earlier activities. We'd be moving well into architecture, design, data modeling, and prototypes. In Part 4 we discussed how some prototypes and evaluations accompanied our tool selections; now our prototypes would be focused on testing our assumptions regarding requirements, system specifications, and design.


Moving into Architecture and Design

The architecture and design activities were among the most enjoyable and creative tasks on the ASDI project. Although the architecture may not have been bleeding-edge, we were proud of the efficiency, safety, and simple elegance of the planned system. The vision of the technical solution emerged through many exciting interviews, brainstorming sessions, and technical explorations.

In a nutshell, the architecture was intended to capture a technically feasible solution while covering the requirements of the system as we'd defined them over the last month. This put significant pressure on the architecture team to look both ahead (to the design) and behind (to the requirements). Rational Rose's integrated environment simplified this challenge by enabling us to do the following:

  • Generate documents through SoDA to allow distribution of architecture and design documents, simplifying review and keeping everyone consistent with the current vision.
  • Update class signatures (methods and attributes) directly from scenarios, so that we could add missing methods on the fly without having to revert to the class specification.
  • Generate RoseScripts (accessible via the Tools menu) for automated tasks such as generating class skeletons, checking model-naming conventions, and testing model integrity and validity.
  • Use Rose's RUP template, providing a model framework that adhered to RUP guidelines.
  • Drag classes from the J2EE class framework supplied in Rose.
  • Use Rose's "unit control" feature to break the model up into pieces that could be version-controlled and worked on in parallel by the team.

Note that because we'd built systems in the past that were similar to this project, our architecture would have benefited if we'd had some reference architectures to draw on. However, we were unable to find any reuse opportunities within existing packages or design patterns, so we simply referred to the existing systems for ideas and classes that we might be able to use in the future.

Migrating from Use Cases to Design Classes

The migration from use cases to design classes was slow, requiring a number of iterations. It involved both analysts and designers, since we had few staff members who were comfortable with both talking about domain with the customer and carrying the analysis through to tool-specific, detailed design artifacts.

Goals for This Activity

It's sometimes tempting to move straight from requirements to code. In fact, we'd done that on previous projects where (because we had a very detailed requirements specification) we were confident in our understanding of the project. This turned out to be a mistake. Requirements were overlooked, scope was hard to track, and a significant amount of work and rework was wasted. Bridging the gap between requirements and code with a design model is critical; it catches mistakes and faulty assumptions long before development and testing.

In moving from use cases to design classes, we hoped to achieve the following:

  • Transfer knowledge from the analysis team to the engineering team.
  • Identify a technical solution that satisfied all requirements -- or, where that wasn't possible, identify requirements that conflicted with the technical solution and determine whether they were critical or could be changed or removed.
  • Identify interfaces that could help determine team structure, architectural layers, and candidates for off-the-shelf software.
  • Scope out the details of the technical solution and start planning how to distribute work among team members.
  • Refine schedule and budget estimates based on details of the design model.
  • Allocate classes (and consequently requirements) to platforms, products, and proprietary code.
  • Produce a software architecture document that could be distributed to internal and external team members for feedback and synchronization purposes.

Steps to a Stable Design

The transition from use cases and analysis classes to design and design classes was unavoidably blurry. A number of steps had to take place before we could have a design we'd feel comfortable with. Figure 1 shows the primary activities we engaged in on our way to defining a stable design.

use case model to design model
Figure 1: Migration from use case model to design model

Previous article parts discuss most of the activities and artifacts (particularly the SOW requirements, use cases, business object model, and analysis classes) leading up to "Architecture" in Figure 1. In addition, these other activities were important to the design effort:

  • deciding on the package structure
  • modeling the data (creating the database schema)
  • creating prototypes and screen mockups

These are discussed in the sections that follow, along with how we handled new and changing requirements.


Package and Subsystem Structure

Before even starting to think about design classes, the entire team got together to agree on a sensible package structure. Whatever we decided on would be captured in design guidelines that would be enforced throughout the team.

Package Structure Selection

We heavily debated whether to package along subsystem lines (Figure 2) or along architectural layer divisions (Figure 3). Table 1 lists the advantages and disadvantages of each of these approaches.

Packaging
Figure 2: Packaging along subsystem lines

architectural layer divisions
Figure 3: Packaging along architectural layer divisions

Approach Advantages Disadvantages
Packaging along subsystem lines
  • It simplified model management. Complex subsystems could be allocated to a large team in a single *.cat file or hierarchy of *.cat files.
  • It enabled easy tests for illegal dependencies between subsystems.
  • It simplified planning of increments to the project.
  • It encouraged decoupled subsystems, allowing for easier visualization of the architecture.
  • It increased the possibility of subsystem reuse.
  • Consistency and shared relationships across subsystems would be more difficult to coordinate. For instance, the DBA might have a harder time seeing the big picture of the data layer, or the dependencies between data abstraction classes and the schema entities.
  • It could promote a "closed box" philosophy that discourages reuse from common service packages.
Packaging along architectural layer divisions
  • Consistency within layers would be maintained.
  • It isolated different technology domains: JavaServer Pages (JSP) in the GUI layer; Enterprise JavaBeans (EJB) and servlets in the business layer; entity beans, classes, and tables in the data layer.
  • It increased the possibility of reusing the system architecture (by enabling reuse of business and data services through the replacement of the GUI for another customer).
  • Not all code neatly fit into one of the three layers.
  • Team leads or remote teams for a subsystem had to check out several *.cat files to update or take ownership of the subsystem model.
  • It was often difficult to report on or visualize a specific subsystem if all pieces of the model weren't checked out.
Table 1: Comparison of packaging approaches

We ended up going with the first approach, dividing the design model along subsystem lines. We felt the system was small enough that we could enforce consistency across the subsystems.

Subsystem Structure Design

An early draft of our top-level package structure resembled Figure 4. You can see from this diagram that the top-level packages identified subsystems (hence the stereotype <<subsystem>> assigned to each one).

package structure
Figure 4: Top-level package structure

It took quite a bit of discussion before we could go from this early sketch to our final, stable package structure. The following are just a few of the questions we addressed:

  • How would we organize common services?
    Answer: Utility services would be separated into individual subpackages (logging; data synchronization and backup; access control; and login).
  • Where would we draw the (often blurry) line between shipping and part management?
    Answer: We ended up consolidating the two.
  • Would we define subsystems according to domain or architecture?
    Answer: Architecture, which happens to align with domain in most areas.
  • Would we allow bidirectional dependencies between packages?
    Answer: No. This is a bad design practice that runs counter to our internal design guidelines.

As an example, we'll focus on the command gateway subsystem. Although the bulk of the system centered on an internal and external Web interface, we also planned to provide a secure, XML-based command gateway that would allow a B2B (business-to-business) interface between ASDI's system and its large customers. This feature would allow those customers to query, submit, and update information to ASDI from their existing systems. This was important because some company requirements couldn't be addressed through a Web interface, but instead required batch or behind-the-scenes submission from that company's code.

Within each package, our initial class diagrams were derived from our use cases, business object model, notes, and interviews. Figure 5 shows the result of progressing from our early thoughts to a detailed design for a portion of the command gateway.

command gateway design
Figure 5: First design for command gateway

In this first round, we simply identified the major pieces of the command gateway subsystem, yet even at this level there were significant issues that had to be addressed:

  • Would we use XML? (Issues included bandwidth consumption, stability, and parser maturity.)
  • Would we push data to or pull data from the customer?
  • Would we supply the command client software or only publish the specification for it?
  • Would we transfer XML over SSL (Secure Sockets Layer), HTTP, or proprietary socket communications?

In a subsequent round of design (Figure 6), we identified more dependencies in the system and started identifying what looked like implementation classes. We were still debating high-level concepts, so we were less interested in documentation and class signatures (methods and attributes). These would be filled in once we felt the design was beginning to stabilize.

Interim design
Figure 6: Interim design for command gateway
(click here to enlarge)

As shown in Figure 7, we later refined some of our dependencies, identified appropriate methods and attributes (hidden in the figure to save space), and added some technical details. For instance, through prototyping we identified JSSE (Java Secure Socket Extension) as a solution for SSL connectivity between the client and server. JSSE was slated to be integrated with JDK 1.4 but was currently only available as an add-on.

Mature design
Figure 7: Mature design for command gateway
(click here to enlarge)

Even this design wasn't final. Although the design had been tested through a number of scenario diagrams, coding continued to uncover inaccurate or missing details over the following weeks and months.


Managing Changing Requirements

As we worked with the architecture and design, we identified the need for new requirements or refinements to existing requirements. It was tempting to ignore small changes, but we'd seen quite a few budgets die the "death of a thousand cuts." Little nicks at the budget could build up over time and set a bad precedent with the customer. We found that tracing all additions and changes helped keep expectations in check and forced us to ask, "Do we really need this feature?" This is a critical point that's often overlooked: if a requirement wasn't important enough to enter into the system, it wasn't worth implementing.

Sometimes requirements were introduced that had a negative impact on the existing schedule and budget. This required us to sit down with the customer to discuss the options -- but first we tried to discuss them internally among ourselves, so that we could credibly present alternatives to the customer as opposed to simply "winging it." The options usually consisted of the following:

  • Defer the requirement. This generally happened when the requirement wasn't all that important, or wasn't as important as the other requirements to be addressed in the current build.
  • Remove the requirement. This happened when the requirement wasn't important at all.
  • Replace an existing requirement with the new one. If an existing requirement wasn't important, or at least wasn't time-critical, we'd defer or remove it to make room for a new feature in the schedule and budget.
  • Add the requirement to the existing work. This option would be considered only if it didn't introduce an unacceptable risk to existing requirements and to the overall system plan. Adding any nontrivial requirements naturally required additional schedule and budget.

Making changes to the use cases wasn't a problem, because we were strictly version-controlling the use cases and could update them directly in the model. In addition, it was easy to integrate changes back into the SOW using Rational RequisitePro. However, in retrospect we wish we'd taken the time to set up Rational ClearQuest to manage requirements changes. Sometimes changes were internally identified, but more often they were externally requested. Our procedure for requirements change management was quite awkward, involving monthly meetings, hardcopy forms, and so on. A more seamless change request process would most likely have introduced more opportunities for controlled scope growth, resulting in a better overall system and a higher contract value.


Data Modeling

We started modeling the data around the same time we started the design effort described earlier. On previous projects, we'd used Rational Rose for design and found the partition between persistent and transient classes to be somewhat awkward: as soon as we identified a class as persistent, we set its persistence attribute and started modeling it in another tool. On the ASDI project, we used the data modeler integrated with Rational Rose Enterprise and found the transition to be much more natural.

Actually, we originally made the mistake of doing it the old way -- stuffing persistent objects into their own folders and forgetting about them -- but then we caught ourselves and transformed these objects into the data model using Rose. With all the persistent classes collected into a package, we could right-click the package and transform the object-oriented model to a data model (by choosing Data Modeler > Transform to Data Model from the context menu).

The data modeler created a database schema in the Rose model. We later moved the schema from its logical representation to a physical DB2 installation, to give the engineering team access to tables and test data.


Prototyping

Good analysis was important as a foundation for the architecture and design, but prototypes were every bit as valuable. Many ideas looked great on paper, but our assumptions required proof that only prototypes could supply.

The engineering team enjoyed the prototyping activities. Typically the schedule for these activities is aggressive, the goals blurry, the technologies new, and the QA light, so prototyping can often be a lot of fun -- and a big waste of money. We found that if a prototype didn't have clear, measurable goals, it quickly drifted off into "Look what I can do..." instead of specific risk-mitigating tasks.

We generally tried to remain consistent with the RUP philosophy of having an evolutionary product, which might lead you to conclude that all our prototypes evolved into the final product. In fact, we reserved the term "prototype" for quick and dirty, throwaway explorations that might or might not fold into the final system in some form. To extract the maximum value from the prototypes, we often ignored coding standards, peer reviews, and the like. Some aspects of the prototype (class specifications, design patterns, or coding idioms) might be able to be reused, but we placed very little pressure on the team to consider reuse at this point. Instead, the results of our prototyping were usually wrapped up in technical notes or sample applications that we could refer to later on in the project.

Right off the bat, a work package had to be drafted that outlined the goals of the specific prototype for its developer. We assigned a budget to each prototype, and a schedule that included interim reviews prior to task completion.

We didn't always prototype by directly diving into code. Sometimes we'd perform tool evaluations through studies before writing any code. When evaluating databases, for instance, we removed some candidates from the list based on our experiences, vendor-supplied information, and third-party reviews.

We found several approaches that worked well for prototyping and tool selection:

  • inspection (reading, reviewing, interviewing)
  • coding (deep slices to explore specific interface, requirements, or performance issues, and broad, thin slices to show connectivity, workflow, and usability)
  • installation and demonstration of prototypes
  • demonstrations by tool vendors

The trick with a prototype was in deciding how far to take it. Few prototypes could be designed to give 100% confidence in a recommendation. Instead, the prototype had to demonstrate enough results to reduce risk to tolerable levels.

Table 2 lists some of the specific prototyping activities we undertook on this project.

Prototyping activityResult
Study (covering features, cost, and performance) of J2EE systemsSelection of Orion Application Server (for more information, see Part 4)
Evaluation of OODBs (covering features and market share), to satisfy customer's preferenceDecision against OODB usage (see Part 4)
Study of relational database systems (covering features, cost, and performance)Selection of DB2 (see Part 4)
Evaluation of JSSE (covering complexity, stability, and security)Inclusion of JSSE in B2B solution
User interface mockups (testing usability, workflow, and "look and feel")Development of user interface guidelines and standards for "look and feel"
Data modeling in Rational Rose Enterprise (using Rose's data modeler)Familiarity with data modeler; generation of database scripts to create tables, triggers, and so on for early prototypes
XML research (see "Related Resources" ) and prototypes, for B2B interfaceAgreement that benefits of well-formed XML outweighed reliance on third-party parser or bandwidth requirements for tag-rich XML
EJB versus JSP and servletsDecision to stick with JSP and servlets for Phase 1
Table 2: Prototyping activities


Summary

Our architecture and design for the system were maturing nicely; our prototypes were largely successful, and we'd soon be getting started on implementation. This meant that it was more important than ever to track progress, keep the vision on course, and carefully plan each iteration and increment.

By now we had tried out and chosen all our major technologies and third-party tools, and we were comfortable that they would do their job. We determined this through disciplined and planned prototypes, and not just hope or reliance on silver bullets. The prototypes also helped ramp up the engineering team, giving us the confidence that we had the knowledge and training we needed to do the job.

Looking Ahead

In the near future, we had to move into actually implementing the system. We planned to target the following:

  • the command gateway, which posed some of the greatest technical risks
  • the GUI, which would provide a useful review artifact to the customer
  • some common services that were needed by a number of subsystem functions

Before doing any implementation, we had to prepare for that stage of the project in a variety of ways, including updating our team structure to meet our new needs, documenting coding and design conventions, and communicating an efficient development approach (including unit tests and peer reviews). The engineering team would need to fully understand round-trip engineering, debugging, profiling, and more.

Major Risks

The JSSE prototypes pointed to a more complex API than we'd originally anticipated. In particular, the area of security posed a huge opportunity for scope creep, so we had to work closely with ASDI to understand exactly what their security needs were. The requirements we were working from didn't get into key strengths, cryptography mechanisms, and other low-level details.

We were guilty of losing a good deal of time on the prototypes. This was due in part to having an engineering team that was ramping up on the domain and technologies as well as getting used to working together.

Finally, having chosen JSP and servlets over EJB, we knew our architecture might need some reworking in Phase 2. We were willing to leave this as a risk for that phase, since we were totally committed to this technology choice.


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=284
ArticleTitle=Applying Rational tools to a simple J2EE-based project Part 5: Architecture and design
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