You are currently browsing the archives for the Object Oriented Design category


Simple RPC Instrumentation in Flex

On occasion developers may find a need to quickly measure the time it takes for a request to a remote service to return a response back to the client without the need to employ an automated testing tool to perform the instrumentation. This information can prove quite valuable for performing application diagnostics on the client and, when measured in terms of code execution, monitoring at the execution level will always be a bit more precise than that which can be measured by using a Network proxy alone, such as Charles or Fiddler, etc.

Obviously there are numerous solutions which can be implemented to monitor the elapsed time of a service invocation, however it was my goal to provide a unified solution which could easily be implemented into existing client code without significant refactorings being required.

In order to achieve this I first needed to consider what the typical implementation of a service invocation is in order to isolate the
commonality. From there it is only a matter of determining a solution that meets the objective in the most non intrusive manner possible.

To begin let us consider what a “typical” service invocation might look like for the three most common services available in the Flex Framework; HTTPService, RemoteObject and WebService.

// HTTPService
var call:AsyncToken = service.send();
call.addResponder( this );

// RemoteObject
var call:AsyncToken = service.someMethod();
call.addResponder( this );

// WebService
var call:AsyncToken = service.someOperation();
call.addResponder( this );
 

Based on the 3 above implementations we can deduce that the common API used when performing a service invocation is AsyncToken. So to provide a unified solution for all three common Services we could either extend AsyncToken or provider an API which wraps AsyncToken. For my needs I chose to implement an API which simply monitors an AsyncToken from which the duration of an invocation can be determined, thus I wrote an RPCDiagnostics API which can be “plugged” into an AsyncToken client implementation.

RPCDiagnostics provides basic performance analysis of a Remote Procedure Call by providing a message which displays information about the operation duration via a standard trace call. In addition, an event listener of type RPCDiagnosticsEvent can be added to facilitate custom diagnostics and Logging.

RPCDiagnostics can easily be implemented as an addition to an existing AsyncToken or in place of an AsyncToken. The following examples demonstrate both implementations.

Implementing RPCDiagnostics onto an existing AsyncToken:

var call:AsyncToken = null;
call = RPCDiagnostics.monitorToken(service.send(),"methodName");
call.addResponder();
 

Implementing RPCDiagnostics in place of an AsyncToken:

var call:RPCDiagnostics = null;
call = new RPCDiagnostics( service.send(), "methodName" );
call.addResponder();
 

Implementing a listener to an RPCDiagnostics instance:

var call:RPCDiagnostics = null;
call = new RPCDiagnostics( service.send(), "operationName" );
call.addResponder();
call.addEventListener( RPCDiagnosticsEvent.EXECUTION_COMPLETE,
                       handler);
 

The RPCDiagnostics API and dependencies can be downloaded via the Open Source AS3 APIs page or from the below links:

RPCDiagnostics
RPCDiagnosticsEvent
Execution

Design Considerations: Naming Conventions

Intuitive naming conventions are perhaps one of the most important factors in providing a scalable software system. They are essential to ensuring an Object Oriented System can easily be understood, and thus modified by all members of a team regardless of their tenure within the organization or individual experience level.

When classes, interfaces, methods, properties, identifiers, events and the like fail to follow logical, consistent and intuitive naming conventions the resulting software becomes significantly more complex to understand, follow and maintain. As such this makes changes much more challenging than they would have been had better naming been considered originally. Of equal concern is the inevitability that poor naming will lead to redundant code being scattered throughout a project as when the intent of code is not clearly conveyed with as little thought as possible developers tend to re-implement existing functionality when the needed API cannot easily be located or identified.

Code is typically read many, many more times than it is written. With this in mind it is important to understand that the goal of good naming is to be as clear and concise as possible so that a reader of the code can easily determine the codes intent and purpose; just by reading it.

Teams should collectively define a set of standard naming conventions which align well with the typical conventions found in their language of choice. In doing so this will help to avoid arbitrary naming conventions which often result in code that is significantly harder to determine intent, and thus maintain. Of equal importance is the need for various teams from within the same engineering department to standardize on domain specific terms which align with the non-technical terms used by business stakeholders. Together this will help to develop a shared lexicon between business owners and engineers, and allow for simplified analysis of requirements etc.

Ideally, code should follow the PIE Principle (Program, Intently and expressively) – that is, code should clearly convey purpose and intent. In doing so the ability to maintain a software application over time becomes significantly easier and limits the possibility of introducing potential risk to project deliverables.

In short, conventions are very important regardless of a teams size; beit a large collaborative team environment, or a single developer who only deals with his own code. Consistency and conventions are a key aspect to ensuring code quality.

Perfectionism, Prudence and Progress

Yesterday there was an interesting article on InsideRIA titled: “How much is too much?”. This is a great topic, one which at times I have questioned myself.

Personally, I never take the “easy way out”, preferring to do things the “hard way”, so to speak. At times the benefits in doing things according to best practices, standards and conventions (a.k.a. “the right way”) may not always be immediately obvious. However over the years experience has taught me that in time the benefits always reveal themselves and the pros certainly outweigh the cons.

When given a good amount of forethought to a decision, a design an implementation and so forth a team almost certainly is afforded the ability to continue development feasibly and in a less challenging manner (as opposed to dealing with endless maintenance challenges). When things are done quickly with little regard for anything other than getting working code out the result is always failure at some level, most commonly the maintainability of a product.

With all this in mind it is important to understand that at the end of the day our development efforts, for better or for worse, are simply a means to an end for a specific business need. Therefore just as writing “quick and dirty” code has a negative impact on the business, so too does being a complete perfectionist. Admittedly, this used to be a challenge for me as I would tend to need designs, tests and code to “feel right” for them to be considered production ready, which typically resulted in me working many extra hours on my own time. This in itself is not necessarily a bad thing, but could rather be considered a labor of passion.

Ultimately the goal should be to find just the right balance of perfectionism, prudence and progress, providing necessary trade-offs where appropriate.

Cairngorm Abstractions: Business Delegates

In Part 1 of Cairngorm Abstractions I discussed the common patterns which can be utilized in a design to simplify the implementation of concrete Cairngorm Commands and Responders. Applying such patterns can be leveraged to help facilitate code reuse and provide a maintainable, scalable architecture, as, in doing so the design will ultimately ensure reuse as well as remove redundancy.

In this post I will describe the same benefits which can be gained by defining common abstractions of Business Delegates.

Business Delegate Abstractions
A Business Delegate should provide an interface against the service to which it references. This can be viewed as a one-to-one relationship whereas the operations and signatures defined by a Service, beit an HTTPService, WebService, RemoteObject, DataService etc. would dictate the Business Delegate’s API.

However, a rather common mistake I often find is that many times Business Delegates are defined in the context of the use case which invokes them, rather than the service from which they provide an interface against.

Correcting this is quite simple: refactor the current implementation to follow the one-to-one relationship model between a Service and Business Delegate.

So for instance, if your applications service layer specifies a “UserService”, your design should essentially have only one Business Delegate API for that Service. All of the operations provided by the “UserService” would be defined by an “IUserServiceDelegate” interface which would enforce the contract between the “UserService” and concrete Delegate implementations, regardless of their underlying service mechanism.

In this manner clients (delegate instances) can be defined as the abstraction (IUserServiceDelegate) and obtain references to concrete Business Delegate instances via a Delegate Factory, and as such remain completely transparent of their underlying service implementation.

This could be implemented as follows:

var delegate:IUserServiceDelegate;
delegate = DelegateFactory.createUserServiceDelegate( responder );
// invoke delegate …

Abstract Delegates
Perhaps the most common design improvement which can be made to improve the implementation and maintainability of Business Delegates is to define proper abstractions which provide an implementation which is common amongst all Business Delegates. Additionally, in doing so you will remove a significant amount of redundancy from your design.

For example, if you compare any two Business Delegates and find they have practically the exact same implementation, that is an obvious sign that a common abstraction should be defined.

Consider the following Business Delegate implementation:

public class SomeDelegate
{   
  private var _service:RemoteObject;
  private var _responder:IResponder;
   
  public function SomeDelegate(responder:IResponder)
  {
      _service = ServiceLocator.getInstance().
                 getRemoteObject( Services.LOGIN_SERIVCE );
      _responder = responder;
  }
   
  public function methodA(arg1:String, arg2:int) : void
  {
      var call:AsyncToken = _service.methodA( arg1, arg2);
      call.addResponder( _responder );
  }

  public function methodB(arg:Boolean) : void
  {
      var call:AsyncToken = _service.methodB( arg );
      call.addResponder( _responder );
  }

  public function methodC() : void
  {
      var call:AsyncToken = _service.methodC();
      call.addResponder( _responder );
  }
  …
}

The above example may look familiar, and when given just a bit of thought as to it’s design it becomes apparent that there is quite a bit of redundancy as every method essentially contains the same implementation code. That is, an AsyncToken is created, referencing the operation to invoke against the service, and a reference to the responder is added to the token.

The overall design would benefit much more by refactoring the commonality implemented across all Business Delegate methods to an abstraction, which in it’s simplest form could be defined as follows:

public class AbstractRemoteObjectDelegate
{   
  protected var service:RemoteObject;
  protected var responder:IResponder;

  public function AbstractRemoteObjectDelegate(serviceId:String,
                                            responder:IResponder)
  {
      this.service = ServiceLocator.
                     getInstance().getRemoteObject( serviceId );
      this.responder = responder;
  }

  protected function invoke(methodName:String, …args) : void
  {
      var operation:Operation = service[ methodName ];
      operation.arguments = args;
           
      var call:AsyncToken = operation.send();
      call.addResponder( responder );
  }
}

By defining a basic abstraction, the original implementation could then be refactored to the following:

public class SomeDelegate extends AbstractRemoteObjectDelegate
{   
  public function SomeDelegate(responder:IResponder)
  {
      super( Services.LOGIN_SERIVCE, responder );
  }
   
  public function methodA(arg1:String, arg2:int) : void
  {
      invoke( "methodA", arg1, arg2 );
  }

  public function methodB(arg:Boolean) : void
  {
      invoke( "methodB", arg );
  }

  public function methodC() : void
  {
      invoke( "methodC" );
  }
}

The same basic abstractions could easily be defined for HTTPService, WebService and DataService specific Business Delegates (in fact I have a library of Cairngorm extensions which provides them; planning on releasing these soon). Pulling up common implementation code to higher level abstract types also simplifies writing tests against concrete Business Delegates as the abstraction itself would need only to be tested once.

There are many more Business Delegate abstractions I would recommend in addition to what I have outlined here, in particular configuring Delegate Factories via an IoC Container such as SAS, however I would first suggest taking a good look at your current design before adding additional layers of abstraction, and the most appropriate place to start would be to define abstractions which encapsulate commonality, promote reuse and remove redundancy.

Cairngorm Abstractions: Commands and Responders

It is quite common to find a significant amount of code redundancy in Flex applications built on Cairngorm. This is by no means a fault of the framework itself, actually quite the contrary as Cairngorm is designed with simplicity in mind; opting to appropriately take a less-is-more approach in favor of providing a more prescriptive framework which only defines the implementation classes necessary to facilitate the “plumbing” behind the framework. Everything else is really just an interface.

With this amount of flexibility comes additional responsibility in that developers must decide what the most appropriate design is based on their applications specific context. Moreover, as with any design there is never a truly one size fits all approach which can be applied to any problem domain; there are really only common patterns and conventions which can be applied across domains and applications. This IMHO is what had allowed the framework to be a success and it is important to understand that this simplicity also requires developers to give their designs the same attention one would to any Object Oriented design.

However over the years I have found a significant amount of redundancy found in Flex applications built on Cairngorm. This appears to be (more often than not) the result of developers implementing Cairngorm examples verbatim in real world applications, and in doing so failing to define proper abstractions for commonly associated concerns and related responsibilities. The most common example of this is the typical implementation of Commands, Responders BusinessDelegates and PresentationModel implementations.

For some of you this may all seem quite obvious, and for others hopefully this series will provide some insight as to how one can reduce code redundancy across your Cairngorm applications by implementing abstractions for common implementations.

This topic will be a multi-part series in which I will provide some suggestions surrounding the common patterns of abstractions which can be implemented in an application built on Cairngorm, with this first installment based on common abstractions of Cairngorm Commands and Responders. Other areas in future posts will cover Business Delegate and Presentation Model abstractions. So let’s get started…

Command Abstractions
First let’s begin by looking at what is arguably the simplest abstraction one could define in a Cairngorm application to simplify code and eliminate areas of redundancy – Command abstractions. This example assumes the concern of mx.rpc.IResponder implementations is abstracted to a separate object. For more on this subject see my post regarding IResponder and Cairngorm.

A traditional Cairngorm Command is typically implemented as something to the extent of the following:

import com.adobe.cairngorm.commands.ICommand;
import com.adobe.cairngorm.control.CairngormEvent;

public class Command implements ICommand
{
  public function execute(event:CairngormEvent):void
  {
    var evt:SomeEvent = event as SomeEvent;
           
    // ModelLocator look-up and common references
    ModelLocator.getInstance()
}
}

The problem with the above Command implementation is that it results in numerous look-ups on the ModelLocator Singleton instance in every execute implementation which needs to reference the ModelLocator.

A simpler design would be to define an abstraction for all commands which contains this reference. as in the following:

import com.adobe.cairngorm.commands.ICommand;
import com.adobe.cairngorm.control.CairngormEvent;
   
/**
 *
 * Defines an abstraction of common references from
 * which concrete ICommand implementations can
 * inherit
 *
 */

internal class AbstractCommand implements ICommand
{
  // define common reference to ModelLocator
  // implementation
  protected static var modelLocator:ModelLocator
                       = ModelLocator.getInstance();

  // Force concrete command implementations to
  // override execute
  public function execute(event:CairngormEvent) : void
  {
    throw new Error( "Abstract operation…" );
  }
}

As in any OO system there are many benefits to defining abstractions and a good design certainly reflects this. For example, just by defining a very basic abstraction for all Commands we have now eliminated the number of look-ups on the ModelLocator for every Command in the application as well as redundant imports. By defining an abstraction for common references your code will become easier to read and maintain as the number of lines of code will certainly become reduced.

Commands are by far the easiest to create an abstraction for as most commands will typically reference the ModelLocator, and if so they could do so simply by extending an AbstractCommand, if not they would implement ICommand as they traditionally would.

So the first example could now be refactored to the following:

import com.adobe.cairngorm.control.CairngormEvent;

public final class Command extends AbstractCommand
{
  override public function execute(event:CairngormEvent):void
  {
    var evt:SomeEvent = event as SomeEvent;
    // modelLocator…
  }
}

You could take these abstractions a step further and define additional abstractions for related behavior and contexts, all of which would also extend the AbstractCommand if a reference to the applications ModelLocator is needed.

Responder Abstractions
Now let’s take a look at an abstraction which is much more interesting – Responder abstractions. In this example we will focus on the most common Responder implementation; mx.rpc.IResponder, however the same could easily apply for an LCDS Responder implementation of a DataService.

A separate RPC responder could be defined as an abstraction for HTTPServices, WebServices and RemoteObjects as each request against any of these services results in a response of either result or fault, hence the IResponder interface’s contract.

For example, consider a typical Responder implementation which could be defined as follows:

import mx.rpc.IResponder;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
   
public class SomeResponder implements IResponder
{      
  public function result(data:Object) : void
  {
    // redundant cast operation
    var result:ResultEvent = data as ResultEvent;
           
    // Redundant ModelLocator lookup and references…
    // ModelLocator.getInstance()…
  }

  public function fault(info:Object) : void
  {
    // Redundant cast operation
    // Doesn’t provide a centralized place for
    // global service exception handling
    var fault:FaultEvent = info as FaultEvent;
           
    // Redundant ModelLocator lookup and references…
    // ModelLocator.getInstance()…
  }
}

By defining a Responder abstraction each concrete Responder implementation would result in significantly less code as the redundant cast operations could be abstracted, and, as with Command Abstractions, a convenience reference to the application specific ModelLocator could also be defined. Moreover, a default service fault implementation could be defined from which each service fault could be handled uniformly across the application.

Thus we could define an abstracttion for RPC Responders as follows:

import mx.rpc.IResponder;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
   
/**
 *
 * Defines an abstraction of common references and
 * functionality from which concrete IResponder
 * implementations can inherit
 *
 */

internal class AbstractRPCResponder implements IResponder
{   
  protected static var modelLocator:ModelLocator
                       = ModelLocator.getInstance();
           
  // Provides a default implementation of
  // mx.rpc.IResponder.result(); which
  // handles casting to a ResultEvent
  public function result(data:Object):void
  {
    var result:ResultEvent = ResultEvent( data );
    resultResponse( result );
  }
       
  // provide default implementation of
  // mx.rpc.IResponder.fault(); which
  // handles casting to a FaultEvent
  public function fault(info:Object) : void
  {
    var fault:FaultEvent = FaultEvent( info );
    faultResponse( fault );
  }
       
  // Force concrete implementation to override
  // resultResponse
  public function resultResponse(result:ResultEvent):void
  {
    throw new Error( "Abstract operation" );
  }
       
  // Provides default service exception handling
  // universally across all Responder implementations.
  // Concrete implementations can also override this
  // method if specific fault handling needs to be
  // implemented
  public function faultResponse(fault:FaultEvent):void
  {
    // implement default service exception handling
  }
}

We could now refactor the original Responder implementation to the following simplified implementation:

import mx.rpc.events.ResultEvent;
   
public final class SomeResponder extends AbstractRPCResponder
{      
  override public function resultResponse(result:ResultEvent):void
  {
    // modelLocator…
  }
}

As you can see just be pulling up common references and functionality to just two abstractions we can significantly remove redundancy from all Commands and Responders. As such this allows designs to improve dramatically as it allows for the isolation of tests and limits the amount of concrete implementation code developers need to sift through when working with your code.

It is important to understand that a design which is built in part on Cairngorm must still adhere to the same underlying Object Oriented Design principles as any other API would, and in doing so you will end up with a much simpler design which can easily scale over time.

Pattern Recognition

Its been said that the true sign of intelligence lies in ones ability to recognize patterns – and there is a lot to be said of that statement as patterns can be found everywhere, in everything, in everyday life.

One of the greatest strengths of human intelligence is in our ability to recognize patterns and abstract symbolic representations even when they occur in contexts different from that in which we originally learned them. It’s why hard to grasp concepts which are foreign or new to us become very clear when explained through metaphor.

This ability to recognize patterns is essential to our survival, always has been. For example, practically all ancient civilizations had a very, very good understanding of the recurring patterns in their environment; something we like to call seasons. This understanding of patterns in time and climate was crucial to the survival of these early civilizations. Our ability to recognize patterns is essential to our learning and understanding of the world around us. Pattern recognition is a cognitive process much like intuition. Arguably they are inter-related or possibly one and the same.

Suppose you you want to lose a few pounds, or save a little extra money, or learn a new programming language etc. but you are not seeing the results you would like. By recognizing patterns in your behavior you will begin to notice areas which need to be adjusted and from that determine an appropriate solution and the necessary adjustments to be made in order to achieve your goal. For example, maybe you’ve been trying to save some extra money and after a few months realize you are getting nowhere. You then analyze your behavior for recurring patterns and realize your spending half your pay every weekend on beer, just kidding, but you get my point.

Pattern Recognition in Software Development
In the world of software development patterns apply in pretty much just the same way – our ability to recognize them is essential to ensuring the success of a software application. When we discover patterns of recurring problems in software we are then able to consider various potential patterns from a catalog of named solutions, i.e. Design Patterns. Once an appropriate solution is found we can apply it to resolve the problem regardless of the domain.

When designing software, patterns are something that should reveal themselves, never forced into a design. This is how patterns should always be applied; you have a problem, and based on that problem you begin to recognize common patterns, or maybe new ones, which can be applied as a solution to resolve the problem. It should never be the other way around, that is, a solution (Pattern) looking for a problem. However this happens quite often and is pretty evident in many software applications. Many refer to this as “pattern fever“, personally I like to call it “patterns for patterns sake“, or simply “for patterns sake“. Because that’s really what it is.

For example, have you ever found a Singleton implementation where an all static class would have sufficed (e.g. utilities). Or a code behind implementation class which masquerades as an abstract class. Or an Interface where there is clearly only a need for a single concrete implementation (e.g. data centric implementations), or a marker Interface which serves no purpose at all. The list goes on and on.

In some cases it very well may just be an innocent flaw in the design, however the majority of the time it’s a tell tale sign of someone learning a new pattern and knowingly, albeit, mistakenly, attempting to implement the pattern into production code. This is clearly the wrong way of learning a new pattern. Learning new design patterns is great and a lot of fun but remember, there is a time and place for everything, and production code isn’t it.

Learning Patterns
One of the best ways to learn a new pattern (or anything new for that matter) is to explore it. Begin by reading enough about it to get some of the basic concepts to sink in a bit. Put it into context, think of it in terms of metaphor – in ways that make sense to you, remember you are learning this. Question it. Then experiment with it. See how it works, see how it doesn’t work, break it, figure out how to put it back together, and so on, but whatever works best for you. Most importantly always do it as a separate effort such as a POC, but never in production code.

Once you get this down and understand the various patterns you’ll find you never need to look for them, for if they are needed they will reveal themselves sure enough.

What makes a good design?

One of my core job responsibilities for the past several years has been to conduct technical design and implementation (code) reviews during various phases of the software development life cycle. This is typically a highly collaborative process whereas myself and an individual engineer, or the team as a whole will begin by performing a detailed analysis of business requirements in order to gain an initial understanding of the specific component(s) being developed. Once an understanding of the requirements has been reached a brainstorming session ensues which ultimately leads to various creative, technical solutions. After discussing the pros and cons of each the best solutions quickly begin to reveal themselves, at which point it is simply a process of elimination until the most appropriate solution has surfaced.

The next step is to translate the requirements into the proposed technical solution in the form of a design document. The design is specified on a high level and is only intended to provide an overview of the appropriate technical road map which is to be implemented. This typically consists of higher level UML Sequence and Class diagrams, either in the form of actual diagrams produced in a UML editor, or could simply be a picture captured from UML drawn out during a whiteboarding session. The formality of the documented design is less important, what is important is that the design is captured in some form before it is implemented. Implementation specific details such as exact class and method signatures and so forth are intentionally left out as they are to be considered outside the scope of the design. See Let Design Guide, not Dictate for more on this subject. Once the design is documented it is reviewed and changes are made if needed. This process is repeated until all business and technical requirements have been satisfied, at which point the “all clear” is given to move forward with implementing the design.

But what exactly constitutes a good design? How does one determine a good design from a bad one? In reality it could vary significantly based on a number of factors, however in my experience I have found a design can almost always be judged according to three fundamental criterion: Correctness, Cohesion / Coupling and Scalability. For the most part everything falls into one of these three categories. Below is a brief description of the specific design questions each category sets out to determine.

  • Correctness
    Does the design solve the problems described in the requirements and discussed by the team? This is Correctness in the form of satisfying business requirements. Are the patterns implemented in the design appropriate, or are additional patterns being used just for the sake of using the pattern? This is Correctness in the form of technical requirements. A good design is well focused and only strives to provide a solution which meets the requirements specified by the business owners, client etc; it does not attempt to be overly clever.
  • Cohesion / Coupling
    Has a highly cohesive, loosely coupled design been achieved? Have the classes, interfaces and APIs been logically organized? Does each provide a specific, well-defined set of functionality? Is composition used over inheritance where applicable? Has related functionality been properly abstracted? Does changing this break that, does adding that break this, etc.
  • Scalability
    Does the solution scale well? Is it flexible? A good design strives to facilitate change with confidence, and with as little risk as possible. A good design also achieves transparency at some level in the areas where it is most applicable.
  • The concepts outlined above are crucial to achieving a good design, however they are often overlooked or misunderstood to some degree. Throughout the years I have began to recognize some commonality in the design mistakes I find in Object Oriented Designs in general, and within Flex projects in particular. Many of which typically can be attributed to violations of basic MVC principles, but most commonly the design mistakes appear to be a negation of Separation of Concerns (SoC).

    There are close relationships between Correctness, Cohesion / Coupling and Scalability, each of which plays a very significant role in the resulting design as a whole.

    So lets start with Correctness, which is by far the single most important facet of design, for if the design does not provide a solution which satisfies the requirements specified then it has failed – all other aspects of the design are for the most part, details.

    It is important to understand that Correctness has a dependency on Flexibility. For example, as architects and developers our understanding of the problem domain is constantly evolving as we gain experience in the domain. Additionally, as requirements may change significantly as a product is being developed, our designs must be able to adapt to these changes as well. Although this poses some challenges it is wrong to suggest that requirements need to be locked down completely before the design phase begins, but rather requirements need only be clearly defined to the extent that the designer is aware of what is required at that point in time and how it fits into the “big picture”. A competent designer understand this well and makes careful considerations before committing to any design decisions. This is where the importance of Flexibility comes into play. In order for a design to be conceptually and technically correct it needs to be flexible enough to support change. This is why good design is so important – to easily facilitate change. As such the flexibility to allow change should be evident throughout the design. A good example might be where the middle-tier has not decided which service layer implementation will be used (e.g. XML:80, WSDL, REST etc.), or the Information Architects have not decided what the constraints of each user role will be. A good design should be flexible enough to allow for changes such as these as well as others with confidence and more importantly, little risk to other parts of the application; after all, you shouldn’t have to tear down the house just to renovate the bathroom – in addition to Correctness and Scalability, this is where Cohesion and Coupling come into play.

    High Cohesion is vital to achieving a good design as it ensures related functionality and responsibilities are logically grouped together, encapsulated and abstracted. We have all seen the dreaded, all encompassing class which assumes multiple responsibilities. Classes such as these have low cohesion and are a sign of future challenges if not addressed immediately. On a higher level, if high cohesion had not been achieved it is easy to notice as there will typically only be one class which comprises an entire API, however quite often low cohesion in classes may be a bit more subtle than one might expect and a code review will reveal areas where low cohesion has been implemented.

    For example, consider the following Logging facility which is intended to provide a very simple logging implementation:

    The above example is such a classic case of low cohesion. I see this kind of thing all the time. The problem here is that the Logger class has low cohesion because it is assuming the responsibility of creating and formatting a time stamp, this functionality is outside of the responsibilities of the Logging API. The creating and formatting of a time stamp is not a concern of the Logger, but rather would be the responsibility of a separate DateFormatting utility whose sole purpose is to provide an API for formatting Date objects. Removing the Date formatting functionality from the Logging API to a class which is responsible for formatting Date objects would facilitate code reuse across many APIs, reduce redundancy and testing as well as allow the Logger class to only define operations which are directly related to Logging. A good design must achieve high cohesion if it is to be successful.

    Coupling is essential in determining a good design. A good way to think of coupling is like this: Think back to when you were a kid playing with blocks, you could easily take any number of different blocks and rearrange them to build whatever you like – that’s loose coupling. Now compare that to a crossword puzzle or a jigsaw puzzle, the pieces only fit together in a very specific way – that’s tight coupling. A good design strives to achieve loosely coupled APIs in order to facilitate change as well as reuse. A classic, yet less commonly mentioned example tight coupling is in the packaging of APIs. Often, many times designers will achieve loosely coupled APIs however the APIs themselves are tightly coupled to the application namespace.

    Consider the of Logging API example from above, note that the API is defined under the package com.somedomain.someproject.logging. Even if the example were to be refactored to achieve high cohesion it would still be tightly coupled to the project specific namespace. This is a bad design as in the event another product should need to use the Logging API it would first need to be refactored to a common namespace. A better design would be to define the Logging API under the less specific namespace of com.somedomain.logging. This is important as the Logging facility itself should be generic in that it could be used across multiple projects. Something as simple as proper packaging of generic and specific components plays a key role in a good design. A better design for the above example would be as follows, this design achieves both high cohesion and loose coupling:

    As with all design, technical design is subjective. Architects and Engineers can spend an infinite amount of time debating the various points of design. In my experience it really comes down to organization and efficiency, that is, organization of responsibilities and concerns, and the efficiency of their implementation both individually and as a whole.

    It may sound cliche’ however before you begin a new design, or review an existing one, consider the following quote before doing so – it pretty much sums up what good design is:

    “Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.”
    - Antoine de Saint-Exupery

    IoC and the Dependency Injection Pattern in Flex

    Within the vast catalog of Design Patterns available to software developers today, one of the most important to consider when designing an enterprise class RIA is the Dependency Injection Pattern.

    Dependency Injection, a term originally coined by Martin Fowler in his well known article Inversion of Control Containers and the Dependency Injection Pattern, is a more specific term for what is otherwise known as Inversion of Control or IoC.

    Fowler’s assessment of Inversion of Control containers concluded that the name itself – Inversion of Control – was too generic, thus as a result from his discussions with various IoC advocates they settled on the more specific term Dependency Injection, also known as DI for short. The terms Inversion of Control (IoC) and Dependency Injection (DI) are commonly used interchangeably to describe the same underlying design principle of separating configuration from implementation.

    There are three basic forms of Dependency Injection, which are generally referred to as type 1 IoC (Interface Injection), type 2 IoC (Setter Injection) and type 3 IoC (Constructor Injection). Before diving into the specifics of how to implement the various forms of DI, I will first discuss what Dependency Injection is on a conceptual level as well as what each specific form means. The examples outlined here are in ActionScript 3, however it is important to keep in mind that like most Design Patterns Dependency Injection applies to any language which supports an Object Oriented Model.

    At the most basic level Dependency Injection can be explained as a way of decoupling classes from their dependencies by injecting the dependencies into them rather than having the classes directly reference specific implementations. A class which directly references other classes is coupled to those classes – these are the dependencies. However a class which does not reference any other classes would probably not be very useful. At some point the dependencies need to be made. Dependency Injection is a solution to how those dependencies are made, and the manner by which they are provided.

    For example, consider the following class which illustrates a typical example of a class’s dependency on another class:

    public class ConfigurationManager
    {
        //defines the configuration to use
        private var config:XMLConfiguration;
       
        public function ConfigurationManager()
        {
             config = new XMLConfiguration();
        }

        public function getLogLevel() : String
        {
             return config.getConfig("logLevel");
        }
    }

    From looking at the code above the dependencies are pretty obvious; the ConfigurationManager class is dependent on the XMLConfiguration class. Now this type of dependency is quite typical so at this point you may be asking what is wrong with doing this?

    The first problem is that the config property is defined as a concrete implementation:

    private var config:XMLConfiguration

    This violates a fundamental OO principle:

    Program to interfaces, not implementations.

    More importantly and perhaps pertinent to the topic at hand is that it also isn’t very hard to imagine that at some point we may want to load a configuration from some other means, such as a properties file, a remote service and so on. In order to do so we would need to modify the class, and from this we can deduce that the class does not scale very well.

    So we could begin improving our current implementation by simply refactoring the ConfigurationManager class to define the config property as an abstraction, say IConfiguration:

    public interface IConfiguration
    {
        function getConfig(name:String) : *;
    }

    public class ConfigurationManager
    {
        //define the configuration as an abstraction
        private var config:IConfiguration;
       
        public function ConfigurationManager()
        {
             config = new XMLConfiguration();
        }

        public function getLogLevel() : Array
        {
             return config.getConfig("logLevel");
        }
    }

    As you can see this is certainly a step in the right direction, however the underlying problem still remains; we are still instantiating an instance of XMLConfiguration directly in the ConfigurationManager – and that is exactly what Dependency Injection is all about: providing a solution to the recurring problem of managing dependencies between classes, and how those dependencies are provided.

    When implementing the Dependency Injection Pattern in an application you do so by creating a context (configuration) which defines all dependencies in an application as well as an Assembler which is responsible for assembling the mappings and associations between objects and their dependencies. This is done by utilizing any combination of the three forms of DI; Interface Injection, Setter Injection and Constructor Injection. Below is a brief description of each form:

    Interface Injection
    Interface Injection is the process by which all dependencies are injected into an object via an interface. For example, the ConfigurationManager example above could implement an interface which defines the operations needed to inject the appropriate Configuration implementation.

    Setter Injection
    Setter injection as you may have guessed is the process of injecting dependencies via public setters; both explicit or implicit. Using Setter Injection the ConfigurationManager could provide public setters from which an Assembler could inject the appropriate Configuration implementation.

    Constructor Injection
    Again as you may have guessed Constructor Injection is the process of injecting dependencies via arguments in the class constructor. Using Constructor Injection the concrete Configuration could just as easily be injected.

    Both Constructor and Setter Injection are by far the preferred forms of Dependency Injection. Interface Injection has some major drawbacks as it somewhat leads to convoluted code since multiple additional interfaces need to be defined and implemented. The fact that “special” types need to be created and implemented in order to facilitate DI using Interface Injection greatly limits the potential for its use.

    There are numerous frameworks for various platforms which provide out of the box Dependency Injection implementations for all three forms of DI. All of these frameworks handle the wiring necessary for easily implementing Dependency Injection in an application, the most notable being the Spring Framework for Java/J2EE. There are also quite a few DI solutions for Flex and ActionScript applications as well. Optionally you could choose to roll your own however I would first suggest investigating some of the frameworks which are currently available as they more than likely provide what you need. The Prana Framework by Christophe Herreman is a good choice as it is one of the most prevalent DI solution available at the moment for Flex.

    Using the ConfgurationManager example from above I have provided a basic example application which demonstrates how to implement Dependency Injection utilizing the Prana framework. The example application uses constructor injection to provide a concrete Configuration to the ConfigurationManager, however I encourage you to experiment with the other mechanisms of injection as well. The example is intentionally kept very simple in that it is only intended to convey the basic concepts of DI and how to use it in Flex with Prana, from this you should have a good understanding of how to implement DI in a larger context.

    Let design guide, not dictate

    A good design should be intended to guide implementation, not dictate it; and for good reason as in the real world of software development requirements and systems are far to complex and dynamic in nature to view a technical design as anything more than a basic prescription intended to form the basis of an efficient implementation. Yet far too often many people seem to believe that once a detailed design has been completed and approved implementation should be a breeze; however, this is just not a very realistic expectation.

    For instance, one of my core job responsibilities is to review technical design documents and provide feedback and direction. This is an iterative process which typically has between 1-3 iterations depending on the complexity of the system. Initially myself and an engineer are given requirements for review. He or she then begins an initial draft of the design and once completed passes it on to me for review. I then review the document and provide feedback where applicable, either via annotations to the document itself or by reviewing with the developer (which is by far my preferred process). Should modifications be required the developer will then make revisions as needed. This process is repeated (within practicality) until final design has been approved.

    At first it may appear as if only a single design iteration and review would be needed, however more often than not, requirements may not be completely understood during the beginning stages of design, nor are they typically ever set in stone so it is very common that a design will need to change during the early stages of a project or even throughout the entire development stage. Once final design has been completed an engineer then begins implementing the design. Theoretically this may appear to be a quite simple process: create a great design which contains as much detail as possible, review it, make revisions and approve it, then just pass it off to any developer for implementation and that’s it, done, right? – wrong!

    There are a number of problems to this approach. Below I have outlined the three I feel are most significant and the solutions I have found to address each.

  • Creativity
    The first problem is that a design which goes into too much detail completely limits or even worse, kills creativity – which in my opinion is the single most important trait a developer can possess, especially when designing. The developer is now merely a typist and will undoubtedly become very bored when implementing the design, especially if it is not even his/her design to begin with! Because of this lack of creativity the final code will ultimately suffer and bugs can be expected. Keeping design on a higher level allows developers to have the creative freedom needed to provide quality implementations and work they can feel is their own.
  • Flexibility
    The second problem is that the more detailed and precise the design the less flexibility there is when requirements change and modifications need to be made to the design and thus implementation. For example, if a design contains very low level details, such as method signatures and other implementation specific details the ability to change the design now becomes increasingly complex and will result in much of the design needing to be reworked significantly. In addition the more detail there is the harder it is to write unit tests against the design as the actual implementation has already been defined. Designs need to be very high level and should not go beyond identifying class names, their responsibilities, relationships and dependencies.
  • Tools
    The third problem is that far too often developers get caught up in all the details of UML notation and related tools. Again, this negates creativity and results in the developer concentrating more on making the design look technically correct rather than concentrating on designing towards a great solution which addresses the problem at hand. In addition, this also results in unnecessary time being spent to complete the design – time which otherwise could have been much better spent on something that produces a better pay off for the project. Now this is not to say that UML shouldn’t be used, actually quite the contrary as I feel a final design should be in UML (or some other format) as a shared language is very helpful in allowing readers to easily understand the design. I always suggest a technique where developers draw out their design in any way that makes sense to them without having to give much thought to anything other than the solution itself. This could be anything from drawing / scribbling thoughts on a pad, to building out a vision from legos – seriously! Only once the design has been envisioned would I recommend bringing it to realization through the use of a formal design tool, such as Visio or other UML tools to be used.
  • The above illustrates the three most common design issues I have encountered, most of which pertain to over-detailed designs, as well as the approach I take to address each. If you have not encountered any of these issues in your own work than that is generally a good sign, however try to keep them in mind when designing as it will pay off in the end. The important thing to remember when designing is to design for flexibility and simplicity. Less is usually more and the KISS principle, especially when applied to software design, will always pay off in the end.

    Implementing interfaces in mxml

    Most Flex developers are aware that mxml files are essentially declarative representations of ActionScript classes, that is, during compilation the mxmlc compiler generates ActionScript 3.0 classes from mxml files before being converted into bytecode that runs in Flash Player. This can be seen by setting the compiler argument -keep-generated-actionscript to true.

    You may be thinking “yeah I know this, and…”, however in the past week I have had two talented Flex developers say to me: “but you can’t implement interfaces in mxml… Can you?”

    Now if you think about that statement a bit more you will probably realize that you most certainly can, however it mat not seem so obvious at first as developers tend to think of mxml for what it is, a markup language and not necessarily from a compilation perspective.

    So in case you are not aware how interfaces can be implemented in mxml I have provided a few simple examples below which demonstrate how a custom component can implement an interface, in this case mx.rpc.IResponder.

    First you define the interface that the component will implement using the implements property of the component.

    <?xml version="1.0" encoding="utf-8"?>
    <mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
             implements="mx.rpc.IResponder" >
    </mx:VBox>

    Next you simply implement the operations defined by the interface as you normally would in a class:

    <?xml version="1.0" encoding="utf-8"?>
    <mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
             implements="mx.rpc.IResponder" >
        <mx:Script>
            <![CDATA[

                public function result(data:Object) : void
                {
                    // implementation
                }
               
                public function fault(info:Object) : void
                {
                    // implementation
                }
            ]]>
        </mx:Script>
    </mx:VBox>

    Now you may be wondering how multiple interfaces are implemented in mxml? This is very easy as well, simply specify the fully qualified class path of each interface as a CSV (Comma-separated values). An example can be seen in the following:

    <?xml version="1.0" encoding="utf-8"?>
    <mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
              implements="mx.rpc.IResponder,mx.core.IUID" >
        <mx:Script>
            <![CDATA[
                    public function result(data:Object) : void
                    {
                         // implementation…
                    }

                    public function fault(info:Object) : void
                    {
                         // implementation…
                    }

                    public function get uid() : String
                    {
                         // implementation…
                    }

                    public function set uid(value:String) : void
                    {
                         // implementation…
                    }
            ]]>
        </mx:Script>
    </mx:VBox>

    And that’s all there is to it.