Guiding custom code changes with GTInspector

In a recent post on the Moose mailing list, Alex talks about how he guided a code migration in Pharo by means of a visualization. The code in question was Graph-ET, the charting engine, and he wanted to port it from Roassal to Roassal2 (the visualization engine of Moose). Essentially, he needed to browse all references to Roassal classes and choose the corresponding class from Roassal2.

In his case, he constructed a FAMIX model out of the Pharo code, and wrote a visualization that highlighted the methods to be refactor ed within the entire class hierarchy. By making the visualization interactive, he could simply click on the method and go change the associated code.


This is certainly a possibility and it already provides a productivity boost. The approach applies equally well to Pharo and other languages, like Java. However, when working in Pharo we can now support this use case better and cheaper.

But first, why is this use case relevant? Because when the changes you have to perform are larger, you need a to do list to keep track of the progress and to make sure you are not forgetting anything. This is a classic migration problem.

So, let’s see what the requirements are. We need to find all methods from Graph-ET that have a reference to classes called RO*. We do not need FAMIX for this. We can directly query the Pharo code model.

(RPackageOrganizer default packageNamed: 'Graph-ET')
     allMethodReferences select: [ :each |
          each method literalStrings anySatisfy: [ :literal |
               literal notNil and: [literal beginsWith: 'RO' ] ] ]

The script above retrieves the list of RGMethodDefinitions objects pointing to the interesting methods for our case. And now, just inspect.

The cool thing is that you can preview the source code in the inspector, and you can even modify the code right there without extra menus and windows. Essentially, you get a highly focused code browser (see attached).


Of course, you can also create a visualization, if you want. For example, you can inspect the below code:

| view |
view := ROMondrianViewBuilder new.
     nodes: (RPackageOrganizer default packageNamed: 'Graph-ET') classes
     forEach: [:cls |
          view shape rectangle
               if: [ :m | m method literalStrings anySatisfy: [ :literal |
                    literal notNil and: [literal beginsWith: 'RO' ]]]
               fillColor: Color red.
          view nodes: (cls methods collect: #asRingDefinition).
          view gridLayout ].
view edgesFrom: #superclass.
view narrowTreeLayout.

And if you click on each method (small square), you again get the editor to the right.


There are things to improve here. For example, the list of items is not casually connected with the code editor, and thus, it does not update when you modify the code. Another thing is that Ring should offer a more concise API (for example, in our case, we had to go through literals to find references to classes).

Still, the existing solution is already useable and useful. And, it does not end here either.

Let’s consider a slightly more complicated problem. While working on a new implementation of CodeCity with Ricky, we stumbled across a similar problem. Long story short, all methods that ended with For: from the CCShape hierarchy had to be changed to work with aNode and not with anObject (details do not quite matter, but aNode is a visual wrapper around anObject). This can be solved similarly as the one above.

     withDeep: #subclasses
     flatCollect: [ :each |
          each methods select: [ :m |
               m selector endsWith: 'For:' ] ]) collect: #asRingDefinition

Executing the script, reveals the list of methods we could work through.


However, in our case, we also needed to ensure that the senders of the target methods are modified as well to pass the node and not the raw object. To look for senders, we can stay in the inspector and simply switch to the senders pane. Again, selecting a method in the senders pane provides an editor to the right.


In this case, too, we could improve the tool. For example, given that the two panes are not casually connected, the sender code is not highlighted on the previewed source code (verticesFor:).

Nevertheless, the existing GTInspector is simple and it already offers an unexpected solution for a common use case. The only thing you have to do is write the query to obtain your methods. Everything else comes out of the box.

This is humane assessment at its very best.

Posted by Tudor Girba at 3 January 2014, 1:09 pm with tags tooling, story, moose, assessment, spike, pharo link