DuckTyping, Interfaces, CFEclipse, and how I write code
Posted At : February 1, 2007 6:47 PM
| Posted By : Mark Drew
Related Categories:
coldfusion,
quack,
cfeclipse
My previous post about CFEclipse and DuckTyping got me thinking about how I develop applications.
In a couple of systems I have written, I create a number of services. What do I mean by this? Well, a service (in my terminology, I am not CS graduate, just an old hacker) in my code is a single component (singleton) that returns objects (such as pages, products, users, you get the idea).
So for example, lets take a simple PageService:
<cffunction name="getPage" returntype="any">
<cfargument name="pageid" required="false">
... some code ...
<cfreturn pageObject />
</cffunction>
</cfcomponent>
This component returns my pages which is all fine, but lets say, I am going to change the way I get pages (for some crazy reason) and instead of using a database, I want to use a file based storage, or an XML file. Instead of changing it, I create a couple more services:
- XMLPageService: gets pages from XML
- DBPageService: gets pages from a Database (my original service)
- FilePageService: gets pages from a FileSystem
Now, how do I instantiate these services? Well, I create a PageServiceFactory. The PageServiceFactory's role is to get me the right type PageService, with a function such as:
<cfargument name="servicetype" hint="type can be:db,xml or file">
<cfswitch expression="arguments.servicetype">
<cfcase value="db">
<cfreturn getDBPageService() />
</cfcase>
<cfcase value="xml">
<cfreturn getXMLPageService() />
</cfcase>
<cfcase value="file">
<cfreturn getFilePageService() />
</cfcase>
<cfdefaultcase>
<cfthrow message="unknown page service requested">
</cfdefaultcase>
</cfswitch>
</cffunction>
This is a great example of DuckTyping for programming and not just the for ( the celebrity harlot which is) performance since, when I do my call, in my controller I call the Factory asking for a Page as follows:
<cfset title = myPage.getTitle()>
<cfset content = myPage.getContent()>
I am able to call the same method on each service even though the service type can change.
One of the requirements for duck typing to work in your code is that all the methods that you would expect to be there, ARE there (otherwise you get a function not found exception). You would have to either very rigorously test your code or setup unit tests that all of the PageServices have to pass.
In Java, you can define an interface that all the PageServices comply with, basically the interface is a contract that the PageServices must follow with the functions and arguments that they have. Most java IDE's and editors, whilst you write your class, will alert you that you are not conforming to this contract and provide ways to overcome this.
This kind of functionality I would love to put in CFEclipse, if ColdFusion had interfaces.
How would the code change? The getPageService function in my Factory would then have a returntype of "IPageService", which would be my Interface, defining what functions all my PageService's have. In CFEclipse, whilst you are writing a new PageService, you would say it implements the "IPageService" interface. If you missed out any functions, CFEclipse would warn you that your new Service is not compatible, all before you have even saved the file.
Now you could have function insight when you type "getPageService("db")". This wouldn't be DuckTyping anymore, of course, but it would definitely remove a lot of the architectural mistakes that you could do in your application.
Or have I missed something?



Also, if you are using duckTyping..you are probably doing it for some performance reasons right? You may also want to reconsider using cfcase then as well and replace it with cfif statements...its a bit faster I've been told.
I shall blog about how you can do this in CF, whilst maintainging the "text" and the dangers of it.
@Christopher: I dont like using Extends in this case, its not really defininging what the Services are. I already use extend in the Services for the init and setConfig methods (they are being instantiated from ColdSpring) so in this case, I would have to have two extends, and thus performance (not the point of this post though) would be even more decremented.
With all of the work you're doing on CFEclipse, I think you should definitely get on the beta so you plan future enhancements for CFEclipse to go along with the new version of ColdFusion. The better the tools are at the time of release, the easier it'll be to code for all those new features.
Do I read your comment and though .Net.
Also, you could plug additional IPageService's in via ColdSpring, for instance, just to make CFE's job harder :-)
so...
Not that this will help CFEclipse at all but one of the cool things about ColdFusion is the "Duck-Typing". Did you know you can even modify the inheritance tree on the fly? I did a proof of concept type thing a while back.... ok, a looonnngg while back. The biggest problem with modifying the inheritance tree at runtime is 1) performance 2) The way Coldfusion seems to cache class instances.
http://www.franciswscott.com/blog/1/2005/11/CFImpl...
Has a link to the actual working files. Though not a good example of what you would use interfaces for :)