|
Comments
|
Today's Top SOA Links
BF on CF Preserve Precious Resources- Recycle
Preserve Precious Resources- Recycle
By: Ben Forta
Jan. 27, 2000 12:00 AM
Doing so gave me the chance to clean up lots of old code (updating it to use new CF features in the process) while rethinking the organization and management of code to facilitate better reuse of common code and components. Code organization and reuse are important topics, and judging by lots of code I've seen at customer sites of late (production code nonetheless), they are topics that need clarifying and addressing. So I'd like to use this month's column to share some of these ideas with you.
Why Reuse?
Well-organized code, code broken into small, bite-size chunks, code thought through and designed to be reusable - that's the kind of code that separates experienced professional developers from beginners. That's true of any language, and CFML is no different. In fact, CFML has several language features designed with code organization and reuse in mind.
The <CFINCLUDE> Tag And that's important to understand. ColdFusion processes the included file as if it were part of the calling page. This means that the two pages share the same scope, so any variables or queries defined before the <CFINCLUDE> are visible (can be read and written to) within the included code. Similarly, any variables or queries defined within the included page are visible in the calling page to any code after the <CFINCLUDE> tag. This also means that there is no protection of data. Within an included page you can (deliberately or inadvertently) change or overwrite data in the caller page. In fact, as <CFINCLUDE> has no formal mechanism for passing data (parameters or attributes) to included code, setting variables explicitly with <CFSET> before a <CFINCLUDE> is often necessary. This is a very important behavior to bear in mind when using <CFINCLUDE>, and it is not an oversight or bug. Rather, this behavior is intended and by design. Because included pages share the same scope, ColdFusion's overhead in including files is minimal. This translates into extremely fast performance. In fact, you'll notice no real difference in execution time between a single thousand-line page and 10 included pages of 100 lines each. So when should (and when shouldn't) <CFINCLUDE> be used? Obviously, if all you're doing is grabbing content to be sent to the client, a <CFINCLUDE> makes a lot of sense. For example, my site uses a collection of JavaScript functions that I want available to most pages. Rather than copy all that JavaScript into each file, I simply insert the following line into each file: <CFINCLUDE TEMPLATE="/common/jsfuncs.cfm"> This way, ColdFusion inserts the entire jsfuncs.cfm file into all the pages that need it. But if your included code does any form of CFML-based programmatic processing or manipulation, it might not be a candidate for use with <CFINCLUDE>. For example, I have a block of code that surrounds the body of each page, code that contains header and title information, menus and toolbars, and DHTML-related code. If this code had been static, <CFINCLUDE> use would be appropriate. But my code isn't static at all; it has all sorts of conditional code in it, like logic to highlight the currently selected menu option. Code like that, code that manipulates data (and can thus inadvertently manipulate data it shouldn't), code that needs data passed to it, code that does more than just include content to be sent to the client that kind of code should not be included with <CFINCLUDE> at all. To summarize, <CFINCLUDE> is fast, it's easy to use and it's ideally suited for use with simple code and content.
Custom Tags Unlike <CFINCLUDE>, Custom Tags have a formal method for passing data to called code. Like any other CFML tag, these tags can take attri-butes, optional parameters passed in the standard NAME="VALUE" format. So while data can indeed be passed to Custom Tags, this isn't an automatic process. You must pass attributes explicitly if they are to be visible with the Custom Tag. Notice that I used the word automatic. It is indeed possible to expose calling page data to the Custom Tag by using the CALLER scope. There is even a special scope (introduced in ColdFusion 4.01) called REQUEST that is automatically shared between calling pages and Custom Tags. But CALLER and REQUEST aren't the default scopes, and using them is your choice. In other words, Custom Tags provide data protection unless you explicitly choose to violate it. (The exception is read-only data, like CGI variables, URL parameters or form fields, which are automatically visible to code within Custom Tags because there's no risk in overwriting them anyway.) And there's more. Custom Tags can be paired (a start and an end tag), and they can also be nested (parent and child tags). This makes it possible to write extremely powerful (and complex) reusable components. All this extra power is a good thing, but it's also expensive. ColdFusion has to do a lot more work to execute Custom Tags while providing the protection of separate scopes, and that translates into slower execution time. Custom Tags don't execute as quickly as <CFINCLUDE>. That's just the way it is, and it's a reality to consider when using them. That doesn't mean you shouldn't use Custom Tags. The slight performance degradation is a small price to pay for all that flexibility and power, but at the same time, if something can be included with <CFINCLUDE>, calling it as a Custom Tag is a waste of resources. When should (and shouldn't) Custom Tags be used? Well, if all you're doing is including a file of JavaScript functions (like the example above), or embedding a common header or footer, or including a set of CSS styles, you should be using <CFINCLUDE>. But if you're writing reusable components, files that contain lots of programmatic and conditional code, components that need to create and manipulate data without the fear of overwriting calling data, code that needs to process runtime-specified attributes, then you should definitely be writing Custom Tags. The code I referred to above-the code that creates the page layout, including styles and menus with correctly highlighted sections-that code is written as a Custom Tag. Here's a snippet showing how that code is called:
<!--- Page settings ---> First I use a <CFSCRIPT> block to define the variables needed in this page. I could have used <CFSET> tags to do this, but when writing long lists of variables (it is a long list; this is just a small part of it), <CFSCRIPT> is quite a bit cleaner. Then the SitePage.cfm file (the actual Custom Tag file containing all the page layout code) is called using <CFMODULE>. I could have called this page as <CF_SitePage> too (the more common form of Custom Tag use), but <CFMODULE> is a little quicker. And this is just the start of it. Between those <CFMODULE> tags are calls to additional Custom Tags, tags that define navigation bars, tags that create content body boxes - and others too. To summarize, Custom Tags are powerful and flexible, and are ideally suited for use with more complex reusable code and components, especially components that are runtime configurable via passed attri-butes.
Application Scope Data The simplest way to do this is to add code similar to the following to your APPLICATION.CFM: <CFSET dsn="forta"> Then you could refer to DATASOURCE="#dsn#" in every <CFQUERY>, and just change that single variable to change all <CFQUERY> tags. Listing 1 is a snippet out of my new APPLICATION.CFM. This code defines a global structure named APPLICATION.settings within my application's APPLICATION scope. By surrounding the code within the statement <CFIF NOT IsDefined("APPLICATION.settings")>, I can ensure that these variables are initialized only once. Of course, because these variables are shared across the entire application, a <CFLOCK> must be used to prevent concurrency issues, but that lock will be processed only once, the first time any page in the application is requested. Again, I use a <CFSCRIPT> block for simplicity's sake and define a single structure for all my global variables. This reduces the risk of creating naming conflicts or mistakenly overwriting variables. The code here defines my data source as APPLICATION.settings.dsn, then creates an array of structures (within the global structure) for menu options - and does a whole lot more not shown in the listing. Now my <CFQUERY> tags can simply use the following for the data source: DATASOURCE="APPLICATION.settings.dsn" This global application structure isn't used just for data sources and menus. For example, I load color and stylesheet information as well as lists of states and provinces into it. Anything that doesn't change (or changes infrequently enough that the structure can be updated as needed) can, and should, go here. (I know of some very high visibility e-commerce sites that load entire product catalogs into structures like these, thereby eliminating lots of database access.)
Summary So it turns out that recycling really is good for the environment. The development environment, that is. Reader Feedback: Page 1 of 1
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
|
SYS-CON Featured Whitepapers
Most Read This Week |
|||||||||||||||||||||||||||