Alchemy

Alchemy offers a new design pattern which works very differently to Dependency Injection, although it may have similarities, and could still be classed as Inversion of Control.

I call this pattern "Factory Injection" or "Composition Injection". Of course, it's entirely possible that I'm not the first person to come up with this pattern, and if anyone has come across anything similar let me know :)

Currently Alchemy is only available as an Orchard module, although I plan to package it as a separate library and implement support for using it within MEF.

Overview of Factory Injection

The core idea is that any given operation can be described as a "Process". A Process is defined as:
  1. A set of inputs ("Context") which can be any number of objects or named parameters
  2. A set of operations on those inputs ("Factories")
  3. A set of outputs ("Results") that are produced by those factories, and can be any number of objects

So far so good. When we run a Process in Alchemy there are three phases:
  1. Describe. At this point all ICompositionProviders are called and asked to describe their operations.
  2. Build. Here each described operation is provided context, and can execute builders which will modify the context.
  3. Execute. Finally a set of outputs are produced from the context, by executing factory methods provided by builders.

A description will typically take the following form, in English pseudo-code:

"Given scope the output can be produced via method"

So, scope is how we modify the process based on input parameters, and within method we can read other outputs from the context to produce our own output.

How does all this benefit us?

The key design idea behind Alchemy is to break a process down into as small units as possible. Any of these units can then be swapped out or modified by another module.

A quick example: Orchard has a Search controller. It has one way you can modify the output - you can use Placement and/or template overrides to modify the shapes produced. However they are always rendered using "Summary" DisplayType so changing the search results will change anywhere else that uses "Summary"; and that includes Blog Post summaries, Taxonomies, and various other things. If you want to modify the Display Type then you'd have to implement your own controller which would be an identical copy of the Search controller, just to change that one string. You'll also need to override the Search controller and routes to enable your own. Finally you'll need to override the Search widget and anywhere else that might reference the Search route, to use your own version.

On the other hand, if Search was built using an Alchemy process, then you could simply inject a new factory or mutator for "ShapeMetadata" which controls the DisplayType when Alchemy is building shapes. You'd know it was a search display being built, because this information is available in the input context, so you won't affect any displays anywhere else.

Actually, I'm already building a new search module that uses Alchemy. This is the "Lens" module and will replace search in both front-end and back-end, as well as providing a pop-up content finder for relationship picking. It needs to behave slightly differently in each place it appears, and this is controlled through a simple string parameter, and appropriate parts of the pipeline are swapped out to produce those small variations in display in behaviour.

Alchemy and Lens are available in the latest source code from the repository here, under the "alchemy" branch; these are alpha versions that are not remotely working properly yet!

Last edited Jan 12, 2012 at 5:03 PM by randompete, version 2

Comments

No comments yet.