Matt asked a question today and since I actually have gotten some work done today, I figured I'd blog about something besides Ubuntu, Hard Drives, and why I can't wait till I'm 100% Mac-ified. Anyway, here is his question:
I have a best practices question: is it bad practice to call a custom tag from a CFC, also is it bad practice to have HTML in a CFC.
First - check out the CFC Guide I have here:
I find that folks tend to miss my Guides pod to the right so I thought I'd point it out.
Is it bad practice to call a custom tag from a CFC? Not at all. You can call other CFC methods, other CFCs, custom tags, web services, etc. You may want to task if it makes sense to move that custom tag's logic into a CFC method however.
Your second question could be read two ways:
Is it ok to return HTML from a CFC method?
and...
Is it ok to have HTML in a CFC method?
The second version matches what you said - but I believe you meant the first version. In general folks almost never do this. The idea is - let the CFC handle logic (getProducts) and let you front end handle display.
That being said - I've done the second way (html in a CFC) in the past when I need to send formatted emails from a CFC, like for Ligthouse Pro's email reports. It would be possible to pass in a template of some sort, but frankly that seems like too much trouble.
Archived Comments
I'm not sure if it's "right" or "wrong" to include HTML in a CFC. I've been using CFCs to handle my site layouts for a while. Really happy with it.
Steve Bryant wrote some good articles on using CFCs in the presentation layer.
I have no problem at all with using CFCs to either return or display HTML, so long as they are View-level CFCs. The idea is to keep your logic separate from your display. As long as you do that, what CF mechanism you use is pure preference in my book.
I started to reply to this, but the reply started to be so long that I just did an <a href="http://cfinternals.typepad....">article</a> on why it's often a good idea for objects/components to generate and return HMTL.
Here's some sample code with using HTML and includes (same basic thing as cf tags) with CFCs:
http://labs.webapper.net/pr...
I try to always use cfc's for logic. The only exception is when I am using an AJAX call to refresh some html. Even then I think you should use a cfinclude if that is possible.
@Mark. I prefer using view cfcs over includes or modules because I can define the arguments they need to receive and because they can be referenced and cached in memory for later use.
Futher, cfcs are extensible. Most of the form cfcs I use extend a base class that generates the correct output from a simple xml definition, binds to the object for data transfer, automatically validates, and so on.
The view cfcs work similarly, and contain "helper" functions for things like automatic query list display and pagination functionality.
@Mark. I prefer using view cfcs over includes or modules because I can define the arguments they need to receive and because they can be referenced and cached in memory for later use.
Futher, cfcs are extensible. Most of the form cfcs I use extend a base class that generates the correct output from a simple xml definition, binds to the object for data transfer, automatically validates, and so on.
The view cfcs work similarly, and contain "helper" functions for things like automatic query list display and pagination functionality.
@jason
Do you have a link for that article from Steve?
@tony
Steve's website has links to both articles:
http://www.bryantwebconsult...
My background has always been working in teams of mid- to senior-level CF developers, and most of these developers I've worked with seem to agree with the Forta/Horwith school of thought regarding when to use CFCs versus CustomTags. http://www.forta.com/blog/i.... Two of my mentors, Adam and David Churvis, teach this approach in their CFMX Master Class (and use it extensively in the PLUM framework), and I've never been disappointed in organizing my code that way.
That being said, I can see some of the benefits to move nearly all reusable type code to CFCs IF you're developing code primarily by yourself or in a small group of like-minded developers.
Also, note that many developers just aren't aware of how powerful and handy CustomTags can be: http://cfzen.instantspot.co...
Ben Nadel has an excellent recent series of blog entries on CustomTags:
http://www.bennadel.com/blo...
http://www.bennadel.com/blo...
http://www.bennadel.com/blo...
http://www.bennadel.com/blo...
@Aaron: Nearly anything you can do in a nested tag configuration can be done in a CFC quicker and easier, plus in a cfc you can break functionality down into internal subroutines, inherit functionality, and you can get and assign values back w/o doing nasty returnvalue/caller syntax where you inject variables into the parent's scope.
Here's a snippet of code from a autogenerating form demo, much like the table generator from your example:
f=createObject('component','form').init();
f.hidden(name='id',value=456);
f.input(label='First Name', name='fn', value='mike', size=25);
f.input(label='Last Name', name='ln', value='long', size=25, required=1);
f.input(label='E-Mail Address', name='em', value='email@sample.com', size=25);
f.select(label='Gender', name='sx', value='m', size=1);
f.option(label='Male', value='M');
f.option(label='Female', value='F');
...
#f.display()#
It beats out performance-wise as well. All-in-all, cfc's are so superior in terms of packaging code that I stopped doing nested tag configurations years ago and never looked back. Pretty much the only thing I use a tag for these days is to do memory/file-based caching routines, and I think I still use the pagination one from time-to-time.
Michael - I really beg to differ. I don't think your example is easier then say
<cf_form>
<cf_formfield ..>
</cf_form>
Certainly for people coming from a non-programming background. Shoot, I come from a programming background and I still find the tag based syntax easier to work with.
Yes, Custom Tags have slower performance, but I do not believe that it is the type of concern that will impact most people. Performance is not _everything_. If it was - we would write in machine language.
@Raymond - Perhaps from the bit of code shown that's true, but that was just done to show how you can have similar syntax in the setup phase. It's when you add a couple of lines like...
if (f.process(object))
object.save();
...that the component-based version begins to show its true colors.
How about automatically marshalling data to and from your business objects, and having automatic form validation and error checking, and being able to include the previous example's form setup inside a "definition" function, such that each registration or sign-in or administration form is its own self-contained block of functionality? Was all of that included in the custom tagset?
What happens, say, when you need an special validation type? Do you dive into your cfx_form routines and patch them (problematic if a shared or public library), or do you just add a "validateMYTYPE" function to your form handler and get on with life?
From a syntax standpoint things are a little different, sure. Then again, you're already cross-training someone who knows input and select into translating select into cf_formfield type="select". Is f.select(...) that much harder? Or easier? Or just six of one, half-dozen of the other?
Again, I have to stand by the component-based approach for sheer power and functionality and extensibility and packaging and all of the other reasons I've already mentioned. And I've written a LOT of form, table, report, and database-management tagsets.
But if everyone agreed on everything, we wouldn't have horse races... (grin)
without doing an explicit test on the code below:
f=createObject('component','form').init();
... from experience, I'm almost certain that the custom tags will run faster (if pure performance is all we care about) under high load/traffic. You get the benefit of CFC performance mostly only when you put them in the Application or Server scope, and in some cases (if you don't have too many concurrent sessions) in the Session scope. But if you're doing createObject calls often on a per request basis (like above), then performance under very high load will decrease (trust me ;-).
The rest of my rant on the subject can be seen here:
http://cfzen.instantspot.co...
I'm not saying that CFCs aren't more powerful, they certainly are, but CTs tend to win hands down when it comes to syntax. Don't forget too that you can have a CT API to CFCs. So you have your ease of use and your CFC structures still in tact.
@Aaron, the createObject call was sort of obligatory in order to show how the component could be instantiated in the first place.
In the real world I'd call a manager or factory to get the form component, which in turn might come from an internal cache or pool of similar forms. You can also write form and view components such that they're "stateless" and can be cached and shared across multiple threads.
Or write them such that the definitions (which is where all of the attribute parsing and heavy lifting occur) are generated and cached, making a new form instantiation insignificant in comparison.
Further, several people have mentioned to me that Scorpio may improve component creation creation speeds quite a bit. Have to see about that one.
Translated, there are many, many ways to skin that cat. Properly designed, performance is NOT an issue. (trust me)
And to quote from your rant: "...I've been coding advanced CF for 5 years, and I've never seen..."
If someone has been coding for five years and has never run across components, factories, frameworks (Model-Glue), ORMs (Reactor), code/form generators, and so on, I'd really have to question how much "advanced" ColdFusion they've done. (grin)
Michael - I think those of us who write CFCs assume that more people in the community also write CFCs. I think the CFC-writing portion of the CF community is a minority still.
@Michael - Okay, I see you understand the power of CFCs and how to use them most efficiently, so I apologize for implying that your code wasn't the most efficient performance-wise.
And I'm also looking forward to the createObject performance increases in Scorpio, so that like creating a new object in Java, hopefully you usually won't have to worry much about performance when instantiating objects on a per-request basis. I trust you man, as it's clear you know what you're talking about and have the experience to back it up. :)
re: "...I've been coding advanced CF for 5 years, and I've never seen..." - actually, I was referring the reactions of other developers to the way this particular "architect" had designed a particular app, which was basically a complex, undocumented, spaghetti FB 2-3 hybrid, with little use of CFCs, MVC, encapsulation, best practices, or any other common ways of doing things. The design was, however, "inventive" and quite advanced (no matter your opinion of it). Unfortunately, no one else could understand what the heck he was doing until he explained it for hours (which he rarely did) or after a developer had worked with the app for at least 6 months. Finally, the CTO decided to rewrite the whole thing in Java... good idea!
That brings up a point which goes back to the original point about whether it's a better practice to use customTags for your View than CFCs: what's best practice in enterprise Java web apps? And incidentally, what's best practice in enterprise ASP .NET web apps? If you know the answer, and I'm sure you do, then you get the point.
@Ray - I don't think you necessarily meant that just because some of us prefer to use customTags for our View that it means we don't also use CFCs extensively, but I agree with your point that probably most CF developers who aren't heavy into the blogosphere are not primarily using the latest OO frameworks or design patterns. In my experience at least, most of us in the trenches are dealing with legacy apps that were originally written pre-CFMX, and therefore the code isn't always the latest and greatest. There's nothing wrong or less-advanced necessarily about these legacy architectures (in fact, many of the rake in millions or billions of dollars), but it's just different. ;-)
@Aaron, nothing to apologize for, it's a good conversation. As to "best practices", I'll take a firm stance on the matter and say, "it depends". If you're still coding most of your application logic in a .cfm file then tags probably make sense (see below). If you're using cfc-based controllers or business objects with an ORM, then I'd code stateless views to match.
@Ray, I understand that many CF developers aren't using objects, much the same as most "old-school" PHP developers aren't using them either. However, many environments are object-based (java, python, ruby) or, like .NET, provide lots of functionality to the developer in terms of pre-packaged objects.
There have been many comparisons of CF to PHP, and with good reason. Both started out as scripting languages that encouraged a thorough mismash of HTML and code. Both have been extended with "modern" language features that all too few use. And both are constantly being extended with half-a-billion or so global functions and tags.
Because of that it's easy for beginners (and "advanced" developers) to start in and use both languages. Unfortunately, those habits are carried over into ever larger and more complex sites, and that's where things usually begin to disintegrate into chaos.
And that's why I tend to resist adding even more "global" functionality in terms of vast arrays of tag libraries. Because if someone is using a cf_form-style system then 9 times out of 10 I'll bet that they're plopping that tag-based form right in the middle of their page, which jumps to a hastily written xyx_process.cfm page that in all likelyhood doesn't do half as much error checking and handling as it should and cflocates back and forth as needed.
Not really what one would consider to be a "best practice".
I see our role as providing the tools needed such that using objects and doing component-based development is a no-brainer. And further, to promote "best practices" that ensure rapid development while also creating a site that's easily maintainable and scalable.
Thoughts?
I agree that a mishmash of logic and html is bad - but when I look at Dotnet and their page behind concept - I think it is taking it a step too far. It seems abstract for the purpose of being abstract - in other words - not practical.
Syntax wise I think custom tags really make sense in some situations. For layout it certainly does:
<cf_layout title="..">
Content
</cf_layout>
For providing complex information. Just look at Flex's datagrid. Yes you can add columns via AS but it is a lot simpler, and a lot easier to understand, in tag format.
Now if the code behind the tag is sucky - thats something else - but just the fact that it is a custom tag doesn't mean it -must- b sucky. ;)