If you haven't already, please see part 1 and part 2 of this series. I've been talking about various ways of doing configuration for web applications. I wanted to use this last part to simply wrap up a few threads, share a few ideas, and, well, wrap up. So here are some thoughts in no particular order.
Database Configuration
More than one person said that they do all of their configuration in the database. Which is nice, of course, but I made the point that you couldn't store DSN information in the database. Outside of that, using the database also means that, like INI files, you will typically only have "simple" settings. Ie, foo=goo. You can't do the complex nesting that I showed in the XML example. It does have one huge benefit. While I think most clients could handle editing an INI or XML file, I may be thinking too highly of their technical skills. It also means the client has to work on a file on the server. Using the database would allow the client to use a super-simple web form to update configuration information. Everything can be done from the browser. (Of course, you can build a tool that would allow the client to update the INI or XML files as well.)ColdFusion Configuration
Christrian brought up this idea. Instead of using INI or XML files, why not simply use CFML?This would allow for more dynamic configuration settings (conditional settings, etc.). My problem with this is that a) normally I'd say configuration items shouldn't be dynamic (I'll contradict myself in a few minutes) and b) it defeats the purpose of having a configuration setup that a non-techie could update. In other words, I could trust most clients with a text file, but not CFML. That being said, it is a very valid option and should be considered as well.
Supporting Multiple Servers
So one of the cool things that you can do with configuration files (no matter which form you use) is to support multiple configuration sets per host. A "typical" site will have three servers. A "Dev" server, a "Staging" server, and a "Live" server. In the past, I would simply modify the config files on each box. However, this means that if you accidentally upload the config file from dev to staging, you will be screwed. A much simpler method is to just have three config files: settings_dev.ini, settings_staging.ini, and settings_live.ini. Your application initialization code would simply check to see what the current server is. You can get this value from CGI.server_name. Once you know the server, you can then use the appropriate file. If you use this method, I'd suggest creating a setting that gives a "pretty" name for the server:In your administration tool, output this value. That way when you are using the administration tool, you can clearly see which server you are on. Sure, it should be obvious, but I find it helpful to remind folks. Clients, for example, may forget that staging.foo.com is not the live site.
Archived Comments
Wonderful series, loved loved it. I really like how you've compared and contrasted the methods - which is always what I feel is missing in books about CF... they often say "here's method 1, here's method 2....now onto the next subject". I'm always left wanting to track down the author and say "yeah, but which way would YOU do it??"
Personally, I'd really really like to see the actual example of how you might do something like this in the database. Obviously the code to retreive settings is basically a standard CFQUERY... but every schema example I come up with doesn't feel right, and I'm not quite sure the best way of caching that intial config query.
Thanks, Ray. Can't wait to see more of these. If you ever bind them into a book, put my name on the purchase list.
Ray
This is good timing as I've been having a bit of a debate about this with some colleagues. Currently they use a similar technique to the one above, which sets a number of settings in the application.cfm/cfc based on the environment. I'm still not 100% this is a good idea (basing your app's setting on environment variables) - what do you do if you're using a clustered environment or an app split across a number of subdomains? Although I will admit it works for most cases - what they do not do ..which I (think they should be doing) is using seperate config files. I'm just not convinced that the app should be responsible for determining what environment or configuration it should be using
Kola: What I could do is a post on handling generic data. One of the issues I've seen in various projects - its easy enough to model the MAIN date for a site (products, reviews, etc). But then you typically have "stuff" - "stuff" being stuff the client wants to edit, but "stuff" not fitting into a nice 'type' like Products. You could almost just call it "Random Content" or "Text Snippets."
I realize I'm coming a little late to this party, but I just wanted you to know that this 101 series is still helping people like me who have recently changed jobs and are using CF for the first time.
For now I'm populating my application variables using ini files since I think I have a better chance of writing a good admin page for those. I'm taking your suggestion to have separate ini files for development, staging, and production servers.
But I do like the flexibility XML offers and may decide to tackle it that way later. I suppose the logic is the same either way... Read the config file, create the struct, populate a form, and overwrite the file if the form is submitted.
I've added 2 cfincludes to run this code from application.cfc (Your "Application.cfc Methods and examples" blog was also very helpful). I know you suggested writing a method or UDF to handle that but I'm not quite there yet. Soooon soooon.
If you have time can you briefly discuss the benefits/differences of doing it that way as opposed to just using a cfinclude.
Thanks again!
You are cfincluding an INI file? Why aren't you just using the getProfile stuff I mentioned in the first entry?
No sorry... I am not including the ini files themselves.
In the application.cfc "OnApplicationStart" function I cfIncluded a cfml template that runs something similar to the getprofile code you mentioned. In the "OnRequestStart" function I check for a "reinit" URL value and if present I cfinclude the same template to refresh the application scope.
Ok, sounds good to me, unless I'm missing a question.
Not really... the only question I had was if there is any downside to using an include to run the getprofile code as opposed to a udf or other method as I think you alluded to in the original article.
No, I think that's fine.