Viewing by month: December 2007

Dec 19 2007

Model-Glue "Results" vs. Other Frameworks

One of the questions I frequently answer about Model-Glue is why there's the added complication of the "results" mechanism. In other frameworks, such as Mach-ii or ColdBox, the controller tier often explicitly adds another event to the event queue.

Update: Mach-ii Correction

Mach-ii has a feature named "event mappings" that solve the issue I bring up in this post, decoupling controller code (listeners) from their context in terms of other event names. Thanks to Sean Corfield for pointing this out.

Framework-neutral pseudo-code:

<cfset event.addAnotherEvent("someOtherEventName") />

For a more concrete example (read close, we'll show why Results help using this one!):

<!--- If the user submitted their profile form w/ valid input, show the saved message event --->
<cfif profileFormIsValid()>
   <cfset event.addAnotherEvent("showUserSavedMessage") />
<!--- Else, show the form again --->
<cfelse>
   <cfset event.addAnotherEvent("showProfileForm") />
</cfif>

It's simple, and it's direct. Nobody has a problem understanding it, and it does exactly what is says.

Quickly on with Model-Glue (and with some prodding from Sean Corfield), I saw that this method has a serious flaw. In a Front Controller framework (MG, M2, ColdBox, Fusebox...), the controller tier becomes brittle when it's too aware of its execution context.

Too aware of execution context?

Experienced MVC and Model-Glue developers know that the best controller is a thin controller. It doesn't overstep its bounds to perform business logic or know too much about the view (other than form / url names), other controller, or anything else going on "outside" of itself.

When we start hard-coding event names into a controller's listener function, we begin violating this. The controller's listener functions go from lean bits of control logic and take on the role of flow-control, knowing their context.

When does this get ugly?

Let's pretend that we've got two forms, both editing a user's profile. One is used by the user her/himself, and the other is used by an administrator. When they're both submitted, the same unit of work should be performed: values from the form are collected, validated, and handed off to the model for action.

We want to follow the DRY principle, and basically use the same listener function / server-side action to handle either.

In our non-result setup, we might end up with something like this:

<!--- If the user submitted their profile form w/ valid input, show the saved message event --->
<cfif profileFormIsValid()>
   <cfif getCurrentEvent() eq "showProfileForm">
      <cfset event.addAnotherEvent("showUserSavedMessage") />
   <cfelseif getCurrentEvent() eq "adminProfileForm">
      <cfset event.addAnotherEvent("showAdminUserSavedMessage") />
   <cfelse>
      <cfthrow message="Invalid event to save a user!" />
   </cfif>
<!--- Else, show the form again --->
<cfelse>
   <cfif getCurrentEvent() eq "showProfileForm">
      <cfset event.addAnotherEvent("showProfileForm") />
   <cfelseif getCurrentEvent() eq "adminProfileForm">
      <cfset event.addAnotherEvent("adminProfileForm") />
   <cfelse>
      <cfthrow message="Invalid event to save a user!" />
   </cfif>
</cfif>

Whoa Nelly! In order to re-use code, we just had to explode it to handle multiple string literals that are all based on stuff going on outside of the controller itself! That's not good!

Implicit Invocation to the rescue!

Mach-ii and Model-Glue are all about implicit invocation. Both focus on a broadcast / listener scheme (with differing implementations). Model-Glue, however, adds a second II implementation, in terms of its "results" mechanism. When a message listener (controller function) runs, it can "state" that something has happened, such as an invalid form submission. It's up to the outside world (your applications Model-Glue XML file) to determine whether or not to handle it.

Under this mechanism, we can simplify our code drastically:

<cfif profileFormIsValid()>
   <cfset event.addResult("formDataIsValid") />
<cfelse>
   <cfset event.addResult("invalidFormData") />
</cfif>

Now, multiple contexts (the admin and the user profile forms) can execute the same code, each taking their own action based on what's occurred.

We've:

  • Kept the Controller lean. All it does is take state, hand it to model components, set view data, and announce results.
  • Decoupled Controller code from View context. We're no longer dependent on what event is being run when inside our controller.
  • Increased flexibility and maintenance. We can now add more events that save profiles (such as a remote event or a JSON exposure of the logic) without having to account for it in a massive .

Parting thoughts

One benefit of architectural frameworks should be provision of easy to use mechanisms that increase the quality of an application's architecture. While it's straightforward to implement an MVC framework, MVC alone doesn't provide the same degree of flexibility and elegance as MVC plus Implicit Invocation.

Given that the MVC frameworks for ColdFusion all organize your code into "units of work" in the form of Fuses, message listeners, or "event handler functions" (best way I can describe ColdBox), ask yourself this: If your units of work call other "units of work" by an explicit name, how's your architecture any different from building an application based on the brittleness of <cfmodule> and <cfinclude>, just like we did ten years ago?

7 comments - Posted by Joe Rinehart at 12:09 PM - Categories: Model-Glue

Dec 14 2007

What Will Ava Do? The results are in!

This evening, I wrote the SQL statement to figure out who correctly guessed our daughter's due date, time, weight, and length, and the results are in!

Ava was born on Sunday, December 19, 2007 at 9:48am at 8lbs 0oz.

Overall

(calculated by ascending sum of oz error + inches erro + days error + hours error)

  1. Susan Fitzgerald
  2. Charlie (my Godfather)
  3. John Quarto-vonTivadar
  4. Heather (from our NWF days)
  5. jd

Here's the winners by category, followed by overall:

Closest on Weight

  1. Jason (from wanax.com)
  2. Charlie (my Godfather) (1oz off!)
  3. Karen L. (2oz off!)
  4. Susan Fitzgerald (2oz off!)
  5. Heather (from our NWF days) (2oz off!)

Closest on Length (all exactly, because I rounded to nearest inch on the backend...oops.)

  1. Charlie (my Godfather)
  2. Kimberly Langston (our most excellent neighbor)
  3. Karen (Dale's sister)
  4. Nikki
  5. MOMENTOR (another neighbor)
  6. Mike Langston (our most excellent neighbor)
  7. Mark
  8. Keith Center
  9. Paul Marcotte
  10. Susan Fitzgerald
  11. Sam
  12. Sean Woods
  13. Doug (of Alagad)
  14. Ryan W
  15. Carla Brown

Closest on Due Date (all tied)

  1. Holly
  2. John Allen
  3. Carrie Bateman
  4. Roy Martin
  5. Mark
  6. Susan Fitzgerald
  7. Lola LB
  8. Heather
  9. Doug (of Alagad)

Closest on Minute Born

  1. Tim Davis (0.05 hours off!)
  2. Chris Hoffman (0.2 hours off!)
  3. Michelle Leonard (0.45 hours off!)
  4. Roy Martin (0.55 hours off!)
  5. Cate Sia (0.70 hours off!)

3 comments - Posted by Joe Rinehart at 5:38 PM - Categories: Off Topic

Dec 12 2007

Rinehart 2.0 - Ava Louise is born!

Hi everyone - thanks for the e-mails, blog comments, IMs, and phone calls!

On Sunday December 9 at 9:48a eastern time, our first child, Ava, was born. She was exactly 8lbs in weight, 20.75 inches long, and immediately displayed impressive lung/vocal power. Mom and baby are both doing well - we slept 6 hours last night (split up between feedings!).

I'm not going to blog too much about her - Dale does an excellent job maintaining our personal blog, and I'm sure she'll write about her in detail.

Here's a few pics from her time in the hospital:

One minute old, and the first picture of her taken by me.

About a day old.

Getting changed by Mom in preparation for the trip home.

Dressed up to go home (that's my hand in there - she's tiny!).

Thanks, Jared, for the low-light no-flash photo tips at MAX!

16 comments - Posted by Joe Rinehart at 11:04 AM - Categories: Off Topic

Dec 6 2007

Firemoss and Model-Glue on New Server

My apologies for any interruptions to Firemoss or Model-Glue web sites this afternoon. I've moved off of a shared dedicated server that was a bit of a co-op between Doug Hughes, Scott Stroz, and myself, and I'm now on my own server.

Please let me know if anything you're using breaks - there's a lot of old stuff linked from this blog! DNS is currently propagating for firemoss.com and model-glue.com, so there's no telling which server you're on, as everything should be pointing to the same database server.

2 comments - Posted by Joe Rinehart at 3:58 PM - Categories: Firemoss

Dec 5 2007

MG3 Goodies: "Request Phase" architecture

One of the largest under-the-hood changes coming in Model-Glue 3 is what's known as a "request phase." It's not the easiest topic to write about, but it's making the framework much nicer to write, and it'll mean further extensibility and ease of modification for Model-Glue users.

The best way to understand it is to first see what happened upon invoking an event in earlier editions of Model-Glue. Basically, it went something like this:

  1. Add the modelglue.onRequestStart event and run results until the event queue is empty.
  2. Add the user's requested event and run results until the event queue is empty.
  3. Add the modelglue.onQueueComplete event and run the event queue until it's empty.
  4. Render views.
  5. Invoke the modelglue.onRequestEnd event and run the event queue.
  6. Render views.

It's a bit repetitive, and it was hard-coded into place. However, it's easy to see three phases in this: request initialization (onRequestStart), user request invocation (ends with onQueueComplete), and request termination (onRequestEnd).

In Model-Glue, the old flow will be in place, but the framework will be configured (via ColdSpring by default) with the various phases to execute as part of an event request.

Each "phase" is really just the execution of an initial event-handler, any queued results, and optional rendering/flushing of the view queue.

By defining internal event handlers (such as modelglue.onRequestStart) and dispatching them as parts of phases, under-the-hood Controllers can take over tasks such as populating the event context ("viewstate") and even configuring the framework itself.

New phases that have been identified:

  1. Request initialization will be a phase. In it, a request context is created (what most people know as "arguments.event") and populated with information from FORM, URL, etc.
  2. Loading of modules (event handlers and controllers) itself will be a phase, occurring after creation of an event context when the framework is in "development" mode or application is initialized.

What this means for you:

For most Model-Glue users, this means you'll have more "plug-in" points such as "onRequestStart." Expect to see points such as the following pop up:

* onSessionStart

* onSessionEnd

* onApplicationStart

* onDevelopmentRequestStart

* onEventContextCreation

* onMissingEvent

For those really looking to modify the heck out of Model-Glue, you'll be able to write your own request phase implementations. I'm not too sure what they'd do, but I'm sure someone will invent something!

3 comments - Posted by Joe Rinehart at 3:45 PM - Categories: Model-Glue

Dec 4 2007

Model-Glue 3 ("Gesture"): Under development now!

I've just kicked off development of what is to become Model-Glue 3.0. It's not going to be anything exciting for a while: the first big milestone is to re-implement the core event bus with unit tests and more flexible (interface driven) design.

My mission for Model-Glue 3.0 is this: it's going to be a framework that you barely notice is there. Model-Glue 1.0 did this, in respect to other frameworks of it's day. It's time to up the bar and find new ways to make life easier.

Key focuses of Model-Glue 3.0 will be:

* Decreasing developer effort through what will be known as "event types" and generation of common workflows.

* Implicit inclusion of UDF libraries through what will be known as "helpers"

* Better support for building modular applications

* Increasing flexibility with even more interface-driven portions of the framework

* Increased plug-in points (onSessionStart, onSessionEnd, onDevelopmentRequestStart)

As soon as something usable is available, I'll flip the anon-access switch on the repository to read-only to make a "bleeding edge" release available. The first public code is likely to be not fully reverse compatible and to not have any ORM support.

23 comments - Posted by Joe Rinehart at 4:31 PM - Categories: Model-Glue