Monday, January 31, 2005

So you want to be a consultant...?

So you want to be a consultant...?

Terriffic article. My company, Anodyne, Inc. has been living this article for the past 10 years.

We tend to work more in the Contracting mode than the Consulting mode now, although we've done it the other way in the past when we were selling more hardware.

ColdFusion Mappings revisited.

I constantly get mappings in cf screwed up when I'm building a new site from scratch. I've been doing it for years, but it just seems to be one of those things that makes you feel like an idiot.

Here are a few points to help (me) remember what's going on with these things and how to set them up right the first time.
  1. They are NOT like web server mappings. They really can only be used inside the cfmodule or cfinclude tags. You can't create a mapping and expect to use it throughout the site. It definitely will not work on pages that are not run through the cf engine.
  2. In my normal setup, their is generally one mapping per application that points to the Application root, not the server root. This helps keep the code somewhat portable and lets Dreamweaver keep up with your locations.
  3. Setting up your site in Dreamweaver - the local root folder should also point all the way down to the root of the application, not necesarily the web root.
  4. VSS should mimic this layout. If you have your application root set to c:\inetpub\wwwroot\intranet\application1, VSS should be set up with a project like this: $/intranet/application1.
  5. One aspect that I find VERY confusing is that using the "/" in your cfincludes calls up your mapping, while using "/" in regular html, like an image source, calls up the web root.
I tend to prefer this method to keep things like images in included files straight for several reasons. If your paths are set up like this, Dreamweaver can keep things straight for the most part in it's wysiwyg views. I tend to work in split mode a lot, so this comes in handy. The images are not displayed from cfincluded content. Maybe this isn't the way it's supposed to work, but it doesn't bug me as much as the broken images that get displayed with other methods.

A lot of people like to set paths in their application.cfm files. While this works fine (and is probably more robust), I just find it ugly to look at inside my code. Plus, everything you reference that way is generally shown as broken in Dreamweaver.

I think if dreamweaver had a way to supply a design time value to it's variables, that would allow the application.cfm method to feel more natural, but I haven't found a way to do that.

Note to self: update this posting if you find a better way to manage these mappings. I'm pretty sure Blackstone worked the same way.

Friday, January 28, 2005

Macromedia taught in High School

One of my co-workers noticed this in the Anne Arundel County (Maryland) Public Schools
2005-2006 "High School Program of Study"

One semester 0.5 Basic/Adv. Technology Credit
Advanced Web Page Design
Students will work with programs such as Macromedia Studio MX, which includes Dreamweaver, Flash, Fireworks, and Freehand to develop more complex web pages and web sites.
Prerequisites: Web Page Design
I think Macromedia should sponsor an official high school cirricula for their product lines. I'd really like to see some ColdFusion and Flash in there. Flex and java would be interesting, too.
  • Annual savings from carpooling: $1,200.00
  • Increased revenue on simple projects: $20,000.00
  • Being able to use your kids for slave labor: priceless.

Wednesday, January 26, 2005

More Identity Theft Offline Than Online

Yahoo! News - More Identity Theft Offline Than Online-Study

With friends like these, who needs crooks? Considering all the news that phishing is getting these days, you'd think the statistics would be different.

What can we infer from this report? Does that mean that current reasonable encryption and data protection strategies work for the most part?

Tuesday, January 25, 2005

Giant buttered cat array

Giant buttered cat array

I couldn't help but put a link to this up. Terriffic idea.

My research into cat based power systems involved copious quantities of masking tape on their paws. It seemed like it would work, but the cat didn't quite get off the ground.

Here's a link to the realtime experiment!

Monday, January 24, 2005

Overloading ColdFusion Constructors

If you've been holding your breath, waiting for overloaded methods in ColdFusion, stop. They will probably never be there. You'll wind up with a bad headache and a bluish complexion. Since the process that generally makes overloading possible is due to the language being compiled, cf would have to determine which function you were referencing each time it was interpreted. It would add a lot of overhead to the engine for a feature that has a workaround and is probably not in that great of demand.

If you're not familiar with method overloading, the concept is pretty straight forward. In languages that support overloading (like java), you can have two functions with the same name as long as they have a different collection of attributes.

function myFunction() {
do something here;

function myFunction(arg1, arg2){
do something completely different;

This won't work in ColdFusion. Each component can only have a single function with the same name regardless of the number and type of arguments passed in. Normally, this isn't that big an issue. Just give the separate functions different names and the problem pretty much goes away. There is one situation I run into almost everyday, however that benefits from an overloading workaround.

I frequently want to overload ColdFusion constructor functions. In many cases, you want to be able to create your objects in one of two ways. In some cases you want a new object that has all of it's attributes initialized to null/empty string/0. In other cases you want to create a new instance of your object and populate its attributes from your database.

As a rule, I don't use the implicit constructor technique that some people use to set up default values for their objects. They do this by putting initialization code in their component outside any cffunction tags. The code gets executed when the object is first created. The drawback is that there is no way to pass values to the newly created object. You can't easily create a new instance of your object with it's attributes populated using the implicit constructor.

Common practice now is to use a function called init() to create new instances of your objects. I actually call mine _init() since it makes the function name float to the top of the method list in Dreamweaver.

In most cases, I give my _init() function a single, optional argument that corresponds to the key used to pull the data from the database. Use a simple switch to check for the existance of the key and you have the basics of an overloaded constructor.

Here's an example:
<cfcomponent displayname="myComponent">
<!--- ==========================================================================
=========================================================================== --->
<cfproperty name="property1" type="string">
<cfproperty name="property2" type="string">

<!--- ==========================================================================
=========================================================================== --->
<cffunction name="_init" access="public" returntype="myComponent">
<cfargument name="property1" type="string" required="false">
variables.property2 = "";

if (isDefined("arguments.property1"))
<cfreturn this>
<!--- ==========================================================================
=========================================================================== --->
<cffunction name="_load" access="private" output="false" returntype="void">
<cfargument name="property1" required="yes" type="string">
<cfquery name="qMyQuery" datasource="#application.ds#">
WHERE property1 = '#arguments.property1#'

<!--- ==========================================================================
=========================================================================== --->

<!--- ==========================================================================
=========================================================================== --->
<cffunction name="getProperty1" access="public" output="false" returntype="string">
<cfreturn property1>
<cffunction name="getProperty2" access="public" output="false" returntype="string">
<cfreturn property2>

<!--- ==========================================================================
=========================================================================== --->


Thursday, January 20, 2005

Macromedia Names Stephen Elop CEO

MSN Money - US:MACR Recent Stock News: Investing

Congratulations Stephen. Here is my personal strategic/merger & acquisition suggestion. If you are looking at buying companies that can add value to your product line, take a look at Sourcegear.

I've been using their SourceOffSite package for years to provide remote source control features to VSS. What I'd REALLY like to see is the integration of their Vault product with Dreamweaver. Source control MUST be a part of any serious development efforts.

It seems like a pretty logical acquisition to me, although I have no idea what would be involved in merging the technologies.

Printing XML: Why CSS Is Better than XSL

If you've ever had the misfortune of working with xsl-fo, you'll appreciate this article.

I commonly use the @print and @screen directives in css to create completely separate printed versions of a page. Anything that is presented on your screen that you don't want to print you change to display: none; for it's style. Notice that in the example below, the main content section of the page is switched from absolute positioning for the screen to normal html flow for print.

@media screen
position: absolute;
left: 0px;
top: 0px;
width: 800px;
height: 110px;
background-color: #ffffff;
position: absolute;
top: 110px;
left: 225px;
height: 390px;
width: 575px;
line-height: 125%;

@media print
display: none;
line-height: 125%;
overflow: visible;
top: 0px;

Wednesday, January 19, 2005

PLPs are back stronger than ever

A few years ago, I had a taste of a product called Spectra. It was a very ambitious product with a lot of great thought put into it. For whatever reason, the product is no more.

One of the concepts that came out of Spectra was a thing called a PLP or Process Logic Path. You've seen PLPs before. They are basically a series of forms that guide a user through a task in several steps. They can be anything from the multi screen checkout process at Amazon to some government form with all it's parts.

These types of processes often present a challenge regarding how to control the user's path through the parts. How does the application respond when the user decides to use their browser's navigation instead of the handy buttons you provided them. Duplicate submissions and lost data entry are typical problems with these processes.

CF Components support this type of process very elegantly. You can create an object to hold all of the data you intend to collect during the process. If you then add your object to the session scope, it will persisit for the length of the users session or until you are done with it. This approach provides a nice benefit of reacting easily to browser based navigation. If the user clicks the back button on your third screen, the form on the second page gets filled in with values from your object that you saved when they left that page. Nothing, however, is committed to your database until they complete the process. At that point, the entire body of data can be stored.

This approach lets the user work on the parts of your process in any order they want. A simple test for existance lets you fire off the object constructor function in order to get started. As long as your constructor initializes all of your object's propeties, the user should be able to enter your process at any step and begin working. Of course if there is any required data, you will have to alert your user to anything they missed before they can complete their task.

One thing to watch: make sure the user has enough time in their session to complete their task. There is nothing worse than filling in 6 of 10 screens and having your session timeout. I tend to use really long sessions with garbage collection and j2ee sessions that end when the user closes their browser.

I'm working on a giant one of these on my current project. I'll post something here if I run into any performance issues (I'll make a note if I see smoke coming out of my workstation).

Tuesday, January 18, 2005

Moving away from FuseBox

I've never really been a huge fan of fusebox. I think most of it's benefits have been balanced out by it's problems over the years. With the cfmx component structure beginning to mature, I think it is now time to consider leaving fusebox behind.

I've had the pleasure of working in 3 fusebox shops in the past year. I'm currently in one now, but I'm not on a fusebox project. All three of the shops had implemented something less or different than the standardized fusebox. FuseDoc was used in only one shop, as were XFAs. None of them were even evaluating fusebox 4 yet.

I find some of the benefits claimed by fusebox somewhat dubious:
  • Increased productivity - I haven't really seen huge gains in productivity, even on large projects with thousands of templates. In many instances, I've even seen productivity losses, especially when it comes to debugging. Also fusebox makes the use of some of the productivity aids in Dreamweaver unavailable.
  • Increased code reusability - True, you tend to get greater code reuse than plain old coldFusion would provide without a dedicated strategy to write reusable code. However, components are even better suited to code reuse than fusebox. Not only can the code be reused, but extension provides even greater flexibility by allowing reuse of only parts of existing code.
  • Easier code maintenance - Again, component based architectures seem to have the code maintenance benefits of fusebox beat. By writing components that maintain their encapsulation (by using the variables scope instead of the this scope), changes to components can be made when needed. In many cases code that relies on the component being changed is unaffected by the component modification. Additional functions can be added without disrupting existing dependant code.
  • More productive team development - For some reason, all of the fusebox shops I've been in have been set up in a similar fashion. All the developers work off of a single development server using CFStudio as their editor. Some use source control and some don't (the shop that didn't use source control on a single dev box is just nuts). I like working on my workstation with a dev copy of cf and dreamweaver. That way I don't have to file a 5 part change request to get debugging turned on.
Another issue I have is that I like to use css positioning for laying out my sites. I have had very little success getting fusebox sites to play nice with the css features of Dreamweaver. If you've had better success, please let me know.

Also, running fusebox in a shared environment can be a problem as well.

I'll probably take a look at Mach-II, but I've heard that fuseboxers have trouble understanding it.

Follow-up post

Monday, January 17, 2005

Display private variables in ColdFusion components

One thing that can be challenging is not being able to see private variables with cfdump when your are debugging your application. Cfdump only shows information about public properties and methods (variables in the "this" scope). Any private properties are not displayed.

In order to support stronger component encapsulation, I use private properties for most object properties. If I find that as an application develops, I always need to add or change some of the funtionality in some components. If the properties are private, I generally don't need to change much of the code that makes use of the components. If you use public properties, changing the name of one of the properties almost always means you've just broken some code that relies on your component.

But the issue remains: It's harder to debug your application if you keep most of your properties private. You can't use the cfdump tag effectively since it won't display any information about an object's private properties.

Here is a little trick I've been using that helps this situation. It's not perfect, but it's better than nothing.

Put this method in your cfcs to provide some insight into your application:

<cffunction name="showPrivate" access="public" returntype="void" output="true">
<cfset metadata = getMetaData(this)>
<cfset privateVariables = structNew()>
<cfloop index="i" from="1" to="#arrayLen(">
<cfset structInsert(privateVariables,[i].name, evaluate([i].name))>
<div style="position:absolute;top:10px;left:1100px; z-index:500;">
<cfdump var="#privateVariables#">

In order for this to work, you have to make cfproperty entries for each private property you want to see in the declarations section of your component. In addition to supporting your debugging, you get entries made to support the cfcomponent browser.

To use this method, you do something like this:


If your object is using composition, the complex values will display like a normal cfdump. If you want to see the private variables of one of your sub objects, make sure you have a getter for the sub object and then you can do something like this:


This works easisest if you put the showPrivate method in a base component that your other components extend. Otherwise you have to add the same method to each component you want this functionality in (which kinda defeats the OOP process).

If I get a chance, I'll see if I can find a way to make this thing drill down into subcomponents. Of course if somebody else wants to finish it, I'd be happy to post your modifications here :).

Wednesday, January 12, 2005

CFLOGIN and CSS gotcha

This one had me looking for quite a while. I had done a quick and dirty setup of the cflogin process on an application. In order to log out my users, I put the bit of code below after my cflogin tag.

The idea was that I would use CSS-Positioning to place the little logout form on the screen when the user was logged in.

<cfif GetAuthUser() NEQ "">
<div id="logoutForm">
<form action="/appRoot/index.cfm" method="Post">
<input type="submit" Name="Logout" value="Logout" class="button">

Here's what I forgot:

NEVER produce output inside your Appication.cfm or OnRequestEnd.cfm files.

It will trip you up more often than not. Some people seem to get away with it, but I always seem to have trouble when I do this.

In the rest of the site, I used css positioning to place all sorts of things. Most of it worked fine, but every so often, I'd get a difference between IE and FireFox that didn't make senes.

What was happening: Becase I rendered my logout form in Application.cfm, it was appearing in the browser before the !DOCTYPE declaration. Since a doctype that isn't read as the first thing on the first line of a page is ignored, the browser gets thrown into quirks mode. Next thing you know, you've got a css mess on your hands.

To get around this problem, I simply replaced the output in Application.cfm with a variable that can be checked elsewhere in the application. I still use the base stylesheet to position the form as before. The code that checks wether the form should be displayed is now inside a file I include on each page that has some other boilerplate information.

Hmmm... maybe I better review the docs on CFSILENT.

A ColdFusion component snippet

Here is a code snippet I use to get my components started. Unfortunately, I've had to play with the formatting a bit to get it to display in this blog format. If anybody knows of a good code posting plugin for, please let me know.

<!--- *****************************************************************
Original Author: Mike Rankin
Original Date: 1/7/2005
Description: Basic component template. Modify this section to work with
your source control program. This is built for VSS.
$Archive: $
$History: $
$NoKeywords: $
****************************************************************** --->
<cfcomponent displayname="myClass" hint="Description of myClass" extends="components.base">

<!--- =============================================== --->
<!--- Declarations --->
<!--- =============================================== --->
<cfproperty name="aPrivateProperty" type="" hint="">

<!--- =============================================== --->
<!--- Constructor --->
<!--- =============================================== --->
<cffunction name="_init" access="public" output="false" returntype="" displayname="Constructor">
// initialize all propeties
variables.aPrivateProperty = "";
// test for overloading. If true, load object from db with a call
// to a db method
// _load(key);
return this;

<!--- =============================================== --->
<!--- Database Methods --->
<!--- =============================================== --->
<cffunction name="_load" access="private" output="false" returntype="void" displayname="Loader" hint="Loads myClass instance from database">
<cfargument name="key" required="yes" type="string">
<cfquery name="" datasource="#application.ds#">
SELECT fieldlist
FROM my Table
WHERE myTable.key = '#arguments.key#'

<!--- =============================================== --->
<!--- Operational Methods --->
<!--- =============================================== --->

<!--- =============================================== --->
<!--- Getters --->
<!--- =============================================== --->
<cffunction name="getAPrivateProperty" access="public" output="false" returntype="string">
<cfreturn aPrivateProperty>
<!--- =============================================== --->
<!--- Setters --->
<!--- ===============================================--->

Monday, January 10, 2005

Interesting poll

Check out the poll on Christian Cantrell's blog regarding browser usage. Very interesting.