Writing Portable Code
If you were to ask me what I consider my strongest skill as a ColdFusion Developer, I would say that I like to think it's my ability to write code that is extremely portable and easy to read/maintain. Regarding portability: it's rare to have to change more than two or three variables (at most) in my applications in order to make them run. It doesn't matter if you copy the code from one machine to another or from one directory structure to another - just change 2 or 3 global variable values and it'll run. That, after all, is what portability is all about.
What that means is that my applications tend to rely as little as possible on settings in the ColdFusion Administrator, as these settings make an application less portable. No CF mappings, Custom Tag Paths, registered Web Services, etc. are required for the app to function. Yes, that includes trying to avoid the necessity for pre-existing verity collections and datasources, although obviously you do have to draw the line somewhere - if a DSN must exist, it must.
I'm not saying that it's the end of the world if you use these administrator features, but I personally recommend getting in the habit of trying to reduce the need for them. You'll generally find that testing is easier, deploying your applications to new environments is smoother, and running multiple copies of your app on the same instance is less painful. If you are going to write an application that requires settings in the administrator, by all means document this well. Prior to CFMX 7, avoiding relying on CF Settings was more important than it is now, since we have J2EE packaging and deployment, but it's still very important (not only for portability but also for readability).
Here are a few ways you can begin to make your code more portable:
- Use CFModule (with 'template' attribute) or CFImport (with relative path) for calling custom tags (CFIMPORT is preferred)
- Represent your UI with custom tags
- Make all forms post to #cgi.script_name#
- Use relative paths for cfincludes, CSS, Javascript, images, and hyperlinks
- store paths in application variables and use base paths, with other paths extending those values
- get objects from an object factory and/or resource pool implementation
- whenever possible - try not to rely on mappings, custom tag paths, or other path or mapping variables in general

You then say do not use mappings. With proper planning, mappings are not an issue and can be set from a config variable meaning meaning very easy portability.
Assets for your HTML layer... again, easy to use a configuration variable and use a virtual web path. Using relative paths for your assets is a pain in the backside unless your are using the front controller patter and can ensure that the path relativeness will stay the same. Yes there are functions out there that calculate relativeness from one file location to another.. why bother in my opinion, just use the web server mapping rather than using up processor time doing unnecessary file system reads and calculations.
your reasons are honorable, just not convinced that the 'don't do that' tone is entirely correct.
What I discussed is something that will apply to anyone who invokes web services from CFML, period. If it read somehow that it applies only to those who "add web services to the Admin console" or "renames them in the Admin console", that would be an unfortunate conclusion and I'd ask you or anyone else to tell me how I might reword to correct that misconception.
The fact is that if you invoke a web service from CFML, a proxy/stub will be created. The problem is that sometimes the web service API on the other end changes, and this cached proxy/stub becomes out of synch. The solution then is to flush it.
I simply started with pointing out that the common approach to flushing it is to do so from the Admin console. Naturally, some will want to do that programmatically so as to avoid having to use the UI to get the task done. I make no comment on whether they should do so, or if it's a problem if they have to do it often. I was simply showing folks how to do it if they need to.
Really, there's nothing about this that has to do with an optional "use of administrator features". It just is what it is: a solution to a possible problem, and a poorly documented one at that.
Still, I don't want you to see the blog entry as all bad. You make other useful points that do support your general assertion of keeping code portable. I'd support that 100%. I just think it's unfortunate that my entry was used as a proofcase of bad practice. I hope I've persuaded you and others that it just isn't the case.
BTW: I see you're still using the default captcha settings in BlogCFC. I blogged about how to change that (http://carehart.org/blog/client/index.cfm/2006/8/1...) and then later did another where I simply give you the captcha.xml with the handful of changes needed. You can just drop that in and ?reinit your blog and voila, simpler captcha. See http://carehart.org/blog/client/index.cfm/2006/10/... Hope that's helpful to you--and, more important, to your readers/commenters.
As for the other comments from DC:
I WISH that cfimport could take a dynamic path like cfmodule does - and until cfimport I only used cfmodule. CFIMPORT is a pre-compiler directive, so it has to be hard-coded... but it's a relative path, which means that if you copy your directory structure from one place to another, it will just work. There is no such thing as 'proper planning' that will not require you to still create the mapping if you rely on them. After 11+ years of doing this, trust me - I make very proper use of storing paths in variables... but if you require a mapping to be there, it does make your code less portable. I'm not sure what you're refering to with regards to HTML assets, unless you don't agree with my recomendation to use Custom Tags for the presentation tier.
So can you confirm for the record (lest anyone think we're mincing words here) that you see now that there's nothing about what I posted that is really related to the rest of your point? I mean, sure, I can understand one thought leading to another, but it does seem that when you wrote the post you were clearly regarding what I wrote as something to spark your argument (otherwise, why mention it at all?)
I realize you're busy, so I'm sorry to draw this out. I just know that you get plenty of readership and I'd just like to clarify things for anyone reading this. Thanks in advance.
I'm going to argue there is nothing wrong with the judicious use of CF Mappings, DSNs and just about anything else that for your application solves a problem more elegantly than another approach (although I agree you don't need to be hard coding things like server names and directory paths which can be calculated once in a config script and stored in application scope).
The trick is to write a simple build engine (or to use something like Ant) to auto-deploy. I have a simple system in my old procedural application generator where I can select a server from a drop down list and an application from a list and "deploy", "snapshot", "restore from", etc. It takes care of mappings, DSNs, creating data tables in selected databases if required, etc.
The problem is that the default setting (of Lyla captcha, which BlogCFC uses) creates a very complex captcha (shown to anyone who tries to create a comment here). In earlier blog posts (linked to there) I explain why that's generally just not needed. We're not guarding Fort Knox in our blogs. We just want to keep out spam pests. My assertion is that we don't need a "double keyed deadbolt lock" so much as just a "screen door"--the simpler captcha, and so I originally showed how to change the file to effect the simplification.
But others also balked at taking the time to change it, so I created the later blog post (the one listed above) that simply offers the updated lyla captch.xml file. You can just drop it into your current BlogCFC deployment. No need to twiddle or even think about anything. Reinit the blog (with the ?reinit query string) and in less than half a minute you can have a greatly simplified captcha.
Again, other entries pointed to from there explain why this is not a bad thing. And I show there what it will look like if you do it, so you can know what you're getting into. This is simply about doing something to benefit your readers every time they comment, at a one time cost of a few seconds to implement the updated file.
Indeed, later versions of Ray's BlogCFC incorporate this new simpler captcha, so many have come to see the benefit. Hope that's helpful.
Agreed. And as usual, it's use case driven. I sell SaaS and co-lo my servers so my only interests are simple "staging to production" builds, easy deployment across web farms and automating disaster recovery, and those are easy to solve with in house build scripts. I don't have to worry about client installs, people using my code on shared server, or anything else, so I take full advantage of that luxury. That said, it really is impressive what can be done to minimize manual configuration requirements if you think about it a little, and an install should never be more complex than it absolutely has to be. I should probably review what is required in my builds and see what could be simplified.
Again, for any who may only be half-reading all this: when you invoke a web service in CFML (using CFINVOKE or CFOBJECT/createObject), a java proxy/stub is created to map the available API from that remote web service. If the web service API changes, your CFML code may get errors because that cached proxy/stub (a java .class file) will be out of synch with the new API.
The traditional solution most have recommended is to go into the Admin console, where you'll find an entry for each such web service that's been executed (not "registered"), and you can hit the available "refresh" button for that web service, which will rebuild the proxy/stub.
All I was saying in my blog entry was that if one wanted/needed to do that programmatically, you could, and I showed the code (both the CF7 Admin API and the "older" ServiceFactory approach).
Perhaps, Simon, your thoughts were triggered by the point I made later in the entry about how the Admin API methods used may vary in their use depending on whether one had renamed a web service in the Admin console, something I then also explained. But the entire entry applied to web services regardless of whether one had renamed them or not. That was really a minor sub-story.
I suppose you could make the argument that the notion of renaming a web service is something that you'd argue against from that standpoint of making code portable, and I wouldn't disagree. But boy, one had to read really carefully to make the connection. :-)
Sorry, again, to readers who think I've been picky or defensive about this. It's just that the wording of the entry above really sounded like a blast against the bigger subject of my entry. Now we can see that it should not be read that way. Where's Officer Barbrady (SImpsons) when we need him: "Let's move along folks. Nothing more to see here." :-)