The contents of this document are a work in progress

Introduction

You may have walked through the Five Minute Tutorial and wondered why all the component scaffolding was needed, when a simple new CheeseImplementation() would be sufficient. There is a number of reasons why this is helpful for any application design.

Here are some of the reasons to use component-oriented programming:

  1. Separation of Concerns
  2. Easier to apply common design patterns
  3. Components are easier to construct and configure
  4. Components are easier to manage
  5. Components are implicitly easier to unit test
  6. Components facilitate advanced application architectures without modifying code

All of these aspects contribute to encouraging better application design. Let's examine each of these in more detail now.

Separation of Concerns

Separation of concerns is a very simple concept that is self explanatory from its name. It is a design pattern that encourages each individual part of a system to have a clear concern (which may also be referred to as a role or function). The boundaries between these parts should also be clear and well defined.

Using components will help you in applying separation of concerns to your design. The relationships between components are represented externally, and can be changed without changing the components themselves, so it becomes more natural to deliniate the component design by separate concerns.

Easier to apply common design patterns

While separation of concerns is the most significant design pattern to appear in a component-oriented design, the use of container functionality can facilitate other design patterns in a simple, consistent manner.

For example, the chain of command pattern is very useful in defining a series of actions, and can be achieved by declaring a requirement on a list of component instances.

Components are easier to construct and configure

As your application design gets more complicated that the one represented in the tutorial, there will be a number of fields in the components that will need to be populated. Features in containers such as Plexus aid in the construction of your objects, making it faster to develop than before, with less code.

So, a component may declare its default configuration, but include an expression that is able to obtain information from the system using it to populate it at runtime, without needing to know anything about the target application at design time. The target application may override the configuration entirely based on its own needs, or even based on other runtime environment factors.

In Plexus, configuration and construction is not limited to setting values on primitive fields either. Complex objects can be configured from XML fragments, as is discussed in the Component Configuration Tutorial. Components can also have other components configured and injected based on declared requirements making construction very simple. These requirements can of course be altered by target applications that may wish to substitute different implementations.

Components are easier to manage

Not only are components easier to construct, but in a good component container such as Plexus they will also be easier to manage through their life within the application.

In Java, you only have control over construction (calling the constructor) and calling methods on the object (or modifying fields). Other behaviour such as finalization is not called predictably and can not be used to perform object clean up, for example.

In containers that support component lifecycles, such as Plexus, the component author has control over all aspects of a component's lifecycle. For example, the component can be consulted when the component has been initialized, started, stopped, or destroyed to name a few. In Plexus, not only can the components participate in the lifecycle, but a component's lifecycle can be completely customised.

The ability to participate in the component lifecycle can enable the component author to perform necessary set up and clean up, and also to easily apply some design patterns to a component without having to recode the component state handling.

Component lifecycles in Plexus are discussed in the Components Tutorial.

Components are implicitly easier to unit test

The above traits lead to making components easier to unit test. When testing code, it is usualy expected that it is tested in isolation, so that the tests are not influenced by external factors and so that the tests are simpler and easier to write. Through separation of concerns, this becomes a reality.

In addition, since component construction and configuration can be altered, it is easy to replace default implementations of other components with simple mocks or stubs that guarantee that you are testing a single component at a time.

Tests generally require quite a lot of object configuration, much of which is duplicated for all but one or two values. Using a component container can dramatically ease this through having pre-set configurations that are modified on a per-test basis.

Finally, since component tests can be run inside the container, the lifecycle of the component can be executed as it would in the real system, without needing to construct the calling objects. This again makes it easier to test a component in isolation.

While components can usually be tested by conventional means, Plexus comes with a testing harness that simplifies the process of performing the regular component construction and lifecycle, running them in-container. This is discussed in the Component Testing section of the developer guide.

Components facilitate advanced application architectures without modifying code

Clear separation of components, along with well-defined interfaces, allow replacing components with other implementations. This can facilitate advanced application architectures without code modifications.

An example of this can be seen in Apache Geronimo's GBuild, which is built on Apache Continuum, a Plexus application. By replacing some components with identical functionality that works with ActiveMQ, a distributed countinuous integration server was built.

Additionally, the container can provide features that can be applied to all components consistently without code modifications. For example, Plexus can resolve components transparently at runtime from a Maven repository.

What are Components?

Szyperski lists several characteristics of components: composition, units of deployment and resuability.

Other projects have also offered what a component may be:

Some descriptions of a component are:

  • A nontrivial, nearly independent, and replaceable part of a system that fulfils a clear function in the context of a well-defined architecture. A component conforms to and provides the physical realization of a set of interfaces. (Philippe Krutchen, Rational Software)
  • A runtime software component is a dynamically bindable package of one or more programs managed as a unit and accessed through documented interfaces that can be discovered at runtime. (Gartner Group)
  • A software component is a unit of composition with contractually specified interfaces and explicit context dependencies only. A software component can be deployed independently and is subject to third-party composition. (Clemens Szyperski, "Component Software")
  • A self-contained piece of software that can be independently deployed and plugged into an environment that provides a compatible socket. It has well-defined run-time interfaces, and it can cooperate out of the box with other components (Peter Herzum, Olivier Sims, "Business Component Factory")

Criteria for Components

Meyer: "Seven Criteria for Components"

  • May be used by other software elements (clients).
  • May be used by clients without the intervention of the component's developers.
  • Includes a specification of all dependencies (hardware and software platform, versions, other components).
  • Includes a precise specification of the functionalities it offers.
  • Is usable on the sole basis of that specification.
  • Is composable with other components.
  • Can be integrated into a system quickly and smoothly.