Method Names for Data Retrieval

Ben Nadel recently posted a blog entry about moving queries to service layers (something I am a big fan of). Both the blog entry and the comments that followed were great and well worth the read. I especially liked Hal Helm's comment about differentiating between queries that are necessarily the same and those that are accidentally the same.

One thing that came up in this discussion was how to name the methods that retrieve data. One example was "getArticlesByAuthorID()" (I'm just picking one of many that followed this pattern). To me, this is a code smell. The method name describes not only what you want, but how you are going to get it.

I would do it differently.

If I am writing a page and I need to get articles for a certain author and I don't already have any methods written to get this kind of information, I would create a method name "getArticles" because "Articles" are what I want to get. Then I would have "AuthorID" as a required argument.

So, the code for my method would start like this (including only relevant attributes):

<cffunction name="getArticles" access="public">
   <cfargument name="AuthorID" required="true">
   
   ...
   
</cffunction>

Now my method name describes what I want, not how I get it. It is obvious from the required argument, however, how I am going to get the articles.

Then I would write whatever code needed to get articles based on the AuthorID.

This would solve the immediate problem, but it would start a nice API to build on in the future.

Now, if I later discover that I want to get the same basic information except that I want to get it by CategoryID, I can do the following:

<cffunction name="getArticles" access="public">
   <cfargument name="AuthorID" required="false">
   <cfargument name="CategoryID" required="false">
   
   <cfif NOT ( StructKeyExists(arguments,"AuthorID") OR StructKeyExists(arguments,"CategoryID") )>
      <cfthrow message="getArticles requires either AuthorID or CategoryID">
   </cfif>
   
   ...
   
</cffunction>

For me the code inside the method might be as simple as passing the arguments to DataMgr.getRecords(), but it also might be a SQL query with some conditionals in the WHERE clause. I might even discover the need to make a private getArticlesByAuthorID method and a private getArticlesByCategoryID method.

The point is, however, that the code needed to retrieve the data shouldn't impact the API. The API should describe what you want, and not be impacted by what steps it will take to get it.

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
I agree with you. Sean C. made a comment on Ben's post to the effect of having the arguments reflect the intent of your method call. So getArticles(authorid="5") or getArticles(active=true), etc. I like that approach, but there seemed to be people who wanted more "expressive" method names. So I suggested writing facade methods where getArticlesByID() calls getArticles(id=). I personally don't do that, but it was just a suggestion I put out if more descriptive names were desired.
# Posted By Tony Garcia | 6/19/09 3:21 PM
Tony,

Thanks for the words of support. I am actually not certain if anyone was positively suggesting that source of action (I read through the comments rather quickly), but it spurred my thought to share how I would handle the situation.
# Posted By Steve Bryant | 6/19/09 8:44 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.8.001.