Roassal is a visualization engine largely used within the Pharo community. Roassal is used to visualize any set of data. In particular, it is often used to visualize large software source code base to assess their internal quality.
What is the goal of the tutorial?
The following tutorial has been designed to introduce users to the Roassal visualization engine. At the end of the tutorial, users will be familiar to the basic API of Roassal as well with the domain-specific builders. Users will know how to visualize objects within a domain to enable exploration and analysis. They will visualize properties and relationships using the features offered by the engine such as shapes, layout, color, size, interactions (to name a few). Users should also be able to know where to find answers to further questions and to get deeper knowledge in the engine. Let's start.
Roassal is easy to install and the installation will not polute your file system. Simply download Moose as indicated on http://moosetechnology.org. You need three downloads: Moose 6.1 image, Pharo60.sources, and a virtual machine. The virtual machine depends on your operating system.
On Max OSX, you can open Moose (which contains Roassal) by drag and dropping the file moose-6.1.image on top of the virtual machine. You should obtain something like in Figure .
In the following section we are going to incrementally use the basics of the Roassal API. In each step we (1) define a goal, (2) list required actions to achieve the goal, (3) show the changes to be made to the source code of the previous step (second step on), and (4) how the code of the visualization should look like after the changes (that you can copy/paste).
Visualize the Collection
class hierarchy using a grid layout
RTBox
shape to represent each classRTGridLayout
classes := Collection withAllSubclasses.
view := RTView new.
els := RTEllipse new
elementsOn: classes.
view addAll: els.
RTGridLayout on: els.
els @ RTPopup.
els @ RTDraggable.
view @ RTDraggableView.
view
Map to the size and color of each box metrics of classes
color:
, size:
text:
of the popup
classes := Collection withAllSubclasses.
view := RTView new.
els := RTEllipse new
color: [ :e | Color gray: 1 - (e methods size / (classes max: [ :c | c methods size ])) ];
size: [ :e | e numberOfLinesOfCode ];
elementsOn: classes.
view addAll: els.
RTGridLayout on: els.
els @ (RTPopup new text: [ :e | e name , ' -> ' , e methods size asString ]).
els @ RTDraggable.
view @ RTDraggableView.
view
Show the class hierarchy using edges and a tree layout.
RTTreeLayout
classes := Collection withAllSubclasses.
view := RTView new.
els := RTEllipse new
color: [ :e | Color gray: 1 - (e methods size / (classes max: [ :c | c methods size ])) ];
size: [ :e | e numberOfLinesOfCode ];
elementsOn: classes.
view addAll: els.
ei := RTEdgeBuilder new.
ei view: view.
ei objects: classes.
ei shape line color: Color gray.
ei connectFrom: #superclass to: #yourself.
RTTreeLayout on: els.
els @ (RTPopup new text: [ :e | e name , ' -> ' , e methods size asString ]).
els @ RTDraggable.
view @ RTDraggableView.
view
Adjust the visualization using normalization to map color and size, and apply a more scalable layout.
color:
and size:
sent during the creation of elementsRTMetricNormalizer
object to map the color and sizeRTEllipse
classes := Collection withAllSubclasses.
view := RTView new.
els := RTEllipse new
elementsOn: classes.
view addAll: els.
ei := RTEdgeBuilder new.
ei view: view.
ei objects: classes.
ei shape line color: Color gray.
ei connectFrom: #superclass to: #yourself.
RTMetricNormalizer new
elements: els;
normalizeSize: #numberOfLinesOfCode;
normalizeColor: [ :e | e methods size ]
using:
{Color veryLightGray.
Color red}
using: #sqrt.
RTClusterLayout on: els.
els @ (RTPopup new text: [ :e | e name , ' -> ' , e methods size asString ]).
els @ RTDraggable.
view @ RTDraggableView.
view pushBackEdges.
view
Add a different kind of edges to depict class dependencies
classes := Collection withAllSubclasses.
view := RTView new.
els := RTEllipse new
elementsOn: classes.
view addAll: els.
ei := RTEdgeBuilder new.
ei view: view.
ei objects: classes.
ei shape line color: Color gray.
ei connectFrom: #superclass to: #yourself.
RTMetricNormalizer new
elements: els;
normalizeSize: #numberOfLinesOfCode;
normalizeColor: [ :e | e methods size ]
using:
{Color veryLightGray.
Color red}
using: #sqrt.
RTClusterLayout on: els.
eb := RTEdgeBuilder new.
eb view: view.
eb objects: classes.
eb shape
bezierLineFollowing: #superclass;
color: (Color blue alpha: 0.1).
eb connectFrom: #yourself toAll: #dependentClasses.
els @ (RTPopup new text: [ :e | e name , ' -> ' , e methods size asString ]).
els @ RTDraggable.
view @ RTDraggableView.
view pushBackEdges.
view
Let's see. Now we are going to load a model of Tomcat into the Moose image and ajdust the visualization to analyze it. The model contains a description of the main properties of the software such as classes, methods and invocations. Also, we are going to link the model to the software's source code, so we can inspect it within the visualization.
Show how the visualization performs on larger software (~1 min.).
classes := MooseModel root first allClasses.
view := RTView new.
els := RTEllipse new
elementsOn: classes.
view addAll: els.
ei := RTEdgeBuilder new.
ei view: view.
ei objects: classes.
ei shape line color: Color gray.
ei connectFrom: #superclass to: #yourself.
RTMetricNormalizer new
elements: els;
normalizeSize: #numberOfLinesOfCode;
normalizeColor: [ :e | e methods size ]
using:
{Color veryLightGray.
Color red}
using: #sqrt.
RTClusterLayout on: els.
eb := RTEdgeBuilder new.
eb view: view.
eb objects: classes.
eb shape
bezierLineFollowing: #superclass;
color: (Color blue alpha: 0.1).
eb connectFrom: #yourself toAll: [ :e | e methods flatCollect: #clientTypes ].
els @ (RTPopup new text: [ :e | e name , ' -> ' , e methods size asString ]).
els @ RTDraggable.
view @ RTDraggableView.
view pushBackEdges.
view
Distinguish Tomcat classes from libraries (Java core and external libs) and change the layout to ease the analysis of dependencies (~2.5 mins.)
color:
to distinguish the source of a class (whether or not it belongs to Tomcat) and remove the previous definition from the normalizerRTForceBasedLayout
classes := MooseModel root first allClasses.
view := RTView new.
els := RTEllipse new
color:[:e| (MooseModel root first allModelClasses includes:e)
ifTrue:[Color blue] ifFalse:[Color red] ];
elementsOn: classes.
view addAll: els.
ei := RTEdgeBuilder new.
ei view: view.
ei objects: classes.
ei shape line color: Color gray.
ei connectFrom: #superclass to: #yourself.
RTMetricNormalizer new
elements: els;
normalizeSize: #numberOfLinesOfCode.
RTForceBasedLayout on: els.
eb := RTEdgeBuilder new.
eb view: view.
eb objects: classes.
eb shape
bezierLineFollowing: #superclass;
color: (Color blue alpha: 0.1).
eb connectFrom: #yourself toAll: [ :e | e methods flatCollect: #clientTypes ].
els @ (RTPopup new text: [ :e | e name , ' -> ' , e methods size asString ]).
els @ RTDraggable.
view @ RTDraggableView.
view pushBackEdges.
view
Test
word. (2) Include in the visualization stubs of the Java core and libs classes (.e.g., Object
). (3) Notice that the model of the methods of a class contain its annotations.
Solution
#hierarchyNestingLevel
in its height, (2) the #numberOfAttributes
to its width, (3) #fanOut
in its color; and the x-position of rectangles must encode #fanOut
and y-position =#fanIn
. The resulting visualization should look like the one below. Analysis of the visualization and highlight insights that you found. Hint: How fanOut
relates to other metrics?
Solution
Links to resources for more detail on the Pharo language, the Moose plataform and the Roassal visualization engine.