OK, been quite a few posts out there, within the CF community, about how you can download the ColdFusion RDS plugins for Eclipse (Well, CFEclipse). Now, if you have Flex Builder 2.0 then you already have it. At least I think you do, it might be an option during install, but either way it's available to you with Flex Builder 2.0. But, you can also go to that first link in this post to download it by itself. Install is pretty cut and dry, but you kind of have to search a little to find out what to do next.

First things first, go to your Window|Preferences, select the new RDS Configuration option, and fill in your server's details. Once you've done this you can go to Window|Show View|Other, expand the ColdFusion option, and select RDS Dataview. Depending upon where you put your 'views' panel (mine's at the bottom, which I think is the default) you will now find the new tab. Expand the server, expand a database, expand 'Tables', right click on a table and select ColdFusion Wizards > Create CFC.

OK, let me give you the good news up front. This wizard will allow you to automatically create Bean, DAO, and Gateway CFCs for your table (anyone remember Sean Corfield's Data Persistence Session at CFUnited?), saving you hours of coding work. The bad news? They aren't perfect, and will require some tweaking on your part.

"Cutter, they were gonna have to be tweaked to begin with anyway, right?" Well sure they were, but they could have been a little further along from the start. I'm not going to lay out all of my grievances here, I'm still really excited to have this to begin with, but I do want to throw out some of the things I really thought could of, should of already been here:

  • Consistent Coding Style
  • This wizard generates three different CFCs, with very different methods and approaches (even within the same files). It's just me, but coding consistency is important. It makes code easier to read, follow, and maintain. So why is it that, in certain places, a cfset tag will have the xml closing style, while in others it will not:
    view plain print about
    1<cfset var foo = 0 />
    2<cfset var foo = "this one">
    This is all over the place in the generated code, even in the same template (or function block). There are even inconsistencies in the code indentation (another necessary thing for code readability).
  • Odd Wizard Output
  • Like the drop down that let's you select 'public' or 'private' for your 'Property scope:' Let me tell you what I expected and what I received. I thought that, in selecting 'private', all of my setter methods within the Bean would have an access type of 'private'. But that didn't happen. In fact, I don't think it affected anything at all (as all of the methods are 'public' on generation.)
  • Odd Code
  • I know that a team of developers probably built these extensions, but who would have thought that they could all be so different? For instance, why does the Bean have an init() method, while both the DAO and Gateway objects do not? "Well, Cutter, maybe it's because the DAO and Gateway don't have any properties?" No, that can't be it. The DAO and the Gateway objects both have database calls, so they must have a property for the datasource name, right?...Hey, why is there a DSN hardcoded in to the cfquery statements? Doesn't make for a very portable object, does it?

    Within the DAO objects: In the read() method, why doesn't it just loop the returned query's columns with 'set' statements, rather than writing each one out line by line? Wrap it in a try/catch, with an empty catch, and it'll skip any column that doesn't have a matching setter method without causing a hard error or interrupting the flow (There does appear to be a good reason for not doing this, but that's another item you'll see below.)

    And what about that create() method? Pass in a bean object, set variables with the value of the 'get' method of each property, and then pass the variables themselves in to the cfqueryparam value attributes (having the server evaluate that variable in the process [not to be confused with evaluate()] Why waste the steps?:

    view plain print about
    1<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.bean.getFirstName()#" />
    The funny thing is, that is how it's done in the update() method.

    And why do I get 'null=[bunchastuff]' on cfqueryparam tags of table columns that don't allow nulls? I don't get that? The Wizard is already reading the table's metadata to give us the column name and data type, it can't get whether it's required?

    And why do I have to pass in a Bean object to my delete() method? All it needs is the ID and it's all set, why waste the memory to allocate for a whole object?

    And then we get to the Gateway. Here's a 'GetAll()' method, that returns the ID of all records from the table and loops through the recordset to create a bean object instance for each record, placing the beans in an array. Whoa Baby! What's up if you have several thousand records in that table? "Hey man? Why'd my RAM utilization just go through the roof?"

    OK, so maybe I'm bitchin' too much. Or, maybe, these a several small points. Why doesn't the the read() method in the DAO loop the columns and dynamically create/fill the new bean? Because the data validation is directly in the set() methods of the Bean. Now, I would put these things in a validate() method of the Bean, which is always called prior to the 'save()' method of the Gateway, but that's my preference. Just like I would rather pass a struct (like the 'form' scope) into my create and update methods, rather than an actual Bean object. A matter of preference.

    So, if my Java skills were greater, and you could decompile a .jar and .class files (Which I don't think you can, last I checked, but Mark will set me straight I'm sure), then I'd try to make the changes myself. But, that's not possible, so I guess I'll forward this post on to Adobe for a possible update (as soon as I figure out who to send it to). It would be nice if there were some sort of XML file one could change, in order to create our own preferential style of code, but that's probably asking for too much. Maybe a consensus on developer's views of several "Best Practice" implementations? Or maybe Adobe should just give the current code to Mark Drew, pay him some dough (that'll get him to MAX, an expensive trip for him when he doesn't get paid for continuing development on the tool we use everyday), and have him find out what we'd like and code it? (Side caveat: I am not saying that Mark would. I'm not his booking agent, nor his headhunter, nor him, so I'm just offering that as a possible solution for Adobe to consider. I would not expect Mark to work on any feature of CFEclipse that he hasn't put on the radar himself as an item of priority [and I know he's got some really cool stuff on that radar], or if he were getting paid to do so [which would only benefit us in the end as well].)

    (He's gonna kill me now...)      ;)

    But, overall, it's a great first step. When I ran it through the paces this weekend, using the Wizard on only nine tables in less than 5 minutes saved me hours and hours of tedious, repititious coding. Sure, I had to tweak it a lot, but it still cut my workload by more than at least two thirds by doing these common tasks for me. And, unlike Reactor, I can see all of the code the wizard generated for me and adjust it directly to my needs (run an MS SQL timestamp field by Reactor and see what it does for you). I can now take my CFCs and plug them in to a Model-Glue app, a Mach-II app, a Fusebox app, or just roll them in to my own architecture (Hey, where did that link go to?) if I wished.

    What do you folks think? Have you played with it yet? What's your take? How would you do it differently?