I'll admit straight away that my background is in procedural code, way back before Object Oriented Programming (OOP) had not been dreamt up, or maybe just no one bothered to tell us humble COBOL programmers!
I started coding with ColdFusion on version 4.5 and the code I wrote was very much like this Form posts to action page that relocates somewhere that displays some links that show more Forms etc.
No framework no structure, spaghetti of the worst sort.
So I looked round and decided to adopt fusebox as a framework and this improved my code a great deal separating out data access, business logic , and display code.
Later versions of fusebox made this even better by forcing the use of XML in the flow of control from request to request, stopping the leak of business logic into the flow control.
Now like every good developer I'm lazy, so if I find myself coding something twice I start to wonder how I can make that code common and call it. The answer of course is to get data access and business logic which is liable to be called from multiple places into cfcs.
I learnt to make my functions as cohesive as possible (focused on as tight a purpose as possible) because that helps to make the API's clean and simple.
I found that making functions only dependant on their arguments, with no other dependencies on variables in shared scopes, made changing code much easier and more predictable. Not like the days of relying on variables passed up from nested custom tags!
So I started to believe that maybe I'm doing OOP already?
Well... NO because I'm still think procedurally.
If someone says to me we need a program that makes a cup of tea, my first thought is not
I'll call the kettle factory and the tea pot factory, inject the tea pot and the kettle into the cup of tea object and then call the makeTea service method which will know how to make a cup of tea by magic.
I expect that's how you guys make your tea, but us 'ol folk work through a process :-)
Kettle must be available
Teapot must available
Ingredients must be available from the 'Tescos' datasource.
Need to 'display' my tea to the user in a 'cup view'.
(work with me here ok?)
So since my system regularly needs to make tea I have Kettle and TeaPot cfc's instantiated in application scope with any init() method already run. But NO injection of other objects.
(gasps of horror already)
So earlier I said I didn't make my functions dependent on any shared scopes; well I lied because they do call other cfc functions by directly referencing functions something like this application.teaPot.openLid().
(more gasps of horror)
I don't have a service layer, data access layer and domain layer as such, but I do have functions grouped logically together in cfcs and by following the principles of cohesion and loose coupling the functions inside those cfcs start to adhere to that pattern automatically as you think through and re-factor code.
There is NO inheritance. So if I see a call to application.kettle.switchOff() I can open the kettle.cfc and find a function called switchOff and see what it does. I don't have to chase up some inheritance tree to find the actual function.
I have NO beans. CF gives us queries as a great way to pass around record sets. Sometimes a structure or an array might be more suitable, but either way CFQUERY and a bit more CF is all you need. If I need to maintain the code that saves an address record to add a new column because of a database change I want to see only a handful of SQL queries and the CF code that works with those record sets. I don't want to see multiple layers of code encapsulating the address record as a bean with bean factories and getter and setter for each column, too many additional lines of code to look at to understand, to go wrong or get wrong.
What about Aspect Oriented Programming (AOP) I here you cry. How do I handle cross-cutting concerns such as logging and security?
You know what? I would rather have the ugly but easily understood
application.utils.log(stuffToLog=stuff)
wherever I need it than the very clever but much more hidden and tricky to understand XML of ColdSpring.
Security can be nicely handled as a plug-in at the application.cfc or fusebox level.
I think much cleverer people than me have taken some very good concepts and developed them to their logical conclusions, but in so doing have lost sight of the wonderful speed and agility that makes CF such a great language in the first place.
Keep the principles foremost but also the KISS principle 'Keep it short and simple' or 'Keep it simple stupid!' And if it makes sense to break a rule once the pros and cons have been considered, then break it!
If this has enraged you mightily please let me know where I have gone wrong :-)
Recent Comments