You are viewing the Articles published in

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

AS3 Quick Tip: Object setPropertyIsEnumerable

Most ActionScript developers are very familiar with Anonymous Objects in ActionScript 3.0 as they provide a convenient mechanism from which properties of an object which are not known at design time can be defined at runtime. This post is just a quick tip on the Object.setPropertyIsEnumerable() method, for more detailed information on using Objects in ActionScript 3.0 visit livedocs.

The Object class has a few useful methods, specifically toString();, hasOwnProperty(); and propertyIsEnumerable();. There is also another method of the Object class which is very useful: setPropertyIsEnumerable() which can be utilized to explicitly omit a property from being included in an enumeration of an object.

Consider the following example:

When enumerating the object instance all properties and their values can easily be retrieved, however it is important to keep in mind that when enumerating an Object the order in which properties are retrieved is not guaranteed. So executing the same loop against the same object instance could yield different results each time, such as “value B, value A, value C” as opposed to what you might have expected, i.e. “value A, value B, value C”.

Now suppose you do not want a property to be exposed via an enumeration of the object, this can be achieved via:

So based on the above examples, if we did not want to expose the “propA” property in a for in… loop we could omit the property as follows:

So when you need to omit properties from being included in an enumeration of an object, Object.setPropertyIsEnumerable(); proves very useful.

Continuous Integration with Hudson

Continuous Integration is a fundamental Agile Development process in which members of a team integrate changes on a regular basis, ideally multiple times per day, which in turn results in multiple integrations per day. The integration process itself is facilitated by an automated integration build which is triggered upon a specific interval to check for new commits to the central repository, or mainline. This is necessary for detecting changes which could potentially break the build as quickly as possible, as it is typically easier to fix these errors sooner rather than later, thus resulting in significantly less integration issues, especially when working on large, collaborative projects where there are multiple members of a team developing against the same codebase.

Continuous Integration does not necessarily require any specific tooling, however it is very common to incorporate a build management tool in order to automate the builds. The most common tool of choice by build managers to facilitate automated builds is Cruise Control. I have been using Cruise Control for years to automate Flex builds as it contains everything one typically would need for automating an integration, staging and production build process. Setting up Cruise Control and modifying the configuration to add new projects is a straight forward process, however I always felt it to be a bit tedious.

Considering Cruise Control is an industry standard as well as the fact that it provides pretty much everything I have ever needed for automating enterprise build processes, I never had a compelling reason to investigate any of the other tools out there. Then last week I received an email from our engineering groups build manager stating that there is a different build management tool being considering called Hudson. Initially I questioned why Hudson was being considered over Cruise Control as CC is, for the most part, an industry standard, so I decided to do a little investigating to see for myself, first by reading the documentation then by running the simple test drive available at the Hudson site which you can use to get an idea of how the tool works.

Downloading Hudson is straight forward and best of all installation is a breeze; simply deploy the web archive (hudson.war) to an existing servlet container (I am using Tomcat 6.0.14) and your ready to go.

Once deployed you can go to the Hudson console, typically located at: http:<host:port>/hudson/ (e.g. http://somedomain:8400/hudson/). The console has all of the features you might expect (as well as some other useful tools). From the console you can easily configure Hudson, create new projects, monitor build progress, view build logs, kick off a build, schedule builds and so forth. Setting up a project is one of the things I really like about Hudson – as opposed to configuring a project in Cruise Control – as Hudson provides a super simple GUI that you can use to create new projects. This is one of its main attractions in my opinion as new builds can be configured in next to no time at all. The Dashboard and UI in general are very intuitive and easy to use, and if you’re like me and still would like to have the ability to look under the hood and modify the configurations, you also have that level of control as well. Kicking off a build manually or scheduling builds is just as easy.

Overall I have to say that I am a fan of Hudson. Admittedly I just started using it so I am certain there is much more to learn about the tool, however if the rest of the functionality is as easy to configure as the basic features then this is a sure sell. I estimate it took me approximately 10 minutes total to download, install, configure a project and run a build (successfully I might add:).

Some key features:

  • Master / Slave builds
  • Distributed Builds
  • GUI based project configuration
  • E-mail / AIM / RSS build notifications
  • Plug-ins / extensibility support
  • Simple Installation
  • Console Auto-refresh

So if you are interested in streamlining your Continuous Integration process I recommend taking a quick test drive of Hudson.

AIR SQL Framework

When working with the Adobe AIR SQL API it is important to consider the various best practices advocated by Adobe regarding performance, security and design. As there is nothing in particular in the SQL API itself to guide developers in following these best practices, developers are left to implement their own solutions, which often may vary across different applications.

For instance, consider the SQLStatement class. In order to optimize performance of the execution of a statement, the statement must first be prepared (i.e. compiled), which optimizes the statement by the runtime prior to execution. Once a statement is prepared, if the text property does not change, subsequent executions of the statement will execute faster. In order to facilitate this particular optimization developers must first be aware of this best practice, then determine the appropriate way to implement a solution in order to take advantage of the advocated practice. A simple way to facilitate this is to define separate SQLStatement instances for each unique statement which is to be executed more than once, as is suggested by Adobe, and assume the text property is not to be assigned a new value. You could take this a step further as well and define a sub class of SQLStatement which enforces the text property is only assigned a value once, thus ensuring the optimization has been set. The AIR SQL Framework provides such facilities.

The AIR SQL Framework is a simple, reusable framework which facilitates advocated best practices when working with the SQL API in AIR.

At the foundation of the AIR SQL Framework sits the following packages:

  • com.ericfeminella.sql The sql package contains a PreparedStatement class for enforcing a SQLStatement instance to only have a text value assigned during instantiation. In addition the sql package contains an ISQLStatementCache interface which can be used to indicate an implementing class is to serve as a repository of reusable PreparedStatement instances.
  • com.ericfeminella.sql.dao The DAO package provides abstractions for both synchronous and asynchronous SQL DAO implementations.
  • com.ericfeminella.sql.utils The utils package provides helper classes for substituting statement parameters and retrieving shared SQLConnection instances

This distribution of the AIR SQL Framework should be considered an alpha release as there are some additional features which I am planning to implement, namely, the addition of support for named parameter substitutions in the SQLStatementHelper class.

I have provided an example project which demonstrates a simple AIR application built utilizing the AIR SQL Framework, along with the source, binary and documentation.

AIRSQL 0.9.1

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:

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:

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:

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.

Class Annotations in Flex

Class annotations, also known as metadata in Flex, are extremely valuable as they allow developers to provide additional information about classes, properties and methods which may not be appropriate to convey through implementation details such as Marker interfaces or some other means. An annotation can be viewed as a comment of sorts that provides a facility which can be utilized to convey the intent of a class, property or method, however unlike comments annotations are compiled into byte code with the class, thus allowing inspection at runtime via object introspection / reflection. Annotations do not directly affect code semantics themselves, however they can be inspected at runtime which in turn may affect the semantics of the running application.

Annotations are also very useful for providing pre-compiler instructions for generating boilerplate code. Although custom annotations can not be used in this way directly in Flex, this usage can be found throughout the Flex Framework. A perfect example of how the Flex framework uses annotations to generate boiler plate code is the [Bindable] meta-data tag, which itself is an annotation as are all meta-data tags in Flex. When a class or property is defined as [Bindable] the pre-compiler in turn reads this attribute and generates the code which facilitates actual data binding; i.e. PropertyChangeEvent, IEventDispatcher etc.

In order to use custom annotations in Flex you first need to instruct the compiler to keep Actionscript 3 metadata. This is achieved by using the keep-as3-metadata compiler argument. An example of setting two custom metadata attributes named “Foo” and “Bar” in the Flex IDE under project > compiler options is as follows.

Additionally annotations can be specified in a flex configuration file as follows:

When you create custom metadata in Actionscript you do so by first declaring the name of the annotation followed by arbitrary properties specified as name/value pairs. For example, you are most likely familiar with the [Event] metadata tag in Flex. The name of the annotation is “Event” and the valid properties for the annotation are “name” and “type”, as can be seen below:

Likewise you create your own custom metadata following the same format. The example which follows defines a custom metadata attribute utilized for annotating a class with version information. The name of the annotation is “Version”, which contains three properties; major, minor and revision.

Accessing custom annotations in Flex is accomplished via the flash.utils reflection APIs; describeType, getQualifiedClassName and getDefinitionByName.

To help simplify the process of accessing custom annotations in Flex I have developed a simple API: MetadataUtils which is an all static class that provides utility operations from which class annotations can be located and inspected, and Metadata which provides a strongly typed implementation of a metadata entry.

As you begin experimenting with your own custom annotations you will quickly find that there are numerous applications where they can be utilized, the most significant of which (IMHO) is to help facilitate IoC / DI solutions. It would be great if at some point Adobe would provide an APT implementation for mxmlc as part of a future release of Flex.