Inside Tapestry Core
Tapestry is defined like that in Wikipedia:
“Apache Tapestry is a component-oriented Java web application framework to implement applications in accordance with the model-view-controller architectural pattern. Tapestry was created by Howard Lewis Ship independently, and was adopted by the Apache Software Foundation as a top-level project. Tapestry emphasizes simplicity, ease of use, and developer productivity. Tapestry adheres to the Convention over Configuration paradigm, eliminating almost all XML configuration. Tapestry uses a modular approach to web development, by having strong binding between user interface components (objects) on the web page and their corresponding Java classes.”
I already used Tapstry and I can confirm that’s very simple to use and it’s very elegant, but what about the inside of Tapestry, it’s also well designed and implemented?
This question is very important for each open source project, it gives the assurance that the evolution and maintenance of the project will be easy.
Let’s discover the inside of Tapestry Core by analyzing it by JArchitect.
Here’s the Tapestry general informations:
The first remark is that Tapestry core is well modularized using packages and also well commented.
Let’s go deep inside Tapestry and discover its implementation and design.
Number of line of code
Methods with many line of code are not easy to maintain and understand, let’s search for methods with more than 40 lines.
SELECT METHODS WHERE NbLinesOfCode > 40 ORDER BY NbLinesOfCode DESC
Only few methods have more than 40 lines, it makes the code more readable.
Cyclomatic complexity is a popular procedural software metric equal to the number of decisions that can be taken in a procedure. Let’s execute the following CQL request to detect methods to refactor.
SELECT METHODS WHERE CyclomaticComplexity > 20 ORDER BY CyclomaticComplexity DESC
Only 4 methods can be considered as complex.
It’s a very good point when we want to understand source code, almost all methods have less than 40 lines of code, and a cyclomatic complexity less than 20.
Methods with many variables
Methods where NbVariables is higher than 8 are hard to understand and maintain. Methods where NbVariables is higher than 15 are extremely complex and should be split in smaller methods (except if they are automatically generated by a tool).
SELECT METHODS WHERE NbVariables > 15 ORDER BY NbVariables DESC
Only 4 methods has too many variables.
Types with many methods and fields
Let’s search for types with many methods, for that we can execute the following CQL request:
SELECT TYPES WHERE NbMethods > 30 ORDER BY NbMethods DESC
And we can do the same search for fields;
SELECT TYPES WHERE NbFields > 20 ORDER BY NbFields DESC
Few types have many fields and methods. And understanding type’s responsibilities and behavior became very easy.
Types with a big depth of inheritance are not easy to maintain, we have to avoid these kind of classes, and of course there are some cases where it’s not problematic.
Let’s search for classes where depth of inheritance is more than 5.
SELECT TYPES WHERE DepthOfInheritence >=5
Only exceptions classes are concerned, and in this case we can consider that it’s not a problem, exception classes don’t contains business logic, and maintain these classes will not be problematic.
The single responsibility principle states that a class should have more than one reason to change. Such a class is said to be cohesive. A high LCOM value generally pinpoints a poorly cohesive class. There are several LCOM metrics. The LCOM takes its values in the range [0-1]. The LCOMHS (HS stands for Henderson-Sellers) takes its values in the range [0-2]. Note that the LCOMHS metric is often considered as more efficient to detect non-cohesive types. LCOMHS value higher than 1 should be considered alarming.
SELECT TYPES WHERE LCOMHS > 0.95 AND NbFields > 10 AND NbMethods >10
ORDER BY LCOMHS DESC
Only 6 types are considered as no cohesive.
The Efferent Coupling for a particular type is the number of types it directly depends on. Types where TypeCe > 50 are types that depends on too many other types. They are complex and have more than one responsibility. They are good candidate for refactoring. Let’s execute the following CQL request
SELECT TYPES WHERE TypeCe > 50 ORDER BY TypeCe DESC
Another way to see the result is the treemap view, where every type, method and field are represented by rectangles, and blue ones concern the result of our CQL request, so we can see visually the types concerned by the request.
In our case 4 types are concerned and we can see also their size, the size is proportional to line of code, but we can change it to other metrics.
Types most used
It’s very interesting to know which types are most used,for that we can use the TypeRank metric. TypeRank values are computed by applying the Google PageRank algorithm on the graph of types’ dependencies. A homothety of center 0.15 is applied to make it so that the average of TypeRank is 1. Types with high TypeRank should be more carefully tested because bugs in such types will likely be more catastrophic.
The interesting thing is that almost all types most used are interfaces, it’s a very good news for design, indeed using interfaces instead of concrete classes enforces low coupling and makes the code more flexible.
For example let’s search for Types used by PageImpl, the class implementing the tapestry web page.
SELECT TYPES WHERE IsDirectlyUsedBy
"org.apache.tapestry5.internal.structure.PageImpl" AND !IsInTierJar
As you can see almost all types are interfaces, so we can change concrete implementations with few source code changes.
We can export result to dependency graph:
Or export it to Matrix view, to have more details about the weight of using these interfaces.
To enforce low coupling Tapestry use injection mechanism to bind with a concrete classes, and to see that let’s search for all fields using Inject annotation to bind with a concrete class.
SELECT FIELDS WHERE HasAnnotation "org.apache.tapestry5.ioc.annotations.Inject"
Many fields use this annotation to inject the concrete class, it make the design more flexible, and easy to understand.
Tapestry is a good framework to use for your J2EE projects, It’s very simple, and as developer you can use only POJO types without having complicated implementation, and it’s also well implemented and designed, and don’t hesitate to look inside the source code, it’s very easy to understand.