Interfaces in ColdFusion – I think I have finally come around on CFINTERFACE

I will admit it…

When all the pre-ColdFusion 8 debate was swirling about whether or not to add interfaces into CFML, I didn’t really get it.  It’s true.  The only OOP I had ever really done was in CFML, never having experienced how interfaces really come into play, and I think I fell into the the easy path of considering it worthless because I didn’t take the time to understand it.  So very quietly, I was in the “we don’t need it!” camp.

Much has changed for me as a developer since that time.  I have gotten quite comfortable in Flex development, and working with Flex made me realize that Java is not really all that difficult to grasp for me now, and I am pretty comfortable getting around there too.  I have begun playing a bit with Groovy as well, so I have been exposed to much more since there actually *was* a debate about interfaces.

So now that debate has long since died, and the pro-interface crowd won  – and then immediately decided that they didn’t actually need interfaces after all – I realized yesterday that I finally get it!

Before I go any further, I would like to give my definition of an interface, because I am sure there are still plenty of CF developers who are where I was just a short time ago with just a very loose grasp, if any, on the concept.  In fact, I am not sure that I am much beyond a loose grasp, but I will do my best to explain.  For those who already know all this, just bear with me here.

In talking about interfaces with another developer on my team yesterday he asked how they are used.  Half joking, I replied “They aren’t!  They don’t *do* anything at all”.  What I meant by this is that you don’t ever actually call an interface and your application never actually asks an interface to do anything.  The interface exists simply to enfore rules in your data model.  In essence it is a zero-tolerance “Object Gestapo” that makes sure that no one ever gets out of line.  An interface is truly little more than a contract that says “Any object that implements me must contain the things I define”.  In essence, I suppose you could think of it as a shell CFC that defines methods, arguments, and return types, that you can’t actually call.  If I then define a CFC that implements that interface, it better damn well adhere to it strictly or the object gestapo comes down on you hard!

So why this extra work, right?  CF is a loosely typed language. Its status as an OOP language has been debated.  However, the fact of the matter is that most of the top slice of CFML developers are writing some really amazing object oriented applications.  Due to this, some of the more strict products from languages like Java might actually have some place in our work.

Let me give a real world solution that might help solidify my swirling thoughts on the matter.  to give background on the environment I am working in, I recently began working for a relatively large insurance provider.   Counting another 17 developers that are just being moved into ColdFusion from other languages, we have one of the larger ColdFusion development groups that I am aware of in my area.  Many of the developers work remotely, and we have several that are in other states.  Due to this, communication must be clear to keep everyone on the same page.

A current project that is in the works is to move our entire policy system off of one third-party vendor to another. The APIs between the two are vastly different, however, we still need the same data available to us in our applications.  To make things more complicated, we will be moving one state at a time.  So effectively there will be two distinctly different policy systems in play until the last state is converted.

My architectural approach to solving that problem is to use a PolicySystemFactory that returns the appropriate PolicySystem to me based on specific business rules.  Any PolicySystem will actually serve as an adapter to the specific API of its third-party system, but the methods that the PolicySystem object exposes to the application  *must* be consistent.  The application shouldn’t really care which system it is talking to as long as the system is giving it the right data and taking the right action on data that is delivered.

How do we ensure that we have the exact same API for not only the two current policy systems, but any future policy systems that we don’t even know about yet?

Well, we could just make sure all developers know about it, and write it in some document hundreds of pages long that no one ever reads.  Then after both of those things fail, the developers will eventually figure it out as the application pukes in different areas as it is getting data in different shapes than it is expecting, or as it tries to use methods differently than the PolicySystem is expecting.  Eventually they will work this out.

Or… You could do both of the above items (communicate & document) and save everyone a lot of trouble by establishing that any PolicySystem *must* adhere to rules established in an interface.  By taking this approach, there is no question whatsoever that the PolicySystem will not break your application by working differently than expected.

How do you implement this approach? (really.. I didn’t mean it as a pun)

First, we would want to figure out exactly how a PolicySystem should be shaped.  In our ultra-simplified example, a PolicySystem must have three methods: getPolicy(id) returning a Policy object, getPolicyAgent(Policy) returning and Agent object, and getPoliciesByStatus(StatusId) returning a structure of Policy objects

This is what our Interface would look like:

PolicySystemInterface.cfc

<cfinterface>

<cffunction name="getPolicy" access="public" output="false" returntype="Policy">
	<cfargument name="id" type="numeric" required="true" />
</cffunction>

<cffunction name="getPolicyAgent" access="public" output="false" returntype="Agent">
	<cfargument name="Policy" type="Policy" required="true" />
</cffunction>

<cffunction name="getPoliciesByStatus" access="public" output="false" returntype="Policy{}">
	<cfargument name="StatusId" type="numeric" required="true" />
</cffunction>

</cfinterface>

As you can see above, we use the <cfinterface /> tag to define this CFC as an interface.  We then write our functions much like we would in a <cfcomponent /> keeping in mind that whatever we define must be used *exactly* the same way by any object that implements it.  So what would one of those objects look like?  Here is our old legacy policy system object.  Take a look at what is going on in line #1 in the <cfcomponent /> tag.

OldLegacyPolicySystem.cfc

<cfcomponent name="OldLegacyPolicySystem" output="false" extends="AbstractPolicySystem" implements="PolicySystemInterface">

<cffunction name="init" access="public" output="false" returntype="AbstractPolicySystem">
	<cfreturn super.init("OldLegacyPolicySystem") />
</cffunction>

<cffunction name="getPolicy" access="public" output="false" returntype="Policy">
	<cfargument name="id" type="numeric" required="true" />
	<!--- NOTE - In real life, we would use a service to create this bean, not instantiate it here!!! --->
	<cfset var Policy = CreateObject("component","Policy").init() />

	<!---
	########################################
	In this area we would access policy info using the OldLegacyPolicySystem (however it does it!) and populate the Policy bean
	########################################
	--->

	<cfreturn Policy/>
</cffunction>

<cffunction name="getPolicyAgent" access="public" output="false" returntype="Agent">
	<cfargument name="Policy" type="Policy" required="true" />
	<!--- NOTE - In real life, we would use a service to create this bean, not instantiate it here!!! --->
	<cfset var Agent = CreateObject("component","Agent").init(arguments.Policy) />

	<!---
	########################################
	In this area we would access Agent info using the OldLegacyPolicySystem and populate the Agent bean
	########################################
	--->

	<cfreturn Policy/>
</cffunction>

<cffunction name="getPoliciesByStatus" access="public" output="false" returntype="Policy{}">
	<cfargument name="StatusId" type="numeric" required="true" />
	<cfset var PolicyStruct = {} />
	<!---
	########################################
	In this area we would load Policies using the OldLegacyPolicySystem and build a structure of them
	########################################
	--->
	<cfreturn PolicyStruct />
</cffunction>
</cfcomponent>

You should notice that we have:
extends=”AbstractPolicySystem” implements=”PolicySystemInterface”

Two things are happening there.  First, we are extending an AbstractPolicySystem object that will hold common functionality among all PolicySystems.   Ours looks like this:

<cfcomponent output="false">
<cffunction name="init" access="public" output="false" returntype="AbstractPolicySystem">
	<cfargument name="SystemName" type="string" required="true" />
	<cfset this.SystemName = arguments.SystemName />
	<cfreturn this />
</cffunction>
</cfcomponent>

For our test case, when we instantiate our PolicySystem we can quickly prove which one we are dealing with by looking at PolicySystem.SystemName.  That said, your application shouldn’t know or care.


By adding the implements attribute we are ensuring that this PolicySystem plays by the rules we defined in our PolicySystemInterface.  No “ifs” “ands” or “but”s!

So, this is the exercise that brought me around on CFINTERFACE.  What are your thoughts?