ArticleS
.
UncleBob
.
JdependFixture
Edit Page:
!title JDepend Fixture !2 Using the JDepend Fixture for FitNesse The JDepend fixture is named ''Module Dependencies''. It provides a FitNesse fixture interface for JDepend. !3 !meta You can get the fixture [[here][http://butunclebob.com/files/downloads/ModuleDependencyFixture.zip]]. Good Java designers partition their application into components. These components may all be placed in a single .jar file, or they be separated into many different .jar files. We want to avoid dependency cycles between these components so that the system is buildable, and that the components are independently deployable. Keeping component dependencies under control is hard, because it's so easy to violate them. Any programmer can put an import or reference into a module that inadvertently builds a cycle, or creates an unwanted dependency. What we need is a tool that can be run at every build to check that there are no cycles, and no unwanted dependencies. JDepend (you can get it at http://www.clarkware.com/software/JDepend.html) is a tool that analyzes component dependencies by scanning .class and .jar files. It generates reports about the dependencies in your application. It also provides an api that you can use to write JUnit tests to ensure that your application has only the desired dependencies. Writing JUnit tests for this can be awkward. So I wrote a FitNesse fixture that allows you to represent the dependencies of your system as a table. The fixture invokes JDepend and makes sure that only the dependencies you signify in the table are actually present in your application. The following table describes a system with two components, where component a depends upon component b. !|Module Dependencies| | |a|b| |a| |x| |b| | | If this were executed as a FitNesse fixture, and if module a really did depend on module b, then the cell with the x would be colored green. Any other dependency would cause the corresponding cell to be colored red. For example, if a did '''not''' depend upon b; and if b depended upon a instead, then the cell with the x would be left uncolored, but the cell denoting the dependency from b to a would be colored red. To say this another way: The names of the components appear accross the top, and down the left side, of the table. The left side denotes the source of a dependency (the depending component), the the top row denotes the target of the dependency (the depended upon component). You put an X in any cell that represents a dependency that you would like to allow. You leave the cells for any unwanted dependencies blank. If any allowed dependency exists, that cell will be green. If any allowed dependency does not exist, that cell will be uncolored. If any disallowed dependency exists, then that cell will be colored red. !3 What is a module. A module is a synonym for a component. For our purposes a module is a package that contains many other packages. For example, the package payroll might contain payroll.tasks, payroll.commands, payroll.exceptions, payroll.reports, etc. The Module Dependencies fixture counts dependencies from the contained packages as dependencies belonging to the component. So, for example, if there are two components named ''payroll'' and ''gui'', and if ''gui.dialogs'' depends upon ''payroll.employee'', then the Module Dependency fixture will infer that the ''gui'' component depends upon the ''payroll'' component. !|Module Depencencies| | |payroll|gui| |payroll| | | |gui | X | | !3 Cycles. If the Module Dependencies fixture detects a cycle between components, it will color all the dependencies within the cycle red, and mark them with the word 'cycle'. They'll stick out like a sore thumb, and you can track them down. Running JDepend to generate the dependency report will be helpful in tracking down the individual dependencies. !3 Table Structure If your modules don't have a cycle, then they are arranged as a tree. If you order the modules in the table such that the independent modules are at the top and left, while the most depended modules are at the bottom and right, then you will see that all the dependencies occupy the section of the table that is ''above'' the diagonal, as shown below: !|Module Dependencies| | |a|b|c|d|e|f| |a|-|X|X| |X|X| |b| |-| |X|X|X| |c| | |-| | |X| |d| | | |-| | | |e| | | | |-|X| |f| | | | | |-| The cells marked with dashes denote the diagonal. You don't have to put the dashes in if you don't want. The fixture will automatically color these cells grey for your convenience. This table topology is handy. If you can arrange all the dependencies such that none are below the diagonal, then you can be certain that there are no cycles between the modules dependencies. !3 Details for use: To use the fixture, download it and put it in a handy directory. On (or above) the fitnesse pages where you want to use it, put !-!path-! statements that point to the directory that contains the fixture .class files. Also put a !-!path-! statement that points to the JDepend jar file. !note Make sure you are using JDepend 2.8+ It is handy to put the following import table at the top of the page !|Import| |moduleDependencyFixture| Denote the location of the class and jar files for the system you want to analyze using the ''Module Dependency Paths'' table as shown below: !|Module Dependency Paths| |C:\mySystem\MyClassFileDirectory| |D:\mySystem\MyJarFileDirectory| You can have as many lines in this table as you like. The JDepend fixture will search them all. Create the Module Dependencies Table by listing the packages that contain your modules accross the top and down the left of the table. Put Xs (or actually anyting non-blank) in the cells that denote desired or allowed dependencies. Leave the rest blank. !|ModuleDependencies| | |a|b|c|d| |a| |!| | | |b| | | |!| |c|!| | | | |d| | | | | Sometimes your module names will be long, with many prefixed packages. For example you might have modules with names like ''com.company.payroll.a'', ''com.company.payroll.b'', ''com.company.payroll.c.one'', and ''com.company.payroll.c.two''. To avoid repeating all the prefixes in the table, you can add a prefix argument in the cell after the fixture name as follows: !|Module Dependencies|com.company.payroll| | |.a|.b|.c.one|.c.two| |.a | | | | | |.b | | | ! | | |.c.one| | | | | |.c.two| | | | | The '.' in the front of the modules above indicate that the prefix should be used. Without the '.' then the fully qualified name of the package should be used. !3 Conclusion. Have fun with this fixture. I hope you find it useful for managing the dependencies between your modules. Remember that the prime motivation for using Object Oriented Design is to manage module dependencies. ---- '''23 December 2004, Robert C. Martin.''' Sample Comment. ---- '''26 December 2004, Stefan Roock''' Cool! Some additional lightweight tools for managing dependencies are described at <http://www.stefanroock.de/weblog/blogger.html>. ---- '''27 December 2004, IljaPreuss.''' Very Nice! I guess the "!" in the latter examples should be "x", too? * ''No, any non-blank entry denotes an expected dependency. I started using !, but then changed the convention to X. '' !* Fri, 25 Nov 2005 04:19:13, Chris, Download link The link to download this fixture could be made more prominent for those of us that ignore the first couple of sentences when reading an article ;) Could you make the words 'download it' into a link? How about an entry on the left-hand menu? *! !* Thu, 16 Mar 2006 10:47:25, Ludger, Download link is broken When I click on the "Here" link, I get a "The requested resource: files/downloads/ModuleDependencyFixture.zip was not found." message. Any ideas? *!
Hints:
Use alt+s (Windows) or control+s (Mac OS X) to save your changes. Or, tab from the text area to the "Save" button!
Grab the lower-right corner of the text area to increase its size (works with some browsers).