By Peter Bell

Beyond the XML Config File?!

Looks like even the Java world is starting to investigate their XML config files to ask whether there is a better way (must be all the Ruby guys making fun of XML pushups :->).

I agree that there are many good reasons to use XML config files, but XML is limited in terms of flexibility. There is a reason that we use programming languages as they allow for looping, conditional logic and a number of other capabilities that allow us to express our requirements more flexibly. You can work around this by using multiple XML config files and pulling in the right one based on conditional logic, but once you get beyond a certain level of complexity, XML ceases to be the most appropriate choice (and at any time it is a pretty verbose choice). It will be interesting to see how this discussion plays out - using Groovy as a config language. Interesting!

Here is someone else who isn't sure about the overhead of using and processing XML files. Not sure that I agree, but it is a discussion I'd like to see opened in the CF world. Python and Ruby developers seem to do just fine without XML (think Rails and more importantly Django). So, in which use cases is XML the most appropriate choice?

Let's also remember that one of the benefits of XML in Java (don't need to recompile) is irrelevant in CF.

Diclaimer: I think XML config files do have a real place. I just think we need to develop heuristics for the use cases when they are not the optimal solution.

Comments
I don't much care for XML code files. They are not flexible enough for me. Or rather, not powerful enough? Not sure which it is. They don't quite jive with the way I program; I don't like using mapped anything or hard coded values. No mapped paths, no custom tag directories, no harded coded URLs. All of my stuff is highly modular (can pick an app up and drop it anywhere) and most every value is calculated via ColdFusion during configuration. Perhaps this can be put into an XML document, but I am not smart enough to figure it out. Basically, the only thing I allow myself to go to the CF Admin for is Data Sources. For everything else, if I can't get it to work without some sort of mapping or hard coding, then I need to find another approach.

Ok, so there endeth the mini rant... let me give an example. Obviously, my dev site and production site are different. They have different data source credentials, different URLs, different emails, different paths, etc. I am not one of those people who has multiple config files for different environments - that kind of organization takes waaaay too much concentration and I think I was dropped on my head as a child. I like to just sync files and make it work.

I usually (recently started) use a Config.cfc configuration component that gets Cached in the APPLICATION scope (sort of). This component has some key values like:

VARIABLES.Instance.IsLive

IsLive is calucated by the Config object based on the server. This is not *hard coded* but RegEx for testing the server name is... but I can give it a list of standard severs names and never have to touch this again.

VARIABLES.Instance.Url

This is the URL for the main application. This is NOT hard coded. It uses the URL, the CGI, and the knowledge of the GetCurrentDirectoryPath() to actually calculate the URL of the application. No hard coding of URLs in my applications please and thank you.

VARIABLES.Instance.RelativePaths
VARIABLES.Instance.RelativePaths.Uploads
VARIABLES.Instance.FullPaths
VARIABLES.Instance.FullPaths.Root
VARIABLES.Instance.FullPaths.Uploads

These are a sample of the path variables. The Relateive paths are all relative to the root of the application (ex. "resources/uploads/"). Then, the Full Paths are automatically calcuated using the root of the application (which itself is calculated) plus the relative paths. So, the relative paths are *hard coded* but ultimately all full paths are calculated which makes the app very portable without making changes to the config.

That's just a sample of what's going on under neath the covers. I don't know how I would do this if it was in XML files. I suppse that I could have a ColdFusion component that does the Site URL calculation and then I could have an XML file that has the list of servers for local/production and the list of relative paths... but then I have doing config work in two different places (component and XML file) and that just seems silly. Config should all be in the same place for the general application info??

So anyway, the long and short of that is that I don't think the XML file configuration idea is powerful enough to allow an application to be highly portable. I think the second you move to XML you need to start either splitting up your configuration code OR hard coding values that SHOULD NOT be hard coded, or replying on path mappings which make the application less portable.

My 2 cents....
# Posted By Ben Nadel | 10/15/06 11:28 AM
Hi Ben,

I'm sure others will hate it, but I happen to love your approach. I still have too many hard coded URL and path mappings because I haven't sat down to figure out the (fairly straightforward) code to calculate all of that on th fly. I love the idea that you can pretty much just drop your applications anywhere and have them work.

Only thing I can't see getting away from is a single CF mapping per application to the root directory so that if I have a mytest application and I want to createobject a test.cfc in my com directory I know the path is mytest.com.test. Have you found any way around that requirement?
# Posted By Peter Bell | 10/15/06 11:36 AM
Pete,

You comment raises an excellent point. By creating a more portable application, I do sacrafice a certain amount of code organization. All of my CFCs and custom tags live INSIDE the application. I dont have any of those organizational folders like :

com/bennadel/cfc
com/bennadel/tags

Frankly, when I first came accross that style of organization I had NO idea what they were doing. It seemed very silly to me. I still don't quite understand it... I think has something to do with old school code orgranization??? Not really sure.

In my applications, I have a root-level "extensions" folder:

www
...extensions
......cache
......components
.........UDF
......customtags
......data
......includes

Then, most of my components live in the same directory (extensions/components/) so extending is not a problem. If I can, I break out grouped components into sub folders (ex. All UDF components -> TextLib.cfc, XMLLib.cfc, CoreLib.cfc, etc go in the UDF sub-folder).

Then, in the application code, most of my component creation goes through a ServiceFactory object that resides in the main CFC directory and hence, it has no problem with path mapping:

APPLICATION.ServiceFactory.GetSecurityController()

which returns initialized objects. I am not *crazy* about this approach as I have to create a method for each type of component... so I am trying to figure out a slightly better way of doing that.

So, I do sacrafice some organization, but since my apps dont have hundredes of CFCs and they are names very appropriately, it has never been a problem.

Then, when it comes to custom tags, I generally always use CFImport or CFModule in which you can give relative paths (from the current template). This requires some hard coding of the template in relation to the application itself, but that rarely every changes for me.

Probably not the answer you were looking for, but it has worked wondefully for me.
# Posted By Ben Nadel | 10/15/06 11:50 AM
Hi Ben,

Yeah, com is an old school naming convention for the components directory, but it is still widely used so I just went along with the crowd as I had to call it something. The main difference with my organization is that all of my files are BELOW the wwwroot level unless they HAVE to be in the wwwroot. The only cfc's I put under wwwroot are remote session facades which have to be accessible over the internet. Just a security thing - I don't want anyone to have any way at all of accessing my cfcs.

For instance I just went to http://www.bennadel.com/extensions/components/. Directory listing wasn't allowed, so I'd have to spend some time playing with different names, but I'd probably eventually hit on the name of one of your cfcs. I honestly don't know whether I'd get anything of use in terms of maybe a file with config info or a DSN password or something and I don't even know how CF would handle the direct request for the cfc, so it may well not be an issue other than maybe allowing be to determine a cuple of the valid cfc names you use, but I just like to keep my files away from such probing just in case!

As for different directories for different components, I do have quite a lot of components (100+ is pretty common) so I like the organizational benefits of a deep directory tree. Also, you can take good advantage of package methods by putting UserService and UserDAO in the same directory so ONLY the UserService can access the package methods of the UserDAO. Not a killer benefit, but I quite like it.

I think I'll live with my CF mapping, but I can see the benefits of the approach that you use.
# Posted By Peter Bell | 10/15/06 12:02 PM
Pete,

All excellent points. I built relatively smaller applications at this time, so organization is not as big an issue to me obviously. Also a good point about the remote accesing of components. Currently, I don't have any remote-accessibly methods, nor does my Application.cfc allow the remote calling of CFCs (since it uses the OnRequest method which blocks this automatically). But, I can definately see the security risk.

I suppose I could move the Application.cfc and the components above the WWW folder and then I would be able to creates components via anthing created through the Application or anything application-scoped, but then I feel that I might conflict with anything else above the WWW root (What if I had more than on application in the server folder (ie WWW, ADMIN, EXTRANET)... they certainly all counldn't have application.cfc files in the same directory.

So yeah, my solutions is clearly not perfect, and perhaps not good for larger applications. But, I am still a firm believer of very few mappings. Also, I am relatively new to higher-level though in the programming world, so I might come to conclusion that mapped paths are just a requirement. Only time shall tell.
# Posted By Ben Nadel | 10/15/06 12:10 PM
Pete,

Just to touch on one thing that I see all over the place. If people are going to create directories for groups of object ( UserServce and UserDAO in your example) it seems that they use redundant naming conventions. For instance I see this a lot:

User
...UserDAO.cfc
...UserService.cfc

Components are always redundantly named. If a componet is IN the USER directory, why are the sub-components prefixed with User??? It seems like it should be:

User
...DAO.cfc
...Service.cfc

Not to knock on the way it is being done for everyone. I used to organize methods that way. For instance, I have an object: FormErrorCollection and really all it was was a queue of messages. When I first created this object, I used to have the method "AddMessage()" which would add a form error message to the queue. But then, I came to realization that all I did in this object was add Messages... so why call it AddMessage()... since its a queue of messages, shouldn't it just be called Add().

Anyway, I've just always been curious about that naming convention that I see everywhere. Wasn't sure if that was "old school" also.

And just one more note... look at the java StringBuffer object. It has an Append() method which takes text. Notice that it is not called AppendText() since this would be redundant as it only ever takes text. This is how I have started to think about naming conventions.

Anyway, hope that didn't come across as a rant or an attack on anyone... I am more just curious than anything else. I am just trying to make way in this OOP world.
# Posted By Ben Nadel | 10/15/06 12:19 PM
Hi Ben,

Very interesting. As with most interesting ideas it was something I'd never really thought about. While there is a bit of redundancy, if you were to share cfcs or reuse them informally, I kind of like the fact that the cfc names are self describing and that putting all my cfc's into a single directory wouldn't cause all of my DAO.cfcs to overwrite each other. Given the relatively small amount of redundancy, on balance I'm happy with it, but it is a god point to raise and one I'd never really thought about!
# Posted By Peter Bell | 10/15/06 12:45 PM
Hey Pete,

I don't think you could apply this idea to inheritence and parent-directories, but here is a proof of concept that I just threw together that shows that you can have non-public CFCs and still call them without mapped paths.

http://www.bennadel.com/index.cfm?dax=blog:348.vie...

Anyway, just didn't want to feel defeated by the security risk :)
# Posted By Ben Nadel | 10/15/06 4:06 PM
Hi Ben,

Very cool - makes perfect sense. To be honest I hadn't even realized that I could use relative paths (without the dots) for create object - just something I had never tried. With this I should be able to get rid of my application mappings fairly easily as I include a file in the root directory to do all of the work in my apps anyway. Thanks for the hint!
# Posted By Peter Bell | 10/15/06 5:21 PM
Hey Pete,

Glad you liked the proof of concept, but I wasn't trying to make you go one way or the other in your own apps. I have very little large application experience and have no idea how this might affect things. I just wanted to prove that it could be done.

Also, I think maybe you misunderstood something (or perhaps miswrote something). You canNOT use relative paths (without the dots) for create object. That's the reason this POC was important.
# Posted By Ben Nadel | 10/16/06 7:24 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.005.