(CF) Eclipse RDS Plugins: First Impressions

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:
    <cfset var foo = 0 />
    <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?:

    <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?

    Comments
    Mark Drew's Gravatar hey cutter, well, you *could* decompile it but since that isnt part of the licence (as far as I know) it would be rude :) Even if you decompiled it and re-did the stuff in it, you would have to recompile it as a Eclipse plugin and put it back into Eclipse (ok, not that tough, but still)

    I dont mind people donating tickets, hotel rooms, conference tickets at all :) All very welcome to get me to MAX! I am always looking out for new features to add to CFEclipse, of course the ones that get the highest priority tend to be the ones *I* need :) And you are right about new features... some cool things are coming (after I get the beta to live status) in the upcoming releases (lets just say there is more working with CFC's and Projects ...)

    I think in Reactor you can change how it deals with MS SQL timestamps, I forget the location in the documentation but you can override how it handles any field (e.g.. setTimestamp and getTimeStamp)
    # Posted By Mark Drew | 7/26/06 8:20 AM
    Douglas Knudsen's Gravatar I put in a entry to the wishlist/bug tool at adobe http://www.adobe.com/cfusion/mmform/index.cfm?name... concerning the plugins. I suggested they use xml/xslt, like reactor does, to generate the CF code. This will make the tool immensly more helpful, eh? Could even package these cusomt xslts with frameworks and distribute them.

    go and hit the wishlist wiht it...enough developers request it...well you know the drill.

    DK
    # Posted By Douglas Knudsen | 7/27/06 12:13 PM
    Mike Nimer's Gravatar cutter, Glad you like the wizards and sorry they aren't perfect. I admit our goal was to help speed up the 80% side of the coding process. But let me try to explain some of your questions/compliants.

    First off there was a team developing these, so a few things like /> at the end of tags slipped through. But those don't change the functionality so it's still ok (no one said CF was xml compliant we just like to code that way ;)

    >Like the drop down that let's you select 'public' or 'private' for your 'Property scope:'
    This changes the scope of the variables "this" scope or "variables" scope. Not the scope of the methods. Although I do understand the mis-understanding. However in most bean patterns the get/set methods are always public.

    Also remember one of the biggest use cases was flex integration, and the CF->Flex bridge will only copy over variables in "this" scope or variables with public get() methods.


    >Bean have an init() method, while both the DAO and Gateway objects do not?
    Perhaps we slipped on this one, but you don't really keep instances of these "objects" around. The methods are used more like static methods - granted there is no such thing as static in CFC's

    >Hey, why is there a DSN hardcoded in to the cfquery statements
    These CFCs are generated from a datasource list of names already registered in the CFAdmin, we know the cf dsn name so we don't need a variable.

    Also this is a case of you can't please everybody all the time. So if you have a special way to define dsns in your code, instead of using the cfadmin. You will need to modify what we code. There are just two many ways that people like to define their "dsn", that it would be impossible to code it in a way that pleases anyone. (So we stick with the hard coded cfadmin name)


    >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

    Throwing exceptions and coding against exceptions - VERY EXPENSIVE and SLOW!. And since we know all of the properties why add the overhead of looping, exceptions, and such.


    >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

    If you notice in the create() method, there is the insert sql and a generic select, both use the same values. By calling the get() method once and re-using the variable the code is easier to maintain, and there might even be a small performance benefit if your get methods have any logic in them. It's a matter of call twice, or call once use twice.


    >And why do I get 'null=[bunchastuff]' on cfqueryparam tags of table columns that don't allow nulls?

    You shouldn't. Only table columns that are nullable should have the check. That is a bug. Granted we are basing it on what is returned by the JDBC driver, so some dbs maybe not give us this information correctly.

    >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.

    First, there is a getAllAsQuery() method so you have both options, return a query or "objects". But if you are coding in a OOP way you want to deal with objects - all the time, not just when it's convienent. And if you are coding a flex/cf app, this isn't as big of a hit as you think.

    Sure it can take some time to create all of the CFC's, but once you do and you send them to the flex client, users could spend the next 20 mins updating users and you never have to call getAll() again. Compare that to an html app, where calling getAll() everytime you reloaded a page to popuplate a select list, which does give you a noticable slowdown.

    For this, it really a matter of how you want to code. We give you 2 getAll..() options.



    Hopefully this helps clear some confusion,
    ---nimer
    # Posted By Mike Nimer | 7/27/06 3:36 PM
    Cutter's Gravatar Mike,

    Thank you for the clarification on this. I do realize this is kind of a sophomore effort on this, as well as a team project. These were just some first impressions. Minor detail items that I either didn't understand or just ate at me a little. Overall it is an outstanding addition, still saving me hours and hours of work, and I definitely think it is a welcome addition to the CF toolbox (Important To Note That: not just the Flex toolbox, but also the CF toolbox). I appreciate you chiming in with the Adobe point of view here.
    # Posted By Cutter | 7/27/06 4:18 PM
    Douglas Knudsen's Gravatar somehting I just learned too: don't try adding tools from this wizard to a project. I just did and it erased all my code!

    oops!

    thank the eclipse gods that eclipse maintains local file history!
    DK
    # Posted By Douglas Knudsen | 7/27/06 4:45 PM
    Mike Nimer's Gravatar No Problem, this seemed as good of a place as any to explain some of the logic in the plugins.
    # Posted By Mike Nimer | 7/27/06 6:59 PM
    Cutter's Gravatar Doug,

    Wow, can't say that ever happened to me. What? You ran the wizard on a table, specified your package directory, and 'zap', all gone? Which version/build of Eclipse are you running? Which version/build of CFEclipse are you running?
    # Posted By Cutter | 7/28/06 6:33 AM
    Douglas Knudsen's Gravatar I'm using eciplse 3.1 the WTP project and latest cfeclipse supporting 3.1. You know, wondering, are these wizards really a CFEclipse thing? They were released with Flex Builder only.

    And yes, it zapped the whole project...freakin waste of like 5 days of work that.

    Never trust a wizard Harry.

    DK
    # Posted By Douglas Knudsen | 7/28/06 9:20 AM
    George's Gravatar Update: After a quick read of the EULA from Adobe, it appears that I was being a little naughty by bundling them together. Hence the quick removal/update of the original post (anyone who got here first was lucky). That doesn't mean that you still can't have a cracking CF dev environment. The zip I produced was files taken from 2 sources: Eclipse 3.3 and the ColdFusion Extensions for Eclipse and the CFEclipse download section of the site.

    To download and install CFE follow the instructions here. To install the CF Extensions just:

    1. Download http://www.cfreport.org/eclipse/ColdFusion_Extensi...... and unzip on your desktop
    2. In Eclipse to o Help -> Software Updates -> Find and Install -> Search for new features to install
    3. Click on New Local Site...
    4. Choose the extracted folder on your desktop
    5. Click Select
    6. Click OK and then click Finish
    7. You'll then be asked to select the features you want to install. Select ALL checkboxes and click next
    8. "Obviously" read the Feature Licenses and the accept the terms
    9. The installation page is an overview of the new features you've selected, all you need to do is click 'Finish' to run the update manager
    10. The Adobe features will require you to install a signed feature, just click 'Install all'
    11. Finally, restart

    Thats it, you're now up and running. Your next two stops are the CFEclipse and Adobe's ColdFusion Extensions site. Also don't forget the reference section at the bottom of this post, espically Charlie Areharts list of over 70+ bloggers (part 1 and part 2)

    References:

    * CFEclipse.org
    * trac.cfeclipse.org for documentation, bug tracking and logging, FAQ's etc
    * CFEclipse Mailing lists
    * ColdFusion Extensions for Eclipse
    * Using the ColdFusion Extensions for Eclipse
    * CFEclipse bloggers list, part 1 and part 2!
    * Volkswagen rotors-
    http://www.dubautoparts.com/volkswagen-rotors.html...
    # Posted By George | 10/2/07 9:44 PM
    Cutter's Gravatar @George - thanks for the update.
    # Posted By Cutter | 10/2/07 10:32 PM
    BlogCFC v. 5.8.001 was created by Raymond Camden. Layout inspired by bluerobot.com., with some JQuery thrown in for fun.