lthough software and architectural reuse has been a constant drumbeat in the technical press for many years, it's still common to see code and designs that violate many principles of reuse. For example, how many software systems have you seen that are similar to the diagram in Figure 1
? Or when trying to reuse code, you find an exisiting component with functionality you need (Component E), but you also find it impossible to reuse the component because it depends on Component Cwhich your new system doesn't need. You might add that component only to find that, in turn, Component C depends upon Component A.
Such interdependencies are still typical of many software projects today. Of course, such code isn't generally produced on purpose. A team typically lays out the architecture, then starts coding up the system. As they code, bad dependencies unintentionally slip insometimes that just happensand the team often doesn't even discover such unwanted dependencies until later in the development cycle.
|Figure 1. A Typical Software System: The figure illustrates the tangled relationships between components in many software systems.|
|Figure 2. An Ideal Software System: Note the linear relationship path between components in this application.||
Now a new open-source tool called "Verifydesign
" is available to monitor code to help prevent unwanted dependencies. Figure 2
shows a more appetizing set of relationships between software components. In Figure 2
, the yellow bars represent the APIs. Components communicate only through these APIs. I intentionally drew lines in Figure 1
from the middle of a component to the middle of another component because that's the reality of most software systems today. Figure 1
emphasizes that many software systems don't bother communicating through the API, but instead go directly to the middle of a component as shown. In contrast, Figure 2
shows a design without the circular dependencies of Figure 1
VerifyDesign lets you define the dependencies between software components. Some examples from Figure 2
- Implementation of Component A depends on Component B's API
- Implementation of Component A depends on Component C's API
- Implementation of Component A depends on Component D's API
In the rest of this article, I will detail how the Verifydesign tool works to define and enforce dependencies.
How Teams use the Verifydesign Tool
Here's an example system that uses Verifydesign. The system consists of a phone and a client that controls the phone. The client depends on the phone's API. The phone's API has no dependencies, and the phone's implementation must depend only
on the phone's API. Along the way, I'll present this information as if to a new developer who doesn't yet understand the design. The code will intentionally violate the design dependency rules to demonstrate Verifydesign's real poweradherence to an actual design. This desired design is what I call the "package design" (as opposed to the actually implemented design).
First, I urge you to download the code
, so you can follow along. The download contains a file named verifydesign/packagedesign/bldfiles/design.xml
, shown below:
<!--The phone's api is defined to depend on nothing -->
<package name="phoneApi" package="biz.xsoftware.api.phone"/>
<!--The phone's implementation obviously implements
and depends on the api -->
<package name="phoneImpl" package="biz.xsoftware.impl.phone">
<!--The client is defined to depend on the phone's api
(not the phone's implementation) -->
<package name="client" package="biz.xsoftware.impl.client">
|Figure 3. Enforced Relationships: The figure shows a graphical view of the enforced relationships between packages as declared in the design.xml file.|
As a first step, run the build and make sure the code you downloaded doesn't violate the design. To run the build, go to the verifydesign/packagedesign
directory and run the command:
ant --f bldfiles/build.xml
You should see a BUILD SUCCESSFUL
message. The XML file shown above contains some basic rules about dependencies that are allowed in the source code. The file declares five packages. A graphical picture of the above "package design" would look like Figure 3
The diagram in Figure 3
represents each declared package in the file as a box, with each arrow representing a dependency. These are the only dependencies allowed in the Java code. What we're trying to achieve is an environment where (for example) when a programmer changes the code such that client depended on PhoneImpl
, the developer should be warned. Now, I'll walk you through Verifydesign's capabilities in detail. For this demonstration, pretend you don't know anything about the design, and we'll wreak some havoc on the system so you can see how VerifyDesign can help.