Moldable Tool

Context

You are developing a software system, and find that the existing development tools fall short in supporting domain-specific questions about the software.

Problem

How can you cheaply and effectively extend the development environment with custom tools that address questions about your application domain?

Forces

— Generic software tools are fine for answering generic questions, but they do not work well when addressing domain-specific questions.

— A plugin architecture can open up an IDE to new tools, but plugins can be complex and expensive to implement, and they often do not compose nicely with existing tools or with each other.

Solution

Make the development tools moldable to the dynamic context of the artifacts they are intended to work with, by associating custom behavior to the artifacts themselves.

Examples

A moldable tool makes its core functionality configurable by means of lightweight mechanisms. For example, a Test Runner in a modern IDE recognizes the presence of test cases by means of various programming conventions, i.e. a test case is a method with a standard annotation, or it's a method whose name starts with test and belongs to a class that inherits from a TestCase TestAsserter subclass: #TestCase instanceVariableNames: 'testSelector expectedFails' classVariableNames: 'Announcers DefaultTimeLimit HistoryAnnouncer' package: 'SUnit-Core-Kernel' class or implements a Test interface.

By the same token an inspector can be made moldable by recognizing that an object it is inspecting has one or more custom views defined as annotated methods. For example, below we see that an Inspector on an instance of a GtLudoRecordingGame GtLudoGame subclass: #GtLudoRecordingGame instanceVariableNames: 'moves' classVariableNames: '' package: 'GToolkit-Demo-Ludo-Model' has a custom Moves view listing the moves played thus far.

The inspector detects the <gtView> pragma of this method, and knows that it should generate a view for this object. The custom view is defined in a just a few lines of code, creating a columnedList from the moves.

The precise mechanism used to mold a tool is not as important as is the fact that the customizations should be cheap, i.e., few lines of code, and dynamic , i.e. detected at run time.

Other examples include:

• a moldable code browser offering alternative views of packages, classes or methods to show dependencies, tests, or other more domain-specific features,

• a moldable debugger to adapt the stepping behavior for domains such as event-driven applications, or parsing rules, or

• a moldable notebook, supporting domain-specific snippets or annotations.

Consequences

A moldable tool requires no up-front configuration, since it will be dynamically molded by the artifacts it encounters.

Conversely, since custom tools are an intrinsic part of software systems rather than the IDE, molding happens when needed.

Some tooling effort is required to open up the existing IDE tools to make them moldable, i.e., dynamically customizable.

Known Uses

Unit testing tools such as JUnit rely either on inheritance or annotations to automatically detect which methods in a package are tests, and adapt the IDE to enable test runners, however the tool adaptation is fixed, and cannot be further customized without writing a new plugin.

The JetBrains IDE allows you to customize the views of objects within a debugging session, though the custom views are specified in the configuration of the tool itself, not in the context of the object.

The Glamorous Toolkit includes several moldable tools. The Moldable Inspector installs custom views, actions ( i.e. , buttons), and search interfaces whenever an object is inspected that defines such custom tools as annotated methods. The Moldable Coder ( i.e. , code editor) also can add custom views, highlighters, actions and searches when editing the source of a class with annotated methods. The Moldable Debugger provides custom views, actions and searches installed as methods in the class of a caught exception.

Related patterns

A Moldable Tool reacts to a Moldable Object, which triggers custom tools such as Custom View, Custom Search or Custom Action. A Moldable Tool should provide a Contextual Playground to enable a live programming interface to the entities it works with ( i.e. , objects, classes, exceptions).

Further reading