Defending the Gateway pattern in ColdFusion
Posted by Joe Rinehart at 8:44 AM
18 comments - Categories:
OOP
In a few recent posts, there's been discussion of the validity and purpose of what's called the "Gateway" pattern in a ColdFusion application's object model. To summarize the critique, it focuses on whether or not it's a good idea to use a pattern that often lets the details of a relational database model (in the form of a ColdFusion query) float up into your application tier.
That's a tough argument to counter because it sidesteps the nature of design patterns.
Instead of focusing on an implementation detail, let's look at the design forces, implementation, and consequences of using the Gateway pattern.
Design Forces
The design forces behind the Gateway pattern are a situation where your domain model needs to speak to an external resource without understanding its format or connection details.
Note that it has nothing to do with a relational model. It just so happens that many ColdFusion applications are data-driven, so we're often connecting to a resource (a relational database) that's external to our object model. Our object model has a need to connect to this resource without understanding its connection or implementation details.
Is it right that the messaging format between our object model and the Gateway implementation is a ColdFusion query? IMHO, sure. More often than not, a ColdFusion query is a fantastic way to show a set of data - a point that's validated when you notice how many other parts of the language (LDAP, email, cfhttp) use it to represent sets. If all you need to do is deal with a set, why force yourself to deal with the complication and overhead of "iterating business objects" and what not when it's not at all necessary?
Implementation
All the Gateway's reference implementation states is that a single Gateway class will know how to speak to an external resource, and that all other objects / applications will use this gateway instead of maintaining knowledge of the external resources implementation.
An example I've got sitting here on my MBP is an application that can use either a MySQL DB, MS SQL DB, or LDAP server to perform authentication. I declare a gateway interface that contains a single method: authenticate(user:User). Each implementation then knows how to perform authentication against either appropriate database tables or the LDAP server. Switching is a matter of updating a ColdSpring configuration file.
In one of the posts criticizing Gateway, it was suggested that higher order objects be used to represent its functionality, such as a Report object that may power an aggregate report or a list of object instances.
I think that's a higher level of architecture than is often necessary for a simple CRUD app, but if it is necessary, I feel the Gateway is both appropriate and an improvement - it should be used in conjunction with the report to abstract the reports data access from its own capabilities. For example, a QuarterlySalesReport's constructor could take an instance of ISalesGateway, an interface defining methods like getQuarterlySalesData(), regardless of whether it comes from a local database or an external provider like SalesForce.com.
Consequences
When Gateway is implemented, your domain model receives one-stop shopping for communication with an external resource (something that lives _outside_ happy object land).
Conclusion
95% of the time, in 95% of ColdFusion applications, that external resource is going to be a relational database. Whether or not that's appropriate for your application is your call - is the tradeoff of dealing with relationally-based sets (ColdFusion queries) one you're willing to make?
Whether or not it's a valid pattern to use is a moot argument - the implementation of the Gateway pattern, even when just to do a bunch of SELECT statements, satisfies its design forces and is therefore valid.
Personally, I love using the Gateway pattern and its distinction from DAO. It's simple, it's efficient, and it's rarely come back to haunt me. I see a few people in the ColdFusion spending a lot of time trying to get rid of queries to be more "pure OO," and I think a lot of this time could be better spent.
Brian LeGros wrote on 07/19/07 10:59 AM
Great post Joe. I didn't realize my little blog was part of any major discussion about the Gateway pattern, but thanks for including me.I definitely see a benefit to how the ColdFusion community has been using the Gateway pattern. I really appreciate you walking through an analysis of the pattern, I think it helps to shed light on the its use and purpose rather than it's implementation. In my blog post I was thinking more in the context of what I do at work, where refactoring systems (even our CF apps) has the potential to be a large initiative. Design by contract and OO practices are heavily employed which has a strong basis in forming dependencies between "boundary" classes using objects rather than data types like primitive values, structs, arrays, or queries. I think this practice is more geared for systems which have to live for possibly a few decades and scale relatively over time.
I think if a shop is going to take a more formal approach to software design for an application which has to fill a more enterprise need, then what I'm advocating is appropriate. That being said, if you are building applications which are being created with little maintenance in mind, you're probably right. Refactoring won't be that much of an issue anyway, so why put the extra work in abstracting out your domain if you can just as easily, and infrequently, refactor the calling class.
Good post man.