For years, I've carried around an irrational guilt over returning Query objects from the data-access layer (DAL) of my ColdFusion applications. The basis of this guilt stems from the fact that I've long-thought of the DAL as a "black box" that simply persists data in an abstract fashion. And, by returning a query object, I've always feared that I was letting my data persistence implementation details - the very fact that I'm even using a relational database - leak out into my service layer.
This guilt is stupid. It serves no purpose other than to make me feel bad about myself and my architectural choices. It needs to end. And so, this post is an attempt to exorcise the demons of self-doubt through the practice of writing and introspection.
I Lean Heavily on the Database in My ColdFusion Application Design
Not only do I have a relational database powering my ColdFusion applications, I heavily rely on the features of that database to make sure that the application runs smoothly and correctly. I always start my application development by designing my database schema first. Then, I add secondary indexes for uniqueness constraints which helps drive idempotent workflows. Then, I add even more secondary indexes for view-rendering performance.
In other words, the database choice and design isn't an "after thought" - a decision that I can defer for as long as possible; it's a critical decision and a necessary ingredient to the success of the application.
Queries Are Just Data Structures
Queries are just data structures. Yes, they have some interesting behaviors baked in. But, they are nothing more than a core data structure of the CFML specification.
Just like a Struct.
Just like an Array.
Just like a Boolean.
Just like a String.
Just like a Number.
Just like a Date.
To have guilt over returning a Query is to have guilt over returning data. I certainly don't feel bad when I return a Boolean or a Number from the data access layer. As such, to have guilt over returning a Query is to be inconsistent with my existing belief system.
Query Objects Don't Make Testing Harder
While I don't do automated testing, part of my guilt has always been based on a belief that a Query object would somehow make testing harder. Which, in turn, made me believe that my choice of returning queries was incorrect.
But, this assumption is invalid. As mentioned above, the Query object is just a data structure. And, as such, Query objects can be manually constructed for the purposes of testing. Again, there's no fundamental difference between a Struct and a Query. So, if I needed to create a Mock Data Access Layer that used in-memory persistence, I could do so and continue to return Query objects.
In fact, I could use Query objects as the in-memory data persistence representation in my mock data access layer. Then, I'm just a map, filter, and reduce away from implementing all of my data access methods.
The Service Layer is Still a "Black Box" to the Rest of the ColdFusion Application
As I mentioned above, part of my guilt has always come from the belief that by returning a query from my data access layer, my "implementation details" about the database were leaking up into my service layer. But, even if this might be true in a local sense, the service layer itself is still a black box to the rest of the ColdFusion application. Meaning, while my service layer may consume queries internally, no query every leaks up and out of the service layer.
NOTE: This is not entirely true. While I do my best to avoid having database transactions in my Workflow layer (the application layer above my service layer), sometimes I include a multi-service transaction to make sure a "unit of work" gets created atomically.
Having a data access layer that returns queries is really just a choice that my service layer is making about its own implementation details. And, I'm OK with that.
The ColdFusion Query Object is Wonderful - And I'm OK With That
The Query object is a big part of what makes the ColdFusion language such a joy to work with! It's powerful and flexible; and, it's a safe data structure that provides elegant developer ergonomics. By working with Query objects I choose all of these things. And, I'm going to stop feeling guilty about my choices! Any guilt that I have is irrational and ill conceived.