onDuplicate() for ColdFusion 9

I just submitted an enhancement request for ColdFusion 9 and I hope this will receive lots of community support.

With the addition of the ability to duplicate() CFCs and the fact that cfthread will do this automatically, we now have something of a hidden problem with ColdFusion. It's the proverbial "waiting to happen" problem. You've got a CFC and you're duplicating it and everything is fine and then suddenly you find some reason to want to have it contain an internal pointer to a caching object or an IoC factory and BLAM! Suddenly you've got a major memory leak in your application where large numbers of singletons (objects that should only be created once) are being duplicated willy-nilly.

The problem isn't that it *can* happen of course, because there are plenty of ways to screw up any piece of software. What got me started down this road is that it occurred to me that

  1. it's invisible: it's the sort of problem that's easy to not see coming, because the pieces of code involved are in very different places -- you set the pointer to the IoC factory in your init() method, but then your cfthread tag or your duplicate() call is somewhere else entirely.
  2. there's a simple and effective solution: the server can check for the existence of an onDuplicate() method and if present use the returned value instead of a deep-clone of the object, making duplicate() an at least semi-intelligent cloning engine.

How does this solve the problem? Very simple. Authors of IoC factories, caching engines and other memory-sensitive components can protect their objects from accidental duplication like this:

<cfcomponent displayname="ColdSpringFactory">

<cffunction name="onDuplicate" access="public" output="false">
<cfreturn this />
</cffunction>

</cfcomponent>

With the simple addition of that one function then the author knows that those objects will never be accidentally duplicated, because any attempt to clone them with duplicate() will result in returning a "this" pointer to the public object. Of course there are other possible applications for this feature (just as there are many applications for onMissingMethod), although in my mind this is the most vital.

So as you're looking forward to ColdFusion 9 and hearing people talk about their favorite enhancement requests, be sure to mention onDuplicate(). :)

Thanks,

ike

p.s. One other place that occurred to me where this might be useful is for setting "constants". ColdFusion has never had any concept of a "constant" and even this wouldn't be a true constant, however, if you had a collection of "constants" you wanted in your application you could create a simple "bean" object containing your constant values as private variables, use an onMissingMethod() to get access to them and an onDuplicate() to prevent their being coppied.

<cfcomponent displayname="constants">
<cfset pi = 3.14 />
<cfset c = "6000km/sec" />

<cffunction name="onMissingMethod" access="public" output="false">
<cfargument name="MissingMethodName" type="string" required="true" />
<cfreturn variables[arguments.MissingMethodName] />
</cffunction>

<cffunction name="onDuplicate" access="public" output="false">
<cfreturn this />
</cffunction>

</cfcomponent>

<cfset area = constants.pi() * (radius^2) />

<cfset e = mass * (constants.c()^2) />

CacheBox

The more I think about this, the more I feel it really needs to be done...

Everyone is reinventing the wheel here, including myself... and frankly, it's silly...

There are currently 2 separate projects on RIAforge running in parallel for integrating memcached in ColdFusion, plus nearly every other framework includes some kind of caching features. Off the top of my head, Transfer, ColdSpring, Lightwire, Mach-II, ColdBox, the onTap framework and probably Reactor ... and that's just the *short* list. And it doesn't even include several other caching projects on RIAForge.

I plan to beg/borrow/steal or do whatever it's going to take to get the best, most scalable caching algorithms currently implemented in any of these open-source projects (which are probably not mine) and export them in much the same way I've been exporting the DataFaucet ORM into a separate project. This new project is called CacheBox. The system will include a "service" component and a "client" component that will automatically detect the presence of the service and when unavailable fall back on a more naive caching algorithm. Once this is done, all frameworks should be able to implement CacheBox internally to manage their cache.

What does this mean? The question of caching will no longer be a question when choosing frameworks. You'll never have to worry about it, because all the frameworks will have the best possible caching architecture available and have the same kind of flexible caching configuration. You'll never have to worry about the scalability of your caching system, whether it leaks or how to purge the cache. The most you'll ever need to do is tweak the configuration. Small apps can grow and when they become large apps that need the support of something like memcached, you can add that support in the background *without* editing them.

A New Rich Text Editor

I was looking for some information about how to set the value of a loaded FCKEditor instance. This is the first time I'd ever used FCKEditor even though I had previously created a TinyMCE plugin for the framework called tapMCE.

The problem with rich-text editors in general, whether you use TinyMCE or FCKEditor or something else is that they tend to be over complicated and far from "user-friendly" to anyone who's not a computer programmer... You and I of course are fine with them, because we're technically educated and familiar with all the HTML concepts that their gratuitous dialogs throw at us like "alternate text" and "vspace". But it's kind horrid to force our strange jargon on people who just want to put a picture in some content.

That problem actually was one of the things mentioned (aside from their being load-heavy) in the blog article where I found this newcomer.

It's called NicEdit and I'll likely be having a look at it soon along with all the other things on my todo list. I may just rebrand the tapMCE plugin to some other name like TapIWYG and retool it so that it becomes an integrator for a couple of different rich editors just to give people the options. That way it'd have a facade where you can specify the options for your whole app and then tweak them for individual editors in the XHTML syntax... and maybe even provide a facade for some common js integration needs like for example, how do you set the value of the editor, because it's probably different across them... so if you could just call a service from the IoC container and declare which input element to set and the value, then you could let the facade worry about the JS specifics. In much the same way that DataFaucet handles database specifics. Now that would be some slick SOA. :)

Caching

I hadn't been aware of the new tools that had become available for managing cache recently with newer JVMs and techniques involving multi-threading support. I just read the ColdBox wiki entry about its cache system and will be taking a closer look at those techniques soon(ish) to improve the built-in caching features in both the onTap framework as well as DataFaucet.

I would actually rather like to see this caching done as a separate project that can be plugged in as a replacement for the naive caching used in these other frameworks and that might also optionally integrate directly into one or both of the two memcached projects on RIAForge. But right now I just don't know enough about them to talk about the techniques for doing those things.

As of this past weekend I'm still working on the recent updates to other parts of the framework, better configuration and the IoC Manager which makes it a Service-Oriented (SOA) approach to CF development.

The SOA comment is interesting to me partly because it's always been the intention of the framework, but was very difficult to accomplish with previous versions. Over the years I've written a lot of rather strange and obscure code, usually to overcome some inherent limitation in the current version of ColdFusion and what I've found in retrospect is that easily a third to half of those boil down to the single limitation of not having had application-specific ColdFusion server mappings. The addition of this.mappings in application.cfc changed all that and made my long-time dream of "SOA" a real possibility...

What's really interesting though is that I had always dreamed of SOA... because until very recently I didn't know what SOA meant. I had recently read the wikipedia article on SOA and discovered that it's really what I've been trying to accomplish with the onTap framework for several years.

IoC Update

I spent most of my weekend working on the new IoC Manager and tweaking some issues with the new lazy libraries, mostly with regard to the xhtml libraries, although there was some time in there spent cleaning up the docs because I created a <cf_doc> tag to make documenting the libraries easier and then I realized that I had a bunch of escaped hashes that didn't need escaping, so the docs were all full of ## instead of # for default values. I had already removed the jso library because for the most part the only functions in it that were ever really used were jso.location and jso.object. And for the docs for all three of the custom tags, function libraries and CFCs I tweaked the documentation info so that it's based on an extremely simple xml packet.

<library name="My Library">
<description>CFC's for doing something</description>
</library>

None of those things were really necessary, I just figured as long as I was doing another overhaul I may as well clean up some of these things that were "laying around" so to speak.

The latest version is coming along quite nicely. The new config.cfc that replaces the previous _appsettings.cfm I think is a really good idea. You can think of config.cfc as being sort of a replacement for Application.cfc, since it gives you the ability to tweak any given part of the framework core which includes handling for many of the CF Application framework features like adding mappings.

The way it works will also eliminate even the *possibility* of running into the pain-in-the-neck situation that all 3 of the ColdFusion community's most popular frameworks run into with regard to wanting multiple copies of the framework on a given server. Fusebox, Mach-II and Model-Glue all want you to write an Application.cfc they include in their app skeletons that extends a component in their core libraries. That's always struck me as a poor convention and it causes problems any time you want multiple copies of one of those frameworks on your server. The onTap framework gives you the same kind of control, but because it doesn't use the convention of deriving Application.cfc from an external source, you never run into that problem. :)

I also discovered a way, using my method for dynamically extending components (which is impossible by the way), to set up the application so that you can use webservices in the root directory with the same Application.cfc in spite of the fact that it has an onRequest() method (which is also impossible by the way). :)

But getting back to the IoC Manager... I haven't released it yet of course because although I think the Manager itself is ready, I'm still updating the Members onTap plugin. I'm redrafting some of the internals of that plugin to use its own IoC Container and to reference an IoC container from the DataFaucet plugin to get its datasource. And configuring IoC containers is pretty simple. You just create a tiny little cfc in the /_ioc directory like this:

<cfcomponent extends="config">
<cfset loadAfter("DataFaucet") />

<cffunction name="configure" access="public" output="false" returntype="void">

<cfset newContainer("MyApp","coldspringadapter").init(my,coldspring,config) />

</cffunction>

</cfcomponent>

The loadAfter() method lets you specify that your particular IoC config needs info from another IoC config before it can load. I'm not sure if I actually needed the DataFaucet container loaded before my container since they both lazy-load their objects, but knowing that my app uses DataFaucet, I figured it would be "better safe than sorry" to do it that way.

IoC and Lazy Libraries

Okay, so I'm finally going to post something actually related to the framework again. :)

Here's the deal. I've been aware for a while that folks have been unhappy with some of the features in the onTap framework, in particular the fact that there are a number of places where code is executed outside of CFCs. This is done in the framework for very specific reasons, and I know for a fact that it's actually more flexible than using CFCs (think "Fusebox lexicon" and you should start to get an idea why). I also believe (although I don't know) that it's not significantly more "dangerous" (see my articles about duck-typing and about descriptive variable names).

Still it's difficult for people (myself included) to see past their knee-jerk responses to something that looks unusual or seems like a bad practice to actually understand the problems it solves.

So in recent weeks, largely because I was already migrating the ORM components out to DataFaucet, I started making some pretty radical changes to the onTap framework. This is good news on several fronts. First if you're already using it, you don't need to worry, because the system was so well encapsulated already (believe it or not, yes, yes it was), that your code shouldn't change by more than a handful of lines. In spite of the fact that I'm taking a few weeks to make these changes, *your* changes shouldn't take more than a few minutes. Secondly the new system is adding CFCs in some critical places and in at least one place this will make the system much more tweakable. It's certainly going to improve on its already very effective encapsulation.

First, the _appsettings.cfm that has confused people for a long long time as the initial method of configuring the framework is going away. It's being replaced by a config.cfc in the application root directory that extends tap.cfc which loads the framework core. This leads to some simplifications of some previous features like application-specific mappings. Want another mapping? Simple.

<cfcomponent displayname="config" extends="tap">

<cffunction name="configure" access="private" output="false">

<cfset addMapping("datafaucet","../datafaucet") />

</cffunction>
</cfcomponent>

Is that a relative path?! In a mapping? Yes it is... and it works. the addMapping() method allows you to specify mappings either absolute or relative to the framework root directory. How does it know? If it finds a directory on the relative path, then it's relative, otherwise it's absolute. Also the addMapping() function automatically prepends the required "/" at the beginning of the mapping string, which has been the source of LOTS of confusion about how precisely to create mappings in ColdFusion 8. Which means this method of adding mappings is much simpler and more straightforward than Application.cfc.

The code for path-settings is also going to become CFCs and there will be a similar, new _mappings directory for the addition of 3rd-party mappings (which should be used sparingly, but will be an important enhancement to the framework's plugin manager).

Now on to the 2 features I mentioned in the article title. I've already added lazy-libraries. In the past the framework has had a bit of a heavy initial load because it loaded its entire set of function libraries on application start. Going all the way back to the ColdFusion 5 days there had been this notion of having a library of functions (DLL wouldn't be an entirely bad analogy), which each understood their own dependencies and could then load those dependencies when they themselves loaded.

Sweet! At least in theory. In practice however loading them always turned out to be a pain. When / where do you load them? Which ones need to load on app start? Which ones can be deferred? Have I loaded x on a given page request? Should I load it on request start? ::sigh:: leading me ultimately to make the framework load them all by default, which was ugly and had some of its own problems aside from the initial load time.

A while back I had this notion of creating a "lazy loading" library out of them, where all those functions before had been in a simple structure, they would become part of a CFC and then could be loaded dynamically as-needed using the new onMissingMethod() feature in ColdFusion 8. I had actually even started working on that change a while ago and ended up giving up and rolling the change back in SVN because I had too many problems implementing it at the time. Well now I've gone back and revisited the idea and I've managed to overcome all the challenges I found before. :)

Sweet! So now you never have to worry about whether or not a particular function is loaded because the library will load it for you when it needs it. And there's an extra bonus that the framework loads faster! I've also added internal references in the libraries themselves so that instead of calling request.tapi.OtherMethod() the internal method calls become lib.OtherMethod() -- using the internal pointer. Granted that if you're calling a method in the same library, it can just use this.OtherMethod() -- lib.OtherMethod() just allows you to traverse the library from the root (similar to the way the default / mapping in ColdFusion lets you traverse files from the web root).

The core onTap.cfc also got a new getLib() method for returning the framework's core library, so that library calls from CFCs can be "composed" rather than referencing the request scope directly.

The only down side to this change is that due to a limitation in the getCurrentTemplatePath() method caused by inconsistency in its behavior (which the CF team last I knew refused to acknowledge), the file methods had to be moved outside of the main library to a new request.fs. structure. Those functions can't be stored in a CFC -- no way, no how. There simply is no workaround that allows them to exist in a CFC. Unfortunately... I believe I've also added getFS() to the ontap.cfc to fetch the file library in the same way that the core library is "composed". This way if at some point in the future it becomes possible to move that library back into the lazy library, then getFS() can just return the getLib() pointer and the getFS() method can be deprecated. So that should be good forward-looking.

If you're using the file.cfc to manage your files, then you don't have anything to worry about with this change. You might need to do a little extra leg-work if you were calling a lot of request.tapi.fileRead() or the like -- you'll just have to change those references, which shouldn't be too difficult.

Lastly I haven't started working on it yet, but I'm planning an IOC-MANAGER for the next release. I say "manager" because although it will have a default IOC package, the system is going to be designed specifically for the purpose of managing multiple IOC packages from different applications / plugins. So where for example ColdBox has just an IOC-type (coldspring/lightwire) to integrate a single IOC configuration, the onTap framework will instead have an addIOC() method for attaching arbitrary IOC packages, and a facade for allowing you to write your own IOC-wrappers (although I plan to include one for ColdSpring and one for LightWire out of the box). Your application code can then either getIOCManager().getBean("name","DataFaucet") for example or it can getIOCManager().getIOCPackage("DataFaucet").getBean("name"). Although I would encurage not doing those all in the same function and instead compose separate getIOCManager(), getIOCPackage() and getIOCBean() functions in your own components. That will minimize the amount of code you need to write later if anything in the core application needs to change - OR - if you later decide to migrate to a different framework.

Cognitive Science - It's Not Just Good, It's Good For You!

I've been talking a fair amount about cognitive science lately, particularly with regard to its relationship to usability / user interaction and with the nature of programming as a profession.

The former relationship should be reasonably obvious - users are human (we hope... most of them anyway, even including pointy-haired bosses), and if we want them to use our software we have to create it with interfaces that are easy and useful, taking advantages of the quirks (strengths and weaknesses) of human thought. We need to know, accept and embrace not only that users want things to happen quickly, but that they need to be named and labeled in ways that will make sense to them at first glance WITHOUT thinking about them. (There's a reason why Steve Krug's usability book is titled "Don't Make Me Think".) Unlike programming tools, we need to make most decisions for our customers in advance based on common assumptions about what our users are LIKELY to do, not what they MIGHT want to do (you handle the "might wants" with additional tools on the back-end, not by forcing them to make decisions up-front).

These are all lessons that Microsoft and Seapine have yet to learn, despite their years of operation. Although the creators of Subversion and TortoiseSVN have learned them! Where Seapine's "mature" Surround SCM is constantly bonking me on the head with a librarian's desk-reference, with numerous annoying dialogue boxes that I mostly don't use any time I want to as much as glance passively at a file, TortoiseSVN only shows me a dialog when I ask for one, and provides me with helpful information up-front (files not currently checked in when committing) that's impossibly buried in the Surround SCM client.

But although I constantly champion the notion of programmers improving their usability skills, this article isn't really about that. This article is about understanding cognitive science so that we can have a better understanding of our own habits and the reasons why some things repeatedly bite us in the ass. What's most interesting and ironic to me about cognitive science is that programmers are CONSTANTLY talking about it ... they just don't know that they are. I actually didn't know much of anything about cognitive science until this past year or so. I started reading books like Dan Ariely's predictably irrational and I realized that, although I have in the past been rather snarky to Larry Lyons on the cf-community mailing list, I probably should have been asking more questions! Although I'm not sure what his official degree status is, Larry studied behavioral psychology in college.

So why all the hubbub?

It's important. It may be more important than studying programming theory or design patterns!

Why?

Consider that your mind is merely a program that's been designed by millions of years of evolution. That program has evolved a number of its own design patterns - ways in which the mind works relatively consistently. These design patterns have evolved over these many millions of years to produce people like you and I who are very well adapted to survive and even thrive in a ... NON-AUTOMATED world. By this I mean to emphasize that we have not evolved to be good at programming computers - far from, computers if anything seek to replace the tools we've naturally evolved for survival in a pre-modern world. So our mental machinery isn't designed for programming - it's designed for things that are far less abstract and as a result, what "works well" for programming computers is often very different from how we've evolved to think.

So where does that put us?

Programming computers without at least attempting to understand cognitive science is like taking a cave man, sitting him in a Swiss watch factory (pre-quartz) and expecting him to assemble fine time-pieces with no training. His brain hasn't evolved to handle it and so he'll work on those watches using the same design patterns that evolved for him to work on hunting and gathering for food. Will he eventually figure it out? Yeah, sure. But the quality of his product will be sub-standard.

Cognitive science is the training to understand the brain's built-in design patterns and how to apply them (or more importantly avoid misapplying them).

What's happening in the software industry is that a lot of people are talking about cognitive science. In fact, they're RANTING about it all the time! They just don't know that's what they're doing. And they're demanding that things change, without first trying to understand why they are this way already! They're looking at the cave man in the watch factory and they're wagging their finger at him and shouting "shape up! You need to produce better quality!" But they're not offering him the training that would actually help.

Here are a few examples:

Every single one of those articles should have made some mention of cognitive biases... yet none of them did.

And I'll go a step further and I'll give another example from my own experiences. Over the years I've received a number of emails saying "x is bad" or "x is a bad idea" ... If you read the above examples, you can see some of that with regard to the "active record" design pattern. The problem is that "active records are bad" is the way our brain is designed to think -- it's simple and it's concrete. The reality is at the extreme opposite end, much more akin to what Sean Corfield says in response to the question "which is the best framework to use", i.e. "it depends". The question "which is the best", sets up the other person with the expectation that you'll give a singular answer - simple, concrete, the way we're designed to think - irrational. The active record design pattern can't be good or bad outside of some context. Every design pattern exists for the purpose of addressing a specific problem or set of problems - they have advantages and they have drawbacks or "consequences".

It's important to note that the evolution of human thought bears no resemblance to "logic". There are logical reasons for our having evolved to think in particular ways. Those reasons are obscure and counter-intuitive. Moreover logic itself has never been a survival strategy for a species. The fact that we can be logical or rational doesn't mean that we are very often, particularly because logical thinking isn't really an advantage to our survival. Logical thinking doesn't much help the cave man to find food or avoid predators. Our "irrational" gut instincts are much more effective at managing those tasks. Similarly logical thinking in the face of an irrational, pointy-haired boss generally doesn't win you brownie points at work either.

As such we've evolved certain design patterns like a "herd instinct". Other people (not myself) will lambast humans in general for even having a herd instinct, referring to them as "sheeple". I don't take that approach. I prefer to think of the herd instinct as "friendliness" and "social cohesion" - it is what allows us to build communities and do big and bold things like building projects that took more than a generation to complete. If not for our desire to band together, none of those projects would have gotten off the ground! It is a good strategy for those things. But my desire isn't to blame people for thinking irrationally ("sheeple"), it's to understand how and why we think the way we do and to encourage others to study thinking as well as a means of not just improving, but elevating our work.

The consequence of herding of course is that it's not a great strategy for growing a society of "free thinkers", leading us to the comments Machiavelli wrote about "innovators" in his biting satire the Prince. The effect of confirmation bias means that we tend not to think of the drawbacks or "consequences" of design patterns. We tend only to think about how they solve our problems. So what are some of the other drawbacks of the "herd instinct" design pattern? It discourages good programmers from implementing great new and innovative solutions to age-old problems for fear of reprisal.

Here's an example from outside the software world. Rabies has been a death sentence since men first started walking upright, and there's still no truly effective treatment. Jeanna Giese is the worlds first full-recovery from rabies. Her doctor had never seen a case of Rabies before, and it's probably a good thing! If he'd been a rabies expert, she would be dead! Why? Because the conventional wisdom in the field is that there is no hope for rabies victims. The standard treatment is pain-killers. And although she is a fantastic example of both the outsider effect and the problems of relying on our education, when Dr. Willoughby spoke about his Wisconsin Protocol at the international rabies convention, other highly respected doctors told him that it shouldn't be used until there is laboratory evidence of its effectiveness! And this is a condition in which, the alternative is guaranteed death!

That kind of fantaical, devout and thoughtless reprisal is hard to swallow. It's precisely what Machiavelli was talking about in the Prince.

There's something else that comes out of the example of Willoughby's rabies protocol, and here's a real kicker. These doctors are also not learning the lessons of cognitive science. Well why should they? They're physicians, not psychologists! And they're doctors! They're beyond all that mushy stuff that gets in the way of either real science of helping the patient.

Aha! But that's the problem in a nutshell.

The fact that we (doctors and programmers) think we're above or beyond the problems created by cognitive bias is merely another example of cognitive bias! And it's the real crippler. It's called the overconfidence effect. Nearly everyone, without respect to age, sex, religion or PROFESSION, believes themselves to be less susceptible to dangers than anyone around them. Every smoker believes they're unlikely to get lung cancer. Each of us (myself included) believe ourselves to be more rational and more logical than our peers... but we're not.

The problem here is that the "overconfidence design pattern" has been quite effective for us in the past in helping us to thrive as a species in a pre-modern world. It does not however help us to program computers, in fact, it hurts us. We're apt to look at a blog entry like this one and think "that's interesting, but it doesn't apply to me -- I always judge the pros and cons of design patterns appropriately". Do you? It's not likely. It's not likely that Hal Helms does or Sean Corfield, Joe Rinehart, Matt Wooward or Peter Sommerlad.

That's the reason why we end up with blog entries that say things like "active records are bad". Really? That statement makes no sense. It's a result of the oversimplification design pattern. Without a context of the problem it's being used to overcome and the impact of its consequences on the remaining application, you can't say that they are good or bad. What's bad is slavishly applying them where they're not very useful or slavishly avoiding them where they would be.

It's that slavishness that causes Java programmers who come to ColdFusion to complain about its STRENGTHS like its lack of strict-typing or for any programmer to praise the virtues of case-sensitivity. (See Sean Corfield's CFUnited presentation. Heresy! Embracing Duck Typing in CFCs.)

And THAT slavishness is a result of the design patterns in your brain!

Cognitive science.

I CAN'T stress it ENOUGH.

Where Has All the Help Gone?!

Years ago it was considered if not horribly important at least a popular notion that software should include "help" documentation that was ... well... helpful...

What happened to this notion? Why is it no longer possible to get helpful help from the help feature in an application?

It used to be that in Microsoft's Enterprise manager I could open help, search for a keyword and if I didn't find it immediately at least I was directed to a copy of the Books Online (BOL) that had been installed on my machine with the client tools. And don't get me wrong, I'm all for "livedocs" and central wikis, they're awesome for centralizing knowledge for a given technology. The ColdBox wiki is pretty thorough, as is the Transfer wiki -- the community is doing a good job of banding together and making information generally available.

No, I'm talking about the efforts of companies like Microsoft in particular (I'm sure I've seen others), where attempts to centralize documentation end up just making things worse than they were before. Take for example, the management tools for SQL Server I mentioned before. I used to be able to hit the "help" menu and get help. NOT ANYMORE! Microsoft has decided to step up into a bold new horizon of tomorrow's software, where requesting help from within an application sends you to a central repository of information for EVERYTHING!

So I hit the "help" menu and first I'm accosted with a dialog box with a series of 3 radio buttons to choose from, only... wait... TWO of the THREE options available to me have been DISABLED! So I'm being asked to make a selection - I can go to their central repository or I can go to their central repository! Wow! So many options! I think I'll go to their central repository. There I'm given a set of frames that do vaguely resemble the old-style help application, just minus the help. In the upper left corner where I'm hoping to see a "search" option or some way to enter a phrase or keywords I see "Filtered by" with a drop-down. I open the drop down and notice ther'es only 1 option labeled "unfiltered". Wow! I can choose between unfiltered help and unfiltered help! So many options! I think I'll get unfiltered help. Below this is a tree of items regarding "help on help (Microsoft Document Explorer Help)" ... umm... What happened to help applications being intuitive? Why do I need help to use the help application?

So finding no help there I move on to the panel on the right where I find they've opened a browser window for me... There's a URL at the top showing me that I'm on an ASPX page. At the top of this page it says "How DO I (SQL Server)". Okay that's good. I appear to be at least in an area related to what I want to know. In this section "SQL Server Database Services (How Do I)", "SQL Server Analysis Services (How Do I)", etc. you get the idea. None of them really what I want to know, which is how to open an/the object explorer.

Oh hey! There at the top! It says "Ask a Question". Have I suddenly found the mythical search feature?! Nope... Takes me to MSDN Search where if I type in "open the object explorer" or even "object explorer" (WITH QUOTES) I get the first 1-10 of over FOUR THOUSAND results, almost none of them having anything to do with SQL Server. So I go back (which in itself is a challenge), and finally as I'm writing this article I see "Search" at the top. Which even once I've found it, still doesn't seem to produce any results that explain how to open the object explorer...

::SIGH::

Credit Where Credit Is Due

A while back I commented that I've been working with ColdBox recently and "not seeing the magic"... but moreover, I made the comment that I'd been seeing a lot of articles where people were raving over how easy it had made their job when it had in reality done either nothing, next to nothing or in some cases less than nothing for them (i.e. busy work). Though I didn't actually explain what I meant by this comment... so here are a couple of examples:

Back in April, Matt Quackenbush posted this article where he talked about "mapped views" in ColdBox. By way of explanation, ColdBox uses these handler.cfc files where each function is an "event", so for example the url index.cfm?event=home.login executes /handlers/home.cfc->login(Event). Then within that login function, you have to set the "view" for the event, which is the name of a template in the /views directory. It looks like this:

<cffunction name="login" access="public" output="false" returntype="void">
<cfargument name="event" required="true" type="ColdBox...requestContext" />
<cfset event.setView("loginForm") />
</cffunction>

So in Matt's description, he's talking about having some common forms that have to be built every time he creates a new site or application for someone. The login form actually is his example. And he doesn't like having to copy and paste those forms from one application to the next since they don't really change. I can appreciate where he's going with this...

He loses me however when he starts talking about how easy it was to create a RequestContextDecorator.cfc to wrap around the event, which then checks to see if the first character of the setView arguments is a / so that he can tell the framework to use the mapping... A whopping 43 lines of code later, in his own words, "That's all there is to it, folks. Yet another task made simple by the power of ColdBox!" ...

umm... Matt? 43 lines of code was easier than this?

event.setView("loginform");
...
<cfinclude template="/globalviews/loginform.cfm" />

ColdBox didn't actually make that job easier -- it made it harder. It added a learning curve where none was needed. And in the final analysis, there's no functional difference between his decorator and just using a local view template with an include -- except that the decorator will be less mechanically efficient.

Then just the other day Will Tomlinson posted on the cf-talk list a subject titled "MG is so cool!" So I had a look to see what marvelous new feature he was going on about... turns out, he was raving over the fact that Model-Glue can turn this:

<cfset application.myappsettings.mysetting = "foo" />

Into this:

<modelglue>
   <config>
      <setting name="mystetting" value="foo" />
   </config>
</modelglue>

Which is then later retrieved via:

<cffunction name="someFunc" access="public" returnType="string" output="false">
   <cfset var theSetting = variables.config.getConfigSetting("mysetting") />
</cffunction>

After having gone through two other methods of setting that same variable before finally settling on this.

umm... okay. I'm not seeing the magic.

Yes I understand encapsulation. That's not my point. The point here is that nobody's really benefited from the extra learning curve here, in spite of Will's enthusiasm for a central config file.

I can only imagine this is a result of endowment. I know that as a species we definitely view things differently once they've had time to "grow on us". I honestly get much the same feeling from people who rave about Eclipse. Others I know in the IT industry tend to describe it with the quirky phase "drinking the Kool-Aid", a reference to Jim Jones.

Have I done it? Probably. I am human and I'm pretty certain that means I'm endowed in a number of ways. As a matter of fact, I encourage you to let me know if you see me saying something like this that looks like it's inspired more by endowment than by the event itself. I'd be interested to know how this phenomenon affects me. :)

Anyway in both of these cases, large amounts of credit seem to be given to frameworks when any credit if deserved at all seems to belong to the ColdFusion server. And really, giving accolades like this to the framework authors imo even kind of cheapens them too. If you're going to give them accolades, give them accolades for things that actaully are spectacular like Mach-II's integration of multi-threading across several different CFML engines, ModelGlue's scaffolds (which I don't care for and so haven't used), etc.

Subversion

It's such an awesome tool... I've worked with a handful of version control systems over the years. I've worked with Visual Source Safe (VSS), I've worked with Perfoce that supposedly was the kernel for VSS years ago (Microsoft licensed the code for their branch like they did with Sybase when they made SQL Server), I worked with Starteam briefly many years ago, I've obviously worked with Subversion and now I'm working with another version control tool from Seapine called Surround SCM.

I so miss SVN...

Of the at least 4-5 version control packages I've worked with, SVN is the only one I actually want to work with. Surround SCM is GARBAGE. So were VSS and Perfoce and probably Starteam though I don't remember it very well. I can't speak for CVS because not being a unix guy I haven't used it, but if it's anything like these others, it sucks too.

I can't just look at a file anymore to see what's in it... if I just have a casual curiosity, without having any intention of editing the file, I just want to see what it does, when I click to open it in Dreamweaver now I'm ACCOSTED by a complicated dialog box DEMANDING that I CHECK OUT the file and inquiring what my purposes are for doing so... I don't want or need to check out the file and I certainly don't need to be bonked over the head with a librarian's desk reference every time I want to see what's in it. Just looking at a file is like being in high-school again and having to undergo an interrogation from my prom date's father. "Ding-Dong! Who are you?! What are your intentions with this file?! Quick, speak up!" It makes me not want to open files honestly -- and therefore, makes me not want to work.

There's also as far as I can tell no way for me to see what files I have checked out! I've been all over both their help files and Google looking for a way to just get a list of files I have checked out and nada! Great, so here I have this project with HUNDREDS of directories and yeah, truthfully I'm not really editing in all of those directories, but I am editing in a lot of them... and it'd be frickin' nice, if the software that controls my versioning and MUST by its very nature know what I have checked out, tell me which files and in which directories are checked out so I can check them in. I have a couple of options. I can check in an assload of files all at once, INCLUDING somehow mostly files that I didn't check out in the first place! Or I can weed through 20+ directories opening each one to see if any of the files are marked and hoping that the flakey engine that marks them is actually working.

At least with TortoiseSVN when the marking engine wasn't working very well (it's improved with recent versions), when I asked it to commit a directory it would scan the subdirectories and tell me what I had checked out and what wasn't in the repository correctly, irrespective of the marks. Surround has no such common courtesy. And it's only made worse by the fact that when I commit, I'm being asked to commit to "change logs"?! First of all, committing something to a version repository IS A CHANGE LOG. If it was out and it changed and then it went back in with changes, that's a change log! There is no need to separate them. It's like separating dogs into "dogs" and "more dogs". And then to make matters worse, once I've committed the files to a change log, I then am forced to COMMIT THE CHANGE LOG! As a wholly separate action that can't be performed in Dreamweaver, forcing me to keep the Surround SCM client open constantly. And god forbid I accidentally try change and commit a file (that I AM ALLOWED TO CHECK OUT) that's already in an existing change log that hasn't been committed.

Why do we demand that everything that is simple and good be complicated until it SUCKS and makes you want to jump off a bridge?

Anemic Domain Models

I had actually not heard the term ... or maybe I had and just didn't take any notice... but I just read this article on Ben Nadel's blog about an experience he had in January, working with Hal Helms down in Florida. I was actually rather surprised to see Ben saying that as late as January this year (just 5 months ago) he was still struggling with the philosophy of OO. And moreover, from reading the article, it looks (at least at first blush) like what he's saying is not only that he learned that the way I tend to do things is more in-tune with the fundamental philosophy of OO, but more importantly that as ironic as it may sound this way of thinking about objects that is "more OO-pure" is precisely the kind of thinking that "OO-purists" tend to say they don't like about my solutions (preferring the "anemic domain model" approach).

So okay... let me give an example...

Ben talks about the "Where's George Dollar". Where's George is a website that lets you see all the places one of your bills has been, based on its serial number. This is where the conversation gets really interesting. My tendency with most stuff like this would be to create a Dollar.cfc with methods for getting, setting and generally managing or navigating its history. In my experience at least in the ColdFusion community, most "OO-Purists" don't like that idea because they perceive it as being "too coupled" and would prefer to have a Dollar.cfc bean (like Ben describes) with just getters and setters (and nothing else) for basic, atomic values which is then passed into a DollarHistoryManager.cfc or similar.

Ben's first instinct:

Dollar = CreateObject("component","DollarBean").init(serial,series,printdate);
HistoryMan = IOC.getDollarHistoryManager();
qHistory = HistoryMan.getHistory(Dollar);

My first instinct:

Dollar = Factory.getDollar(serial,series,printdate);
qHistory = Dollar.getHistory();

Ben's first instinct is even the way that I perceive is generally encouraged by the 2 ColdFusion frameworks that present themselves as being like more traditional OO development (Mach-II and Model-Glue), where doing anything with the data in an "event" requires the creation of a "listener" or "controller" CFC that has as its sole purpose the job of passing the dollar bean to the other objects that will perform any actual actions with the information.

What is generally cited as the reason not to do things the way I'm naturally inclined to do them (my first instinct) is the notion that it's somehow "more coupled"... which to me just seems odd... it's "more coupled" because it assumes the object will have and connect to a database... Okay, fine... So it works in 98% of cases... why is the 2% edge case a problem, when you can simply subclass the Dollar object to make it fetch its data in some other way for those edge cases?

If anything I perceive what is my first instinct as less coupled because it doesn't require the extra external objects to manipulate the data. Your controller then doesn't have to care at all what objects connect to which services -- all it has to know or care about is that the object has that getHistory() method. Hence the controller is actually less coupled since it only has to worry about the interface to the Dollar and not about the interface to both the Dollar and various service objects that might need or want to use that Dollar.

Hal describes my first instinct as an "idealized model" - creating objects which behave the way we wish real-world objects behaved, rather than the way they actually do behave. In Ben's approach, the Dollar behaves the way a real-world dollar behaves - the only info you can get from it is what is printed directly on it. If you want to know where it's been, you have to go to an external resources like the Where's George site and enter its data to get your history. And the objects in Ben's design would be the same way -- the only thing you can get from the Dollar object would be its atomic data (values that can be printed on its surface), requiring the system to find some external resource if it wants any other information about that Dollar. In my approach, what Hal describes as an "idealized model", the "idealized Dollar" doesn't force you to go find some external resource. It's like having a magical bill that talks and saying "hey you, where have you been" and having the bill itself rattle off a list of places.

It's where the Dollar meets the cell phone. Years ago if you wanted to make a call, you had to go find a phone. Now you just carry a phone with you. But if you want to know the history of a bill, you're still stuck going and finding a computer with internet access, even though you carry bills all the time. So in an ideal world, since we already carry bills, it would be great for "smart money" to be able to give us that information while we're standing on the corner. This is perhaps a bad example simply because getting the history of a bill, while interesting, usually isn't very useful (if at all).

Ben makes one last comment that the Anemic Domain model generally gives you all the overhead of OO without the benefits. It's interesting if not downright frustrating to me because at least I personally perceive that a preference for anemic domain models as being "the way things are done in OO" or "the way things are done in Java" is one of the larger reasons why more people haven't either tried or used the onTap framework.

Am I way off-base? What do you think?

More Entries

BlogCFC was created by Raymond Camden. This blog is running version 5.5.006.