Things keeping me busy
What have I been up to these days, one might ask?
A large amount of my time is spent working for these guys:
Art & Logic. Since November 2007, I have worked as a consulting developer on a number of projects - mostly ActionScript / Flash projects. In May, gears changed again - A&L needed someone to take over their IT Operations and I stepped up to the plate.
As of right now, I am both managing their IT infrastructure as well as completing a couple of Flash dev projects before I focus on IT needs exclusively.
In prior months, I completed some consulting gigs for various companies, including working with Google employees on a
Olympic Torch Relay gadget using Google Maps. Keep an eye peeled - I plan to post about other work with Google in the near future.
Labels: development ajax web consulting Google ArtLogic work
n-th time a charm?
As people have clearly noticed... I get in and out of the blogging thing a lot. Mainly because time = money. Though recently time = some money + a large degradation of sanity + a larger degradation of sleep.
Nonetheless, I am going to try to blog again - more. Finally. Really!
Something interesting for the day. Google has begun hosting Ajax libraries. Why should anyone care? It simplifies the integration of AJAX JS library code into your development project. No longer do you need to maintain a specific branch of library code with your source. Instead, leverage a very simple api at Google to import the exact version you need. AND better yet, Google claims they will maintain any stable version provided to them (via the libraries' core dev team) indefinitely. Now that's cool.
http://code.google.com/apis/ajaxlibs/
Labels: ajax development web javascript google api personal
Some additional thoughts (not all mine!)
First of all, I want to apologize to everyone who has read and contributed comments to my post series on Cairngorm and Modules. Why am I apologizing? For my absence following the posts. Those who know me know that I often have to bury my head in the sand just to get some work accomplished - otherwise, it doesn't take more than a shiny object to distract this ADHD boy from anything useful :-p Nonetheless, I will make an effort to respond to comments in a more timely and helpful fashion.
I am extremely pleased to see the conversations brewing throughout the cairngorm-devel group over on Yahoo! Groups on Cairngorm and Modules. After all, that was my intention with these posts - stimulate thought, dialog, and hopefully inspiration.
It became clear to me after reading several comments and list posts that I do need to respond in order to clarify my position. These posts were never intended to suggest change to the Cairngorm micro-architecture. The combination of modules and Cairngorm patterns as I played it out is HARDLY a best practice. Experiment is far better adjective. And I don't expect to ever see support for modules (or any other api) built in to the Cairngorm classes. I feel that would be violating a key aspect of the library:
micro-architecture.
I have always understood Cairngorm to be a series of 'enforced' best practices - specifically, best practices surrounding Model-View-Controller (MVC) and supporting patterns which enhance adherence to the MVC paradigm. They don't rely on language-specific features outside of the run-of-the-mill Object-oriented concepts and likely could be ported to OO language of choice without a lot of work. They don't encapsulate cross-cutting concerns like modules, logging, security, etc. I would contend that is for specific-purpose libraries. Unforunately, my posts seem to have clouded what should be perfectly clear - Cairngorm doesn't need all this stuff.
I applaud the Adobe Consulting crew for resisting the 'why doesn't Cairngorm implement feature X ?' As soon as that happens, it will cease to be a micro-architecture and become just another monolithic framework - complete with all the weight most applications don't need (but it looks great on paper!).
On an aside, I am pleased to see that Cairngorm 2.2 does address two issues I raised in my posts - the visibility of the commands instance variable within the FrontController, and the addition of a removeCommand() method. These should have been addressed, not because I wanted them for modules support, but because it affected the extensibility of the core classes. Bravo guys!
Alistair, Steven, Adobe Consulting: Keep up the good work. And thank you for keeping Cairngorm micro. I couldn't agree more with your approach - stick with repeatable best practice, keep things small, and don't over engineer from the start. That's a hard bit to chomp but all the more important.
For everyone else: Contribute your ideas! My approach has already started the conversation going about 'what is best practice'. Several individuals responded that they liked the flexibility of modules adding views and commands, but the ModelLocator is a bad example of a extensible object.
Personally, I am inclined to agree. Since writing these posts, I feel that giving up the compile-time checking of a single, statically defined ModelLocator is not quite worth enabling a dynamic behavior. The same may also be true of the ServiceLocator! Imagine the security implications if a 'third-party' module could redefine an important web service endpoint to a hostile URL! I am more inclined to see ModelLocator and ServiceLocator objects in a RSL library leaving modules to define views, view helpers, and command objects.
But then again - maybe that's a bad idea too! Your turn community: speak up.
Labels: Cairngorm, Consulting, Flex 2, modules
Cairngorm + Modules: Zenith
We've made a pretty long journey through Cairngorm 2 and its internals. But wasn't the whole point to discuss Cairngorm with the mx.modules API introduced in Flex 2.0.1? Ah yes, most-observant grasshopper. Patience is the key.
Most of this journey has been to address aspects of Cairngorm that makes the use of the modules API cumbersome and crude. Now that these aspects have been addressed, let's look closer at what a shell application and module might look like in the Cairngorm world.
In my first post of this series, I considered a story of how Cairngorm and modules might look. A shell or parent application would hold the keys to the kingdom, so-to-speak. If a module wants to play, it needs to tell the shell application everything it has to contribute. ICommand objects would be registered with the FrontController; value objects and model data would be 'declared' to the ModelLocator; views are known through a new ExtensibleViewFactory; etc, etc, etc. So who is going to do all this work? Well, the module should when it becomes known and loaded to the world.
Behold the ICairngormAware interface - an interface which declares two simple methods that a Cairngorm-compatible module must know, register() and unregister(). As the theory goes, when a module is loaded by the modules API (such as by a ModuleLoader object), it will call the ICairngormAware.register() method after successfully loading the module. The module will then register its necessary classes to the authoritative locators and carry on its merry way. Here is an example onModuleLoad handler:
public function onLoadModule(event:ModuleEvent):void
{
trace('Module loaded');
var t:ModuleLoader = ModuleLoader(event.target);
var m:ILocatorAware = ILocatorAware(t.child);
m.register( new CairngormInfo(null, null, frontController, null ) );
}
According to the Modules API, the ModuleLoader creates an instance of the module class loaded from its .url property and refers to it using the .child property. Here, we use that instance to call the register method. And if we expand this theory to unloading and unregistering as well, the concept should remain the same.
HALT! We have a problem.
See, the Modules API appears to destroy any references to the module itself prior to unloading (as far as I can see). Which breaks the idea of using the ModuleLoader unload event to unregister our components... by that time, we're too far in the event to do this cleanly. HOW ARE WE GOING TO CLEAN UP?! Mass hysteria, chaos, DOOOM!
Well - it turns out, there is a quick, dirty little hack. Force a call to the unregister() method when the Module.REMOVED event plays out. Since this occurs before the UNLOAD event, we can remove our components before the unload occurs. Not as clean as I would like it, but it gets the job done.
There you have it - Cairngorm and Modules married through some nice use of interfaces and extending the Cairngorm classes. My only beef is the use of a private commands[] collection in the FrontController class - we had to get dirty and re-implement the class. Thank you Adobe for providing the Cairngorm source!
As promised, I have provided an
archive of the source code discussed across these posts. I STRONGLY ask and encourage more knowledgeable individuals to critique and improve this code - I enjoy learning from others and I know this topic has been discussed in multiple places across the Internet.
Labels: Cairngorm, Consulting, Flex 2, modules, Software Engineering
Cairngorm + Modules: The ViewLocator
Great. We've visited the model and the controller partitions of the MVC design pattern and changed the Cairngorm 2 micro-architecture to behave in a more dynamic fashion. It was when I visited the view partition that I began to question some things. See, the model partition has a singleton which is authoritative for all model objects in the application - the ModelLocator. The controller partition also has a class which is responsible for Command objects and their 'wire-up' to the application's event dispatch plumbing. Even with first glance, the view has a singleton object responsible for all view duties - the ViewLocator.
But everything is not what it seems here.
The ViewLocator has knowledge of all the ViewHelper objects within Cairngorm, not all views. I like to think of concrete ViewHelper classes as similar to the .NET 1.0 concept of a code-behind for ASP.NET pages, but specific to view code only. A ViewHelper should contain any dependent 'logic' code for the view. Classes within the controller partition can then use the ViewLocator to retreive a handle to the ViewHelper object and inspect or otherwise operate code therein. But this is not the actual view. Instantiating a ViewHelper object will not give access to the classes Flex 2 is using to actually make-up the view. I can not, for example, use the handle from a ViewLocator to pass to PopUpManager.createPopUp() and hope to get the appropriate view displayed.
Perhaps I misunderstand the relationship between ViewLocator, ViewHelper, views and the other objects of Cairngorm - but most importantly, I can't make an application aware of a new view compiled within a module this way. I need some sort of authoritative list of view classes available within the application. And so I propose the ExtensibleViewFactory class - a singleton object, just like a ModelLocator, but expressly for the instantiation and maintenance of view classes within the application.
package net.digitalmaelstrom.cairngorm.extended.view
{
/**
* The ExtensibleViewFactory holds a list of available view classes which may be instantiated.
*/
public class ExtensibleViewFactory
{
protected var fClasses:Dictionary = new Dictionary();
private static var ref:ExtensibleViewFactory;
public static function getInstance():ExtensibleViewFactory
{
if( null == ref)
{
ref = new ExtensibleViewFactory();
}
return ref;
}
public function ExtensibleViewFactory()
{
if(null != ref)
{
throw new IllegalOperationError("Using ExtensibleViewFactory" +
"constructor is not supported, use getInstance()");
}
}
public function addViewClass(id:String, viewClass:Class):void
{
if( fClasses.hasOwnProperty(id) )
{
throw new Error("View " + id + " is already registered.");
}
else
{
fClasses[id] = viewClass;
}
}
public function removeViewClass(id:String):void
{
if( !fClasses.hasOwnProperty(id) )
{
throw new Error("View " + id + " is not registered." );
}
else
{
delete fClasses[id];
}
}
public function getClass(id:String):Class
{
if(fClasses.hasOwnProperty(id) )
{
return fClasses[id];
}
else
{
throw new ArgumentError("View " + id +
" has not been registered");
}
}
public function createInstance(id:String):*
{
var factory:ClassFactory;
if( fClasses.hasOwnProperty(id) )
{
factory = new ClassFactory( fClasses[id] );
}
}
}
}
With the ExtensibleViewFactory, I can create an instance of a view class knowing only its string identifier. As a couple of asides, I should probably add some properties or methods to inspect the available list of classes, their identifiers - and possibly even some way to manage the in-memory instances. But this is only an initial proposal - I have no doubt work remains to refine these solutions to robust, functional code.
In my last installment, I will attempt to demonstrate how all this code pieces together to create a simple concept to load and register a modules components, then unregister and unload a module. Oooooh the excitement!
Labels: Cairngorm, Consulting, Flex 2, modules, Software Engineering
Cairngorm + Modules: The FrontController
Last time, we took a look at the ModelLocator and gave it the ability to add or remove model 'slots' when a Flex 2 module is loaded or unloaded. From there, we will embark to advance the FrontController so that command objects may be added or removed at runtime.
The good news is that this functionality is already present in some form. Enter addCommand() ! See, that's easy. We just call the addCommand() method when a module is loaded into the application to introduce any additional command objects to the Cairngorm event dispatching. All we should have to do from here is introduce a removeCommand() and be on our way.
public class ExtensibleFrontController extends FrontController
{
public function removeCommand(commandName:String):void
{
if(null == commands[commandName])
{
throw new CairngormError(
CairngormMessageCodes.COMMAND_NOT_FOUND, commandName);
}
CairngormEventDispatcher.getInstance()
.removeEventListener(commandName, executeCommand);
delete commands[commandName];
}
}
... and we're done, right? Well, not quite. It turns out that the original FrontController definition also includes this unfortunate line:
private var commands : Dictionary = new Dictionary();
Yes, that is unfortunate. See, because of the
private designation, our subclassed definition is unable to access commands[] and therefore unable to perform the removeCommand() logic as planned.
When all else goes wrong in open-source, copy, paste, AND GIVE CREDIT! So...
(Give credit to [c] 2006 Adobe Systems Incorporated for the original FrontController source)
protected var commands:Dictionary = new Dictionary();
(... copied addCommand(), getCommand(), execute() from FrontController.as ...)
/**
* Unregisters an ICommand class and disassociates all event listeners.
*
* @param commandName An ICommand class reference which has been previously registered with the FrontController.
*/
public function removeCommand(commandName:String):void
{
if(null == commands[commandName])
{
throw new CairngormError(
CairngormMessageCodes.COMMAND_NOT_FOUND, commandName);
}
CairngormEventDispatcher.getInstance()
.removeEventListener(commandName, executeCommand);
delete commands[commandName];
}
Since we're copying/pasting anyway, might as well change the
private designation of commands to
protected. Armed with our new ExtensibleFrontController, we can add and remove ICommand classes on a whim!
To the view!
Labels: Cairngorm, Consulting, Flex 2, modules, Software Engineering
Cairngorm + Modules: The ModelLocator
As stated in my previous post, I feel some changes are needed to Cairngorm in order to improve its dynamic behavior and pave the way for Flex 2 modules. The first place in my mind to do that is the heart of any application, the model. Let's define an ExtensibleModelLocator based on a dictionary so that model "slots" may be added or removed at runtime. I decided to extend the IModelLocator interface for this purpose:
package net.digitalmaelstrom.cairngorm.extended.model
{
import com.adobe.cairngorm.model.ModelLocator;
/**
* IModelLocator defines a set of methods which allow the runtime to register/unregister
* model objects as needed.
*/
public interface IExtensibleModelLocator extends ModelLocator
{
/**
* Removes the model 'slot' specified by key.
*
* @param key Name of the model slot to remove.
*/
function removeModel(key:String):void;
/**
* Indicates whether the provided key exists within the ModelLocator.
*
* @param key Name of model slot to test.
*/
function contains(key:String):Boolean;
/**
* Retreives the stored object from the ModelLocator instance.
*
* @param key Name of model slot to retreive.
*/
function getModel(key:String):Object;
/**
* Sets the stored object for a given key within the ModelLocator instance.
*
* @param key Name of model slot to store.
*/
function setModel(key:String, model:Object):void;
}
}
The concrete ModelLocator class should implement this interface. The code to use the locator is more verbose than before, but may go something like:
const IMPORTANT_COLLECTION_KEY:String = "myCollectionKey";
const ANOTHER_MODEL_SLOT:String = "UUIDxxxxxx-xxxx-xxxx-xxxxxxxx";
var model:MyModelLocator = MyModelLocator.getInstance();
var myCollection:ArrayCollection = model.getModel(IMPORTANT_COLLECTION_KEY);
model.setModel(ANOTHER_MODEL_SLOT, new Object() );
Clearly, the concrete class should maintain a well-behaved nature - throwing exceptions when accessing model slots that haven't been initialized previously, etc. But the benefit is that the setModel() method may be used by a module on initialization to inform the ModelLocator of its necessary model objects.
There is not anything tricky going on here. If anything, we're simply being more verbose in hopes that the additional information will allow the Flex 2 environment to know more.
Where to next? The Controller, of course!
Labels: Cairngorm, Consulting, Flex 2, modules, Software Engineering
Cairngorm + Modules = Resolved?
A few days ago, I mentioned that I have been working to find working harmony between Cairngorm and the Flex 2 mx.modules API. The solution I propose is hardly airtight and should be considered, critiqued, and coersed into a happy, object-oriented Zen of a mx.modules + Cairngorm marriage.
In other words, I'm asking for collaboration from the community.
To start, lets look at Cairngorm in the context of adding or removing functionality. The FrontController, ModelLocator, ServiceLocator, and ViewLocator (or just locator) classes to be more specific. Most of these classes follow the
Singleton design pattern in order to control instantiation and provide a single point-of-entry to each partitioned responsibility (model, view, controller, services, business logic). While this is desirable, only one of the Cairngorm interfaces for the locator classes allows behavior to be defined during runtime - the addCommand() method defined on the FrontController. There is no way to define an additional model "slot" within the ModelLocator or introduce a new 'service' to the ServiceLocator outside of its compile-time definition.
For the sake of my sanity, I am going to break up this post into a series of posts. Each post may cover some aspect of Cairngorm, the mx.modules API, or the ensuing integration. The last post will include a download link to the source for the interested reader.
Labels: Cairngorm, Consulting, Flex 2, modules, Software Engineering
Cairngorm + Modules = Trouble
I have been working with Adobe Flex 2 since it first became public back in July of last year. Since then, I have followed it's continued development and the development of its many available libraries closely. One of these libraries, Cairngorm, is a micro-architecture designed by Adobe Consulting to impose best-practice structure on Flex 2 code. Not to mention that it is one of my personal favorites. It allows a clear separation between most important responsibilities within a Flex 2 app.
Another, more recent, addition to Flex is a set of objects in the mx.modules namespace introduced in Flex 2.0.1. This rather simple application programing interface (API) allows blocks of code to be independently compiled and may be loaded or unloaded into another Flex application, essentially extending or contracting its functionality on a per-need basis. This is an important capability for larger software projects and hopefully its presence within the Flex framework will increase its acceptance by developers.
It wasn't until I began to investigate how Cairngorm and Flex modules might work together that problems start to rear their ugly heads. First arises the question 'how do we use Cairngorm in conjunction with modules?'. Does each module have its own set of singleton locators, event dispatcher, etc? Should the shell application manage these aspects?
I feel the story should go something like this: Cairngorm should have a universal and consistent approach throughout the application - modules or no. In practice, this would mean that only a single set of locators exist for the five aspects within Cairngorm: model, view, controller, services, business logic. When a module loads into the shell application, it should inform the shell what objects are available within the module and register these with their appropriate locator. For example, when my module SuperDuperModule loads within an application, it will add its command objects with the FrontController of the shell application. When events are dispatched up to the FrontController, the appropriate commands should fire as necessary.
The converse is true as well, however. When a module unloads, it should remove its objects from the top-level locators and leave dependent objects in memory as candidates for garbage collection. From my understanding, this is a complicated process. Much like trying to delete an open file, you wouldn't want to remove all the references to a model object that is still being "used". I am going to leave this topic alone for the time being, but hope to revisit it in the not-too-distant future.
Okay, the story makes sense. So - where's the problem? Well, actually, several problems exist with Cairngorm's current form. Most of the locators do not support adding/removing child objects at runtime. Only the FrontController supports dynamically changing its runtime 'knowledge' and it only supports adding a command through addComand(). We will have to modify Cairngorm to support these additional capabilities.
Stay tuned for more as I try to hammer out some of these issues and make Cairngorm + Modules less trouble.
Eh, check later.
Labels: Cairngorm, Flex 2, modules, Software Engineering
Agile software methodologies
One of the most fascinating aspects that I find working in software development is the interaction of people, teams, and the methods which they use to solve the difficulty of managing all of them.
Recently, my eye has turned to agile software methodologies. These paradigms absolutely fascinate me. Not simply because they tout "agile" but because they push or shift team communication to the forefront. More frequent. Less duration. More to the point. Less hype and "lecure" speak.
I hope to include a comprehensive list of agile methodologies in this post. Later posts will include resources, videos, etc related to these topics.
Manifesto for Agile Software DevelopmentAgile Methodologies
Scrum
eXtreme Programming
Crystal
Context Driven Testing
Lean Development
Articles
The New Methodology - Martin Fowler
Watch for more to come.
Labels: agile, AMDD, Crystal, eXtreme Programming, Scrum, Software Engineering
Stoking fires
Observant others may notice that I have not posted an entry this month - a fact which completely violates my attempt to post more and often.
Funny how we always find excuses ...
Well, I am in the midst of preparing to head to Chicago to speak at the Northeastern Illinois University NEIU Conference on Creativity. Titled
Stoking the Creative Fire: From Inspiration to Realization Across the Lifespan, the conference covers a diverse pool of talent. Naturally, you have the traditional
creative professions: published authors, journalists, photographers, and such. However, other fields were tapped for their creative insight including an opera singer, social workers, a dermatologist, a yoga instructor, professors of mathematics, physics, and anthropology, and myself, a software engineer and technology consultant.
Part of the fun for me isn't just the chance to speak on the more creative aspects of technology, but being able to listen to the variety of professions - particularly psychology and social work (a familiar area from my college days as a volunteer crisis counselor).
When I have a few moments to spare, I'll share some of my experiences and overall reaction being the tech geek amongst the cultured and literary folk :)
Labels: Consulting, creativity, Personal