June 25, 2007
I want to discuss a concept that I have been using for a while but have not been able to find it discussed on books or blogs I've read. I am talking about a formal layer of the application architecture that, for lack of any better name, I call "Application Services" layer.
Usually applications require some supporting functionality needed to perform their job but which is not part of the application's "business logic" per se. For example, you may be using something like Mailer.cfc to handle all outgoing mail from your application. Now, this component encapsulates some logic but it has nothing to do with the purpose of your application (well, assuming your application is not an email utility of some sort), and usually when you use this kind of tools you only require to have a single instance laying around maybe on the Application scope, or an instance that is passed around from object to object. This type of functionality is what I call an Application Service, and the collection of many of these services provide a layer of supporting functionality to the application. This layer of support is what can be called an Application Services Layer (do not confuse with Service Layer, which is something completely different)
Furthermore, these application services provide additional functionality to the application which may also be required by other layers; thus making it hard to fit this concept within any of the other layers of the application and reinforcing the idea of treating this collection of services as an application layer or tier on their own.
To better illustrate this, let's say we have a "bugTracking" component which should be called when exceptions are thrown so that errors are handled on a standard way. This service may do things like sending an email report to someone or writing to some specific log. Obviously calling this "service" would be very useful whenever an error occurs regardless of where it happens. Since the last thing we want is to be duplicating code, then we would end up needing to use this same service regardless if the error occurred while rendering a view on the presentation layer or applying a business rule on the domain model. Therefore the utility of an application service cuts across the traditional separation across application layer boundaries.
If we gather all these services that our application may need at some point and store instances of them on the Application scope, we can provide a support layer for our application that can be accessed from anywhere on our code; and since this is a layer of shared resources we are not really violating any rules of layer separation because these services are neither used (nor shall be) for outputting content to the browser or performing business logic.
Now, I imagine someone could argue that instead of having everyone invoking the Application scope to get to these services, they could be injected into the CFCs that require them via some form of dependency injection. However, in doing so we would be required to modify the interface of our components by adding a setter or an additional constructor argument for this specific service. The problem with this is that we would be forcing the object interface to be aware of this dependency which is not really related to the purpose of the object, complicating thus any future refactoring when the service may no longer be needed. At most to maintain a proper separation, we could have some sort of registry to handle the access to these services, but that can be discussed on a different post.
At the end, even if I am not using the correct name, I think it should be recognized the benefit of having an "Application Services Layer" to provide the supporting features needed for an application.