Interactive Development With ActiveDeveloper
Volume Number: 20 (2004)
Issue Number: 4
Column Tag: Programming
Interactive Development
by Aidan A. Reel
Interactive Development With ActiveDeveloper
An Introduction to Interactive Development and a review of Inter*ACTIVE - Technology's ActiveDeveloper
Introduction
This article introduces interactive development, an approach that increases your quality and productivity as a developer. It also reviews a toolset that permits this style of development to be used with Apple's development tools. Before delving into the grit of the article, a short computing backdrop explains where my interest in interactive development stems from. We will see that interactive development is not new, but has been supported by some IDEs for over 30 years. I'll outline the functionality that tools need to provide in order to be regarded as interactive development tools. I will discuss features within Objective-C that can be utilized in order to provide such tools. Finally, I will introduce, and review ActiveDeveloper (AD), a toolset that brings interactive development to ProjectBuilder and Xcode.
Backdrop
As a developer in the early 1990s, I coded with NeXTSTEP. NeXTSTEP allowed me to truly grasp Object Orientation. It was using instances in InterfaceBuilder that turned on the light. That phrase, 'using instances', is central to this article. I became aware that Brad Cox based his Objective-C's extensions on a language called Smalltalk. This introduced me to the language that I would use continually for the next 10 years, namely Smalltalk.
Smalltalk and its various IDEs (ParcPlace, IBM, Digititalk) taught me the power of having no compile-link-run cycle and having access to the instances within a running application. When I understood how to use tools such as workspaces, object inspectors and the stack based debugger properly, I realized were NeXT had got its power from. Again it was working with instances. Smalltalk allows you to investigate a running program in real time. It is possible to halt execution, edit code, change attribute values on-the-fly, and resume execution. In other words, you, as a programmer can operate on your living program. You can inspect instances, traverse references, observe the actual state of your program, i.e. objects, at any point, as it runs. Having seen how the program is working (or not), it is possible to edit methods there and then in the debugger, and re-execute it. All of these activities flow from the keyboard. When you save a method, it is not only saved but compiled, and available for execution. Your workflow is not interrupted waiting for the compile and linking to complete, restarting the application and directing it back to the point of execution under investigation. You start where you left off, all in the time it takes to press command-s. These tools are an intrinsic part of Smalltalk IDEs.
So, after many years firmly settled in the Smalltalk industry, I had an opportunity to do some development for Mac OS X. I found myself staring at ProjectBuilder, and InterfaceBuilder. After the initial shock of how familiar they still were, and the fact that I was able to use my 1993 copy of NeXTSTEP Programming by Garfinkel and Mahoney to reintroduce myself to the developer tools and frameworks, when all was said and done I was back to the compile-link-run cycle. Regardless of the richness and maturity of Cocoa, returning to the disruption of start stop start stop programming was extremely frustrating. I soon found myself browsing the web for tools that sounded as if they supported some form of interactive development. Eventually, I found a reference to ActiveDeveloper and sat down to see what it offered.
That brings us (more or less) up to date. I am a developer whose main development experience has been supported by a language, and toolset that permitted a very interactive style of development. Faced with an environment that did not natively support such an approach, I started to use a 3rd party product that pertained did. Now you have an opportunity to read about this style, and experiment with the same.
What Interactive Development Is and What it is Not
Lets start with the negative, what interactive development isn't. This is not another methodology aimed at removing identified problems in software development. Nor is it a process encouraging the adoption of a unified set of tasks that reduce the risk inherent in software development. Interactive development is a lot more humble. To the developer, it is about a new set of (easy to use) tools, rather than a new (difficult to appreciate) development strategy.
It is closer to the spirit of extreme programming in that it will enthuse the developer, and inspire them by making it easier to write robust code. As they realize that their code is improving at the same time as their productivity is increasing, their morale and confidence improves.
Before a developer can fluently use these new tools, they need to understand the mindset to be adopted. You will be pleasantly surprised to find that this mindset is very easy to adopt, and soon becomes second nature.
There are two aspects to interactive development. One is interactive investigation, and the other is interactive coding.
Interactive investigation is the task of understanding classes and frameworks by investigating instances of the classes involved. You create instances of any class, and inspect them while they are active. It is possible to send messages to their attributes and to inspect the resulting object. A tool, normally referred to as a workspace, provides a general context in which code can be written and executed. So, for example, the following code,
[[NSWorkspace sharedWorkspace] launchedApplications];
could be written in a workspace and executed. The resulting object can be inspected in an object inspector, or browser. Inspectors provide the developer with a graphical interface to display, and browse an instance's values and references. You can traverse the various references to display other instances. Inspectors also provide a coding area whose context is the currently selected attribute. Using this context permits the sending of messages to the selected attribute. This kind of exploration and investigation cements the developer's understanding of the classes under scrutiny.
This kind of investigation normally melts into incremental development. A developer will start by reading some documentation or guessing that a particular class may suit their needs. Taking these classes, and creating instances and investigating their behavior, the developer can confirm that these classes do indeed support their requirements. Typically, if they have written code that confirms this, then this very same code will probably be quite close to what they require. So, the next step is to move this code to a method. Note that I say move rather than convert. Because you are performing your investigation in true Objective-C, this task is typically a matter of copy & paste, changing some temporary variables into instance attributes, which is not a major task. There is no converting, rewriting, or debugging of a new piece of code.
Developers can also be faced with having to quickly understand complex classes in order to enhance or debug. With interactive investigation, the developer can work within a workspace (away from the complexity of the existing application) on salient classes, inspecting instances, traversing references, and sending messages to attributes. In effect, building up a mental picture of the instance graph. In the same way that a picture is worth a thousand words, being able to interrogate live instances is worth a thousand pages of documentation. A slight exaggeration but I think you will understand the sentiment.
Next, interactive coding avoids the compile-link-rerun cycle. In doing so, the programmer is freed to continually concentrate on the problem at hand. Being able to sustain an uninterrupted train of thought increases developer productivity, and quality of work. Imagine a writer being expected to save after every edit, issuing reformat commands, linking in adjoining paragraphs, and restarting viewers before they could see the effect of their changes. As a writer, the disruption to the creative process would be unacceptable. Yet, that is the process accepted, and expected by most programmers. Interactive coding avoids the disruption, releasing you to work at your own natural pace. It needs the support of special tools, editors that avoid having to recompile the classes just edited, re-linking modules and rerunning the application. The editors should allow you to reload changes even while the application is running and allow the developer to observe the changes, in action, immediately.
How it works
Interactive Investigation
The good news with interactive investigation is that the underlying mechanisms used by these tools (workspaces and object inspectors) do not necessarily have to be understood by developers in order to avail themselves of their functionality.
With regard to ActiveDeveloper, your project includes a library supplied with the product suite. The process to follow in order to include this library is explained in detail in the supplied documentation. It is important to note that the inclusion of this library is only required during development; the deployed application has no dependencies on ActiveDeveloper, and as such, there is no decoupling project required after code freeze. You can confidently ship the packaged application.
Interactive Coding
Interactive coding, as supported by ActiveDeveloper, is achieved via dynamically loading categories. Since categories play a major role in ActiveDeveloper's support for interactive coding, I have included this section as a refresher on categories. If you are experienced in the use of categories and dynamic loading, feel free to skip the next two sections.
Categories
Categories are an extension to Objective-C. The extension is used:
- as a structural aid, permitting a developer to arrange their code into distinct sets of methods.
- to extend existing classes. Developers can add methods to existing classes when they have no access to source code.
Rather than having your class contained in one large monolithic file, it is possible (using categories) to split the class into a number of smaller files. We organize the files to hold methods that have some kind of similarity, or relationship to each other. So, for example, we could group all accessor methods together in one file, all private methods in another file, methods that implement persistency in a third file, and so on. The intention is that this separation leads to the class being easier to comprehend and maintain.
It is possible to add categories to classes that you do not have the source code for. It is by using categories that companies such as OmniGroup can extend Apple's Cocoa Framework. It is important to appreciate that since we do not need access to the source code of the class in order to extend it, we do not need to recompile the entire class in order to include the new category methods. We just compile the methods in the category. This fact has some very powerful side effects, as we will see later.
Each category can reside in its own file set (interface and implementation). The following listings display templates of category interface & implementation files.
Listing 1: Category Interface Template
Category Interface Template
#import "CLASSNAME.h"
@interface CLASSNAME ( CATEGORYNAME )
METHOD DECLARATIONS
@end
Listing 2: Category Implementation Template
Category Implementation Template
#import "CATEGORYNAME.h"
@implementation CLASSNAME ( CATEGORYNAME )
METHOD DEFINITIONS
@end
The interface file imports the class's main interface file and proceeds to declare itself as a category by virtue of the (CATEGORYNAME) after the CLASSNAME. We then provide a list of the methods that this category will contain. The implementation file imports the category interface, declares the category name in the same manner as the interface, and proceeds to provide the method definitions.
There are some restrictions in using categories. and the main one is that you cannot add new attributes to a class. In the above interface template, we only declare methods, not attributes.
Related to this is the fact that category declarations do not actually need to provide an interface file at all. We could simply provide the implementation file.
Note that if a method with the same name resides in more than one category, it is unpredictable as to which method will get executed if called. Thus the developer of an extension should try an ensure that name clashes are unlikely. One convention is to use prefixes to any method names defined in categories that extend classes you do not own.
Dynamic Loading
The Objective-C runtime supports the loading of category files at runtime, referred to as dynamic loading. This is a very powerful feature enabling classes to be extended during an application's lifetime. All instances belonging to the category's class now have access to those newly loaded methods, even instances created before the category was loaded.
There is no reason why a category cannot be loaded numerous times during an application's lifetime.
It is these facts that allow tools to support interactive development. The special editors mentioned earlier ensure that after the edits have been saved, the category file is reloaded into the running application.
There is an important caveat to dynamic loading and its use in supporting inactive coding editors. I will return to this when you have gained more of an understanding of ActiveDeveloper.
Summary
In this first part of the article, we described techniques that offer a more productive, interactive, exploratory style of development, and gave them the umbrella term of interactive development. We explained that these techniques can only be adopted if supported by appropriate tools, such as workspaces (supports the execution of isolated snippets of code), object inspectors (permits the browsing of instances), and advanced editors (provides the editing and loading of category files thus avoiding the compile-link cycle).
We now turn our attention to one such tool set, available to use in conjunction with Apple's Developer Tools.
The Product
ActiveDeveloper is a product marketed by Inter*ACTIVE - Technology (www.interactive-technology.com), that facilitates interactive development. It runs on multiple platforms (Mac OS X, Windows WOF).
A demo version is available and I suggest, if you already haven't done so, you obtain a copy, and use it as you read along.
You will notice from the web site styling, and AD's interface, that the product has its genesis firmly in NeXTSTEP. The styling may not be to everyone's taste, but I found it reassuring to know that the product has such a long lineage.
The demo version has the normal limitation found in demos of not being able to save your work (your workspace code and editor code). It has another, more annoying limitation, a time out, apparently based on the number of explorations made during a session. I found the time out to be too frequent, and pretty frustrating. I believe the creators are aware of this, and are considering increasing the limit.
As of version 2.15, AD includes a comprehensive user guide that takes you through installation, the most frequently used tools in the package, and explaining the rules of how to structure your own existing projects in order to use the AD tools.
When AD starts, you are presented with AD's main window, the console. You will tend to use this window to observe system messages, and to start your applications. One precompiled sample application is available immediately to start investigation, the ActiveAppKitExplorer.
Figure 1. The ActiveDeveloper Console.
On clicking start with ActiveAppKitExplorer selected, the following window appears.
Figure 2. The ActiveAppKitExplorer main window.
You have just started a new AppKitExplorer application that consists of this single window, and have entered into an ActiveDeveloper session with it. I initially found the Info Panel in the window title confusing. I mistook it for the info panel of ActiveDeveloper rather than the single window of a new, separate application.
The AppKitExplorer serves as a to explore all of the Cocoa classes available to ActiveDeveloper out of the box. As you use AD, you will find that you also avail yourself of this application as a quick way to get an AD session up and running.
Interactive Investigation
Typing shift-command-w from AD opens our first workspace.
Figure 3. ActiveDeveloper Workspace.
The top pane (the import pane) allows you to add import statements, by default both <Foundation/Foundation.h> and <AppKit/AppKit.h> are imported. These imports provide the context for the lower pane (the coding pane) used to construct code. Only classes declared in interface files imported via the import pane are available for use in the coding pane. Since Foundation.h and Appkit.h are imported by default, any class from these frameworks can be investigated. The 3 buttons above the import pane are all used to execute the currently selected code in the coding pane. All execute the code, but present the results in different ways. The Eval button simply executes the code, there will be no feedback (other than that in the code) to indicate that the code has been executed. The Display button will display the textual representation of the object returned by the last statement in the highlighted code. This textual representation will appear in the Transcript tab of AD's console. Finally, the Inspect button will present the object returned by the last statement in an inspector, referred to in AD as a runtime object browser.
Remember we said that workspaces allow us to write small code samples and execute them. Returning to the example from earlier, type the following into the coding pane.
[[NSWorkspace sharedWorkspace] launchedApplications];
Note that this code has nothing to do with the application currently running. Because we have access to the Objective-C runtime via the running application, there is nothing to prevent us from creating instances from any class, as long as the class is in the context of the workspace. So the entire Cocoa API is available for such exploration. In this case, from within the workspace we have obtained an instance that refers to all the applications currently running. We can close them, hide them, etc., all from AD's workspace. This is the kind of flexibility and powerful exploration that working with instances exposes.
A word of warning from the Smalltalk community. "Do not perform brain surgery on yourself." It would be a simple matter to kill AD, or any other application, from within this workspace. I leave that as an exercise for the student! Make sure you have saved any important work beforehand.
Highlight this code and click on the Inspect button.
Figure 4. Executing Objective-C code in a Workspace.
A runtime object browser similar to the following will appear.
Figure 5. Exploring an instance in the Runtime Object Browser.
This window displays instances in the top left hand side browser panel, the root panel. The resulting object from the executed statement is an instance of NSCFArray, so we see such an instance displayed in our runtime object browser. The properties of the instance are visible in the adjoining column (in this case elements of the array) and by choosing these properties and traversing rightwards we can explore any instance on display. The lower pane is used to display the textual representation of the currently selected instance. This pane can also be used as a coding pane hence the appearance of the Eval Display Insect trio. The context of the pane depends on the selected instance. For example, select one NSCFArray in the browser panel, type the following code snippet after the textual representation in the coding pane:
[self className];
Now, highlight and copy this statement, then click Display. We will see NSCFArray appear in the Transcript tab. Select any item in the array, paste our copied statement after the textual representation, select, and execute our statement via Display, and we now see NSCFDictionary appear. If we repeat this by choosing an item in the Dictionary, we should see NSCFString appear in the Transcript.
What all this goes to prove is that the coding pane's context is the context of the selected attribute. To reinforce this point, click on NSApp in the runtime object browser, and select the _keyWindow attribute. In the coding pane, type in the following code:
[self setTitle:@"AppKitExplorer Main Window"];
Highlight and Eval. You should see the title of our running application change.
So, if we want to do some random exploration, we can use a workspace to create instances for us. There are more examples of this type of ad hoc exploration in the accompanying user guide.
More usually, we use the workspace to initiate exploration of the application we have just started. Going back the workspace, type:
[NSApp delegate];
Now, inspect it. The runtime object browser will display the controller in its list of objects. Again, we can traverse this object, write code in the coding pane, and continue on our Eval, Display, Inspect circuit.
It is quite easy not to realize how impressive the above examples are. In the matter of the few moments it takes to start AD, and its demo, AppKitExplorer, we can start to create instances of any class in Cocoa and examine it. Think for a moment of what is involved in setting up a project in order to explore a Cocoa class: setting up a new application, creating classes and methods in order to create instances, and coding a GUI to display the results. Not to mention relying on NSLog statements, or setting breakpoints to use GDB to provide limited access to attributes.
Comments On ActiveDeveloper's Support for Interactive Investigation
Overall, ActiveDeveloper supports the standard functions required to carry out instance based investigations. The product gives the impression that it is built by developers who focus on the technical aspects rather than on usage. This is no bad thing, but does have the downside that the product does not do itself justice in terms of it's interface, and to a lesser extent, its usability.
There are numerous user aids that could be included to enhance the developer's life. As the coding panes stand at the moment, they provide basic coding support (matching brackets). Developers have grown used to more support in terms of syntax coding, emacs like text selection, code completion, etc.. The coding panes could be improved to allow the selection of discreet areas of text, and have it Evaled, Displayed, or Inspected from the keyboard rather than having to break off to use a pointing device. Including the commands in the popup menu would help.
When traversing the attributes in the runtime object browser, the coding panes lose their contents. It would be nice if there was some technique to retain code that was written earlier. Related to this, it would be good to have more preferences to play with. Apart from developers loving their fonts, and color schemes, they also have their own preferences as to window layout, multiple or single browsers, etc.. The preferences available could be increased.
Given the technical achievement underlying these tools, I feel a little whiny in these usability comments. Although they are important in their own right, we should not over look the fact that interactive investigation functionality is there, now, in a stable, and robust form. The usability issues do not prevent you from increasing your productivity, but you would have an even smoother investigation process if they existed.
Interactive Coding.
AD takes advantage of being able to dynamically load a category at runtime to side step the compile-link cycle. In keeping with the rules of categories, and dynamic loading when using AD's class editor, we can load new classes, load new methods onto existing classes, and reload existing methods. Dynamic loading does not support the reloading of existing class definitions, or code that contains global symbols that are already present in the running application.
So, avoiding the compile-link cycle is achieved by placing those methods that you will be working on most in a category file, and using a special editor to do your coding.
Typing shift-command-c from the console brings up the editor window.
Figure 6. ActiveDeveloper's Class Editor.
We see the familiar Eval, Display, and Inspect buttons. This means you can perform interactive investigation from within the editor as you are coding. This turns out to be quite a convenient feature. There also appears a new Load button. This is used to dynamically load a category into the application that is currently running under AD's tutelage.
The top left hand pane is used to provide import statements at the start of a header file (referred to as the prefix import pane) while the bottom left hand pane is used to provide import statements that you wish to appear at the end of header files (referred to as the postfix import pane). The middle left hand pane displays the signature of methods contained in the file, and can be used to navigate to methods by clicking on the signature. Finally, the right hand pane is the coding pane.
When a class is constructed to have its interface details contained in the implementation file, AD will reward you by keeping the interface file in sync with the implementation file. This feature releases you from having to maintain both the interface and implementation files. The auto generation of the header occurs when saving the implementation file. Since saving is disabled in demo mode you will not be able to observe this feature in action.
As already stated, the documentation that comes with AD has improved substantially over the last few releases. It now contains a number of examples showing how to activate your existing projects.
Comments On ActiveDeveloper's Support for Interactive Coding
The process of activating your own projects is covered comprehensively in AD's user guide. Once you activate two or three projects you will find that it is a pretty straightforward, almost mechanical, process.
AD's interactive coding editor utilizes the same coding pane as the object browser and workspace, providing a consistent feel between the tools. You will find working between them to be transparent.
Returning to the caveat mentioned earlier, one fact to be aware of when using categories is there is currently no way to delete a method from a running application once it has been loaded. This derives from the fact that there is no mechanism available in Objective-C to unload categories. The original purpose was to load methods into an application, and keep them there. What this means for us is that although we may have deleted a method from the category file, its last definition will still exist in the application's method space until its quits. In reality this is not a serious problem as the method will not exist the next time the application is executed. It is also possible to provide an empty method as your last edit, such as
methodName; { }
Another restriction related to the nature of categories is the fact that you cannot use AD to add or remove instance variables, or change the super class. This needs to be done within Apple's development environment. I found that this does not happen too often. Most time is spent modifying behavior rather than properties.
The same comments regarding the GUI of the class editor are applicable here. Given the quality of editors on the market, AD's coding panes are somewhat lacking. In the editor's case, this is quite unfortunate in that you will be spending most of your time in AD's editors, rather than in Apple's IDE, because of the dynamic loading support. So, you will miss functions, such as auto formatting, syntax coloring, font selection, color schemes, all the usual suspects.
GDB and AD - Interactive Debugging
An area that I haven't mentioned yet is interactive debugging. It is possible to use GDB and AD in concert. You can attach GDB to a running application started from AD, using the application's process id. From within GDB, you can set breakpoints, etc., as normal, and have the application pause. You can use AD to edit a method, and reload it. When you use continue execution in GDB, you will find that the new edition of the method is available for execution.
It is also possible to inspect objects using the memory address displayed in GDB's value column.
Inspect an instance via its memory address
This code snippet can be written, and Inspected in any of AD's
coding panes. Replace Ox123456 with the address of the instance you are interested in.
id anObject = (id) 0x123456;
return anObject;
Figure 7. GDB and AD in Concert. Note the address in GDB, the code snippet in the Workspace and the instance displayed in the object browser.
This leads to a very flexible debugging environment where you can work, as it were, in three dimensions. The first being the time line of the stack trace, the second being on-the-fly code changes, and having the debugger execute it when the application is continued, and finally, the 3rd line of attack being the ability to completely traverse live instances in object browsers.
Closing Comments
I have taken you, at quite a pace, through the essence of interactive development, and the tool functionality needed to support it. Within the Objective-C arena, I explained the language features that permit such tools to exist, and introduced you to one such toolset. Finally, I now present my ranking as to how well I feel AD compares to the interactive development tool set provided by Smalltalk IDEs.
Some interactive development tools are missing, such as a true Smalltalk style debugger, but there are fundamental differences between the Objective-C runtime, and Smalltalk runtimes which mean that certain Smalltalk tools, such as the debugger, can not be replicated completely. So this is not a criticism of AD more than a reality check. So, for features supported I would award 9 out of 10.
From my usage of the tools over the last few months, I have found it stable and reliable, and I use it constantly. Out of 10, I would give ActiveDeveloper's tools a rating of 8 just for the sheer power that the functions it supports provide. A 10 would be easy to award once the GUI supports more of the functions that developers have come to expect.
The documentation does not cover all the functionality provided by AD. There is little discussion on what the other tabs in the console are for, nor how to use the buttons, such as retain and release, in the object browser. Little mention is given to the ability to start Interface Builder from AD, and use AD to investigate the inner instances of IB as it is running. You find it mentioned in the FAQ page. But the documentation does achieve the most important goal, that of explaining how to set up your environment, and how to use the most important features. It takes you, in a logical sequence, through the most important functions, and by the end you will be up and running with your own projects activated. Marks here are 7 out of 10.
As an aside, retain and release allow you to quickly add/remove an instance to the root panel of the object browser. If you know you will need to revisit a selected instance buried deep in an object graph, by pressing retain, the selected instance will appear in the root panel. It is now at hand for future use. When it is no longer of interest, select it, press release, and it disappears. A very useful feature.
Product support has been excellent, all queries were answered promptly, and I feel there was genuine commitment to the product. Nine out of 10 for product support.
So an overall score of 8, which is well deserved.
In closing, I hope you enjoyed reading this article and found it easy to understand. More over, I hope that you have been introduced to something that will have a lasting beneficial effect on your development style.
Aidan has finally returned home. Having wandered away from NeXTSTEP around 1995, he quietly slipped back through Cocoa's doors last year. In the meantime he worked on some of Europe's leading Smalltalk projects, gaining an appreciation for simplicity. He can be contacted at aidanreel@mac.com.