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 domain-specific tools that address your application domain?

Forces

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

For example, consider a generic debugger being used to debug an event-driven application — you want to step through the chain of events, not the stack. 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 play 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.

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, \ie 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.

If we OPT-click on the Moves heading, we see the method that implements this view: GtLudoRecordingGame>>#gtMovesFor: gtMovesFor: aView <gtView> ^ (aView columnedList) title: 'Moves'; priority: 40; items: [ self moves ]; column: 'Index' text: [ :eachItem :eachIndex | eachIndex asRopedText foreground: Color gray ] width: 45; column: 'Roll' text: [ :move | move roll ]; column: 'Player' text: [ :move | move player ]; column: 'Token' text: [ :move | move token ]; updateWhen: GtLudoMoveRecorded in: self announcer

The inspector detects the <gtView> pragma ofthis 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.