Tom Sugden: Cairngorm Archives

November 23, 2009

Modularity in Flex Applications

There has been talk recently about the trend towards inversion-of-control frameworks in Flex. In addition to this, a higher-level movement can be seen towards modularity frameworks. Such an approach to architecture can bring many benefits, particularly in enterprise settings with larger teams and formal release processes. This post explains what modularity means in the context of Flex and discusses some of the benefits and options available for implementation.

What is Modularity?

Modularity is something more general than the Flex Module and ModuleLoader components. These are a form of modularity, but the principle is broader: modularity is about separating applications into smaller units that can be developed and deployed independently. In the context of Flex, these units might be modules, sub-applications or any other kind of encapsulated content. A modular application usually has a structure like that shown in Figure 1.

Modularity Figure.002.png

Figure 1 — The structure of a modular application

In the figure above, the application consists of a thin shell that loads three modules: Dashboard, Contacts and Messages. These modules represent different functional areas of the application. Their implementation detail is independent of one another. The application shell is responsible for loading and laying out the modules, and providing a means of communication between them. This might be a global data model, a registry of interfaces, or in the case of Figure 1, some kind of message bus.

What are the Benefits of Modularization?

Modularization can bring benefits for end-users of an application and also for the teams that develop and deliver them; Here are some of the benefits:

  • A module can be developed, tested and profiled in relative isolation.
  • Build times are shortened, since changes to one module don't require other modules or the shell application to be recompiled.
  • Modules can be loaded on demand, so the initial download for an application is smaller.
  • If a user never uses the features of one module, that module need not be loaded.
  • Individual modules can be deployed into production, instead of redeploying an entire application.
  • Different modules can be loaded for different users based on their entitlements.
  • A module is easier to understand and maintain than a monolithic application, since it is more functionally cohesion.
  • The interactions between modules can be confined to a thin API, reducing regression as an application grows.

The benefits in terms of architecture and development efficiency are arguably the most important. Small groups of developers can work on individual modules. The contracts of communication between modules can be agreed, so the implementation is free to change and improve without regression.

Framework Provisions for Modularization

Some frameworks have features to help with building modular applications. PureMVC was probably the first to do so with the multi-core version of the framework and its Pipes utility for controlled flow of messages between modules. The Parsley application framework is also designed to support modular applications, in which a module would normally have its own inversion-of-control context that inherits object definitions from the context of a shell application. Parsley includes a messaging framework that can be used for loosely-coupled communication between modules.

The other frameworks are hot on their heels. Spring Actionscript will have modular support as of version 0.9, where each module can have its own context with the option to inherit the object definitions of its parent. A parent context will be able to control which object definitions are exposed to a child context. And the lightweight Swiz framework is going to improve its support for modular development in the near future with its 1.0 release.

In addition to these established frameworks, there are some emerging frameworks focussed more specifically on modularity. Potomac and Adobe Gravity are two new frameworks inspired by OSGi, the dynamic module system for Java. Both aim to provide the infrastructure for loading bundles (i.e. modules) at runtime and communicating between them through service interfaces. Adobe Gravity remains an Adobe internal project but there are plans for a future open-source release, while Potomac is publicly available and includes some developer tooling in the form of a Flash Builder plug-in.

Cairngorm 3 and Modularization

One of the key messages of the Cairngorm 3 reference architecture (currently in draft) is to separate applications into distinct functional areas that can be developed independently; in other words a modular architecture, where each functional area is a module. The Cairngorm guidelines recommend that communication between functional areas takes place through a thin API that might consist of interfaces, events and data transfer objects. This approach minimizes dependencies between the distinct functional areas of an application. It promotes what Robert Martin terms "good dependencies" in the direction of stability. More details can be found in the Creating Functional Areas draft document.

The Enterprise Solution: Adobe LiveCycle Mosaic ES2

LiveCycle Mosaic ES2 is far more than a modularity framework, but modularity is an important part of its design. It's a client-and-server-side technology for building applications by composition, combining different pieces into personalized views that are focussed on the activities that different users perform. On the server-side, reusable application assets can be stored and shared, while LiveCycle DataServices is available for integrating with different data sources. On the client-side, applications are assembled from different tiles, that can be developed from scratch or adapted from existing Flex and HTML applications. A customizable shell application loads and lays out the tiles, and the framework provides a publish-subscribe messaging API for communication between them. For more details about the Adobe enterprise solution to modularity, refer to the LiveCycle Mosaic ES2 product page.

Conclusion

As we attempt to build bigger and better applications in Flex and AIR, the topic of modularity becomes more important to ensure efficient development, scalability and maintainability. It is vital to be able to separate portions of a large application so they can be developed, tested and deployed independently. The Flex SDK provides some simple means of modularization with Modules and Sub-Applications, and some frameworks build on top of these to provide more features. Furthermore, Adobe has now released an enterprise solution in LiveCycle Mosaic ES2 that provides the infrastructure for rapidly developing and deploying RIAs to the browser and desktop in a modular way.

Posted by tsugden at 10:32 PM | Comments (0)

September 13, 2009

Coming Soon: Cairngorm 3

Cairngorm is about to undergo a transformation that will broaden its scope and increase its value to clients and partners. Instead of centering around a specific implementation of the Model-View-Controller pattern, Cairngorm 3 will consist of a set of best practices, tools and libraries, many of which apply across frameworks. This is the knowledge gathered by the Adobe Technical Services organization and partners over the last five or six years, condensed and presented to help others to deliver successful Flex projects in the enterprise.

For those familiar with the Cairngorm 1 & 2 micro-architecture, the traditional Cairngorm library remains a part of Cairngorm 3. Our best practices for applying the Cairngorm library will be shared, together with information about tried-and-tested extensions. And like before, Cairngorm 3 will recommend a layered architecture that separates concerns and supports test-driven development, but this time the approach has been refined and most parts of it complement multiple frameworks.

So what is Cairngorm now if it isn’t just a framework? Well it’s a foundation for delivering successful Flex projects. It’s the answer to the question, “What are the best practices for Flex in the enterprise?”, to help set new teams off on the right track. It’s the information that can’t always be found in official documentation or framework manuals. It's going to be accessible, informative and open-source. And it’s coming soon...

Posted by tsugden at 8:57 PM | Comments (6)

January 11, 2008

EventfulTestCase: a FlexUnit extension for testing event dispatching

NOTE: The extension described in this post has now been incorporated into FlexUnit 3. The syntax has changed slightly, but the concepts described in this post remain. This feature is not yet available in FlexUnit 4, which is a major update, but work is underway to provide even better support for unit testing the event dispatching behavior of your classes.

Introduction

The events that a class dispatches form an important part of its contract with clients, yet for one reason or another they are seldom tested. Perhaps this is because event declarations are optional in Flex and specified as metadata, or perhaps it is because the FlexUnit assertions were mostly ported from JUnit and not tailored specifically to Flex. In either case, programming mistakes and design flaws in event logic can have far-reaching consequences, effecting any dependent event listeners and the classes beyond them.

To illustrate the importance of event testing, consider the case of a NuclearReactor class that dispatches temperatureChange events to indicate the effect of adding fuel. Perhaps we also have a MeltdownAlert class that listens for these events in order to raise an alert whenever a boundary temperature is crossed. The melodrama should make it obvious: if the NuclearReactor has a bug that prevents it dispatching events in the expected manner, the MeltdownAlert will never trigger and a catastrophe will unfold.

So it is clearly important to ensure event dispatching logic is correct. To promote the best-practice of unit testing the dispatch of events, I have written a small extension to the FlexUnit TestCase class that makes it easy: EventfulTestCase. This is a new base class for any tests that involve the dispatch of events. It supports both standard Flash events and also Cairngorm events.

The following ActionScript source files accompany this post:

Writing Eventful Test Cases

The process of writing an eventful test case involves first recording the expected events, then performing the action under test, and finally asserting that the expected events occurred. EventfulTestCase defines three kinds of functions to help with this:

  1. expect functions - used to record the events that are expected to occur during the test case.
  2. assert functions - used to assert that the expected events actually occurred.
  3. actual event getters - used to access the actual events that were heard so that more specific assertions can be carried out.

Example 1: testing the dispatch of normal events

Shown below is a simple example which asserts that the temperatureChanges event is dispatched when the addPlutonium() function is called.

public function testAddPlutonium() : void
{
   // record the expected event
   expectEvent( reactor, TemperatureChangeEvent.TEMPERATURE_CHANGE );
         
   // perform the action that is being tested
   reactor.addPlutonium( plutonium );
         
   // assert that the expected events occurred
   assertExpectedEventsOccurred( 
      "The temperature change event was not dispatched." );
}

If the expected event is not dispatched, the test case will fail and the developer will be presented with a failure message to assist in debugging. In this case, the message might look like: "The temperature change event was not dispatched. Expected events <temperatureChangedEvent> but heard events <reactorStoppedEvent>". Now the developer knows that the addPlutonium() function contains a logical error which causes the wrong event to be dispatched.

Example 2: testing the dispatch of Cairngorm events

The next example is a little more complex and asserts that two Cairngorm events have occurred. Since Cairngorm events are dispatched through the CairngormEventDispatcher singleton instead of a regular Flex EventDispatcher, the CairngormEventSource adapter class must be used as the event source.

public function testRefreshPlutoniumStocks() : void
{
   // record the expected events
   expectEvents( 
      CairngormEventSource.instance, // adapter for Cairngorm events
      GetLocalPlutoniumStocksEvent.EVENT_NAME,
      GetNationalPlutoniumStocksEvent.EVENT_NAME );
    
   // perform the action that is being tested
   reactor.refreshPlutoniumStocks();
 
   // assert that the expected events occurred
   assertExpectedEventsOccurred(
      "The Cairngorm events to fetch local and national " +
      "plutonium stocks were not dispatched." );
}

Example 3: performing more detailed assertions

The final example builds on the first, demonstrating how to use the actual event getters for performing more detailed assertions.

public function testAddPlutonium() : void
{
   // record the expected event
   expectEvent( reactor, TemperatureChangeEvent.TEMPERATURE_CHANGE );
         
   // perform the action that is being tested
   reactor.addPlutonium( plutonium );
         
   // assert that the expected events occurred
   assertExpectedEventsOccurred( 
      "The temperature change event was not dispatched." );

   // assert on the details of the actual event
   var temperatureChangeEvent : TemperatureChangeEvent = 
      TemperatureChangeEvent( lastActualEvent );
      
   var expectedTemperature : Number = 550;
      
   assertEquals(
      "The expected temperature change did not occur.",
      expectedTemperature,
      temperatureChangeEvent.temperature );
}

Known Limitations

EventfulTestCase only listens for the expected events and cannot hear unexpected events. The consequence of this is limited detail in the test failure messages. Only the expected events that actually occurred can be reported. The reason for this limitation is that the Flex framework does not enable us to listen to unspecified event types. In other words, we need to register listeners explicitly for each type of event that we want to listen to. One work-around would be to override the dispatchEvent() function of the EventListener framework class, but that would be overly intrusive. This limitation is not severe since the failure messages that can be provided are still reasonably useful.

It should also be noted that EventfulTestCase relies on the fact that most event dispatching takes place synchronously in Flex. When a function dispatches an event, we can be sure that any registered listeners will hear that event synchronously before the function continues and returns. In Flex applications, asynchronicity is typically confined to the I/O operations performed by the Flash Player, and these sit outside the normal realm of unit testing. It is usually possible to mock genuinely asynchronous behaviour, so that the class in question can be tested synchronously. When this is not the case, or for integration testing purposes, a more sophisticated solution is required.

Conclusion

The bugs and design flaws associated with event dispatching often slip the net when unit testing, allowing them to lurk in the deep and strike later. The EventfulTestCase extension helps to prevent this by making it quick and easy to test event dispatching. The process involves three stages: recording expectations, performing actions and asserting that the events occurred. As we attempt to build bigger and better Flex applications, we must test more thoroughly to ensure our success, and this must include testing events.

Posted by tsugden at 10:28 PM | Comments (7)