Wednesday, October 10, 2007

DIAPER 101

I've had a number of requests to explain DIAPER a little bit more since my last post, so I thought I would put a few thoughts here.

DIAPER is just an acronym for the sections I'm using in bean/vo style ColdFusion objects. These sections are:

Define: this is just a group of cfproperty tags that provide basic documentation for the object's properties. cfproperty doesn't really do anything in a programming sense for plain cf components, so I wouldn't normally do these if I wasn't using some sort of code generator or I was planning on handing off the actual coding to someone else instead of doing it myself. They provide a nice place to do a little documentation that gets picked up by numerous cfc introspection tools.

Initialize: This is your typical init() function that you use to get your component instance started. Mine almost always just start off with a list of cfarguments that match the "D" section above with all of the properties set to be not required and with a default. Following this, all of the arguments are assigned to a structure called "instance" that is stored in the variables scope. Using a structure of property values instead of just putting them into the variables scope individually is just a way to make them a little easier to use with some inspection utilities that I tend to use.

Access: These are your typical getter/setter functions that you see in lots of cfcs to provide access to private variables/properties. With DIAPER, though, the setters are changed into a "set", a "test" and a "do". This is done primarily to support unit testing and provide a way to circumvent your business rules. The way this works is that in normal operation, we call the set function as we normally would. It then does two things: 1) tests the value that you are trying to set against any business rules you may have for this property. Normally, I use lots of regular expressions here and use cfthrow to bail out of the function if the value doesn't pass. This can also get pretty complex when you do things like compare values with other components and queries. Lastly, the "do" function actually sets the value. Also having the "do" function allows you to bypass your business rules which can really come in handy with unit testing.

Pretty simple, really, but I wouldn't want to code all of this stuff by hand if I can avoid it.

Sean Corfield made a comment about how he is using the new onMissingMethod feature of cf8 in his work now. I really like the idea of eliminating some of the clutter that all these methods tend to put in my cfcs, so look for a new template eventually that will take advantage of that approach in cfcBlaster.

Print is pretty much a developer tool that lets you spit out the content of the component quickly. It is akin to the "toString" methods you see in so many other languages.

Equals lets you test two instances of a component to see if they are equal to each other. I don't find myself using this too often, so I still am not sure exactly what the best approach here is. If you want to use it to see if you have two handles on the same instance, then I would suggest adding a guid property to your component that is populated when you creat your instance. Then you can just compare those values. If on the other hand, you have a need to check if two instances are functionally equivalent, then the approach of serializing your properties and comparing the values seems to work. This area could use a little more testing, especially when dealing with aggregates.

Run is used to return an instance of the component with reasonable values in all of its properties. This is a big help with unit testing or testing your aggregate functions where you don't want to fire things into your db. It's roughly equivalent to a method that provides you with a mock object which can be tricky to get right using some of the unit testing frameworks.

A few things to keep in mind. cfcBlaster does not do anything with aggregates. You still need to code those yourself. In the accessor section of my components you will see "add" and "remove" methods that handle those. They get used extensively in my DAOs to populate components retrieved from the db that have parent/child relationships. Note that one of the interesting disconnects between objects and rdbms systems is that I never represent a many-to-many relationship in objects. I'm always dealing with one side of that or the other, unlike how that would be represented in the db.

Another thing to keep in mind is that DIAPER is all about your business logic (ie, it lives in your model). It doesn't deal with presentation at all, so if your set up with an MVC framework, these objects don't deal with controller or view issues at all.

No comments:

Post a Comment