You are on page 1of 12

CompuwareCorporation

Knowledge-driven
WHITE PAPER

Application Development

Introduction Equally difficult to analyze is the entire scope of Java code from
source level. Many aspects of a Java application are not visible to the
Ever have a fragile application where simple changes break
IDE. Traditional code inspections or digging deeply into source code
something else? Did you solve why it was fragile or just resolve the
cannot reveal many potential flaws.
immediate bug? Perhaps you needed to modify code you did not
write or cannot remember. You had to dig into the source code Expert advice is available from many sources in the Java community.
and discover enough information to make those changes. Perhaps Books, articles, and online information provide excellent guidelines
you have had an application that just was not running, providing and examples. Information is readily available in the areas of
inconsistent results or not running effectively. structured programming and Java expertise from such authors
as Martin Fowler (Refactoring, Reducing Coupling), Joshua Bloch
Resolving these different problems almost always begins by gaining
(Effective Java Programming Language Guide), Robert Martin (Agile
in-depth program understanding, identifying potential impacts of
Software Development: Principles, Patterns) and others. In addition,
change and then applying expertise to resolve the situation. To gather
the Java Specification is the definitive Java resource and written by
application knowledge, engineers use their IDE and rely on personal
a team of experts led by James Gosling, Bill Joy, Guy Steele and
or team experiences to guide any changes. For this approach to be
Gilad Bracha, among others.
effective, each engineer and team is required to have experienced all
possible code, design, and runtime problemsa tall order!
Designs unveiled
This white paper explains how automated decomposition of the
Over the years, many researchers1 have investigated the analysis
structures of your applications facilitates more rapid program
and visualization of programs for the purpose of comprehension. All
understanding. Then we will show how to assess package structure,
of these past efforts focus on class or method level analysis for C++
identify package design issues and discuss refactoring. Next, we
and Smalltalk. For Java, package structures can now benefit from the
will show you the value of automatically checking your application
previous research by applying the same recommended techniques.
against the knowledge and experiences of industry experts.

To understand a software program, one has to first understand its


general design and structure. In Java, code is structured in classes,
which are organized in hierarchical packages. A top-down approach 1 D.L. Parnas, Carnegie-Mellon University, On the criteria to be used in decomposing systems into
toward understanding Java programs means to discover the purpose modules, Communications of the ACM, Vol. 15, No. 12, 1972, pp. 1053 - 1058.

and relationship of packages. - S. Demeyer, S. Ducasse and M. Lanza, A Hybrid Reverse Engineering Platform Combining
Metrics and Program Visualization, WCRE99 Proceedings (6th Working Conference on Reverse
Engineering), IEEE, pub. October 1999.
Unfortunately, it is not easy to determine these properties of
- F. Steinbrckner, C. Lewerentz, Metrics Based Refactoring, Proc.of the 5th European Conference on
packages in Java just by viewing the source code. Software Maintenance and Reengineering (CSMR 2001), IEEE Computer Society Press, pub March
2001, pages 30 - 38.

- M. A. D. Storey, C. Best, J. Michaud, SHriMP Views: An Interactive and Customizable Environment


for Software Exploration, Proc. of International Workshop on Program Comprehension, pub May
2001.

- R. Kollman, M. Gogolla, Metric-Based Selective Representation of UML Diagrams, Proc. 6th European
Conf. Software Maintenance and Reengineering (CSMR 2002). IEEE, Los Alamitos, pub. 2002.
Figure 1. Layering for the
JUnit package.

How do you now find issues that might be lurking within the design Though engineers can explicitly establish a layering, it is also
and Java code? Through the published works of the industry experts, possible to reverse-engineer the layering structure from the package
there is great wealth of information on how to decompose software dependencies. OptimalAdvisor defines the layer of a sub-package in
to clearly see the design and to identify errors not readily obvious. acyclic package architecture as follows:
Frequently there are only a few examples provided. These examples
The layer of a package is the maximum length of a dependency path to a
do not always clearly translate into identifying the same condition
package with no dependencies.
in our own applications. Its a big challenge for engineers to read
and understand the volume of Java standards and best practices. Figure 1 is an example of package structure layering of JUnit. JUnit is
Applying the standards and techniques to your daily job can be an open source project for unit test and available from www.junit.org.
daunting.
Unlike the JUnit example shown in Figure 1, most Java programs
OptimalAdvisor can reverse-engineer an intended architecture and have cyclic package structures. In such cases, it can be difficult to
highlight design flaws, based on generally accepted design principles. comprehend the intended package structure. A simple way to deal
A key concept in OptimalAdvisor is that of a layered architecture. with cyclic package structures is to simply ignore dependencies that
In a layered architecture, a program is decomposed in a number of are part of a cycle. However, this would not provide insights into
layers, such that each layer only depends on lower layers. In general, how the application is really architected or the types of problems
a layered architecture is easier to understand, test, maintain and still awaiting discovery.
extend.

2
Figure 2. Simple layering
applied to java.

OptimalAdvisor uses a more advanced algorithm called smart Program understanding case study: JDK 1.4
layering. Smart layering is a heuristic algorithm to determine,
from Java code, the layering that best represents the intended Simple layering
architecture. The smart layering of a package is the simple layering
Illustrating the use of OptimalAdvisor, we examine the JDK1.4 Java
corresponding to the package graph with undesirable dependencies
package, the core package of the Java language class library. From
removed. An acyclical graph is formed where undesirable
Figure 2, it is clear that the Java package structure does not have a
dependencies are identified and ignored. There are, of course,
strict layering. In fact, the only package that is not used by other
many possible sets of undesirable dependencies that lead to an
packages is the sql package. Thus, it is not possible to determine
acyclic graph.
any intended layering from Figure 2. It is not likely that the sql
OptimalAdvisors advanced layering chooses the sets which have the package is the top level of Suns Java packages. However, this is what
minimal total weight of the undesirable dependencies. The weight the source code provided for information.
of a dependency is the number of references from one package to
another. The weight is an indicator of the effort necessary to remove
this dependency. Therefore, the smart layering algorithm assumes
the minimum effort necessary to make a package structure acyclic.

3
Smart layering of OptimalAdvisor The analysis reveals some unexpected dependencies. For
example, java.lang depends on java.awt. Further
In Figure 3, OptimalAdvisor has implemented smart layering
analysis with OptimalAdvisor shows that this is the result of
and it reveals the intended layering. For example, undesirable
two classes: the SecurityManager in java.lang depends
dependenciesthose pointing upward in the hierarchical design
on the AWTPermission in java.awt. Java.awt uses
are now visible.
AWTPermission and java.lang. Moving AWTPermission
Disregarding sets of undesirable dependencies that are not as to java.lang would solve this problem. The remaining action is
important to the design helps create acyclic graphs. In Java, the to appropriately rename AWTPermission.
java.lang package is at the bottom. Other low level packages
Making java.lang independent from java.awt is important
are java.io and java.util. The higher-level packages include
when users want to replace awt with their own user interface
java.beans, java.applet and java.awt. This corresponds
library. Please note that this fix does not solve the problem
to the idea that higher layers represent higher levels of abstraction.
completely, as java.lang still depends on java.awt indirectly
via other packages. Further analysis with OptimalAdvisor would
reveal those other areas for improvement in the Java framework.
Simply moving classes from one package to another cannot always
solve every problem.

Figure 3. Smart layering applied


to java.

4
Case study: JMeter In this next case study, OptimalAdvisor easily discovers JMeters
design issues, which are automatically resolved through the
Visualization helps you understand the application design that is
refactoring capabilities of OptimalAdvisor. See in figure 4 that the
implicit in your source code. With the design now established, you
JMeter design structure does show a top-down hierarchy.
need automated error detection with tips to resolve issues and tools
to assist and automate the refactorings. OptimalAdvisor implements However, there are several classes where there are two-
the industry experts knowledge on design construction, efficiencies, way dependencies, such as between controllers and
and good design from their collective experiences. OptimalAdvisors JMeterUtils. The controllers package has 65 dependencies
automation to identify issues reduces the risk of missing or just not to JMeterUtils and 2 dependencies up from JMeterUtils.
recognizing design problems. From Martin Fowler and Joshua Bloch This means these two packages have cyclical dependencies on each
to the Java Specification, OptimalAdvisor takes accepted design other. Figure 5 shows the one of the originating points of these
concepts and brings them into actual daily coding practice for upward dependencies from the JMeterUtils class source code.
engineers.

Figure 4. JMeter has cyclical


dependencies between controllers
and JMeterUtils.

5
Figure 5. JMeter source code where
one cyclical dependency originates.

Most likely, in your own code, you may have experienced symptoms reduces risks while supporting accelerated or agile programming
such as these. When changing one class you broke the application techniques. As a built-in safety valve, OptimalAdvisor does not
somewhere else. Cyclical dependencies generally make the apply any refactorings until you are completely satisfied with the
dependent components sensitive to change. design structure.

Where OptimalAdvisor detects a design error and can automate


Refactoring mercilessly
the refactoring, there will be a light bulb to suggest possible
Now design structure visualization and error detection provide resolution(s). In the JMeter case study, there are two ways to correct
understanding of your code. So, what is next? two-way dependencies: Move the referencing source code to the
referenced package or use Dependency Inversion. Attempting to
These issues must get resolved. Making design changes is normally
move the referencing code into controllers actually resulted in the
time-consuming, manual and error-prone. OptimalAdvisor enables
threads package now have more cyclical dependencies against the
you to make design structure changes by dragging and dropping
controllers class. Figure 6 illustrates this point. Not wanting to
types and sub packages from one package to another. UML diagrams
make the situation worse, using Undo puts the UML diagram back
immediately reflect changes of your what if analysis. This provides
to the previous state. Remember, there has been no effect on source
insight to what would become of your package structure if you apply
code yet.
the design techniques and refactoring identified by OptimalAdvisor.
Changing and refactoring the design structure in OptimalAdvisor

6
Figure 6. JMeter controllers and
threads packages now have more
cyclical dependencies.

Automated refactoring with Dependency Inversion was the other After these changes, the controllers class now only has
recommendation. What is Dependency Inversion? It is a standard downward dependencies on JMeterUtils. Removed now are the
way of removing some cyclic dependencies by inverting the cyclical dependencies. That is Dependency Inversion and one of the
dependencies between two classes. standard refactorings that OptimalAdvisor can automatically apply
to your code. Other auto-refactorings performed by OptimalAdvisor
Example of Dependency Inversion refactoring are moving dependencies into the calling packages and removal of
unused dependencies.
Create an inner interface in JMeterUtils, for example,
controllersListener. Take all the controllers For JMeter, following the recommendations and allowing the
method calls from JMeterUtils and add them to the refactor to update the code model takes just minutes. This just
controllersListener interface. saved you changes to 31 different source files and completed all
the changes error-free. Figure 7 shows 100 percent of the acyclical
Replace all occurrences of controllers in JMeterUtils by
dependencies are now resolved, resulting in a good top-down
controllersListener. Have controllers implement
package hierarchy and a more stable code base.
the controllersListener interface. This is possible because
controllersListener consists of the methods that were Robert Martins Agile Software Development: Principles, Patterns, and
originally in controllers. Remove imports from JMeterUtils Practices, 20022 provides more details of Dependency Inversion.
and add them to controllers, if they are in different packages.

7
Code AnalysisFixing what you cannot find Error categories

OptimalAdvisor automates the analysis of Java applications for Correctnessviolations that are likely to cause a bug.
54 violations in the areas of code and design correctness and
Designhelps improve maintainability and object-oriented
effectiveness. These are not syntax or runtime errors that an IDE
programming (OOP) design. Future modifications to classes would
might help resolve. Neither code inspections nor unit testing will
be problematic when the code violates these rules.
easily discover these types of problems.
Performanceviolations that are likely to cause problems with
The rules are automations derived from best practices for Java
speed, memory, or resources.
applications from leading authorities such as Joshua Blochs Effective
Java Programming Language Guide3, the Sun Java API Specifications,
Dov Bulkas book on Java Performance and Scalability4, and others.

Figure 7. The new top-down package


and class hierarchy for JMeter.

2 Agile Software Development: Principles, Patterns, and Practices by Robert C. Martin, pub. 2002.

3 Effective Java Programming Language Guide by Joshua Bloch, pub. Addison-Wesley 2001.

4 Java Performance and Scalability by Dov Bulka, pub. Pearson Education 2000.

8
Severity of violations are categorized as: >> Method name matches Constructor nameIts probably a
mistake, and its definitely confusing. Normally it takes a long
Highthe violation is likely to cause a runtime error, performance
time to determine the cause of the problem without automated
problems, or design issue.
help. A typical case is where you accidentally create a
Mediumthe violation may cause a problem, but the rule can be constructor with a return type of void. It looks like a constructor
ignored under legitimate circumstances to your users, but to the compiler it is a method.

Lowthe violation may affect the maintainability of the >> Class does not initialize all public and protected static fields
application, reflect a common practice, or be the result of a rule This class has some public or protected static fields that are not
that can cause many false positive violations. initialized. Known as Run-On Static Initialization, it can be the
source of subtle bugs.
Examples of automated error detection:
Rules descriptions include possible remedies to individual violations,
>> Ambiguous Overloaded methodsunseen by the engineer, the which then guide the developer in their choices of solutions. Each
compiler decides which method to call violation has examples of suggested improvements and links to
experts materials, books and online details behind each rule. The
>> Overridable methodsthe called method or its children can
specific source files are highlighted and the user is taken into the
change the behavior and results under different conditions
IDE at the correct line of code to begin corrective action.
or by some future change of indirect components within the
application.

Figure 8. JMeter code validations.

9
Figure 9. Example 1Overloaded,
ambiguous methods.

Code Analysis case studyJMeter Method: public void set(Object key, Object value)
has an ambiguous parameter 2 in public void set(Object
Looking into code validation for JMeter reveals some surprising
key, HashTree t). org.apache.jmeter.util.
results. Even though the JMeter application does work, there are
HashTree is an instance of java.lang.Object causing
49 high-severity violations detected that are likely to cause runtime
this ambiguity.
errors or performance issues or are design issues.

JMeter has overloaded ambiguous methods as noted in Figure 9.


The compiler and runtime environment, not you the engineer,
could determine the results.

public void set (Object key, Object value)


{
data put (key, new HashTree (value));
}
public void set (Objectkey, HashTree t)
{
data put (key, t);
}

Figure 10. Example 1JMeter overloaded, ambiguous method.

10
public Driver ()
{
this (null);}
public Driver(String file){
super ("JMeter - Java Apache Project");
init(file);
initGUI(); }
protected void init(String file) {
this.properties = JMeterUtils.getProperties(file);
engine = new JMeterEngine();
}
/*overrideable*/
protected void init(String file) {
this.properties = JMeterUtils.getProperties(file)
}

Figure 11. Example 2JMeter overridable method invoked in constructor.

Another example of code validation is where overridable methods


are involved in a constructor, clone() or readObject().
Source code from JMeter, in figure 11, demonstrates public
Driver (String file) calls overridable method: protected
void init(String file). The superclass constructor runs
before the subclass constructor gets a chance to run.

In all cases of overridable methods, the class is likely to fail after


the code is complete and you ship the class to your users. Users of
your method could later create a subclass that might override the
indicated method. This problem would be very difficult to diagnose.
It is critical to fix this problem if other applications use your class;
for example, your class is part of a public class library.

How do you resolve the second example problem in JMeter?


You could prohibit overriding of the called method by making it
private, either by making the method itself private or
requiring that constructors are private (using static factories to
create instances).

Another approach is to extract the overridden method code into a


private method, then call this new private method from the
constructor or from the original public method.

Setting the method as final prevents the overriding with the


additional protection of prohibiting subclassing in the future.

11
CompuwareCorporation

Conclusions

Software architects usually have a layered architecture in mind


when designing applications. However, without proper tool support,
code tends to get polluted with undesirable dependencies during
implementation and maintenance.

OptimalAdvisor reengineers the application design from the actual


source code and calculates metrics to evaluate the high-level
architectural structure. It presents engineers and architects with
a way to quickly evaluate the internal quality of large software
products.

Using a tool such a OptimalAdvisor will improve the structure of


your software, making it easier to understand, test, maintain, reuse
and extend. It also helps to educate developers and bring them to a
higher level of software expertise.

To learn more about OptimalAdvisor, visit


www.compuware.com/

Compuware products and professional servicesdelivering IT value


Compuware Corporation (NASDAQ: CPWR) maximizes the value IT brings to the business by helping CIOs more effectively manage
the business of IT. Compuware solutions accelerate the development, improve the quality and enhance the performance of critical
business systems while enabling CIOs to align and govern the entire IT portfolio, increasing efficiency, cost control and employee
productivity throughout the IT organization. Founded in 1973, Compuware serves the worlds leading IT organizations, including more
than 90 percent of the Fortune 100 companies. Learn more about Compuware at www.compuware.com.

Compuware Corporation Corporate Headquarters


One Campus Martius
Detroit, MI 48226
For regional and international office contacts, please visit our web site at www.compuware.com

All Compuware products and services listed within are trademarks or registered
trademarks of Compuware Corporation. Java and all Java-based marks are trademarks or
registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
All other company or product names are trademarks of their respective owners.
2005 Compuware Corporation 1/05

You might also like