This article is part of the Quality Busters series, where I look at common influences on application quality from the enterprise view of the operational environment and non-functional requirements. Addressing these influences is a matter of making tradeoffs, with no single solution solving all problems.
But it worked in the test environment!
The SHEEP application team had just finished packaging the new SHEEP.ear file for deployment on the production systems. The new version of the application passed all the quality assurance and user tests in the test environment. Management gave the final approvals and everything was set for upgrading the application servers.
On the morning of the upgrade, everything went well and the users encountered no problems. But around noon, when one of the sales managers began reviewing the
previous day's activity as he usually did at that time, he received various
Java RemoteException errors. He
called the help desk, which in turn contacted Susan, on the SHEEP team.
Susan, who updated the sales dashboard to use new features available in the recently upgraded database system, was initially confused by the errors because she could not reproduce them in either the development or test environments. All indications were pointing to a possible problem with the database's JDBC driver JAR file. But which one? The test and production systems had a dozen copies of the JAR file, all with different sizes and dates. After determining the CLASSPATH active at the time, Susan was able to find the particular JAR file being loaded. Further investigation helped her because she found version information stored in the MANIFEST.MF file within the JAR file.
After several hours of tracking down JAR files, Susan determined that the production server was not correctly updated with the latest version of the JDBC driver JAR file when the production database system was upgraded. The SHEEP team had not noticed this because none of the applications used any of the new database functionality -- until this recent upgrade. Susan had the technical operations team install the updated database client components on the production server to fix the problem.
What went wrong? The SHEEP team assumed that the production environment had been updated in the same way that the development and test systems had. Because the team assumed that the systems would be identical, they did not add testing logic in the application to ensure that the proper version of dependent components were available.
Modern applications depend heavily upon shared components. These components can range from shared modules developed in-house (such as common object modules, DLLs, or JAR files), to open source or commercial libraries (often packaged as DLLs or JAR files), to program products (such as IBM® WebSphere® or IBM DB2®) and operating systems (such as OS/400® or AIX® ).
Just as applications change to address changing requirements, components also change -- often several times per year. When a component changes, often you must change the application that depends on it, too.
The only way an enterprise can avoid addressing component management is to keep the computing environment static -- no upgrades to hardware or software. Clearly, this is not an option.
Component management can be roughly divided into five aspects: upgrading, identifying, tracking, storing, and testing.
Why upgrade component X to a newer version?
One can probably argue that most programmers like to work with the newest version of software. The development team's instinct might, therefore, be to upgrade to the latest version simply because it is the latest version, and then look at the new features that they can use. This may be fine for development and research; but when thousands or millions of users are dependent upon an application working, it becomes necessary to be more conservative and slower in upgrading.
Often, operations management does not want to upgrade until they feel it is necessary. This might be when:
- The applications have been completely tested with the new version
- The component provider withdraws support for the old version
- Other component upgrades require the new version
In all cases, the operations team and management will insist that the upgrade be fully tested before deploying it in the production environment.
Is this copy of component X at version 1.5 or 1.6?
Sometimes identifying the version of a shared component merely by looking at the component itself is difficult. File size and date alone are insufficient for identifying component versions. Text files that are external to the component and that contain a version flag are inadequate because they are easy to lose, alter, or separate from the component. Ideally, version information should be stored within the component itself.
Two common versioning approaches with program-level components are: file name and internal.
With file name identification, you put version information into the component's file name. Using this approach, version 1.5 of component X might be named X_1.5.jar.
The advantage to this approach is that the user can see the version information quickly. This approach has disadvantages, however. For one, thing, it's possible to change or remove the version information simply by renaming the file. In addition, such a naming scheme adds deployment work, since all references to the component must specify the new name (you might need to update all the CLASSPATH entries, for instance).
Many packaged components, such as JAR files, provide a mechanism for recording descriptive information in the package. For JAR files, this is the MANIFEST.MF file. (See Resources for more information about using MANIFEST.MF for version identification.)
Several advantages to this approach are:
- It is difficult to lose or alter version information.
- It records details about the source versions making up the component.
- It eliminates changes necessary in programs or CLASSPATHs that reference the component.
One disadvantage is that it can be harder to view the version identification of a particular component. Sometimes you'll need a special utility program, such as pkzip, to do so.
What programs use component X?
When a component is upgraded, it is necessary to find all items (programs or other components) that reference it -- or rather, to have a dependency relationship with it. These dependency relationships form a dependency hierarchy. This hierarchy must be recursively evaluated until the topmost programs are reached. In most cases, no changes are necessary to these dependent items, as most component upgrades are backward compatible with previous releases. But, eventually, something changes -- perhaps the interface signature, data formats, or protocol -- and the dependent items must change as well.
You either must track or discover the dependency relationships.
Tracking the dependencies involves maintaining a document (a database, diagram, or some other representation) that records all the relationships. One difficulty with this approach is keeping the document up-to-date. It is easy to forget to update the document when a component is updated.
Discovering the dependencies involves a program following the references in the program items -- such as parsing the CLASSPATH or PATH environment variables or capturing classloader activity. One difficulty with this approach is a shortage of full-coverage tools that can identify all components.
Keep in mind that indirection can often make tracking dependencies difficult. Remember to review the environment variables (such as CLASSPATH, PATH, and LIBPATH), command-line options, configuration files, and other places where indirection is used to find the desired components.
Where is component X stored?
A component has to be put somewhere on the computer for programs to access it. From a purely technical perspective, the location of the component is not important. The component location can be specified using various forms of indirection (such as environment variables, configuration files, and command-line options). However, the component location can have bearing on managing application component dependencies.
Two common approaches to component location are: shared and private.
The shared location approach is commonly used with components that come with a framework product, such as WebSphere Application Server. The WebSphere Application Server, for example, provides an XML parser component in a JAR file (xerces.jar or xercesImpl.jar). An application integrating with WebSphere Application Server and using XML could reference the XML parser in the WebSphere Application Server directory.
This approach has several advantages:
- It reduces the size of the application, since the component already exists on the host system
- It ensures that the application can take advantage of upgrades to the component when the product is upgraded.
A disadvantage, however, is: Code written with this approach assumes that a particular product at an expected release level has been installed on the target host system.
The private location approach is commonly used with standalone software products, such as the open source Eclipse IDE. Eclipse ships with its own, complete Java™ Virtual Machine (JVM) and related Java components stored in its own directory structure. Even if another JVM runtime already exists on the target system, Eclipse (and most standalone products using the Java language) will install its own private copy of the runtime rather than use the existing version.
The advantage of this approach is that it ensures that the proper releases of all dependent components are available as part of the product installation. However, a disadvantage is: The host system may end up with multiple copies of the same functional component -- often at different versions. To illustrate this, try searching your system for all copies of java.exe (or its equivalent on your platform). Each instance is associated with a private copy installed with some application or product.
Does component X break anything?
When upgrading to a new version of a component, adequate testing is vital. This may require that you perform full regression testing of the application. Reviewing and understanding what has changed in the component may condition the amount of testing. Never release an updated component into a production environment without some level of testing.
When you work with shared components as an architect, ask these questions (among others).
- Is a new version of the component necessary?
- Has the component added new functionality that you can use?
- Is the vendor dropping support for the old version?
- Was the product that provides the component updated?
- How will you identify components created in-house?
- Will you identify components by file names or internal identification?
- How do you identify externally obtained components?
- How do you add identification to the component?
- Are all components tracked through configuration management practices?
- How do you track dependencies between components and programs?
- How can you programmatically discover those relationships?
- Will the application use a private copy of a component or access a shared copy?
- If the application uses a shared copy of a component, what processes are in place to ensure that all dependent application teams are notified when the component is affected?
- What testing processes are in place for component upgrades?
- Do you have processes that reproduce the production environment, including all components, in a development environment that assists with problem resolution?
The use of shared components helps programmers be more efficient -- eliminating the need to write code that someone else has already written and keeping programs smaller through shared resources. Unfortunately, this comes at a cost: You must manage more items and dependencies. Failure to consider these shared component dependencies can result in application problems. Sometimes the interfaces to shared components change, thus forcing program modifications (and all the subsequent testing and deployment work). Management activities must track components (including version information), and provide a review path for upgrading components and a deployment path to ensure that components are properly propagated from development to production.
- Read the author's other articles in the Quality busters series on developerWorks.
- Find a detailed assessment of designing applications using commercial components in Building
Systems from Commercial Components, Kurt Wallnau, Scott Hissam, and Robert Seacord (Addison-Wesley, 2002).
- Explore this introduction to design and management considerations for developing a software product line Software Product
Lines: Practices and Patterns, Paul Clements and Linda Northrop (Addison-Wesley, 2002). While this may seem most appropriate to commercial software houses, this author believes
in-house software development within an enterprise can benefit from following
these practices.
- In Software Release Methodology, Michael Bays
(Prentice Hall, 1999), push beyond normal configuration management books that talk about source control and version assignment. This book puts more emphasis on the release and deployment
aspects of configuration management, including keeping track of the production
environment.
- Read Managing
Systems Migrations and Upgrades: Demystifying the Technology Puzzle, Charles Breakfield and Roxanne Burkey (Butterworth-Heinemann, 2002) for a general
overview of managing hardware and software upgrades.
- Find the details on the MANIFEST.MF file contents in Sun's JAR file specification.
- Read up on the MANIFEST.MF version attributes in Sun's optional extension versioning.
- Visit the Web Architecture zone on the IBM developerWorks site for articles and tutorials covering various Web-based solutions.

Michael Russell has a bachelor's degree in physics and a master's degree in computer science. He was a logistics engineer, a technical services manager, and a certified IT architect at IBM for nearly 14 years. He is currently a Web application architect for a resort company in Orlando. He has experience in Windows, UNIX, and OS/400 environments. He uses Web technology for entertainment through his own company, Vicki Fox Productions (http://www.VickiFox.com).