GT Releaser: a case study exemplifying Moldable Development

GT Releaser: a case study exemplifying Moldable DevelopmentAdapting the IDE to fit the context of a software systemAndrei ChisBlockedUnblockFollowFollowingMar 13In this article we explore how explaining a software system can look like, if we actively adapt the IDE to fit the context of that system during development.

Software systems are highly contextual.

For development tools to be effective, they have to take that context into account.

It follows that tools must be moldable so that programmers can adapt them to their current needs, easily and frequently.

OverviewSoftware is shapeless.

Programers craft software exclusively by interacting with development tools.

Hence, tools provide the shape of software.

But they also do much more: development tools have a direct impact on our thinking habits, affecting the way we perceive, and reason about our software systems.

Software is also highly contextual.

For development tools to be effective, they have to take that context into account.

It follows that tools must be moldable so that programmers can adapt them to their current needs, easily and frequently.

The essence of moldable development is to empower programmers to customise development tools for their own systems.

In this article we take a look at one system, GT Releaser, and explore how explaining its inner structure, usage scenarios, and technical details can look like if we do it through customised tools, rather than generic ones.

GT Releaser in a nutshellGT Releaser is an engine for releasing new versions for nested Pharo projects used by Glamorous Toolkit.

We presented it in a previous article.

In short, GT Releaser starts from a configuration loading the latest code of a Pharo project, and creates a new fixed semantic version loading that code.

An interesting aspect about GT Releaser is that its development follows the practice of moldable development:As we create a system we also create the tools that help us to better understand and reason about that system.

Next, we look at several questions that both a programmer working on GT Releaser, as well as a user that wants to create new releases can run into, and explore how we can answer them by simply looking at the internal structure of the system using an object inspector.

Exploring a loading configurationIn GT Releaser loading configurations are expressed as Metacello baselines.

Metacello is a package management system used in Pharo.

A baseline contains the list of packages from a system, their loading order, and dependencies to other baselines.

When trying to understand what is loaded by a given baseline, it is often useful to reason about its dependencies to other baselines.

Exploring a loading configuration — the generic wayTo reason about dependencies involving a baseline in GT Releaser, we create an object modelling that baseline.

This is an instance of the class Project and contains the list of packages and dependencies defined in the baseline.

To explore the object we can start from a code snippet creating it and view it in an object inspector, a tool that should help us understand that object.

As a concrete project let’s look at Brick, the widget library from Glamorous Toolkit.

Inspecting an object modelling a baseline in GT Releaser using the `Raw` view.

By default, the generic Raw view shows us the list of attributes from this object, together with their values.

The attribute childProjects contains the list of dependencies.

We select it, and drill down in that object to see what it contains.

In this case it is a collection.

We select next the Bloc dependency, explore it further, and also drill down into its dependencies.

Exploring nested dependencies by navigating based on attributes through objects modelling baselines.

By navigating through object attributes a few times, we can get a better understanding of dependencies.

Above we see that Brick depends directly on Bloc and Beacon, and that Bloc depends on five other projects.

Nonetheless, getting a fine-grained understanding of all nested dependencies, and finding out details, like that fact that Brick has both a direct and indirect dependency to Beacon, requires many steps and manually tracking details.

For example, as we explore dependencies we could sketch the following graph.

Sketching the dependencies between projects loaded by Brick.

Exploring a loading configuration — the moldable wayAlternatively, since all the information that we need are in the Project object, instead of manually building the dependency graph, we can create a small custom tool that does this for us.

The code below extracts and uses a graph layout to visualise all dependencies for the baseline that loads Brick.

Creating a custom view for exploring all nested dependencies for the baseline of Brick.

With this view we can easily get a grasp of all loading dependencies for Brick.

Since it proved useful we can take a few more minutes and simply make this view a first-class entity in the IDE, so that any user or programmer can access it whenever inspecting a Project object.

For that we add a new method in the Project class that defines an inspector extension creating this view.

Adding a custom extension to Project objects that displays the graph of dependencies.

Now, just inspecting the object modelling the baseline is enough to get a graph showing us all the loading dependencies directly in the inspector.

Inspecting all nested dependencies from a baseline using a dedicated view.

In the case of GT Releaser, we created the above view during the development of the framework, as it proved useful.

However, we also needed other types of views.

For example, this view does not show the repository containing the baseline.

Especially when having multiple baselines in a repository, that information is useful to have.

To get that extra information, we can create another view.

In this case, the snippet below builds a view grouping together all baselines from a repository.

Building a custom view that groups baselines based on the repository containing them.

Once we have this snippet, we can turn in into an inspector extension.

Inspecting all nested dependencies grouped by the repository containing them using a dedicated view.

We can also add other views to show immediate children and parent dependencies for a given project.

With these we can now navigate though baseline dependencies without having to go into implementation details.

The screenshot below shows such a navigation scenario.

We start by looking at the child dependencies of Brick and then Bloc.

In case of Sparta, we switch to the dependencies graph.

Then we dive into Beacon, and look at the source code of the baseline.

The source code is shown using another custom view.

Exploring baseline dependencies in the inspector using only custom views that do not contain implementation details.

Diving into a releaseUntil now we only looked at dependencies between baseline.

However, the goal of GT Releaser is to create new versions for a system.

Let’s explore next a release object.

A release object is an instance of the class ProjectRelease.

It points to a Project object and adds information about the semantic version of that release and the branch on which the release is performed.

Releases are performed for all dependencies of a projects, if there are new changes.

We can attempt to extract what project versions will be created as part of a release, by just looking at object attributes.

For example, in the screenshot below we observe that for Brick the next release v0.


38 will be done on the #release branch, and that the RepositoryRelease object for the Brick repository has the attribute isPassiveRelease set to false, meaning that there are new changes in this repository.

Exploring a release object to find our details about the release by looking only at object attributes.

As with dependencies, the Raw view focuses on the technical implementation of a release object.

We can use it to understand what is going to happen when performing a release, however, that is again a tedious activity.

Instead, we can create a custom view that directly shows us the dependency graph, and for each project adds information about the release.

We also can highlight with grey projects that have no new changes since the previous release, and hence do not need a new generated release.

Exploring information about a release using a dedicated view attached to the release object.

We can observe that three baselines, Bloc, BlocLayout and BlocCore, have the same release version, v0.



This indicates that they are most likely placed in the same repository.

To confirm this we can also annotate the view showing projects grouped based on repositories with release information.

Exploring information about a release by looking at the view grouping projects based on the repository containing them.

This view gives a complete overview of the next release.

We see that the release happens at the level of a repository and that all projects from a repository have the same version.

In case a new release is not needed for a repository we use the existing version and highlight the repository in grey.

Diving into release actionsWhile looking at a release from a high-level perspective is useful, what also proves useful is grasping in more details what actions will be executed in order to actually create that release.

For example, what actions are performed to create the v0.


38 release in the github://feenkcom/Brick repository?To solve this, in GT Releaser all release actions are reified as objects and are computed when the release object is created, before it is executed.

By adding a view that shows those actions we can explore them directly in the inspector.

For example, below we are inspecting the object that models the github://feenkcom/Brick repository in the v0.


38 release.

We can observe that to perform this release the master branch is merged into the release branch, the baseline code is updated, some metadata is exported, a new commit with a tag is created and finally the local changes are pushed.

Exploring the release actions performed in the github://feenkcom/Brick repository for the v0.


38 release.

Above we are only looking at the actions performed for a single repository.

Also useful is to see the complete list of actions for all repositories affected by the release.

We can also get that directly through an inspector view by inspecting the object that executes the actual release.

Exploring all the actions for creating a release.

Exploring the actions executed after a release is created.

Above we explore the release actions using two views.

The first shows the actions executed to create the actual release.

The second the actions executed after all the versions are created, which at the moment push changes.

Release actions in detailsSeeing the list of actions gets us more information, but it still does not always help us to understand what an action is going to do.

For example, what will the action for compiling the baseline of Brick do for release v0.


38?To get more details we can inspect actions.

If we inspect the action for compiling the baseline of Brick we immediately see the new code of the baseline and can look at a diff between the current version of the baseline and the new one.

Like this we see that creating version v0.


38 for Brick consists in adding links to fix versions for Bloc and Beacon.

Looking at what changes are done in a baseline in order to create a release version using an inspector view.

It can be also useful to see how the baseline in version v0.


38 differs from the baseline in the previous version of Brick.

The view Diff previous version shows us that.

We discover now that both versions use the same fix version for Beacon.

Only the Bloc version is updated.

Looking at the changes between the new version and the previous version using an inspector view.

Other actions expose the user to other kinds of information.

Below, the action for exporting metadata shows that metadata, which is a JSON file containing the concrete versions for all external dependencies.

Viewing the metadata that will be generated when creating the new release.

The action to commit shows the message that will be used for the commit.

Looking at the message that will be set for the commit that creates the new release.

Apart from just viewing data about a command, a user can also execute commands right in the inspector.

Both the views for showing a single action or a list of action allow users to execute actions.

Below the user executed the first three actions; those actions are highlighted in grey.

Release actions can be executed directly in the inspector.

Actions already executed are highlighted in grey.

The inspector as a user interfaceUntil now we did not see a dedicated user interface for GT Releaser.

We interacted with the tool only though the object inspector.

The object inspector allows us to see both implementation details and high-level views for our objects.

Thus the inspector acts both as a user interface for end users and a development tool for programmers working on the tool.

This way the inspector can provide under one uniform interface a way to interact with a software system at two different levels of abstraction: one for end users and one for programmers.

And there is no barrier between these two different ways to look at a software system.

They coexist together, and switching from one to the other is only one click away.

The cost for this user interface was also very low, almost for free.

We developed it incrementally while we built our domain model and wanted to have a better way to reason about it.

Using it then during development to understand the application far outweighed the initial cost to create it.

Often software systems support end users, from the very beginning, through dedicated user interfaces that are completely separated from the development tools used to create those systems.

But if the IDE is supposed to be integrated, it should allow us to look at software systems both from the perspective of an end user or that of a programmer.

.. More details

Leave a Reply