The ColdFusion OverSeer Application

In the comments on my rant about the new and improved unhelpful help systems companies like these days, Mark writes:

Speaking of needing help, the thought occurred to me the other night that it would be really cool if one of my CF apps could at least read the Application variables of another of my CF apps on the same server. Essentially, the first CF app is an administrative one needing to check the status of one of the apps it helps administer. Where I need help is that I have no idea how to let one app see another's application scope. Is there a method way to do this? And, if not, could we ask for it in CF9? Very best regards.

...

I hate it when I forget a critical piece of information when asking for help... Neither of the applications are using onTap. Just plain jane CF8 standard.

Well I'm certainly not one to begrudge a little help to others in the industry, whether they're using my applications or not. :) And this question actually came up at my new job in Boston recently, my new boss (the technical one) was facing the same issue and asking me if I had any new info... and actually after thinking about it for a few minutes, I did come up with a solution, although he didn't seem to like it. (Or possibly didn't understand my explanation, it's tough to tell.)

So here I'll give explaining it another shot, with the caveat that, I haven't tested any of this, it's pure theory. :)

If you dig into the ColdFusion ServiceFactory you can find an object somewhere that gives you access to session scopes across the server. The problem is, there doesn't appear to be any similar functionality for applications. To make things even stranger, the SessionManager (not sure if that's what it's called) lets you filter those sessions by application name! :P So although it's no solution for applications that have unknown names at run-time, if you know the name of the applications you want to monitor you can loop over those names and fetch the sessions for each and that way you know based on the active sessions whether or not that application is currently running.

What follows is pseudocode, not actual working code.

<cfloop index="appname" list="appx,appy,appz">
<cfset sess = SessionManager.getSessions(appname) />
<cfif arraylen(sess)>... it's running! ...</cfif>
</cfloop>

Then inside that if where you've checked to see if it's running, you can drop into that application briefly using the cfapplication tag.

<cfloop ...>
<cfif apprunning>
<cfapplication name="#appname#" sessionmanagement="true"
sessiontimeout="#blah#" applicationtimeout="#other#" />

</cfif>
</cfloop>

The annoying bit here is that you'll have to make sure you know all those application settings for that application, so you don't overwrite them with horribly inappropriate attributes, like for example suddenly disabling client management in a running application would be horrid. So you will need some kind of central repository to store the information about each app's settings.

When you're done, make sure you remember to return to your original application (the manager app) by using the cfapplication tag one more time after the loop.

Anyway, I hope this is helpful. :)

p.s. One other alternative to knowing if the application is running in advance is to store the application settings actually in the application scope, then declare a really short application timeout (1 second for example) in the cfapplication tag and if those settings aren't declared when you drop into the application, you'll know it wasn't running and you can let the application expire after the 1 second. It also won't run the application's onApplicationStart and set up any code it needs for that application, which is why you need it to expire after 1 second to reduce the chances of someone else touching the real application at the same time and it dying because it doesn't have its application variables. (That's a race condition.) But there's not really any way to resolve that race condition, you just have to set the timeout short and hope that 1 second is brief enough for it to expire before anyone else hits it. If the application is running however, then you have to execute the cfapplication tag again right away with the appropriate settings to keep it from dying and I make no guarantees that it won't crap out someone else's page if it changes settings like client management.

<cfloop ...>
<cfapplication name="#appname#" applicationtimeout="#CreateTimeSpan(0,0,0,1)#" ... />
<cfif isDefined("application.timeout")>
<!--- it's running! --->
<cfapplication name="#appname#" applicationtimeout="#application.timeout#" ... />
</cfif>
</cfloop>

p.p.s. There's a planned feature for ColdFusion 9 (Centaur) to have a Server.cfc that would be able to do some things like the Application.cfc, for example code that executes when the server starts or stops. If they implement this (which I suspect they will), then that would give us some additional (and more bulletproof) options for monitoring applications. Each application could then register itself with the a server object when it starts and the whole thing becomes pretty simple. ... Well... you can actually use the server object technique now, but it's a little trickier because each application has to instantiate it and you have to have to lock its creation to make sure there's only one of them... But here's a code snippet anyway...

<cfcomponent displayname="bootstrap">

<cffunction name="init" access="public" output="false">
   <cfargument name="appname" type="string" required="true" />
   <cfargument name="appscope" type="struct" required="true" />

   <cflock name="server.appmonitor" type="exclusive">
      <cfif not isdefined("server.appmonitor")>
         <cfset server.appmonitor = CreateObject("component","my.appmonitor.class") />
      </cfif>
      <cfset server.appmonitor.addApplication(appname,appscope) />
   </cflock>
</cffunction>
</cfcomponent>

And then in each of your Applications you've got to do this in the Applicatin.cfc.

<cfcomponent displayname="application">

<cffunction name="onApplicationStart" access="public" output="false">
   <cfset CreateObject("component","bootstrap").init(this.name,application) />
</cffunction>

<cffunction name="onApplicationEnd" access="public" output="false">
   <cfset server.appmanager.removeApplication(this.name) />
</cffunction>

</cfcomponent>

Okay... that's 3 separate methods and I spent twice as long writing this as I planned... :P I think I'm done. :)

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.

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.

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?

Hillenious on Framework Comparisons

I just read this blog from Eelco Hillenious about selecting frameworks for use in web application development.

He makes the comment that you shouldn't limit yourself to a specific language (i.e. ColdFusion), which I don't consider particularly relevant with regard to the frameworks comparison article I wrote this past few weeks. The purpose of my article was primarily to show people who are being indecisive about choosing a framework that the choice is much less important than the fact that they pick one and move forward, because, learning to use ANY framework will teach you some fundamentals about not just frameworks, but about programming in general (encapsulation, code reuse, etc) - the reasons why we have frameworks in the first place. To that end I wasn't really interested in convincing programmers who work with Java, Ruby or Python that they should use frameworks - my focus was on ColdFusion developers.

There are however still some useful and interesting thoughts on the subject of choosing frameworks and the psychology of programming in general. In particular I like that he points out the problem of making decisions about technologies on the basis of how effective their marketing has been.

Framework Comparisons

Sean Corfield recommended that I post my frameworks comparison article somewhere online to encourage more people to read it (since it wouldn't require downloading a 12mb distribution). So I've gone ahead and put it up here.

This is a first draft and it's still pretty rough, let me know if you have any corrections! :)

Strict Typing

A guy calls a plumber because the plumbing in his house is backed up. The plumber answers the phone, says "My name's Joe, I'll be over in a few minutes".

A plumber arrives at the door a few minutes later, the homeowner answers the door, "you're Joe, I presume?" The plumber answers "ahh, no my name's Jimmy. Joe had an emergency, so he sent me over instead. Funny 'cause Joe's a competitor of mine."

The homeowner gets his shorts in a knot and sends Jimmy away saying "I called Joe because I know he's a certified plumber! If you're name's not Joe, then I don't want to see you on my property!" He then calls and reschedules a later appointment with Joe...

What the homeowner won't discover is that Jimmy

  1. does better work than Joe
  2. costs 20% less.

Unique-ISH Features

Or perhaps "Uniquely Feature-ish", which could be shortened to "U-Fish", which would be oddly appropriate as a double-entendre... What the hell am I talking about?

When I finished the initial draft of the Galleon Forum ports article where I showed side-by-side samples of code from several popular ColdFusion frameworks plus my own blasphemy, I included a section toward the end of the article titled "Unique-ish features". Once or twice over the years, I've been asked what I think are the "unique features" of the onTap framework and I've always said oh well the SQL library (ORM) and the XHTML library and I may have mentioned one or two other things... but in the article I made a point of mentioning that there really isn't such a thing as a "unique feature". There are only "currently unique features", meaning that it hasn't been replicated or ported to any other contexts... yet. Any feature can be ported to whatever framework or other context where you want to use it.

I realize that I'm going to have to edit that section again. If you look at the list of features, you can see the obvious bias in the list of features and I'm pretty sure I'll be adding some to the list for ColdBox and Model-Glue because I overlooked them (or wasn't aware of them). But what I really overlooked is that I made no mention of the goals of each framework project. The onTap framework has a goal of being a full-stack framework, that's no secret. It is that way because that's what I feel is most helpful to me personally in producing what I feel are good solid application very quickly. There's a fair amount of the same kind of "bells and whistles" stuff in ColdBox as well. I personally perceived Model-Glue as being fairly sparse, although that may be because I wasn't interested in the IoC or the scaffolding at the time.

And then I noticed an article on Peter Farrell's blog about feature requests for the next version. I'm going to quote Peter here so you can have a better idea what I'm talking about:

YOUR SUGGESTIONS

Feedback from users of any project is the only way we can develop software that works for you. No suggestion is too stupid to be said here, but don't be offended if we question if it is in line with the core values behind Mach-II. This is our job ;-)

We have no plans to introduce "full stack" features into Mach-II. By "full stack" we are referring to things such as built-in ORM (since it's easy to integrate ORM already via a plugin or ColdSpring) or scaffolding. So please hold back suggestions that would clearly make Mach-II into the next Rails for ColdFusion project. If you're in doubt about the category of your suggestion, then please offer it up, but don't be offended if we categorize the suggestion as "full stack".

So if you were to put the timelines of these projects, mine, Model-Glue and Mach-II all out on a sheet side by side, you might see lots of little dots on the map for the onTap framework showing where little helper features were introduced or enhanced and maybe a few less on the line for Model-Glue and then the line for Mach-II would be pretty sparse (though they do add features). And you might think "oh Mach-II isn't very actively developed". But that's misleading because their scarcity of features isn't an indication of the amount of time the team devotes to that project. Indeed the Mach-II team are also devoting time to other related things like training and I understand they were doing some training in the hotel just before cfobjective. The fact that their "feature list" is sparse is much less an indication of their involvement with the project than it is an indication that they have a very specific goal to keep the project from becoming inflated with lots of ancillary code. They want to keep the project small, that's their goal.

Long story short, it's not entirely fair to view the list of "unique-ish" features the way that you might see them in the product comparisons on the back of a box of software where the manufacturer shows a long list of features with a column for each of their competitors and check marks next to each feature showing how their product has more than any of the other products. If you want a project to which very large amounts of forethought are devoted to each new enhancement and the project itself is kept small and you can "grab it and go" and it doesn't make you download all sorts of things you're not going to use, then Mach-II would be a very good choice.

And then you can integrate it with DataFaucet to use for your ORM. ;)

More Entries

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