SourceForge.net Logo

Home
StructureMap on SourceForge
Basic Architecture
Concepts
API Documentation
FAQ
Configuration Schema
    Memento Sources
    Node Normalized Xml
    Attribute Normalized Xml
    Attribute Usage
    Instance Lifecyle Scoping
Configuration Management
    StructureMapDoctor
    StructureMapExplorer
    deployment Task
    verification Task
    ValidationMethod Attribute
    Other NAnt Tasks
Troubleshooting
Singleton Injection

High Level Concepts

Object Oriented Design

Object oriented systems are composed of a myriad array of objects communicating by sending messages to exposed interfaces. To a large degree, the qualities of an OO design are determined by the structure, organization, and responsibility assignments of the objects in a system.  The qualities of a system most affected by structure are flexibility, extensibility, maintainability, and testability.  Applications usually meet their demise when the system is determined to be too difficult or costly to change. The symptoms of a dying application are a loss of clearly defined structure, an unclear division of responsibilities in the code, and difficulty testing and troubleshooting the application.  

Over the years a series of rules and principles have been discovered and developed to describe well-structured systems.  Possibly most important is Separation of Concerns – pulling separate aspects of the system like persistence, security, or business logic into separate classes and packages.  Another key concept is the combination of highly cohesive classes in a loosely coupled structure. The more highly coupled two components of a system are, the more difficult the system is to maintain, test, and reuse. A class should have a cohesive set of responsibilities in a narrow domain.  In other words, simpleton classes that do only one thing are much easier to code and test than God classes that take on far too many unrelated responsibilities. 

By itself, StructureMap does not improve an application.  StructureMap simply makes using good design techniques for structuring an application easier.

Impact of Test Driven Development and Emergent Design

The advent of Test Driven Development (TDD) techniques and emergent design methodologies like Extreme Programming has refined the way that we build OO systems.  Taking an evolutionary approach to OO design and structure is best accomplished through supple code.  The desire to express design through automated unit tests requires and enforces a very fine grained approach to class design.  Both practices are maximized by loose coupling between classes.

Another wrinkle is the desire to test classes either in isolation or in small clusters of classes. Because each class is small, it depends on many of its neighboring classes to provide services in order to accomplish anything.  In order to truly test a class in isolation, TDD practitioners use Service Stub objects or Mock Objects as stand-ins for the external dependencies of the class being tested. Utilizing these testing techniques requires a mechanism to substitute the dependencies at runtime. The responsibility for discovering and attaching dependencies can be removed from a class to maximize testing automation opportunities. Much of the goal of StructureMap or any IoC container is to provide an easy mechanism to attach and assemble dependency chains.

 

Building Blocks of Object Oriented Programming

At the coding level, the building blocks of an object oriented design are encapsulation, polymorphism, and inheritance. Encapsulation is important for the sake of loose coupling.  As an example from classic 3-tier systems, a user interface object calls a business logic object that will in turn call database access objects to persist new data. The UI code should not need to be bound to any kind of database engine or really know anything about how the business objects process the requests.  Using encapsulation, the UI code does not have to be so tightly coupled to the internal mechanisms of the business logic code. On the other hand, we want the dependencies of the business logic objects to be externally attached to enable reuse and testing, so how does the UI code create and utilize the business logic without breaking encapsulation? One answer is separate constructor functions on the business logic classes, one for testing and one for production. Another alternative is to use an IoC container like StructureMap to instantiate and assemble the business logic objects.  The UI code only needs to ask StructureMap for an instance of the business logic type.

Polymorphism is the ability for multiple objects to be interchangeable by exposing the same interface.  Polymorphism is the single most important abstraction technique in object oriented design.  By making a class dependent on a public interface, the class should be able to work with multiple implementations of the interface.  The extensibility of a system is greatly improved with the ability to plugin a new implementation class into an existing interface slot. Mock objects and service stubs use polymorphic interfaces to allow the real functionality to be replaced with hard-coded testing implementations for automated testing in isolation. Polymorphism is an abstraction however. At some point the proper implementation of an interface needs to be created and attached to the necessary calling classes.  A common technique in TDD is to use an interface as a point of abstraction to enable mock objects in order to isolate a class for testing.  StructureMap can be used as a generic mechanism to utilize polymorphic instances as an alternative to hard-coded factory and builder classes.

 

Inversion of Control (IoC) Containers

Inversion of Control containers like StructureMap, PicoContainer, and Spring are an attempt to improve OO designs by minimizing the effort necessary to utilize existing OO techniques. The Inversion of Control moniker refers to the indirection of object instantiation and linkage. Objects do not directly create and call other objects, StructureMap "injects" dependencies into an object instance through the object's constructor or public properties.

StructureMap is not really a "Container" of anything except the knowledge of which classes to create for a requested interface.  The term "Container" originates from the J2EE world when the early IoC frameworks were considered to be simple, lightweight replacements for heavier J2EE application servers.  StructureMap does not track created instances or manage instance lifecycle like most of the Java IoC Containers.

 

Dependency Injection / Inversion of Control (IoC)

In a well-factored OO design, a class may have dependencies on other classes to perform useful tasks. These dependencies can be attached in roughly two ways, the class can create its own dependencies, or the dependencies can be “injected” into the class instance.  Removing the responsibility for creating dependencies from a class is called Dependency Injection, or Inversion of Control.

Dependency Injection has a couple of variants.  The dependencies can be attached by either setting properties or using a constructor function to setup all dependencies at instantiation. StructureMap primarily uses the Constructor Injection variant of IoC. The advantage of this method is a guarantee that the proper dependencies are setup before any execution can take place on the new class instance. The constructor function can become a contract stating the dependencies of one class on the services provided by other classes.  Another advantage is a streamlining of a classes public interface by negating the need for public setter properties. 

New in version 0.90 is the ability to use Setter Injection as well.  This is particularly important when using StructureMap to configure and create class objects that are external to your application code.

 

Plugin Pattern (Fowler)

This pattern refers to a mechanism of creating an object instance of a certain interface at runtime.  The actual configuration and implementation of the instance is usually controlled by external configuration.  Using a Plugin pattern allows a new class to be “plugged” into an existing codebase without modifications to the existing code.  StructureMap can be used as a generic Plugin mechanism.  This pattern is very common in application frameworks.

 

Memento Pattern (GoF)

A Memento pattern is an object that models the internal state of another object instance.  The purpose of a Memento is to externalize the configuration of an object instance so the object can be recreated with the same state at a later time. Another way to think of a Memento is as a dehydrated object.  Just add just runtime water, and presto, an object instance of the same configuration.  The intrinsic Xml and binary serialization capabilities of .NET are examples of the Memento pattern in .NET.  StructureMap uses the Memento pattern to store configuration information.

 

Open/Closed Principle (OCP)

A module should be open for extension but closed for modification

Software systems are never completed, only abandoned when the ability to change or extend a system is compromised by poor structure or amount of rework necessary to implement the new changes.  In situations where system requirements will be changing, the Open/Closed Principle can be utilized in conjunction with a Plugin pattern to extend an existing codebase by adding a new module with minimal or no changes to existing code.  

OCP is frequently employed in user interface frameworks.  Using OCP, new screens and menu commands could be added to the user interface by configuring the application to use the new classes without changing existing code.  Another common example would be adding security rules or business rules to frequently changing application.

 

Dependency Inversion Principle (DIP)

Depend upon Abstractions.  Do not depend upon concretions

Simply put, the Dependency Inversion Principle is about creating a firebreak around volatile or simply difficult to test modules.  Using DIP removes a direct coupling between two classes, enabling the usage of mock objects, service stubs, and different implementations of the dependency.  In a TDD process, DIP is often used for no other purpose than to facilitate automated unit testing.  A common example from the .NET Framework is the IDb* interfaces in ADO.NET.  Building a system around the abstract interfaces instead of Oracle or Sql Server classes avoids a tight coupling to a specific database.engine.

 

Service Stub

Removes dependence upon problematic services during testing.

A Service Stub replaces an external dependency with a static stand-in object.  Service Stub's are typically used to hard code return values.  A classic example would be a data access class that returns a DataSet.  A Service Stub for this object might return a DataSet read from a static file instead of pulling the information from a database.  During testing, the data returned by the data access interface would always be known, so that the processed outcome of the data from other classes should also be static -- facilitating automated testing.

 

Mock Object

A debug replacement for a real-world object

A mock object is particularly useful for dependencies on external systems that are difficult to test.  Mock objects enable the runtime replacement of a real object that might be slow, difficult to setup, or non-deterministic with a well behaved “Mocked” object that behaves in a known way.  The goal of mocking is to test one class independently, even though it cannot function without interacting with the class's dependencies. 

StructureMap was largely developed during a WinForms "Smart Client" project.  The user interface used a Model-View-Controller design for all screens.  Each controller class interacted with a view, and other classes like web service proxies and object caches.  In unit testing for a typical controller class, both the view and web service proxies would be mock objects to test the controller interfaction with its dependencies.

Mock objects are active participants in the testing process.  StructureMap directly supports using the NMock framework for dynamically mocking classes.  StructureMap can also inject static mocks or stubs at runtime.