By Peter Bell

When to Make your Own Types - a Nice Introduction

It isn't new, but this PDF from Software Magazine provides a nice concise view of some of the benefits of what I call custom data types.

Unfortunately, implementing these in ColdFusion is a bit of a pain only due to the cost of object instantiation, so my best solution to date is to "hack it" using a DataTypeFacade singleton and getting my business object to delegate most property specific actions to that facade which in turn calls the appropriate data type (so I have singletons for DateTime, SSN, PhoneNumber, etc.). That works pretty well in practice.

How do other people implement custom data types in their CF applications?

[Why a facade? Because I don't want to have to inject 50 different data types into each transient business object - I feel it is cleaner to just inject a single facade - especially while my API is still settling down.]

Comments
Could you edit the baseCFC class in ColdFusion to implement custom data types? Just a thought, it may be a stretch.
# Posted By Aaron Roberson | 5/25/07 4:20 PM
Steve McConnell's Code Complete also offered a pretty good discussion of this (but, I know you knew that - just in case someone else wanted to know) =)

I haven't really thought about why I don't do it in CF as I might in Java, but this might go back to my post some time ago at http://www.codeodor.com/index.cfm/2007/1/15/More-c...

I was speaking generally there about creating more classes in other languages (like Java) than I do in CF, and speculated it was because 1) I've developed bad habits in CF, 2) the performance issues in the back of my mind, and 3) CF is just more expressive and has less need.

The part I didn't think about were the small "types" that you might just want for documentation and encapsulation purposes. I realize that's what a class is too, but as long as we are making a distinction, I'll settle on "type" to mean things (I assume) most people wouldn't think to create a class for, like geographic coordinates, or age, or perhaps x,y point on a plane if you weren't creating a graph/geometric library (of course, if the focus of your application included any of these, you WOULD probably think to create a class for them, but if they were only there incidentally, you probably wouldn't).

So with that in mind, I'm just going to throw this out there, and see if it sticks. It's not something I've given a ton of thought to, so forgive me if its heretical (I think it is, but since I try not to be religious about code/technology related things, I have no problem throwing it out there)

I wonder if its as beneficial in dynamic languages as static ones (or even in static ones with the tooling we generally have available). Certainly we get a good degree of documentation by simply choosing good variable names (this is not limited to dynamic languages of course). On top of that, if you need to change the representation (say from int to string or float), you don't have to go all throughout the application changing the type everywhere (in fact, with refactoring support nowadays, this isn't even all that bad in static languages anymore).

So, two of the big reasons for going ahead and creating the type aren't really issues. The only big issue I immediately see remaining is something like, as Fowler mentioned, needing to store not just an integer age, but the number of months as well. Of course, this is doable by using floats, but should you actually want to store it as two integers (one for numYears and one for numMonths), then you run into a problem.

But for me, I think YAGNI is in order. How often does that happen? Enough to justify doing it for every conceivable type? I haven't been burned (that I've noticed, anyway) by not doing that, so until I see otherwise, I'll probably stick to not creating the types. When I see that I'm doing a calculation in 2 different places, and that it is not localized to one class, then I'll go the full abstraction route and create a type/class for the offending code. Even then, I may just choose to use a mixin, but maybe not.

I certainly see the value in doing as Fowler suggests, but I also see value in YAGNI (and I think I see more value in YAGNI). You just REALLY have to follow it - my policy is that the first sign of duplication that is not localizable to one class probably means you ARE going to need it.
# Posted By Sam | 5/26/07 9:51 AM
I find that I get a *lot* from custom data types. I use them in a fairly non-standard way as a core unit of reuse of functionality. I give all of my properties methods like displayValue(), displayField(), inputtoValue(), asSQL(), and validate(). So, for a currency, displayValue might be '$' & numberformat(value, "99.99"). displayField() displays a calendar dropdown for a date and three boxes for a phone number. inputtoValue() takes the three fields for a phone number and automagically concatenates them into a single value. asSQL() is smart enough to handle the pre-processing of values to be able to save them into a SQL db, and validate() handles any validations.

I actually implement tis using a datatype singleton and a set of singletons - one per custom data type, but the power and DRYness of this just rock. It is how I get something like Djangos custom data types and I couldn't imagine writing web apps without this now - even if it breaks MVC (or extends it by suggesting there are four core things - Model, View, Controller and Datatype).
# Posted By Peter Bell | 5/26/07 7:17 PM
"I use them in a fairly non-standard way as a core unit of reuse of functionality"

Out of curiosity, what would be a /standard/ way? (I ask, because I thought that /was/ the standard way =) )

As for the rest, I see your point, but I've gone a different route. It seems like the purist in me would say, each individual property of an object should be an object, and the view (for instance) should Tell (Don't Ask) it to draw itself. But, (and correct me if I'm wrong), you've got (what seems to be) a data type datatype (if that makes sense), where you might call it a service, telling it to draw_a_field_for(the_value_of_some_property_that_is_the_type_you_represent). In essence, a Type object (or object of type Class), as opposed to each one being an object.

Where I've differed is that I've got a query object which holds all of the properties and associated metadata and data for a given class. (Say, each class would have columns: field_name, field_type, display_order, etc. Then the view will loop through that query (sorted by display_order) and will invoke methods like display_#field_type#_field(value).

I get the benefits of reuse, but perhaps not the benefits of smaller files. I haven't run into a problem doing this (yet?), but I like (my understanding of) your approach as well (enough to try it at some point).

Thinking about it, I feel like I'm using my view as a service class, but I'm violating TDA it seems. (I'm a bit fuzzy on what exactly is telling and what is asking - because some ways seem like either word works).

On the other hand, my understanding of your approach means yours is also violating TDA, in that you are not telling a property to draw itself, but telling its type to draw a value (and I admit my understanding may be completely wrong). But your approach has the added benefit of higher cohesion, smaller files (and thus more easily read code), among other things related to the two.

I don't know that I'd go as far as adding the D to MVC (though, I can't be sure if it may actually warrant it), but I /can/ see value in the approach. I just am not sure if it brings /enough/ of it (and only because I've accomplished the same without the extra classes, at the expense of a little more complex classes (versus a more complex architecture, I suppose).

I'm going to give it a try and see if I like it better (though I think this approach is somewhat different from what Fowler described in the article you linked). I'm not sure where yet, as I've generally been trying to avoid using the session or application scopes as requirements (I've broken down on session only because there seemed to be no good way to pass a message that I needed to pass except through the URL).

Thanks for the clarification, and response to anything I've said here that needs to be set straight =)
# Posted By Sam | 5/27/07 9:48 AM
Just a clarification: near the end when I said "(though I think this approach is somewhat different from what Fowler described in the article you linked). I'm not sure where yet, as I've generally" I meant "I'm not sure where I'll use it yet" as in, just to play around with, or put it in an app or framework or whatnot.
# Posted By Sam | 5/27/07 9:52 AM
@Sam,

Well, what makes my approach non-standard is that I violate MVC. I see Data type as a fourth primitive as I find there is such a strong linkage between how I display a field (View) and process it (Controller) that it makes more sense for me to put it all into a single bean.

In THEORY I have exactly what you are suggesting. In theory every single property is its own object. In practice, if I'm displaying a list of 200 objects each with 10 properties, I'd have to create 2000 transient objects just to display that view. In ColdFusion that would be non-performant, so I use the whole DataType facade and Singleton data types to spoof what I really want in a more performant manner. I still call User.displayField("FirstName"), but instead of delegating to a FirstName object, it delegates to the DataType Singleton, passing in the property name, property type and vale. A hack, but it works quite nicely and is well encapsulated within the Base beans displayField(), displayValue() and other methods so fairly easy to reengineer if ColdFusion ever becomes Ruby :->

Your approach is similar except you have everything in one big file. I prefer to have each of my custom data types (and for me an application could have 50 or 80 different custom data types) as a nice tight bean - performance is still fine as they are all singletons, but your approach was what I did last time round (actually I used a case statement instead of lots of discrete methods which was why I refactored).

I really don't feel I'm violating TDA (Tell - Don't Ask). I'm just hacking round the fact that creating a transient object for every property of every object I display would be horribly non-performant in CF. When I write the Ruby version of the framework, I'll be able to get away without that hack.

This approach is different to Fowlers insomuch as his approach is specifically part of the model handling model concerns. I happen to find that for web apps I get a more maintainable code base adding D to MVC after trying a lot of other alternatives, but your mileage may well vary!
# Posted By Peter Bell | 5/27/07 1:54 PM
"what makes my approach non-standard is that I violate MVC. I see Data type as a fourth primitive as I find there is such a strong linkage between how I display a field (View) and process it (Controller)..."

I see, but I don't quite understand what violates MVC about the approach. Is there something in that linkage? I never thought MVC meant we can only have classes that are models, views, and controllers, but I may have misunderstood MVC (or what you are saying).

"Your approach is similar except you have everything in one big file... "

... Which I dislike very much, and makes me want to try what you are suggesting =)

"but your approach was what I did last time round (actually I used a case statement instead of lots of discrete methods which was why I refactored)."

One thing I thought about doing is attaching methods to queries. But, that can't be done (unless they let you add a pointer datatype in cf8!). What would be more accurate and possible would be convert to array of structs and attach the method to each struct (or just one if it made sense to do it that way). But, that approach seems overly complicated even if it would be pleasing to use (which I'm not even convinced of yet).

In the end, it doesn't bother me THAT much to have the big file if its not overly complicated and if it doesn't need to change much (since the idea is to never have to look into it anyway). At this point I feel it is meeting those conditions, but that doesn't mean I shouldn't improve the architecture if I have the time and desire.

"I really don't feel I'm violating TDA (Tell - Don't Ask)."

I see what you mean now with the extra explanation.

"When I write the Ruby version of the framework, I'll be able to get away without that hack."

I have a feeling with just about any ORM you'll have problems with a large enough data set (of course) =). But I think you'll have problems much sooner (or with a much smaller data set) than you would have them /without/ the ORM, and I would guess it's not linear degradation, though I have no proof of that guess. Of course, with CF8 if they've truly increased the performance of creating CFCs as much as I've read, it may cease to be a problem.
# Posted By Sam | 5/27/07 2:23 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.005.