See the link below for the files I created at last night's Denver CFUG. As they are now, you'll need ColdSpring installed to run index2.cfm. You can simply uncomment out the 3 lines in the PersonService.cfc init function to revert back to the non-ColdSpring version. Then the index.cfm file should work.<br /><br />These files are similar to the Person Address example I did back in May.<br /><br />Thanks to all those who came, asked good questions and helped troubleshoot my errors (again, the errors were on purpose and meant to be a way to help those attending learn). :)
I meant to blog this earlier, but I will be presenting at the Denver CFUG tonight. It starts at 6:30, but I probably won't be on until about 7:30. I'm hoping to cover quite a bit regarding Beans, DAOs, Service layers and ColdSpring. It is quite ambitious, but will hopefully get some people interested and more familiar with all of the above. It will definitely be very code-centric because I haven't even made any slides.
The best part is that there will be pizza and cookies. So come one, come all to the greatest show at the University of Denver. There are already more than 30 people RSVP'd, so it seems there must be a bit of interest in the topic at hand.
See you there.
If you're a CF Developer, it seems that the jobs are plentiful. However, it does seem that the majority of employers want people who are familiar with the OOP style of applications. Mutiple job posts on Ben Forta's and other blogs lead me to believe that finding experienced developers is getting difficult. I think part of the problem is that those developers who are familiar with OOP, frameworks, etc. are pretty well rooted and aren't ready to up and move across the country. So the next step will be for the companies to start looking at allowing more remote work to be done.
Personally I only started to learn OOP in my spare time less than a year ago. I then started using it at my primary job. To help myself learn I joined some email lists, started listening to the podcasts and reading the blogs, and just asked questions. I have found nothing but helpful answers from the ColdFusion Community.
What has been fascinating is that without even looking, but with simply making my presence known via the lists, commenting on blogs, and the occasional goofy call-in to a podcast (yes I'm the Matt Williams that thinks/pretends MS Word is a good IDE on CF Weekly) , employers have been finding me. These employers say they are having a hard time finding help from people with OO and/or framework experience. These employers have already decided that a remote contract worker can be beneficial. It seems that these companies mostly like that I am learning and desire to write better code, not that I have been creating reusable components since the launch of CFMX.
So the point of this post is to encourage others to spend some time learning. Many people learn best by example. So download sample code (see Sean Corfield or Brian Kotek or Ray Camden) and check it out. I found code from both of them to be quite helpful But the best thing is to build something. Build Anything. Build a Hello World app, add a form to customize the greeting, whatever. To paraphrase Nike, "Just Code It."
So Hal wrote an article that ties to the "GroupThink" podcast i discussed in my last blog entry. Thanks to Dave Shuck for pointing this out to me. I also noticed Trond posted about the article on his blog.
The title of the article is misleading: "Creating Object-Oriented Presentation Layers". Although he promises to have a follow-up article where he will go into just that, this initial article explains more of the difference of "Real-OO" versus "Pseudo-OO" (ROO vs. POO?). My understanding is that the main difference is in how we think about objects in our application. Hal discussed the basic shopping cart example and showed how the POO-er would concentrate on the data aspect whereas the ROO-er would think about what services the Shopping Cart object would offer.
Thinking about objects in terms of services they provide make me think that the Service Layer I have been using - that which I learned about from others - makes even more sense. A ShoppingCartService will have functions like "addProduct()", "clearCart()", etc. And if it has a "saveCart()" function that requires persistence beyond the session, then I would still use a Data Access Object to write that cart to the database.
In the article Hal admits that "we must make the objects created from these classes persistent. DAOs and gateways are one way to do this...". And he continues on to caution that DAOs and gateways should be "subservient to an OO design." I totally agree and am glad he put it this way. We should not spend all of our time focusing on data persistence objects such as DAOs and Gateways. But it is important to understand them and be able to write them. Once you do though, using code generators or tools such as Reactor can help make that data persistence "subservient" to your OO application. In fact, if you use Reactor, all you worry about is the Service Layer (at least for the model).
In the beginning of the article, Hal talked about the difficulty of making the transition from Procedural Programming to Object Oriented Programming: "so hard, in fact, that many never make the transition." I want to encourage people looking to make this transition to read Hal's article. Also spend some time learning what a DAO and Gateway do. But once you have that concept down, think about your application in terms of what services it will offer. Then begin to use those DAOs and Gateways as slaves to the service layer accomplishing the dirty work (i.e., data persistence) behind the scenes.
Thanks for sharing Hal. I look forward to your Presentation Layer follow-up.
Wow. It's been almost a month since my last post. The title of this blog entry came to me after listening to Helms and Peters Jun 4 Podcast titled 'GroupThink'. Hal cautioned us against following the group mentality of "This is how everyone else is doing it, so it must be right".
Personally, I feel quite guilty of this. I am not an OO Programmer, I just play one on the internet. From the podcast, I understand Hal to be saying that there is a lot more to OO than just writing beans, DAOs, and gateways. He says while they may be necessary, they are mostly just grunt work. According to Hal, what I have been doing is better classified as "Pseudo-OO" (POO). Jeff Peters joked, "Dude, your code looks like POO."
So what are we to do? Abandon all these concepts? I don't think so. I believe that the beans, DAOs and gateway along with a Service or Facade object does make sense for a lot of web applications. These CFCs generally exist for the simple purpose of getting information to and from a database. And at least for the application I am working on, that is about all I need to do.
My company has customers and sells stuff. Our customer service department needs to view, add and edit information about the customers and their purchases. How else can I write this app other than to get the info from the db, present it to the user in a form, and record any changes back to the db?
The podcast has definitely made me think (hence this blog entry), and I believe that was the main purpose. What will it take to before I can consider myself a real OO programmer? I have no idea. Perhaps I'll need to do a mind-meld with my brother who has been programming Java apps for several years. For now I'll call myself a CFC Programmer. This is probably more appropriate since ColdFusioin is missing so many real OO pieces (Interfaces, constructor, etc.)
I believe the real point here is don't be satisfied with "good enough" or "it works so it must be right". Using these data persistence CFCs is just the tip of the Object Oriented Programming iceberg. What's underneath the surface is yet to be seen. I think that learning more about Java and Design Patterns would be a next step. However, I really think that Jeff and Hal just want us to spend more time thinking about, tinkering with and pushing the limits of ColdFusion.
I highly recommend listening to this podcast. I'd love to hear other thoughts about this too.
I'll be giving a presentation at the July Denver CF User Group. There I will cover how I created and used the Service, DAO and Bean CFCs from my blog post last week or so. This will be my first speaking engagement on anything CF related so I'm excited. So if you are in the area, I encourage you to come on down. I would also recommend coming to the June meeting at which Rob Rusher will give an introduction to CFCs talk. I plan to go to that so I can see where he leaves off and pick up from there.
For more info, go to the Denver CFUG Web Site.
Here is some info on the database included with the sample files from my previous blog entry.
I don't yet have any SQL scripts for MySQL or SQL Server, but for anyone who can't get into MS Access, here is the list of fields for each table. You can enter whatever data you would like, just be sure to put a date into the LastModifiedDate fields as I think it breaks without it.
PersonID - int, primary key, autonumber/increment
FirstName - varchar, 50
MiddleName - varchar, 50
LastName - varchar, 50
Gender - varchar, 2
YearOfBirth - int
Username - varchar, 50
Password - varchar, 50
LastModifiedDate - date/time
AddressID - int, primary key, autonumber/increment
PersonID - int
AddressType - varchar, 50
CompanyName - varchar, 50
JobTitle - varchar, 50
Department - varchar, 150
AddrLine1 - varchar, 150
AddrLine2 - varchar, 150
City - varchar, 50
State - varchar, 50
Country - varchar, 50
PostalCode - varchar, 50
Phone - varchar, 50
Fax - varchar, 50
Email - varchar, 150
LastModifiedDate - date/time
Here are some sample files to demonstrate a basic Service layer. The PersonAddressService.cfc is a basic API (Application Programmer's Interface) for various database objects. These files emulate the simple idea of a Person table that links to an Address table (one Person can have many addresses).
To run this, you will need to unzip the files into a directory you can browse to. You'll also need to set up a datasource pointing to the MS Access database. If the Access file prompts for a username and password, the username is administrator and the password is blank.
I generated the DAO and Bean files using the Eclipse RDS plugin wizard. Some code generated by this doesn't seem like best practices, but is functional. In general there is a lack of comments in all files. I wanted to get the files posted as soon as possible.
The only file that does any output is index.cfm. It simply gets a Person and outputs his name and addresses. You can uncomment some code that will emulate Form fields coming into the page and doing an update on that Person. I have not gone as far as doing a Create (Insert) or Delete.
See below for download link.
I have started (and hope to finish within the next couple of weeks) a bit of a guide that will walk you through the basics of Object Oriented Programming with ColdFusion. It will include some terminology explanations, how I wrote these files, and details of what is really going on in the code.
I also want to show how this basic set of CFCs can be cleaned up and better managed with ColdSpring and Reactor. And if ambition really takes off, I could show how this 'Model' can be plugged into Model-View-Controller frameworks such as Model-Glue and Mach-II.
Leave a comment if you have any problems or have any questions with these files.
I'm working on a set of CFCs that is the basic idea of a Person that has multiple Addresses (simple database with 2 tables: Person and Address). Because there seem to have been quite a few questions (on the CF-Talk, Model-Glue, etc. lists) regarding Service Objects lately, I'll try to post this as sample code this weekend. I probably won't do a full app, or even tie it to a framework. Instead, there will be a simple cfm file that makes calls against the Service CFC.
The first iteration will be standalone, but a ColdSpring version may follow as I feel using ColdSpring makes implementing a Service layer much cleaner. And if anyone is interested, I could demo how this can tie into Mach-II or Model-Glue.
If anyone has any suggestions or ideas for this type of sample code, please leave a comment.
So I attended the AOP session that Chris Scott did at cf.Objective(), but I must have had a bad atte
So I attended the AOP session that Chris Scott did at cf.Objective(), but I must have had a bad attention span since I couldn't get it. Luckily though, Chris has 3 great tutorials on his blog that I was able to read through and get a better understanding from. The easiest way to get to each tutorial is look in the archives. The intro is in Sept. of 2005; Tutorial 1 is in October; and Tutorial 2 is in November.
I have a part of my app that I thought could use AOP (Aspect Oriented Programming). Basically there are numerous places that if specific data has changed, then someone wants to know about it. The currently used legacy app just has a bunch of cfifs and cfmails to handle this. Just now I set up a 'Notification Aspect' that when applied to an Update function, will see if the changing data meets the criteria for someone being notified. If so, it will log the change into a table.
The only problem I'm having is that I don't feel my Notification Aspect is abstracted very well. The tests to see if the changed data needs to be logged into a table are pretty specific. The 'before advice' I'm using now will only work for one possibility. I suppose I could do a switch statement that is based on the target and do different tests based on that. hmmm, back to Eclipse...
In most Data Access Object (DAO) examples I've seen, the Read function gets the data via a query, then populates the Bean by calling the init function and listing all the fields for that table. I didn't like this because this adds one more place to change if the table gets a new field. Plus, in a table of 30 or so fields, listing those out just looks ugly, even if you use a code generator.
So I did the following to dynamically create a structure of all the table columns and their value (we're only talking about 1 record here).
At the top of the function... <cfset var struct_Params = StructNew() />
After the query...
<cfloop list="#var.qry_Read.ColumnList#" index="col">
<cfset var.struct_Params[col] = qry_Read[col]>
Then just use argumentcollection to pass the struct to the bean's init function...
<cfset arguments.myBean.init(argumentCollection = struct_Params) />
This way, if a new field is added to my table, I should only have to add the getter/setter to my Bean, the setter call in the init function, and any possible changes to View pages.
The event-bean term in Mach II allows you to create an object in the mach-ii.xml file. It pulls any url or form variables and will put them into a bean object if the getter and setter are defined. I was using this before doing calling the read function in my DAO, but have changed my mind.
My Mach II code looked like:
<event-bean name="obj_PersonBean" type="myApp.model.Beans.PersonBean" />
<notify listener="PersonListener" method="getPerson" />
...other stuff and the view thing...
The person listener then passed the obj_PersonBean to the PersonService.cfc using event.getArg('obj_PersonBean').
In my quest to make my the Service Layer more independent of Mach II, I decided to take out the event-bean creation in Mach II, and let the Service Layer handle it. Now my Listener just passes the Primary Key which gets into the event from the form or url. The service cfc now takes the Primary Key as an argument instead of the object. The Service layer already has the PersonBean as an object courtesy of ColdSpring Dependency Injection. The getPerson function just runs the init, passing in the Primary Key. Then the Read Function of the DAO gets the rest of the data and populates the rest of the object.
Now I need to do something similar to my update Events which still have event-bean. I guess I'll have to pass in event.getArgs() to the Service.