Monday, July 14, 2014

Onion architecture and MEF

Correctly applying Onion architecture results in stable application concerns being protected from volatile application concerns.

Volatile concerns / responsibilities are coupled with specific frameworks, platforms or tools. For example, persistence is volatile because over time the platform used may change (e.g. Oracle to SQL Server). Another example is UI.

Stable concerns / responsibilities of an application remain the same over time, regardless of the latest technology trends. In other words, business / application functionality is not driven by how a particular platform or framework is used, the requirements for what business functions the application should implement don't change (i.e. stable). In Onion architecture, this would be defined as the Application Core. This is very similar to a fundamental goal of SOA - protecting client applications from volatile provider applications by using stable abstract business services. 

A principle of Onion architecture is the inner layers cannot have dependencies on outer layers (i.e. dependencies are inward only). As you move further into the center, the concerns become more stable - where the domain is the center and most stable part of the application. This implies that dependency inversion is key to ensure this principle is not broken.

MEF can resolve these dependencies (e.g. act as an IOC container) dynamically. In other words, MEF can discover concrete dependencies at runtime. This has the huge advantage of allowing the Application Core (stable concerns) not needing explicit registration of available components. The Application Core can be completely clean of any knowledge of components that implement volatile responsibilities. This results in the volatile responsibilities being pluggable. The below diagram illustrates this concept, where the library responsible for implementing the volatile responsibility (in this example it is persistence) references the Application Core library. It is referencing the Application Core library because it needs to be able to implement IOrderRepository.

Application Core has an abstract dependency on an order repository - IOrderRepository - and needs somehow to resolve a concrete implementation of this interface (i.e. resolve the concrete implementation defined in the SqlPersistence library). With the appropriate usage of MEF (Export, Import attributes etc), this can easily be achieved. It's important to point out again, that nothing is referencing the volatile library. You could easily swap in another library which is implementing IOrderRepository, and the Application Core would require no changes - i.e. pluggable.