Fine-tuned example

The 10 min. tutorial is focused on demonstrating the main features of Component-Watch in a quick but representative example.

This document continues further the same example, showing some fine-tuning you can perform on the project definition. It will help to better understand how Component-Watch is working but also emphasis the principle of the tool.

The idea is that you should put in the project definition the knowledge you have about your application. There's no magic, a tool cannot deduce by itself the intelligence you've put on the structure. (It's the reason why fully automatic code analysis tool are always disappointing as it comes to structure analysis of big programs) The aim of Component-Watch is to allow you to express the structure, show it and verify it. So, there's inevitably some manual operation to add value to the project definition. But the more structure and naming rules you've put in your code (especially in package naming) the easier it will be.

The fine-tuning steps will be:

  • Merging some components.
  • Change the pattern-matching defining the content of some components.
  • Creating another partition (orthogonal to the "layer" partition)
  • Creating more diagrams

To have, at the end, a project expressing the essential structure of the Component-Watch program itself.

The fine-tuned project is available in the examples. Just open the <install_directory>/examples/self-analyse-tuned.xml project (or use the "File/Reopen project/self-analyse-tuned" menu item).

Merging components

In the preceding example, there are 3 boxes for the ASM library. It's not because there are 3 ASM jars (asm-3.2.jar, asm-analysis-3.2.jar, asm-tree-3.2.jar) in the classpath of the application that it must be mapped in 3 components. In fact, two of those boxes (asm-analysis and asm-tree) appear not referenced at all, it's just because they are referenced by the ASM "core" jar which is not analysed.

There are two solutions:

  1. You care about relations between sub-components of the ASM library and you decide to analyse them. So you can add in the main project definition org.objectweb.asm.* in the analysed classes definition.
  2. You don't care about internals of ASM (because it's an external library) and you want to view it as a single component.

Let's choose the second option and merge the 3 ASM components into one. Here, luckily, all the ASM classes share the same root package "org.objectweb.asm". So we can easily define the "ASM" component in one single selection based to the class package rather than container jar.

  • Select the "asm" component in the components list of the "Components" tab.
  • Click on the "Edit component" toolbar button to open the edition dialog box.
  • In the "Classes" table, go to the first pattern and change it to org.objectweb.asm.** then leave the field.
    • Delete the other two patterns (Delete the jar selection then leave the cell, by pressing TAB for example, and the line will disappear)
    • Update the obsolete comment if you want (it's no more an automatic creation from classpath entry).
  • Press "Ok" to commit the edition and close the dialog.
  • In the component list, select the "asm-analysis" and "asm-tree" components and delete them with the "Delete component" toolbar button.

What you got is one single ASM component matching all ASM-related classes from any jar. In Component-Watch there is no forced mapping between components and the way they are packaged.

Note: If you analyse the project again, you will see 2 warnings saying that there are unused matching patterns in the "External components" layer. It's because the references to the deleted components are still there. You can edit the "External components" layer component definition to fix that.

More on pattern-matching

Now we will go a bit deeper in pattern-matching. Take a closer look to the classes contained in the "Sfac" components ("sfac-core", "sfac-utils" and "sfac-launcher"). Select each component in list under the "Components" tab, and in the details of the component displayed on the right, take a look the "Classes" tab.

What you see the following:

  • In the "Core" component: all the classes are in the net.sf.sfac.gui packages and sub-packages.
  • For the "Launcher" component: only one class in the net.sf.sfac.launcher package.
  • In the "Utilities" component: Several sub-packages of net.sf.sfac are used (but not the packages of the other components).

So as an exercise (because the final result will be the same), let's try to use the package names rather than jar files to select the same set of classes for each component.

As Component-Watch selections can also define exclusion patterns, we can easily reflect the package naming rules expressed above.

So let's change each component class selection pattern to:

  • sfac-core
    • include: net.sf.sfac.gui.**
  • sfac-launcher
    • include: net.sf.sfac.launcher.*
  • sfac-utils
    • include: net.sf.sfac.**
    • exclude: net.sf.sfac.gui.**
    • exclude: net.sf.sfac.launcher.*

Note: In practice, you have to double-click on a include icon to toggle it to an exclude in the pattern edition

Edited "<i>sfac-utils</i>" component.

Creating another partition

So far, there is one structural concern that was carefully crafted into the application but not yet expressed in the project description: separation between Model and GUI.

Practically, this is another partition of the application into two sub-sets: "Model" and "GUI". This partition is independent (orthogonal) to the already defined "layer" partition. So, to express this orthogonality let's call the new partition elements "silo" (which intuitively suggest something vertical while "layer" suggest something horizontal).

Remind that, for the tool, "silo" and "layer" are just identifier of component type without any special signification, you could as well have used "subsystem", "group", "tier" ...

So, with the partition helper (same procedure as for the layers) define the two silos as following:

Silos paritioning

In this case also, you want a rule enforcing the layering (Rem: here your 'layers' are named 'silo'). You want to be sure that classes belonging to the "Model" silo cannot reference the classes from the "GUI" silo. So, add a "Layering Rule" to saying that the "GUI" silo, is above the "Model" silo.

Silos layering rule

Creating more diagrams

Now that we have a tuned model expressing all the structure that was put in the application, let's define more diagrams to show it.

Let's create a simple diagram showing layers and silos dependences.

Configure a new diagram as following:

Silos and layers diagram definition

And you will get (after some manual layout enhancement):

Silos and layers diagram

We can also do a diagram displaying everything. Just do a redo the "Component-Watch structure" diagram proposed in the 10 min. tutorial but add a new cell group to represent the silos with following values:

  • Group Name: Silos
  • Base Style: Vert. swimlane
    • Background color: Orange
  • Components: silo:*Added silos group in definition

And you finally get (still after some manual layout):

All-in-one diagram

Conclusion

In this example you have learned that:

  • The components that are defined in Component-Watch are not necessary matching the java packages or the jar boundaries.
  • How to write more complex pattern matching with includes and excludes.
  • Orthogonal structural concepts can be expressed with overlapping grouping components.
  • How to write several diagrams showing different views of the same component set.

The two examples show how Component-Watch fulfils its goals of discovering, showing and assessing the structure of java programs. Though the component-watch program itself that is analysed here is not a big program you can see that the tool really add value with its ability to display the actual (and intended) structure of the application.

On bigger applications with more complex structure developed by more developers during a longer period using more libraries ... (and so on) ... the usefulness of the tool will only increase!