Contextual Playground
Context
You are using a Moldable Tool, and you are ready to start exploring your software system.
Problem
Where do you start exploring?
Forces
— An editor for coding new methods typically provides no facilities for testing the code.
— When we code new behavior as methods, we must repeatedly change our context to incrementally develop the logic.
— Testing the code requires a separate setup.
— Setting up code to prototype and test logic can be cumbersome.
— Writing tests first for parts of the logic of a complex method may can be overkill.
Solution
Use a contextual playground of the tool to programmatically explore the entities of interest, and prototype new behavior.
Steps
A contextual playground provides a live programming interface to programmatically interact with the software entity managed by a Moldable Tool. The playground will be bound to the context of the object, so self and all slots ( i.e. , instance variables) can be accessed exactly as they would in a running method.
Use the contextual playground to write code snippets to extract data, test hypotheses, navigate to parts or other related objects, to explore the API, or to prototype new behavior. Evaluating the code will typically open a new instance of another moldable tool on the result returned by the code, with a new contextual playground. Code snippets that turn out to be useful or interesting can then be copy-pasted to existing methods, or extracted to new methods using an Extract method refactoring. The same process can be used whether the extracted code consists of accessors, assertions, examples, or new behavior.
Examples
The page Inspecting Python objects with custom inspectors shows how to obtain an inspector view of an instance of a Python MovieCollection
class. The notebook page contain live code snippets, which function as contextual playgrounds within the context of the notebook page. From there we can navigate to a moldable object inspector, a moldable tool for exploring live instances. In this case we are exploring a live Python instance of a MovieCollection
object, with several custom views showing the Directors, Years and Movies of the collection. At the bottom of the inspector we see a contextual playground bound to the context of the Python object.
In this contextual playground, we can experiment with Python code to perform a query over the collection and navigate to a particular Movie instance. Note that self in the code snippet is bound to the context of the MovieCollection instance. Once we have identified some useful code, we can extract it as a new method of the object. Similarly, if we identify an interesting instance, we can use the code to define an Example Object.
Evaluating this snippet opens another Python object inspector on the resulting Movie, seen in the third pane. The third pane also has a contextual playground, which can be opened by dragging up the handle at the bottom of the pane.
Consequences
By prototyping new behavior in a contextual playground, you obtain immediate feedback for experimental code.
You may need to evaluate multiple snippets in multiple playgrounds to get to interesting information.
Known uses
A REPL (Read-eval-print loop) or language shell is essentially a contextual playground for a programming language or an operating system.
The JavaScript console of a modern web browser also functions as a contextual playground: while inspecting a live web page, you can explore and programmatically interact with the live objects in the run-time environment of the page.
The moldable tools within GT all provide contextual playgrounds: notebook pages, object inspectors, code editors, and the debugger, in particular.
You can also see this process at work in the short video Exploring the GitHub REST API in 7'.
Related patterns
Use a Project Diary to start live coding. You can use a contextual playground to prototype custom tools (see Custom View, Custom Action and Custom Search) for a Moldable Object within a moldable inspector. A snippet within a contextual playground that yields an interesting object can be extracted as an Example Object. A contextual playground for an Example Object can also be used to explore and prototype assertions for that example.
GT implementation notes
The following steps illustrate how the Inspector Playground can be leveraged to explore an object's state, experiment with code, extract methods, extract (test) examples, and add custom views to a live object.
Suppose we are implementing a StackMachine
class to simulate an RPN calculator. So far it just holds a stack
slot initialized to an empty OrderedCollection
, and nothing else. We want to implement operations to perform calculations with the stack machine.
Exploring the object's state
We start by exploring a live instance.
StackMachineV0 new
We would like to push some values onto the stack but we need to explore the API of the underlying objects.
From the Inspector we dive into the stack slot and query its
Meta
view to see which add
operations it has.
We find the addLast:
selector, and experiment with it in the Inspector Playground.
We see in the stack's Items view that it has been updated.
Extracting a method
We generalize the code as follows.
We select the code and perform an
Extract method
refactoring, and name the new (binary) method !
.
(For illustrative purposes we have multiple StackMachine classes to represent the different versions. In reality we would just have one class.)
We push two values onto the stack from the Inspector Playground.
Extending the API
It would be nice to inspect the stack and the top of the stack, so we test each of the following snippets in the Playground, and extract them as methods.
stack. stack isEmpty. stack last "top".
Our API now looks like this: StackMachineV1
Extracting an example method
We rewrite our scenario as an example:
example := self class new. example ! 3. example ! 4. example
And again we extract a method. We add a <gtExample>
pragma, with some assertions. StackMachineV2>>#stackWith3and4
We can generate an instance directly from this method ( Play and inspect ).
Adding a custom view
We'd like a custom view for the StackMachine that mirrors the stack
slot's
Items
view.
From the live example, we navigate using the
Raw
view to the stack's
Items
view, Secondary-click on the tab and see that the method that implements this view is called gtItemsFor:
(implemented in SequenceableCollection>>#gtItemsFor:
.
Now we can quickly implement a forwarding view as follows: StackMachineV3>>#gtStackFor:
It looks like this: