On Code Generation

I just read Brian Rinaldi's article on building a code generator . He lists five steps to build a code generator. I think the article is a good one overall, but it inspired me to point out where I would (and have) done things differently.

His steps are as follows (quoted directly from is article):

  1. the Admin API in ColdFusion MX 7;
  2. accessing database metadata in varying RDMS;
  3. converting this data to a basic XML format;
  4. transforming your XML into code with XSL;
  5. the CFML code necessary to bring the first four parts together into a functional application. 

1. The Admin API in ColdFusion MX 7

Brian uses this to get a list of available databases. I agree that this is nice, but I don't think it is an essential part of code generation. If someone has to type in the datasource, that doesn't completely negate the value of the code generator.

If you choose to use the Admin API, however, you might consider running your code as an extension in the ColdFusion Administrator. If you run your code in the CF Admin and you use the Application.cfm at the root of the administrator (in CFMX 7), then you will have a variable called "variables.factory". This holds the Admin API - and without you having to know the username and password. I don't think that this is a security problem as someone had to enter to the username and password to get your code to run in the first place.

I will also add in that you can see an example of how to do this as well as how to get a list of supported datasources can be found in my CodeCop code checker program.

2. Accessing database metadata in varying RDMS

I agree with Brian that this is an essential step (though Peter Bell has some good thoughts on code generation and the limits of database metadata). The approach that he used, however, means that he has to write different code for each database. He could have gotten the same information by using DataMgr. A call to DataMgr's getDBTableStruct() would get all of the same information for any database supported by DataMgr (which currently includes MS Access, MS SQL Server, MySQL, and PostGreSQL).

3. Converting this data to a basic XML format

This step isn't necessary unless you want to use XSLT for your code generation (see Peter Bell's thoughts on XSLT code generation). Assuming that you want to use XSLT, however, DataMgr can help you out again. In fact, you can skip the previous step and just have DataMgr give you an XML representation of the table structure. A simple call to getXml() will return an XML string for that table. If you need to add more information to the XML, just use ColdFusion's built in XML functions to add data to the XML.

4. Transforming your XML into code with XSL
and
5. The CFML code necessary to bring the first four parts together into a functional application

These two steps are really the same for me. This is the "generate the code" portion of the process. No doubt essential (it is the point, after all). I have already mentioned that XSLT may or may not be the best choice

Let me just mention one other tool that may be of use if you decide not to use XSLT (which is a fine option). 

I have a small component (tag.cfc ) which can be extended to be an object representation of virtually any tag. I have already extended it for cfcomponent, cffunction, and cfargument (as well as some of my own custom tags). You can use it to generate code for virtually any tag. I don't want to imply that it is better than XSLT, just another approach.

Conclusion

I really liked Brian's article. It got me thinking about how I do things differently. I have been intending to work on my code generator again for some time (I actually use it for myself on most new projects, but it isn't quite "ready for Prime Time" yet). Hopefully I can work on that again as soon as I release DataMgr 2.0. 

UPDATE

Here is a handy link to Brian's response (so you don't have to copy and paste from the comment below):

http://www.remotesynthesis.com/blog/index.cfm/2007/1/17/Generating-Code-vs-Generating-Applications  

Technology Convergence

Ever since The ColdFusion Podcast first came out, I have thought that I would like to listen to podcasts about ColdFusion. Despite my intentions, however, it hasn't really happened.

The ColdFusion Podcast has been inactive lately (though they plan to start again next year), but ColdFusion Weekly has been brodcasting pretty regularly. In the past several months, however, I have listened to only one or two podcasts from each.

Basically, I am unable to listen to a podcast while I work because it is to distracting. If I am not working, then I am usually spending time with my wife. Since she is not a programmer, it seems rude to make her listen to a podcast about ColdFusion.

Ideally, I would listen to a podcast on the drive. A few things prevented this, however - an unwillingness to wear headphones as a drive and a lack of an MP3 player in the car.

Thankfully, a combination of factors has finally solved this. My wife and I recently went to NYC for a brief vacation. While there we picked up a new iPod Nano for my wife to replace her iPod Shuffle (at the Apple Store of course!). This means that I have an iPod Shuffle now (I love leftovers! - product of being the youngest siling, I suppose).

This summer we bought a new Honda Element (not so flashy as the Mini Cooper it replaced, but more useful and still lots of fun).

The Element has an auxillary input, the result of which is that I can listen to the iPod in the car while driving. I did just that today on my drive out to the post office. The drive was only long enough to get through about half of the most recent ColdFusion Weekly, but it was still really nice.

It really felt like I was just listening to a normal broadcast radio show on ColdFusion. In many ways, new technology has the same feel as the old. The major difference is that network radio is unlikely to cover ColdFusion programming, so niche markets are well served by technology that makes content production and distribution.

I look forward to hearing more of both podcasts in the future.

  

cfdiff

I have some custom tag sets that have recently started to fork into different versions - not good for easy of use or maintenance. I wanted to coalesce them into one master version (in hopes of releasing a beta soon). Unfortunately, unifying three versions of several files (some of them quite large) represented a bit of a task.

I started this task in my usual way, but opening up two versions of each file and going through them screen by screen. It didn't take me very long to think that my time was too valuable for such a boring task. It seemed like the sort of thing that could be automated. Then I remembered a blog entry by Rick Osborne about cfdiff - a tool to do just what I was doing.

I'll start with the bad news.

Not yet being an SVN person (soon! honest!), I found the Google Code page for cfdiff difficult to use. I really just wanted to download a zip like I can on RIA Forge (where I would love to see this project move).

I wasn't able to find any documentation for the project. I saw a screen shot of a really nice report on Rick's page, but I couldn't figure out how to produce it with his code. Without documentation, I was hoping to find an example implementation of the code (I find that often all I need). Of course, this means that I really need to look at some of my projects, like DataMgr, and add a file in the download with a bit of explanation. In my defense, I have the CFC docs and some presentations available.

Now on to the good news.

Although I am not yet an SVN person, I was able to put in the SVN url in my browser and download the files individually. It wasn't my preferred approach, but nor was it a major inconvenience.

A short look through the code, turned up the DiffFiles method. This method was easy enough to understand. You just pass in the full path for each of two files that you want to compare as well as the carraige return character (though it does have a default for this). It returns a query that you can dump on your page.

This wasn't as attractive a result as I was hoping for, but no less useful for that. It provides the line number for each file where a difference can be found. It has to provide two line numbers because it does a good job of identifying two lines as being the same even if they are in different line numbers in different files (due to differences earlier in the file). This made going through the files fast and easy.

It seems to always report the line after the last line as a difference. This isn't really a problem because it is easy to get used to. In fact, it is somewhat nice because if you get an empty query, you can bet it wasn't able to find one of the files.

All in all, cfdiff saved me a lot of time and found differences that I may have missed had I tried to compare the files by hand. 

ColdFusion Coding Rules

Now that the first code checking application has been reviewed, I though it would be a good time to discuss the rules themselves.
For my entry, I just put together a few example rules. I looked to rules I would want to check for and turned to the list of rules for ActiveSoftware's CF Code Review Tool for inspiration. Mostly, however, I just tried to put together a few rules to demonstrate some of the capabilities of the tool.
Now that Ray has had a chance to review it, I would like to put together the first public beta as soon as I get the chance. In order for the tool to be realy useful, I need to have it start with a good list of coding rules.
To that end, I would love to get suggestions on what rules people think that a tool such as this should use (keeping in mind that the tool will allow you to add others as you see fit or have it not check for rules that are included).
To get the ball rolling, here are the rules that I included in my entry:

  • Don't use a relative URL in cfschedule
  • Use the accept attribute when uploading a file
  • Avoid Evaluate()
  • Don't start includes with /
  • Avoid shared scopes in CFCs
  • Prefer StructKeyExists() over isDefined()
  • Prefer Len Over Empty String Tests
OK. That is the list as it stands now. I think it needs to be expanded and improved.
Who's first?

The Joy of CFCs

A few years ago I started a project that I knew would likely be the largest I had yet attempted. The project would also be my first on ColdFusion MX, so CFCs seemed like a good tool to keep my code organized.
As it was my first project with CFCs, I had no experience with how best to utilize them. I read about objects and design patterns. Reading, of course, doesn't substitute for experience. Still, I have been happy with the result overall.
This week, as I was changing some functionality per some new requirements, I discovered that I had written one piece of functionality three different times in three different CFCs (talk about violating DRY!).
I changed the constructor (well, the init method) of two of the CFCs to pass in a third. I was then able to call the functionality from one place. This change in code in the CFCs didn't change the methods or arguments in the CFC except the init method. The result is that I didn't have change any of the code throughout the application that relied on this functionality.
Basicaly, I kept the API the same and so I was able to change the guts of how my logic worked without needed to change any of the code that used that logic (of which I had a lot). I could do this because I had used CFCs in a well-encapsulated way and had maintainted the API of the CFCs.
The point (if there is one) is that if you are thinking about using CFCs but you are worried that you don't know enough to take full advantage, I would encourage you to go ahead and give it a try. Even if you don't use them correctly, you will probably be ahead by using them. I have been.

In Defense of CFCs for Output

A just read a comment arguing against output CFCs as more difficult to maintain than Custom Tags. As this differs somewhat from my experience, I wanted to explore the idea.

In a comment to blog entry by Terrence Ryan, Sean Corfield said that he thought designers could edit Custom Tags easier than CFCs. This because they could use their WYSIWYG editors on the custom tags.

I agree if the output is limited to a small widget. If the output is the for the layout (the overall design) of the page, however, I would disagree.

My problem with using Custom Tags for layout comes from the need to have different parts of the design in different custom tags (or using an awkward "action" attribute).

Using Output CFCs allows me to have the layout in only one file - which just like an HTML file of the design (once you ignore the cffunction tags - easy to do). This is easy to edit for anyone that knows HTML. For others, you could save it as a .html file for WYSIWYG editing and back again (though I have yet to have that need).

This is far outweighed by the advantages of this approach. Among them having all of the layout in one file, the ability to easily switch between different layouts, the ability to easily switch to different output formats (PDF,Word,etc), and the ability to easily gain control over the <head> for any page.

Since I am too lazy to rehash these benefits completely, I will just point you to my article on Handling Layouts with Components. Feel free to download some example layout components as well.

Note that if you are worried about the performance implications of this approach, Terrence Ryan's blog entry covers that pretty well. Of course, he isn't using the exact approach that I am, but I think the point remains valid.

Preview of New Code Creator

Recently, a few ColdFusion programmers have written code generators. I was pretty excited about this until I realized that they don't write code the way I write code. I figured I wasn't the only one to want code generation "my way".

So, I started work on a code creator that would write code however you want it. The code creator provides a wizard and tools for creating a code generator. The generator is a cfc that extends a provided Generator.cfc. Each generator would take the information from the wizard and creates code from it.

Keep in mind that this is just a preview at this point. That being said, feel free to take a look and give me any feedback.

http://www.bryantwebconsulting.com/clients/generator/

I know it still needs plenty of work, but I am curious if this is something that others would find useful and what improvements other see that it needs.

Things I know that I need to add:

  • The ability to select the type of form field based on the datatype.
  • Limit the length of the form fields based on the length allowed in a column.
My hope (perhaps idealistic) would be that we could get some generators to create code for the different popular frameworks. This would make it more generally useful and provide another means of learning and comparing frameworks.

Incidentally, I am currently calling this "Configurable Code Creator", though I am not committed to that name, so I am open to suggestions.

This code is built on several other tools on which I have been working. Namely sebtags, DataMgr, and tag.cfc (now in version 0.2). I hope to write more about each of these in the future.

Platform Independence with Java

One of the great things about ColdFusion is that it works the same on any supported platform. Still, some things are always different. Carriage returns and directory separators are different based on your OS. Fortunately, you can use Java to bridge the gap.

Directory Path Separators

Windows uses "\" to separate directories but other operating systems use "/". Java, however, will tell you which one is used by your system.

<cfset fileObj = createObject("java", "java.io.File")>
<cfset dirdelim = fileObj.separator>


Now the "dirdelim" variable will hold your directory delimeter ("\" for windows and "/"for other systems).

Carriage Returns

Carriage returns (end of line characters) also vary based on the operating system (Mac uses character #13, Linux uses #10, Windows uses #13 followed by #10).

Until recently I handled this like so:
<cfset cr = "
">


This has always worked, but has always felt a bit ugly. It also sometimes threw off the color-coding of my editor.

After I uploaded XmlHumanReadable, I got an email message from Fabio Serra suggesting a better technique.

<cfset
cr = CreateObject("java","java.lang.System").getProperty("line.separator")>

Much like the directory path separators, this returns the carriage return character for your operating system.

Summary

If you take advantage of these Java commands, your code can be easily ported between different platforms without worry.

I am sure there are other simple Java commands that can make our lives easier. If you know any, I would love to hear about them.

My First cflib.org Submission

I have been a fan of cflib.org for a long time and I have used countless UDFs from that site. Today, I posted my first submission - XmlHumanReadable.

We'll see if the submission get accepted, but I am pretty excited by it. It takes an XML Document (or string) and returns the XML in a format that is easy to read (properly indented so that it is easy to follow). This can be useful if you need to examine the contents of a WDDX packet or other XML string.

An Example of XmlHumanReadable in Action.

UPDATE!

XmlHumanReadable is now available on cflib.org:

Download XmlHumanReadable.

Using argumentCollection with Super

I recently had the need to use argumentcollection with super. Unfortunately, super can't be used with argumentCollection or with named arguments (which would allow me to loop through a structure and set arguments with cfinvokeargument).

Fortunately, I found a solution in the comments of the ColdFusion LiveDocs. As pointed out by "eblackey" (on "Using inheritance and the Super keyword"), if you copy super to this.super, you can then reference methods of this.super using argumentCollection or named arguments.

Adding this line to the pseudo-constructor (anything within <cfcomponent>, but not inside any method - that is not in <cffunction>), will copy super to this.super.
<cfset this.super = super>

Then, when calling a method ("myMethod()" in this example) of super from a method in your component, you can do this to pass all of the arguments of your method to super.myMethod:
<cfset this.super.myMethod(argumentCollection=arguments)>

Note that you won't be able to call private methods from this.super. If you have a constructor that is called when you first instantiate a component (an init method, for example), you might consider copying super there instead of in the psuedo-constructor so that you only make the copy when the component is instantiated and not every time that it is called.

This workaround solved the problem for me. I just started using it, so I will post again if I run into any trouble with it.

Until then, good luck!

UPDATE

This problem exists in ColdFusion MX 6.1, but not 7. See the following link for a related bug in CFMX 7:
http://ray.camdenfamily.com/index.cfm/2005/10/27/CFMX-7-and-Super-Fixes

Thanks to Brian Kotek and Sean Corfield for correcting my oversight.

More Entries

BlogCFC was created by Raymond Camden. This blog is running version 5.8.001.