20.1 Creating a dedicated report from scratch
For the purpose of this exercise, let’s start a report dedicated to ArgoUML. To identify relevant concerns, I browsed the documentation present on the ArgoUML site. More specifically, the development guidelines. Here are some excerpts:
- “All instance variables are private.”
- “Don’t use deprecated methods or classes.”
- “Don’t use very long package and class names... keep class names shorter than 25 chars”
Let’s start with the first issue: “all instance variables are private”. To check this, we create a query that retrieves all attributes that are not static, that are not stub and that are not private:
spec := REPConcernSpecification on: MooseModel root allModels first.
spec
query: 'Non-private attributes'
meaning: 'The ArgoUML guidelines say that all attributes must be private'
as: [:model | model allAttributes select: [ :each |
each parentType isStub not and: [ each isPrivate not and: [
each hasClassScope not ]]]].
spec open
Executing this script results in a browser as below. To the left we have the index with our item in red. It is red, because indeed the ArgoUML violates this concern. Selecting the concern reveals the list of offending attributes to the right. In fact, list to the right is a complete instance of a MooseFinder (see Chapter 5) that offers us various possibilities for navigation and enquiry.
In the same way we can define the rest of the concerns. For convenience, we can also group concerns into composites:
spec := REPConcernSpecification on: MooseModel root allModels first.
spec label: 'ArgoUML Report'.
spec composite: 'ArgoUML design problems' meaning: '' with: [
spec
query: 'Non-private attributes'
meaning: 'The ArgoUML guidelines say that all attributes must be private'
as: [:model | model allAttributes select: [ :each |
each parentType isStub not and: [
each isPrivate not and: [ each hasClassScope not ]]]].
spec
query: 'Deprecated classes still in use'
meaning: 'Deprecated classes should not be used anymore'
as: [:model | model allModelClasses select: [ :each |
(each isAnnotatedWith: 'Deprecated') and: [
(each clientClasses reject: [:e | e = each]) notEmpty ]]].
spec
query: 'Deprecated methods still in use'
meaning: 'Deprecated methods should not be used anymore'
as: [:model | model allMethods select: [ :each |
(each isAnnotatedWith: 'Deprecated') and: [
(each invokingClasses reject: [:e | e = each parentType ]) notEmpty ]]]
].
spec composite: 'ArgoUML naming problems' meaning: '' with: [
spec
query: 'Classes with too long name'
meaning: 'A class should not have a name with more than 25 characters'
as: [:model | model allModelClasses select: [ :each |
each nameLength > 25 ] ].
].
spec open
Up to now we only defined concerns that are expressed with a query and that spawn a group of items as a result. If the group is not empty, the concern is considered to be violated and it turns red. If the group is empty, it appears green.
There are cases in which an issue is better represented with a presentation different from a list. Also, a concern is not necessarily black or white, but it can simply be something we might want to watch for.
Reading further ArgoUML documentation, we get to a section dealing with the use of Facades in ArgoUML. Here are some relevant excerpts:
- “A Facade class provides the most common functions”
- “For each subsystem X in ArgoUML that uses the subsystem Y, the designer of the subsystem X must decide if he wants to use the API of Y when using the subsystem Y ... or use the Facade class of subsystem Y”
Given that the use of Facades is important in ArgoUML, a concern can be to make them more visible so that people are aware of their existence. Furthermore, because ArgoUML offers one Facade per module, it would be interesting to offer an overview of the modules that contain such a Facade.
Thus, we would like to create a small visualization to highlight the places that contain Facades. Given that this task presupposes more code, it requires the creation of a class:
REPComputedConcern subclass: #TMBArgoUMLFacadeMap
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'TheMooseBook-Examples'
In this class we define the following methods:
label
^ 'Facade watcher'
explanation
^ 'Map of packages containing Facade classes'
computeResult
^ self model allModelNamespaces select: [ :each |
each classes anySatisfy: [:class | '*Facade*' match: class name] ]
browser
| browser |
browser := GLMTabulator new.
browser column: #map; column: #code.
browser transmit to: #map; andShow: [:a |
a mondrian
title: 'Package map';
painting: [:view :facadeNamespaces |
self viewFacadeNamespaces: facadeNamespaces on: view ]].
browser transmit to: #code; from: #map; andShow: [:a |
a text
title: 'Facade class';
display: [ :namespace |
(namespace classes detect: [:each |
'*Facade*' match: each name ]) sourceText ];
when: [:namespace | self result includes: namespace ]].
^ browser startOn: self result
viewFacadeNamespaces: facadeNamespaces on: view
view shape label
text: #name;
fontColor: [:each |
(facadeNamespaces includes: each)
ifTrue: [Color blue]
ifFalse: [Color gray]].
view nodes: (self model allNamespaces select: [:each |
'org::argouml*' match: each mooseName ]).
view shape horizontalOrthogonalLine.
view edgesFrom: #parentScope.
view horizontalTreeLayout
The first two methods provide the proper label and explanation text. The third method takes care of computing the result of the query. The last two are more interesting as they define a browser to present the information. These two methods make use of Glamour (see Chapter 18) and Mondrian (see Chapter 15).
Once we have the class, we simply add it to the overall report by inserting:
spec composite: 'To watch for' with: [
spec concern: TMBArgoUMLFacadeMap new ].
Spawning the complete report results in a browser like shown below. First, the "Facade watcher" concern is black denoting that we do not expect a certain answer. Second, the presentation is offered in the form of the browser defined above: the visualization to the left shows in blue the packages that contain a Facade, and selecting one shows the source code to the right.
That is it. We have just built a dedicated report that can act both as a checker of hard rules, and as a documentation with complex presentations.