O Refio, Refio, wherefore art thou Refio (ExtJS Design Patterns)

For longer than I can remember I have been writing complex data centric applications and trying to leverage JavaScript  and DOM to do more and more of the work.  In the early days, yes pre this decade, we had to do a lot of the heavy lifting ourselves.  In today’s world we have a wide range of frameworks we can choose from.  All of these provide for different object implementations with the same goal in mind.  ExtJS is the most fully fledged out framework to date but there are competitors not far behind, for example Javeline.  Like many implementations it will come down to developer adoption which is often a result of how well that company caters to developers.  But getting into why a framework gets adopted is for a future blog post.  The purpose of this post is to talk about design patterns of an application with a focus on ExtJS.  In many cases I get dropped into the middle of an application development life cycle and in most of these cases I have noted a consistent implementation which in ‘my’ opinion lacks certain elegance. 

Since I am very evidently sticking my nose out I had best explain ‘What is Elegence?’ In terms of a JS implementation the object model should provide for an obvious segmentation of functional areas that reflect their purpose and the interface itself.  Having an overly flattened object model simply makes it confusing for developers to inherit the code base and work with it.  I usually layout my base class with the following structure. 

  • .ui
    Contains all of the components that make up the base interface.  Most often this a direct pointer to the created viewport.
  • .user
    The user class holds the context of the currently logged in user and any methods for login, logout, options etc.  It will contain interface components/methods but most often these are modal dialog in nature so do not impact on UI. The user class should also provide for permission methods.
  • .remote
    The remote class is most often a function and is in charge of ALL remote calls whenever possible.  It is important that an attempt be made to push all of your remote REST calls or any server requests through a single point of entry/exit.  In some cases this is not possible, for example with a tree control or with a panel with autoLoad set, but these are special circumstances.
  • .component
    The component object is a holder for specific component objects that your interface supports. It relies on both ui and user classes.  Often I have a common or core subclass within component that provides for common functionality that is shared amongst components.
  • .util
    A catch all class for methods that support all the other primary classes.
  • .config
    I flip flop on this one frequently.  The config object is used to store configuration objects that are commonly used throughout the application.  For example default panel configs that are applied with Ext.applyIf within functions.  I flip/flop on this one because with it being exposed it opens opportunity for nosey hackers to fiddle with it and introduce behaviors.

In many cases I see very large flattened object models and exposed components because for some very bizarre reason people have not picked up on the ref property of a container config in ExtJS.  Ref is your best friend and simplifies your life.  As you may well know one of the major challenges in ExtJS or any JS application is maintaining a reference to that object you just created.  Sometimes we drop in our on ID so that we can use Ext.getCmp(‘thatDangObject’) or pre-create a id with Ext.id, add it to the config and store the id somewhere for later retrieval.  Well by using the ref function you do not need to.  For example let’s look at a standard 3 panel viewport with a North, South, Center layout. 

First off you will note __root.ui, __root is a reference to the base class of the application but I will get to that a little later.  For now you can assume that myapp.ui is now a pointer to the created ExtJS viewport object.  If you were to use FireBug and look at myapp.ui within the DOM explorer you would see under myapp.ui, _panelNorth, _panelWest and _panelCenter.  A quick comment, if you have not heard of Firebug stop reading this article, get it, learn how to use then by all means come back and read the rest. A note about my use of the underscore in the ref property.  I use this for two reasons.  One, I know that the ref name I come up with will NOT conflict with any ExtJS property and more importantly they show at the top of the list in the DOM explorer when expanding the object. 

__root.ui= new Ext.Viewport({
layout: 'border',
items: [
{region:’north’, ref:’_panelNorth’},
{region:’west:’, ref:’_panelWest’},
{region:’center’,ref:’_panelCenter’}
]});

With ref one of the very spectacular things you can do is move it up the object hierarchy by the use of ‘..\’. So for example if I had a tbar in the _panelNorth and I want to have it exist within the DOM hierarchy directly under myapp.ui I could add in ref:’..\_topTbar’ in the tbar config within the north panel.  There are cases you may want to do this but remember if you do then you loose your logical object flow in your code which means as a result you had better name it something very logical.  For example really which is better of the below two: 

                myapp.ui._panelNorth._topToolBar
                myapp.ui._panelNorthTopToolBar 

Personally I prefer the first case because that little ol’ dot tells me something directly where as in the later example I am trusting the name to indicate it.  I will defer to dot whenever I can! 

Dude it’s an object no need to wrap it more’, this is one of my favorite issues I see in ExtJS development.  Creating components that wrap ExtJS components because of the need to track some aspect of that component.  It is kind of akin to that annoying Uncle who thought it was cute to wrap a small present inside a big box that was also wrapped.  It’s not funny and it just adds waste!  Waste is the important word here.  Not only are you wasting time but you’re wasting memory and my time while I try to figure out what the hell you are trying to do.  You can add anything to an ExtJS config object and it will show up as part of that object.  Take for example the following panel config: 

__root.ui._panelCenter.add({
	xtype:’panel’,
	ref:’_panelForSomething’,
	_myProperty1:’abc’,
	_myProperty2:’def’,
	_myMethod:function(){callmyprivateMethod(this)}
})

Now when I want to get to _myProperty in this added panel I can simply say myapp.ui._panelCenter._panelForSomething._myProperty1 and I get abc.  What I often see is the reverse where a class has been created that contains the control and a lot of extra code expended to make available certain properties/methods of the container available for consumption.  If you are comfortable with the security issues of this then make use of that ExtJS object.  There is a reason they have the functions Ext.apply and Ext.applyIf, read up on them as they are another best friend of ExtJS development.  A small comment on the use of underscore!  I realize and recognize that this is not a recommended implementation according to Mr. Crockford but I would argue this point with him with some zealousness and perhaps a slight grin on my face that I am arguing with Douglas Crockford! 

I mentioned the term security and this leads me to my next point. Not everything needs to be a publicly accessible method or property. Object scope is an incredibly important aspect of any complex application design and making EVERYTHING scoped at the object level is just asking for some pimple faced annoying genius kid to go nutty on your application in Firebug and post it up to the world in some sense of accomplishment over your lack of thinking!  This is where ‘design patterns’ come in, there are many, most notably Douglas Crockford’s. It is Crockford’s implementation that is used witin ExtJS for components. I could probably dedicate an entire book or a least a lengthy blog post to JS design patterns for the purposes of this discussion I will outline two that I use primarily.  The first is a basic class that one instance of will be created for the purpose of service the application. 


function myClass(scope){

	// private variables
	var _me = this;			// internal reference
	var __root = scope		// constructor reference
	var pTermLength = null		// exposed property

	// private methods
	function doSomething(){};

	// shared methods
	function pIAmASharedMethod(){};

	// shared property setters/getters
	function pSetTermLength(v){pTermLength=v};
	function pSetTermLength(){return pTermLength};

	// public methods/properties
	this.doSomething=pIAmASharedMethod;
	this.getTermLength=pGetTermLength;
	this.setTermLength=pSetTermLength;
	this.letItAllHangOut=new Number(1)
}

Notice that in this class we only have 3 exposed or public methods and one exposed variable name.  I like to have my public methods point to private functions.  This allows for internal/private functions to call them directly without the use of the this reserved word.  It also means that your exposed methods and properties are simply pointers.  When using this style of implementation it is important that you come to a consistent naming convention on the function and variable declarations. With regards to variables the basic rule of thumb is you should not let them hang out there publicly but rather create public setter and getter methods.  If the variable has a direct impact on the behavior of the class and typing is important then don’t just let it hang out there for consumption and override. Using a getter/setter implementation allows for you to check type and value scope of the var before fubarring your class.  Now I will fall back to Mr. Crockford and his implementation which is slightly different and serves a different purpose.  Remember the above example is for a class that will behave more like a singleton. ‘Why not a singleton’ you ask, well I will get to that next.  Mr. Cockford would say the above implementation should be done thus: 


function myClass(scope){

	// private variables
	var _me = this;			// internal reference
	var __root = scope		// constructor reference
	var pTermLength = null	// exposed property

	// private methods
	function doSomething(){};

	// shared methods
	function pIAmASharedMethod(){};

	// shared property setters/getters
	function pSetTermLength(v){pTermLength=v};
	function pSetTermLength(){return pTermLength};

	// public methods/properties
	return {
		doSomething : pIAmASharedMethod,
		getTermLength : pGetTermLength,
		setTermLength : pSetTermLength,
		letItAllHangOut : new Number(1)
	};
}

Note that in this case that when creating an instance of the class it returns an object which in essence does the same thing as the earlier class.  The difference is that the return statement returns an object which is in essence a singleton or in this case a singleton expressing the instance of the object.  My problem is that a singleton implementation is extremely limiting in its internal scope referencing.  You must follow the object convention of using commas and can NOT have locally scoped variables within the return object.  The argument would be that you should not have locally scoped variables within the returned object but I feel that is limiting.  This leads me to the second style of class implementation and for this let’s try and use a real world example to show why.  Let’s assume we have an application with a standard viewport.  On the left is a tree in which a bunch of users are listed.  In the center panel we have a tabpanel implementation.  When the user selects a user in the tree we have to create a new tab panel for that user.  Obviously then we are going to have a class that manages the interface for the selected user in the tab panel.  In Mr. Crockford’s implementation we would have a class which we would create an instance of and part of its initialization would be to create the interface.  Problem here though is we now have to write a bunch of code to manage the instances of user we have created.  Where should that code go then within are architecture?  Logically it should go in the user class itself but that class is only designed to manage an instance of a user not instances. 

Remember way back in this article I had a child class of off base entitled component.  Well this is where out component would go.  Let’s look at the code for our user class that manages multiple instances: 


function myClass(scope){

	// private variables
	var _me = this;			// internal reference
	var __root = scope		// constructor reference
	var pTermLength = null	// exposed property
	var instances=[];

	// private methods
	function doSomething(){};
	function createInterface(instance){
		// create the interface for the instance and store
		instances.push(__root.ui.center.add(instance.config))
	}

	// shared methods
	function pIAmASharedMethod(instance){};
	function pcloseAllUsers(){
		Ext.each(instances,function(o){
			__root.ui.center.hideTabPanel(o.id)
		})
	}

	// shared property setters/getters
	function pSetTermLength(v){pTermLength=v};
	function pSetTermLength(){return pTermLength};

	// public methods
	this.closeAllUsers=

	// start component
	this.component=function(config){
		var _me=this;				// pointer to this instance
		var myTermLength=1			// local instance variable

		function initialize(){
			createInterface(_me)
		};
		this.config=config
		this.doSomething = function(){pIAmASharedMethod(_me)},
		this.getGlobalTermLength = function(){return pGetTermLength()},
		this.setGlobalTermLength = function(v){pSetTermLength(v)},
		this.getTermLength=function(){return myTermLength},
		this.setTermLength=function(v){myTermLength=v}
		this.letItAllHangOut = new Number(1)		

		// init instance
		initialize();

		return _me;
	}; //-> end component
}

Notice a couple of things: 

  1. Initially we created a single instance of this class with myapp.component.user=new myClass(this) where this is a pointer to the root of our application myapp.  This means that the class can now get to any of our child classes, such as ui via the locally scoped variable __root.
  2. When we want to create a new user interface we call new myapp.component.user.component({some config})
  3. The component creates a locally scoped variable entitled _me that points to its self. On creation the internal initialize function is called which in turn calls the base class createInterface function and passes an instance of its self.
  4. Since createInterface is passed a pointer to the instance and instance has a public property that points to the passed config our createInterface method in the base class can now say create the tab panel using the passed instance.config.  The createInterface stores a pointer to it in a LOCALLY scoped array.
  5. When creating the component it returns a reference to itself for further manipulation.

Now a couple of other things.  Let’s assume that the config we pass to the component creation contains a ref value, for example it is set to ‘userABC’. Now if we want to get to it publicly through our object hierarchy it would be myapp.ui._panelCenter.userABC.  This of course would only get us to the ExtJS component.  Now is where things can get a bit confusing and there are several approaches you can use depending on your requirement. 

For arguments sake let’s assume you want to be able to get to that control directly then you could do this.  Remember you can add anything to that config! 


// start component
	this.component=function(config){
		var _me=this;				// pointer to this instance
		var myTermLength=1			// local instance variable

		function initialize(){
			createInterface(_me)
		};
		this.config=config
		config._doSomething = function(){pIAmASharedMethod(_me)},
		config._getGlobalTermLength = function(){return pGetTermLength()},
		config._setGlobalTermLength = function(v){pSetTermLength(v)},
		config._getTermLength=function(){return myTermLength},
		config._setTermLength=function(v){myTermLength=v}
		config._letItAllHangOut = new Number(1)		

		// init instance
		initialize(config)
	}; //-> end component

Now we have added our public component methods as part of the config of the ExtJS object.  So now I can say myapp.ui._panelCenter.userABC._doSomething() 

The advantage of doing this is of course the base user class when enumerating through its array of component instances can access each of the public methods of each since they are part of the ExtJS component. 

How you decide to implement these types of components comes down to what your needs are.  Questions such as does this need to be accessible from other classes, what are the security risks of being public exposed, do I need a component or will a singleton do?  Should my controller base class provide all the functionality needed? 

In my next post I will discuss the overuse of Ext.extend and Observable. When to use it and when to not use it. 

One last thing to think on… config.instance=_me!!  Now you’re going down the rabbit hole and saying to yourself ‘I should have taken the blue pill’  Try it and see what you see in Firebug DOM J 

Until then….cheers 

Keith Chadwick

Advertisements