<?xml version="1.0" encoding="utf-8"?>
			
			<rss version="2.0">
			<channel>
			<title>Iterate Me: Brian Klaas: Blog - Software Development</title>
			<link>http://www.iterateme.com/blog/index.cfm</link>
			<description>Educational, software development and pop culture all mashed up.</description>
			<language>en-us</language>
			<pubDate>Mon, 06 Sep 2010 20:31:02-0400</pubDate>
			<lastBuildDate>Tue, 07 Jul 2009 13:29:00-0400</lastBuildDate>
			<generator>BlogCFC</generator>
			<docs>http://blogs.law.harvard.edu/tech/rss</docs>
			<managingEditor>brian@iterateme.com</managingEditor>
			<webMaster>brian@iterateme.com</webMaster>
			
			<item>
				<title>Book Review: Spring Recipes</title>
				<link>http://www.iterateme.com/blog/index.cfm/2009/7/7/Book-Review-Spring-Recipes</link>
				<description>
				
				&lt;img align=&quot;right&quot; src=&quot;/blog/images/posts/springRecipies.gif&quot; width=&quot;125&quot; height=&quot;164&quot; hspace=&quot;10&quot;/&gt;I&apos;m a really big fan of &lt;a href=&quot;http://www.coldspringframework.org/&quot;&gt;ColdSpring&lt;/a&gt;. I&apos;d say that it is one of the key enablers for enterprise-class, object-oriented software development using ColdFusion. I can&apos;t imagine building a CF app without it now.

ColdSpring took its inspiration from the much larger, much more powerful &lt;a href=&quot;http://www.springsource.org/&quot;&gt;Spring&lt;/a&gt; framework. ColdSpring represents but a mere subset of everything that Spring can do. That&apos;s not a knock against ColdSpring &amp;mdash; Chris Scott was very clear about his intentions when he originally developed the framework. As I&apos;ve tried to expand my knowledge of software development, and, more specifically, &lt;a href=&quot;http://groovy.codehaus.org/&quot;&gt;Groovy&lt;/a&gt; and &lt;a href=&quot;https://www.hibernate.org/&quot;&gt;Hibernate&lt;/a&gt; in particular, the Spring framework has come up again and again. I decided it was time to move beyond my ColdSpring-based understanding of Spring and try to learn about Spring itself.

The first stop on this journey has been &quot;&lt;a href=&quot;http://www.amazon.com/Spring-Recipes-Problem-Solution-Approach-Professionals/dp/1590599799/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1246987367&amp;sr=1-1&quot;&gt;Spring Recipies: A Problem-Solution Approach&lt;/a&gt;,&quot; by Gary Mak. This is an intensive, though not exhaustive, look at what Spring has to offer. It covers all of the major components of Spring, above and beyond its very robust &lt;a href=&quot;http://en.wikipedia.org/wiki/Dependency_Injection&quot;&gt;Dependency Injection&lt;/a&gt; framework. 

The book covers numerous aspects of the larger Spring framework, including:

&lt;ul&gt;
&lt;li&gt;The Basic and Advanced Spring Dependency Injection Container&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Aspect-oriented_programming&quot;&gt;AoP&lt;/a&gt; in Spring: Classic, 2.0x and the AspectJ&lt;/li&gt;
&lt;li&gt;Spring JDBC templating&lt;/li&gt;
&lt;li&gt;Spring Transactions Framework (for database transactions)&lt;/li&gt;
&lt;li&gt;Spring + Hibernate&lt;/li&gt;
&lt;li&gt;Spring MVC&lt;/li&gt;
&lt;li&gt;Spring Testing Support for JUnit and TestNG&lt;/li&gt;
&lt;li&gt;Spring Security&lt;/li&gt;
&lt;li&gt;Integrating Spring with Portals and Portlets&lt;/li&gt;
&lt;li&gt;Spring Web Flow (of particular interest to me)&lt;/li&gt;
&lt;li&gt;Spring &quot;Remoting&quot;&lt;/li&gt;
&lt;li&gt;Spring support for scheduling and email&lt;/li&gt;
&lt;/ul&gt;

There are a few other topics covered as well, but the point of listing all that is covered in the book is to give you an idea of the depth and complexity of the Spring framework. Dependency injection is just one part of this ginormous (and some say needlessly complex) framework. One of the nice things about Spring is that although it&apos;s large and complex, you can use just the pieces you want: you don&apos;t have to utilize the _entire_ framework in building your Java application.

Each one of the above topics is given fairly good coverage in the book. Some topics are relatively straightforward and so don&apos;t get a lot of pages, while the more complex topics get many more pages. The writing is clear and the examples quite good, even for someone like me who isn&apos;t exactly an expert in Java development. It was very clear to me, after completing each major section, why I would or would not want to use a particular feature of the larger Spring framework. The examples, which are numerous, demonstrate Spring&apos;s power at templating otherwise duplicate code throughout whatever application development needs you may have. Yes, this results in more and more XML, though annotations go a long way to reducing the amount of XML in the configuration files.

One flaw in the book &amp;mdash; and it&apos;s more a limitation of the printing industry than anything else &amp;mdash; is that once the basic examples are out of the way, the author refers you to the online documentation for additional examples or much of an in-depth coverage of a particular aspect of the framework. This isn&apos;t entirely surprising, though. There are &lt;a href=&quot;http://www.apress.com/book/search?searchterm=spring&amp;act=search&amp;submit.x=0&amp;submit.y=0&quot;&gt;many books written about the individual parts of the larger Spring framework&lt;/a&gt;, so it&apos;s doubtful that one, single book could cover everything in depth and detail.

The book&apos;s clarity and intelligence has inspired me to learn more about some of what Spring can do. &lt;a href=&quot;http://static.springsource.org/spring-webflow/docs/2.0.x/reference/html/index.html&quot;&gt;Spring Web Flow&lt;/a&gt; is really interesting to me, as a developer of Web applications, and I plan on learning more about it and figuring out how I can implement some adaptation of it in my own applications. I suppose that I should go and try to build a Spring-based application as well, but I like to bring things back to ColdFusion whenever possible. 
				</description>
				
				<category>Software Development</category>				
				
				<pubDate>Tue, 07 Jul 2009 13:29:00-0400</pubDate>
				<guid>http://www.iterateme.com/blog/index.cfm/2009/7/7/Book-Review-Spring-Recipes</guid>
				
			</item>
			
			<item>
				<title>Be Part of the Solution</title>
				<link>http://www.iterateme.com/blog/index.cfm/2009/4/30/Be-Part-of-the-Solution</link>
				<description>
				
				A &lt;a href=&quot;http://thinkvitamin.com/features/hey-lose-the-pedantic-negativity/&quot;&gt;blog post over on Vitamin&lt;/a&gt; (a fine resource for Web application development articles) got me reading a commentary by Virginia Hefferman at the New York Times Magazine about the &lt;a href=&quot;http://www.nytimes.com/2009/04/26/magazine/26wwln-medium-t.html?_r=3&amp;pagewanted=1&amp;ref=magazine&quot;&gt;knee-jerk reflexivism so rampant in online &amp;quot;commenting&amp;quot; tools&lt;/a&gt;. It&apos;s a worthy read (even if she fails to make the distinction between generalist sites (ie; newspapers) and specific, targeted communities).

It got me thinking, though, about something I&apos;m making a conscious effort to do in my everyday Web application development work: be part of the &lt;em&gt;solution&lt;/em&gt; to a problem and encourage others to be the same. 

Here&apos;s the crux of the matter: You can&apos;t just say that a Web application or framework or library is terrible. &lt;strong&gt;You have to be willing to say how to make it better.&lt;/strong&gt; It&apos;s easy to dump in 140 characters or less, but how about you try to figure out a way to make it better? Here&apos;s a classic example of this, refracted through the lens of my day job:

&lt;div style=&quot;background-color: #d5ffd9; border: 1px solid #000000; padding: 8px;&quot;&gt;
Faculty member: This is the worst application I&apos;ve ever had to deal with.

Me: If you have suggestions on improving or fixing the application, I&apos;d love to hear them.

Faculty member: [Silence]
&lt;/div&gt;

Now this may just be a case of a user feeling that they have vastly more important things to do than figure out how to solve someone else&apos;s problems, or that we should be good enough at what we do to just get it right the first time out. They&apos;d be partly right on both fronts. But it&apos;s so easy, so trivial to dump all over the work of others, particularly when enabled with the commenting power found in blogs, Facebook, Twitter, and elsewhere, that we forget that if we know how to do it better, we should ourselves up to the same possibility of negative attack and offer how to do it better.

I&apos;m not saying that you then have to go out and implement every feature request or idea someone comes up with (and &lt;a href=&quot;http://www.37signals.com/svn/archives2/getting_real_forget_feature_requests.php&quot;&gt;a single feature request should rarely turn in to an implemented feature&lt;/a&gt;), but you can &amp;mdash; should &amp;mdash; demand that they who complain be part of the solution.

I&apos;d argue that the same should go for movies, literature, and politics, but that&apos;s a whole other post. 
				</description>
				
				<category>Software Development</category>				
				
				<pubDate>Thu, 30 Apr 2009 11:44:00-0400</pubDate>
				<guid>http://www.iterateme.com/blog/index.cfm/2009/4/30/Be-Part-of-the-Solution</guid>
				
			</item>
			
			<item>
				<title>JK Rowling on the Power of Failure and Imagination</title>
				<link>http://www.iterateme.com/blog/index.cfm/2009/4/6/JK-Rowling-on-the-Power-of-Failure-and-Imagination</link>
				<description>
				
				I &lt;a href=&quot;http://twitter.com/brian_klaas&quot;&gt;tweeted&lt;/a&gt; about this earlier today, but &lt;a href=&quot;http://harvardmagazine.com/commencement/the-fringe-benefits-failure-the-importance-imagination&quot;&gt;JK Rowling&apos;s 2008 Harvard commencement speech&lt;/a&gt; on the twin pillars of failure and imagination was an awfully good read (though not good enough to topple &lt;a href=&quot;http://news.stanford.edu/news/2005/june15/jobs-061505.html&quot;&gt;Steve Jobs&apos; Stanford commencement address&lt;/a&gt; as the best I&apos;ve read). 

&lt;object width=&quot;400&quot; height=&quot;302&quot;&gt;&lt;param name=&quot;allowfullscreen&quot; value=&quot;true&quot; /&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot; /&gt;&lt;param name=&quot;movie&quot; value=&quot;http://vimeo.com/moogaloop.swf?clip_id=1711302&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1&quot; /&gt;&lt;embed src=&quot;http://vimeo.com/moogaloop.swf?clip_id=1711302&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1&quot; type=&quot;application/x-shockwave-flash&quot; allowfullscreen=&quot;true&quot; allowscriptaccess=&quot;always&quot; width=&quot;400&quot; height=&quot;302&quot;&gt;&lt;/embed&gt;&lt;/object&gt;

The speech was timely for me as I&apos;ve recently been dealing with the issue of failure in relation to a product we rolled out at the beginning of the year which was, ultimately, deeply flawed and brought upon my head the wrath of many, many users. 

The product didn&apos;t fail to meet the feature requests and needs of the users. It had all the features they had requested and then some. Where it failed, miserably, was in implementation. From the overall UI direction, to security, to QA testing, there were failures large and small which, when driven home through extensive use of the product, made many in our user base not just dislike the product, but &lt;em&gt;hate&lt;/em&gt; it. I&apos;ve now come to look at it as the &lt;a href=&quot;http://blogs.msdn.com/rick_schaut/archive/2004/02/26/80193.aspx&quot;&gt;Word 6.0&lt;/a&gt; of our product development history.

There&apos;s a silver lining, though. Through failure, we&apos;ve gone hat-in-hand to our users to ask how we can do things better and have gotten some really great ideas on how to fix things in return. We&apos;ve taken a look at our overall development process and tweaked it to improve visibility earlier in the product development cycle. We&apos;ve reviewed QA and testing practices and empowered that team to speak up earlier and hold releases if evaluative criteria have been met.

Failure is a powerful tool in the software development arsenal. It&apos;s scary, sure, but a superb teaching tool because it forces you to imagine how to do things better and then to actually do better the next time around. 
				</description>
				
				<category>Software Development</category>				
				
				<pubDate>Mon, 06 Apr 2009 09:44:00-0400</pubDate>
				<guid>http://www.iterateme.com/blog/index.cfm/2009/4/6/JK-Rowling-on-the-Power-of-Failure-and-Imagination</guid>
				
			</item>
			
			<item>
				<title>A Small SVN/Eclipse Pointer</title>
				<link>http://www.iterateme.com/blog/index.cfm/2009/2/9/A-Small-SVNEclipse-Pointer</link>
				<description>
				
				I&apos;m sure that this is well documented and common practice, but I&apos;d never run in to a problem submitting my Eclipse .project files to a Subversion repository before. I mean, why not, right? The .project file is included when you first try to commit, it&apos;s in the same folder as the rest of the files versioned by Subversion, so what could possibly be wrong with doing that?

When I went to check out a project using &lt;a href=&quot;http://subclipse.tigris.org/&quot;&gt;Subclipse&lt;/a&gt; in to a fresh install of Eclipse, I found out why. The new project wizard won&apos;t let you check out a Subversion-controlled project if there&apos;s a .project file in the contents you are trying to check out. Oops!

The moral of the story: don&apos;t put your .project file in to the repository. Not that it needs to be there anyway, but that was my noob mistake.

As I couldn&apos;t delete the .project file using Subclipse, I fired up the lovely and handy &lt;a href=&quot;http://versionsapp.com/&quot;&gt;Versions&lt;/a&gt; to take care of that for me. Once the .project file was deleted from the repository (along with a note about my foolishness in the commit log), I was good to check out using the new project wizard in Eclipse. 
				</description>
				
				<category>Software Development</category>				
				
				<pubDate>Mon, 09 Feb 2009 13:31:00-0400</pubDate>
				<guid>http://www.iterateme.com/blog/index.cfm/2009/2/9/A-Small-SVNEclipse-Pointer</guid>
				
			</item>
			
			<item>
				<title>IE Caching Wastes Hours of My Life</title>
				<link>http://www.iterateme.com/blog/index.cfm/2008/12/30/IE-Caching-Wastes-Hours-of-My-Life</link>
				<description>
				
				I should have known better. I should have remembered. I&apos;ve seen it before, but it bit me again: IE&apos;s abusive caching destroys the quiet peace of developing with JavaScript libraries like &lt;a href=&quot;http://www.prototypejs.org/&quot;&gt;Prototype&lt;/a&gt;.

Here&apos;s the issue: I was updating the content of a &amp;lt;div&amp;gt; on a page via a form field on the same page. Very simple stuff. It worked flawlessly on Safari and Firefox (no surprises there), but failed on IE7. I tried the same code on a different machine running the &lt;em&gt;exact same version of IE7&lt;/em&gt; down to the xxx.xxx.xx.xxxx build, and it worked just fine. I tried it on a third machine and it failed. WTF?

The culprit, as I should have remembered from reading endless blog posts every day, was IE&apos;s overly aggressive caching strategy. Now on the Web application in question, we&apos;re setting HTTP headers to &amp;quot;No-Cache&amp;quot; to avoid these kinds of issues, and that works well for full page reloads. It does not, however, always work for XMLHttpRequest calls.

The default setting for IE is to &amp;quot;Automatically&amp;quot; check for new versions of Web pages when requests are made. If you look under &amp;quot;Tools&amp;quot; -&amp;gt; &amp;quot;Internet Options&amp;quot; -&amp;gt; &amp;quot;Browsing History&amp;quot; -&amp;gt; &amp;quot;Settings,&amp;quot; the default is to check for new versions of Web pages &amp;quot;Automatically.&amp;quot; However, IE&apos;s idea of &amp;quot;Automatically&amp;quot; doesn&apos;t take in to account XMLHttpRequests.

The solution is simple: append a random value to each AJAX request and the problem vanishes because now each URL being requested is &amp;quot;unique&amp;quot; and IE&apos;s default, aggressive, abusive caching strategy is foiled. 

JavaScript example:

&lt;code&gt;
var cfcURL = &apos;myService.cfc&apos;;
var randomizer = Math.floor(Math.random()*50000);
var params = &apos;method=getContent&amp;differentiator=&apos; + differentiator;	
var myAjax = new Ajax.Request(cfcURL, {method:&apos;get&apos;,parameters:params,onComplete:udpateSomeDiv});
&lt;/code&gt;

Hours of my life wasted on something that should just work. 

Oh, that&apos;s right, that&apos;s Apple&apos;s motto, not Microsoft&apos;s. 
				</description>
				
				<category>Software Development</category>				
				
				<pubDate>Tue, 30 Dec 2008 08:45:00-0400</pubDate>
				<guid>http://www.iterateme.com/blog/index.cfm/2008/12/30/IE-Caching-Wastes-Hours-of-My-Life</guid>
				
			</item>
			
			<item>
				<title>How Do You Stop Users from Creating Duplicate Accounts?</title>
				<link>http://www.iterateme.com/blog/index.cfm/2008/10/24/How-Do-You-Check-For-Duplicate-Accounts</link>
				<description>
				
				I&apos;m prepping to build out a consolidated registration site for a couple of the services that we provide at &lt;a href=&quot;http://distance.jhsph.edu/&quot;&gt;my place of work&lt;/a&gt;. Instead of replicating a registration process across a couple systems, we&apos;re building a centralized registration system and users can then take those credentials and log in to the services that they need. (We&apos;re not replacing existing user accounts with &lt;a href=&quot;http://openid.net/&quot;&gt;OpenID&lt;/a&gt; and &lt;a href=&quot;http://oauth.net/&quot;&gt;OAuth&lt;/a&gt; or anything like that &amp;mdash; sorry!)

There&apos;s a lot of work we&apos;ll be doing to make the process simpler and more elegant than the current set of processes. One major hurdle remains, however: how to prevent users from creating duplicate accounts.

When users register for a site &amp;mdash; any site &amp;mdash; and if they don&apos;t access the site right away or within the next couple days, they often forget their account information. If they wait long enough, they&apos;ll even forget the email address with which they registered. This is particularly problematic in online education, as someone may take a class, then not take another for a year or two, but return to take another class at some distant point in the future when their email (or physical) address may have changed. We don&apos;t want them to make new accounts because then we don&apos;t have a unified history of their activity (and this can cause problems with things like prerequisite courses).

A common approach I&apos;ve seen and we&apos;ve used in the past is to check against the provided email address. If there&apos;s already an account in the system with the given email address, then you let the user know that they already have an account and provide them a link to retrieve that information.

However, if the user is trying to register with a different email address, they&apos;re going to make a duplicate account. The system isn&apos;t going to know that bsimpson@hotmail.com and santoslhalper@gmail.com are the same person. So what to do?

I&apos;m considering the following, but am very open to suggestions:

&lt;ul&gt;
&lt;li&gt;Check the first and last name: if there&apos;s a match to the first and last name, suggest display a list of email addresses that match and say &amp;quot;Hey, if one of these is your email address, go ahead and retrieve your account info.&amp;quot;&lt;br/&gt;&lt;br/&gt;&lt;/li&gt;
&lt;li&gt;Check the first and last name and city and state or country: It&apos;s very unlikely that there are two Janet Halzipools in Buffalo, New York, but one never knows. (In parts of South India, for example, a name like Omar Khan is very common, though less so in Reno, Nevada so maybe this approach won&apos;t work particularly well.)&lt;br/&gt;&lt;br/&gt;&lt;/li&gt;
&lt;li&gt;Check another unique identifier: We don&apos;t/won&apos;t/never will store Social Security Numbers, but if you have another unique identifier, you can always check against that. The University that I work for distributes unique identifiers to some, but not all, of our user base (hence the need for a separate set of authentication data). This would work pretty well, but if the user no longer has access to the email address which is associated in the system with this unique identifier, how do they retrieve their account information? Do you ask them to engage in the manual task of contacting support and then waiting for a response from support to get information updated in the system?&lt;/li&gt;
&lt;/ul&gt;

Once of my key considerations about any of the above strategies is this: if you find what you think is a match, how do you prompt the user to see if this is them without making them think their account security is at risk?

Again, any suggestions are welcome. Even if I can&apos;t remove duplicate account creation, if I can significantly reduce it with one or more of the above strategies, I&apos;ll be happy. 
				</description>
				
				<category>Software Development</category>				
				
				<category>ColdFusion</category>				
				
				<pubDate>Fri, 24 Oct 2008 21:47:00-0400</pubDate>
				<guid>http://www.iterateme.com/blog/index.cfm/2008/10/24/How-Do-You-Check-For-Duplicate-Accounts</guid>
				
			</item>
			
			<item>
				<title>Considering Mate and Swiz</title>
				<link>http://www.iterateme.com/blog/index.cfm/2008/10/1/Considering-Mate-and-Swiz</link>
				<description>
				
				I have a confession: I don&apos;t get to do much Flex development. I read up on it. I&apos;ve attended trainings. I go to classes. I watch webcasts and screencasts. I don&apos;t, however, have a lot of opportunities (or time) to build Flex apps. A lot of what I do mixes rich media and lots of text, and I&apos;m not sure that Flex (or Flash) is the best environment for lots of text. Feel free to argue or disagree in comments below.

One thing I do know is that I don&apos;t like to work without frameworks, regardless of the language in which I&apos;m working. Frameworks and standard libraries can take a lot of work out of developing applications, and can often help you organize your application according to best practices. In ColdFusion, I don&apos;t build applications without &lt;a href=&quot;http://www.mach-ii.com/&quot;&gt;Mach-II&lt;/a&gt; (or Model-Glue, but I&apos;m mostly a Mach-II developer).

In my Flex development experience thus far, I&apos;ve been working without additional frameworks (because &lt;a href=&quot;www.adobe.com/products/flex/&quot;&gt;Flex is a framework&lt;/a&gt;, after all). I&apos;ve played with &lt;a href=&quot;http://opensource.adobe.com/wiki/display/cairngorm/Cairngorm&quot;&gt;Cairngorm&lt;/a&gt; and understand how applications need to be laid out using that micro-architecture. It&apos;s a bit unwieldily for me. &lt;a href=&quot;http://puremvc.org/&quot;&gt;PureMVC&lt;/a&gt; is powerful as well, but, again, requires all sorts of extra classes and overhead that I&apos;m not a fan of. (And, honestly, I&apos;m not making AS3 apps, I&apos;m making Flex apps, so the advantages of a &quot;framework not tied to Flex&quot; don&apos;t really work for me.) I really like the XML-based configuration that Mach-II, Spring/ColdSpring, and other frameworks provide. I know that some people hate coding in XML, and it does have its downsides, but I think that the simplicity and clarity it brings to the process outweigh the large XML files.

As fortune would have it, there are two good options that have made their way from private alpha in to public beta: &lt;a href=&quot;http://mate.asfusion.com/&quot;&gt;Mate&lt;/a&gt; and &lt;a href=&quot;http://code.google.com/p/swizframework/&quot;&gt;Swiz&lt;/a&gt;. Mate is from the team at ASFusion, who brought us some really cool Flash tips and tricks as Flash, Flash Remoting and Flex began to be integrated with ColdFusion. Swiz is the brainchild of the very smart Chris Scott, who brought us the excellent &lt;a href=&quot;http://www.coldspringframework.org/&quot;&gt;ColdSpring framework&lt;/a&gt; (a requirement for anyone building CF apps these days).

In my initial explorations of these frameworks, I think the strength of each is as follows:

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mate&lt;/strong&gt; uses an event map to describe the flow of events/actions within the application. I really like that and it makes a ton of sense, especially coming from an XML-based framework like Mach-II.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Swiz&lt;/strong&gt; uses Inversion of Control and beautiful and handy things like annotations to significantly reduce coding and elegantly manage dependencies within your application.&lt;/li&gt;
&lt;/ul&gt;

Mate also offers all sorts of nicely encapsulated helpers for remoting and binding and dependency injection which make it pretty attractive. I don&apos;t know enough about Swiz at this point to say if it has all the same helpers and conveniences (and honestly, the documentation for Mate helps me understand a lot more about that framework that Swiz as Swiz currently lacks an equal amount of documentation). So given those conveniences and my comfort with the XML-based configuration/&quot;event map,&quot; I think Mate is the way for me to go, for now.

I&apos;ll blog about my experiences using Mate as I build apps with the framework. I&apos;m personally very thankful that such smart people have provided the developer community at large with these great, powerful, time-saving tools. 
				</description>
				
				<category>Flex</category>				
				
				<category>Software Development</category>				
				
				<pubDate>Wed, 01 Oct 2008 08:39:00-0400</pubDate>
				<guid>http://www.iterateme.com/blog/index.cfm/2008/10/1/Considering-Mate-and-Swiz</guid>
				
			</item>
			
			<item>
				<title>Designing the Obvious Moment</title>
				<link>http://www.iterateme.com/blog/index.cfm/2008/9/12/Designing-the-Obvious-Moment</link>
				<description>
				
				&lt;img align=&quot;right&quot; src=&quot;/blog/images/posts/designingTheObvious.jpg&quot; width=&quot;125&quot; height=&quot;188&quot; border=&quot;0&quot; hspace=&quot;10&quot; /&gt;&lt;a href=&quot;http://rhjr.net&quot;&gt;Robert Hoekman Jr.&lt;/a&gt; has written two quite excellent books on user interface and interaction design. I read these books earlier this year, but thought I&apos;d finally get to blogging about them as part of my ongoing book reviews.

&lt;a href=&quot;http://rhjr.net/dto/&quot;&gt;Designing the Obvious&lt;/a&gt; was the first of the two books and, for me, the more successful of the two. It&apos;s rich with UI design aphorisms that simply make good common sense. Written in a simple, conversational style that draws heavily from actual Web application development experience, this book, and its counterpart just make sense. The book deserves to be read by anyone who actually builds any kind of Web application user interface, no matter how simple or complex. One of the things I really liked about his approach was the whole concept of turning beginning users into intermediate users quickly. That was the inspiration for my whole series of posts on the &lt;a href=&quot;http://www.iterateme.com/blog/index.cfm?mode=entry&amp;entry=BFD57087-D227-BED8-3CCFA05C6845D9B4&quot;&gt;Contextual Guidance API&lt;/a&gt;. His outright demand that you make it simple, eliminate anything unnecessary in the app and in the design, and focusing on how you accomplish a task at every moment within the application is great advice. My team has taken that advice to heart and has begun designing our new applications around much of Hoekman&apos;s advice in this book. The result has been applications that visually make more sense to our clients, and clients that are really happy with what we&apos;re developing.

&lt;a href=&quot;http://rhjr.net/dtm/&quot;&gt;Designing the Moment&lt;/a&gt; is focused on very common, very specific moments of interaction with a Web application and how they can be made better. It&apos;s less cohesive as the previous book, which took more of a big-picture view to the art and process of designing user interfaces. In this book, the examples are very specific, somewhat less generalizable, but many of the same principles from Designing the Obvious come in to play. My sincere feeling is that a number of the solutions presented in this book will become outdated over the next couple of years (ie; blog and social networking site design) but, again, the basic principles of clarity, task-orientation and removing all but the essential are more than sound.

Designing the Obvious should be mandatory reading for all Web application developers, even those who rarely work on the UI. At the end of the day, the interface is the application, no matter what application you&apos;re using. Knowing how to create great interfaces is key to building great applications. 
				</description>
				
				<category>UI</category>				
				
				<category>Software Development</category>				
				
				<pubDate>Fri, 12 Sep 2008 09:37:00-0400</pubDate>
				<guid>http://www.iterateme.com/blog/index.cfm/2008/9/12/Designing-the-Obvious-Moment</guid>
				
			</item>
			
			<item>
				<title>The Interesting and Not So Interesting of Google&apos;s Chrome</title>
				<link>http://www.iterateme.com/blog/index.cfm/2008/9/2/The-Interesting-and-Not-So-Interesting-of-Googles-Chrome</link>
				<description>
				
				I&apos;ll readily admit that explaining the idea behind the Google Chrome project via a &lt;a href=&quot;http://books.google.com/books?id=8UsqHohwwVYC&amp;printsec=frontcover#PPA2,M1&quot;&gt;comic book&lt;/a&gt; created by the genius Scott McCloud (whose book &quot;&lt;a href=&quot;http://www.amazon.com/Understanding-Comics-Invisible-Scott-McCloud/dp/006097625X/ref=pd_bbs_sr_1?ie=UTF8&amp;s=books&amp;qid=1220360575&amp;sr=8-1&quot;&gt;Understanding Comics: The Invisible Art&lt;/a&gt;&quot; should be required reading for anyone who does any kind of visually creative work) is great. Licensing it via &lt;a href=&quot;http://creativecommons.org/&quot;&gt;Creative Commons&lt;/a&gt; is even better.

But I&apos;m not sure I get the need for another Web browser. If anything, I see this as merely a way for Google to continue to drive traffic to Google properties and bring a some &amp;quot;innovation&amp;quot; to the table in the process. If anything, it gives them an opportunity to start displaying &amp;quot;Works Best in Google Chrome&amp;quot; buttons on all their Web properties, just at the point that we&apos;ve begun to collectively move away from Web applications that only work in IE or Firefox.

I&apos;m pleased that Google has chosen to use &lt;a href=&quot;http://webkit.org/&quot;&gt;WebKit&lt;/a&gt; for the rendering engine, so if a page looks fine in Safari, it&apos;ll look fine in Chrome. However, they&apos;re using their own JavaScript engine, so Chrome becomes yet another Web browser on which you must test your applications.

Looking at the features of Chrome that Google itself highlights in the overview comic book, some of their innovations just don&apos;t seem compelling enough to warrant another browser.

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stability&lt;/strong&gt;: Safari, for me, is a very stable browser. Firefox and even Internet Explorer aren&apos;t half bad either. Browser crashes in this day and age are usually the result of a) out of control memory consumption by bad JavaScript, b) plug-in interaction gone haywire, or c) an error thrown at the operating system level. Chrome will address a) by having each tab be individually threaded and sandboxed, which will prevent one bad application in one tab from bringing down the browser &amp;mdash; but that means applications can and will still crash, such as writing an email in GMail (the example used in the comic book). The plug-in interaction really can&apos;t be handled unless Chrome bans plug-ins, which is unlikely. Chrome itself is built on top of other operating systems (Windows, Mac, Linux), so it&apos;s still going to crash when there&apos;s an OS issue. No big win here, other than the individually threaded tabs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A Faster JavaScript Engine&lt;/strong&gt;: Um, &lt;a href=&quot;http://webkit.org/blog/189/announcing-squirrelfish/&quot;&gt;SquirrelFish&lt;/a&gt;? &lt;a href=&quot;http://www.mozilla.org/projects/tamarin/&quot;&gt;Tamarin&lt;/a&gt;? SquirrelFish is going to be part of WebKit, and Safari 4.0, and it&apos;s mighty fast. Firefox 3.1 will contain a new, very fast JavaScript engine. Processors get faster and so JavaScript processing on those processors gets faster. Google&apos;s new JavaScript engine (V8) may be faster, and it brings to the table some interesting compile-time optimizations. It&apos;s going to generate machine code rather than run interpretatively, but I wonder if this will only work if you use Gears and the &lt;a href=&quot;http://code.google.com/webtoolkit/&quot;&gt;GWT&lt;/a&gt;. If you&apos;re not required to use Gears +/or the GWT, then Chrome still have to compile and translate the JavaScript in to machine code when the page is loaded, generating a slowdown on page load times. At the end of the day, to the end user, will it really be remarkably faster, especially as SquirrelFish and the other JavaScript engines are open-source projects with lots of smart people working on them from all over the world? If V8 turns out to be a truly excellent JS engine, then it&apos;s nice that it&apos;s going to be available for other browser makers to use. Time and performance studies will show if it&apos;s useful and adaptable for others to use.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: Sure, IE 6 is very insecure. IE 7 is better, and there are exploits available for Firefox and Safari. But those browsers are pretty dang secure compared to where we were a year or two years ago. Apple may not be the best when it comes to openness and fixing exploits on the same day they&apos;re discovered, but they&apos;re not terrible, and serious exploits are fairly uncommon. Phishing detectors are built in to Firefox and IE, though sadly not Safari, so that&apos;s nothing new. The sandboxing Chrome brings to the table is interesting, especially as plug-ins (a common source of browser crashes and Windows-based exploits) are going to exist outside and &amp;quot;above&amp;quot; the sandbox for each individual tab. I wonder, though, if plug-in makers (ie; Adobe) are going to have to rewrite their plug-ins so they work via this new kind of sandbox. Are there improvements here? Yes, in the sense of the double-sandboxing of plug-ins, and the simple sandboxing of each page so that keyloggers or other malware can&apos;t see what you&apos;re doing in a given tab. That&apos;s a nice win for consumers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User Interface&lt;/strong&gt;: Um, Safari&apos;s interface? Firefox 3&apos;s interface? How much simpler can you get with a default UI and still be able to click through basic tasks in a browser? The &amp;quot;nine most recent or related pages&amp;quot; view by default? No thanks, I&apos;ll go where I want to go.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Open Source&lt;/strong&gt;: Well, WebKit, the core of Safari, is open source. The Mozilla project is open source. The final result may not be entirely open source, but how is this a big advantage or difference for Chrome?&lt;/li&gt;
&lt;/ul&gt;

I&apos;ll readily admit that the &amp;quot;Each tab gets its own thread/processing space&amp;quot; is rather nice. It&apos;ll make things work more smoothly. I&apos;d imagine, however, that it wouldn&apos;t be too hard for this to be added to Safari, Firefox, or even IE. I also like the idea of the Task Manager for the browser, so you can see what resources are being consumed by each tab and kill tabs that are problematic. (Though I do find it interesting in their illustration of this in the comic book that they point to plug-ins (read: Flash) as the real problem with memory bloat and crashing Web browsers.) And Google wouldn&apos;t be able to make the Task Manager work inside of someone else&apos;s browser, so they needed to write their own to accomplish that task.

I do appreciate the fact that Google is giving a wake-up call to browser makers. I do appreciate competition. I do appreciate the different approach they&apos;re bringing to the JavaScript engine and the double-sandboxing of tabs and plug-ins. 

I&apos;m still not convinced that this is a way of driving additional traffic to Google properties (well, of course it is) and that we won&apos;t start seeing &amp;quot;You must use Google Chrome to access GMail. Download now!&amp;quot; appear in the not-too-distant future. I also hope that this doesn&apos;t hurt the development of Gears for Safari, or Firefox, as I think that&apos;s an important project and the tools it brings to the table should be available across Web browsers.

I&apos;m also not convinced that the average user will switch away from Internet Explorer. It&apos;s the default, it&apos;s what they&apos;re used to using, it acts in a way that they are used to, and users, quite simply, hate change. Google is a trusted brand, but that doesn&apos;t mean they&apos;re going to get my parents, or my co-workers, or the students at the University where I work to change from clicking on that &amp;quot;e&amp;quot; on their desktop to &amp;quot;launch the Internet.&amp;quot; If they&apos;re going to take market share away from anyone, it&apos;s going to be Firefox and Safari, and, to a far lesser extent, Microsoft&apos;s dominant Web browser. 
				</description>
				
				<category>Software Development</category>				
				
				<pubDate>Tue, 02 Sep 2008 10:46:00-0400</pubDate>
				<guid>http://www.iterateme.com/blog/index.cfm/2008/9/2/The-Interesting-and-Not-So-Interesting-of-Googles-Chrome</guid>
				
			</item>
			
			<item>
				<title>On Creativity and Creative Culture</title>
				<link>http://www.iterateme.com/blog/index.cfm/2008/8/26/On-Creativity-and-Creative-Culture</link>
				<description>
				
				Ed Catmull, the cofounder and president of &lt;a href=&quot;http://www.pixar.com/&quot;&gt;Pixar Animation Studios&lt;/a&gt;, wrote &lt;a href=&quot;http://harvardbusinessonline.hbsp.harvard.edu/hbsp/hbr/articles/article.jsp?referer=/hbsp/hbr/articles/article.jsp&amp;productId=R0809D&amp;TRUE=TRUE&amp;reason=freeContent&amp;FALSE=FALSE&amp;ml_subscriber=true&amp;_requestid=13159&amp;ml_action=get-article&amp;ml_issueid=BR0809&amp;articleID=R0809D&amp;pageNumber=1&quot;&gt;an excellent piece for the Harvard Business Review on developing a creative -- no, inspired and inspiring -- business culture&lt;/a&gt;. It&apos;s an excellent read and totally applicable to any number of industries, from movies or theater to software development.

Catmull&apos;s central premise -- that you must hire truly creative people and give them free reign to succeed or fail wildly, and that &lt;strong&gt;everyone&lt;/strong&gt; involved in the process has value and voice and must be allowed to contribute -- speaks directly to my years of running a theater company and the thousands of hours I put in to directing. One of the very early lessons I learned is that I never had all the answers. Yes, there are lots of directors as dictatorial auteurs out there, but some of the best moments and best ideas in the productions I directed didn&apos;t come from me. They came from the set designer, or the stage manager, or the actor in the bit part, or the crew member who saw something, something inspiring and creative and &lt;em&gt;right&lt;/em&gt; and felt they could stand up and say something to me and I, in turn, was not so stupid as to pass up their great idea because it didn&apos;t come from me. I learned you had to foster that environment from day one, and if you did, you&apos;d get a final product that was about 100% better than a product you tried to design, develop, and deliver with autocratic power.

There are limits to this approach, of course. Someone has to take final accountability at the end of the day. Someone (or a group of someones, in Pixar&apos;s case) needs to be able to say &amp;quot;You know, that&apos;s interesting, but it&apos;s just not going to work.&amp;quot; You still need leaders and teams running the show from the top, but if everyone who remotely touches the project feels that they have a voice, that their voice matters, that we are all equal and creative and working towards the same goal, you inspire passion, inspiration, and, sometimes, greatness.

That&apos;s key to building a successful team, regardless of your industry. Pixar, of course, has the advantage of money, time, reputation, and &lt;a href=&quot;http://www.imdb.com/name/nm0005124/&quot;&gt;some&lt;/a&gt; &lt;a href=&quot;http://www.imdb.com/name/nm0004056/&quot;&gt;real&lt;/a&gt; &lt;a href=&quot;http://www.imdb.com/name/nm0083348/&quot;&gt;geniuses&lt;/a&gt; running the show. But the same principle applies if you&apos;re running a 68-seat theater company or building complex enterprise software. Don&apos;t discount the suggestion of the administrative assistant who uses your software or the stage crew member who has to bring on and off 38 pieces of furniture each night. They&apos;re involved. They have ideas. Listen and make them feel valued, and you&apos;ll end up with something much better than you could have ever made alone. 
				</description>
				
				<category>Software Development</category>				
				
				<pubDate>Tue, 26 Aug 2008 08:53:00-0400</pubDate>
				<guid>http://www.iterateme.com/blog/index.cfm/2008/8/26/On-Creativity-and-Creative-Culture</guid>
				
			</item>
			
			<item>
				<title>SOA in Practice: The Art of Distributed System Design</title>
				<link>http://www.iterateme.com/blog/index.cfm/2008/8/21/SOA-in-Practice-The-Art-of-Distributed-System-Design</link>
				<description>
				
				Thanks to the hour a day I spend riding mass transit to and from work (instead of the two hours a day I&apos;d spend sitting in my car), I get to read a lot. I&apos;d like to think that I&apos;m spending most of this reading time on contemporary fiction, but that&apos;s really not the case. I&apos;d estimate that a good 80% of my time is spent reading technology articles or books, or Entertainment Weekly. =)

Call me crazy, but I do read a good number of technical books on the subway. I&apos;ve not yet delved in to the arena of books reviews, but there&apos;s no good reason for that, especially with some of the excellent books I&apos;ve read of late.

&amp;quot;&lt;a href=&quot;http://oreilly.com/catalog/9780596529550/index.html&quot;&gt;SOA in Practice: The Art of Distributed System Design&lt;/a&gt;,&amp;quot; by Nicolai M. Josuttis, is a great introduction to the complexities of designing and deploying a service-oriented architecture for your business application needs. It&apos;s largely devoid of code, which some developers may find frustrating. I think that&apos;s a good thing, as SOA is about approach and not necessarily about the code it takes to set up and run those services.

I suppose you could call this a book for managers, or system architects who are just looking to get in to service-oriented architecture design, but I think it provides such a thorough, clear introduction to the idea of SOA (free from the marketing jargon of companies trying to sell you their SOA &amp;quot;solutions&amp;quot;) that it&apos;s valuable for any developer who wants to create more loosely coupled services inside a single application or across applications. After reading endless issues of &lt;a href=&quot;http://www.eweek.com/&quot;&gt;eWeek&lt;/a&gt; and &lt;a href=&quot;http://www.informationweek.com/&quot;&gt;Information Week&lt;/a&gt; and &lt;a href=&quot;http://www.cioinsight.com/&quot;&gt;CIO Insight&lt;/a&gt;, I certainly knew some of the principles behind the idea, some of the SOA bus solutions available, and how governance was really important to SOA rollouts, but as for the practicalities of how one might go about doing this in the real world? Not so much.

Aside from the clear insight Josuttis brings to the book from his own SOA experiences, it&apos;s the lessons learned the hard way that I found to be most useful. Josuttis brings up a lot of issues with messaging and &lt;a href=&quot;http://en.wikipedia.org/wiki/Idempotent&quot;&gt; idempotence&lt;/a&gt; that I had simply not considered before and now form a cornerstone of how I&apos;d look at developing a truly service-oriented architecture. That alone is worth the cost of admission.

Perhaps its lack of code will lead some reviewers to say this book is more for pointy-headed managers than developers (even I wanted to see a bit more on how he handled the messaging patterns he raised with some code examples, or some kind of concrete solution rather than saying &amp;quot;This is out there, deal with it&amp;quot;), but I think it&apos;s a darn fine and thorough look at getting started with SOA. 
				</description>
				
				<category>Software Development</category>				
				
				<pubDate>Thu, 21 Aug 2008 14:54:00-0400</pubDate>
				<guid>http://www.iterateme.com/blog/index.cfm/2008/8/21/SOA-in-Practice-The-Art-of-Distributed-System-Design</guid>
				
			</item>
			
			<item>
				<title>News and Tidbits on ColdFusion 9 (aka Centaur)</title>
				<link>http://www.iterateme.com/blog/index.cfm/2008/7/24/News-and-Tidbits-on-ColdFusion-9-aka-Centaur</link>
				<description>
				
				I just came across two blog posts which highlight some probably and some possible features for the next version of ColdFusion. My friend Adam Lehman (on Adobe&apos;s CF team) made &lt;a href=&quot;http://www.adrocknaphobia.com/post.cfm/centaur-coldfusion-9-user-research-complete&quot;&gt;an interesting post about the process that Adobe uses to develop new features&lt;/a&gt; for new versions of their products. It&apos;s a really interesting read, and the &lt;a href=&quot;http://www.productdevelopment.com/&quot;&gt;Synchronous Development process&lt;/a&gt; they use sounds quite interesting. You can&apos;t get the full details on that process from the SyncDev Web site because, well, their business is to sell consulting services. The key process idea of &amp;quot;Sell, Design, Build&amp;quot; (rather than &amp;quot;Design, Build, Sell&amp;quot;) is a really interesting one as it ensures that your customers (and people you want as your customers) would actually want to buy your product before you ever build it. That&apos;s pretty powerful stuff for ensuring that your customer base will actually go out and buy your product. This is especially true of software, where versions above #4 tend to be about adding &amp;quot;nice&amp;quot; features when the product has already solved the core problems it was meant to solve &lt;em&gt;or&lt;/em&gt; where the product has a free (often open-source) alternative.

While Adam doesn&apos;t talk about anything that hasn&apos;t been announced elsewhere, it&apos;s an interesting and valuable read to understand not only Adobe&apos;s product development process, but where the ColdFusion team, specifically, is coming from in determining the product&apos;s future.

Brian Rinaldi has put together &lt;a href=&quot;http://www.remotesynthesis.com/post.cfm/coldfusion-9-what-we-know-so-far&quot;&gt;a much more extensive look at all the public knowledge about ColdFusion 9&lt;/a&gt;. From process improvements to actual feature descriptions, his overview is a great read for anyone interested in the next version of the product and the language. I found it particularly interesting that it appears that Adobe has not gone the route of the &lt;a href=&quot;http://en.wikipedia.org/wiki/Active_record_pattern&quot;&gt;Active Record pattern&lt;/a&gt; with their &lt;a href=&quot;http://www.hibernate.org/&quot;&gt;Hibernate&lt;/a&gt; integration, which I think may not save developers a ton of time but will instead allow for more flexible, robust uses of Hibernate from within ColdFusion 9. Hibernate is going to save developers a lot of time as it is, so I don&apos;t think there&apos;s a big loss in productivity by not going the Active Record route. (Implicit getters and setters will be a &lt;strong&gt;huge&lt;/strong&gt; time saver, however.)

The big unknowns are the &amp;quot;management features,&amp;quot; as they&apos;re sometimes called. Those are the easy-to-grasp, sexy, obvious features which make it much easier to sell a product upgrade to managers. This could include &lt;a href=&quot;http://www.iterateme.com/blog/index.cfm/2008/7/14/Yet-Another-Reason-CF-Needs-a-Quality-IDE-Refactoring&quot;&gt;a real ColdFusion IDE&lt;/a&gt;, or audio/video management tools, workflow and BPEL engine integration, or who knows.

We&apos;ll know a lot more by the time MAX is over at the end of November. I&apos;m looking forward to the time we&apos;ll finally get to play with CF9! 
				</description>
				
				<category>Software Development</category>				
				
				<category>ColdFusion</category>				
				
				<pubDate>Thu, 24 Jul 2008 13:00:00-0400</pubDate>
				<guid>http://www.iterateme.com/blog/index.cfm/2008/7/24/News-and-Tidbits-on-ColdFusion-9-aka-Centaur</guid>
				
			</item>
			
			<item>
				<title>Doing the Upsert</title>
				<link>http://www.iterateme.com/blog/index.cfm/2008/5/21/Doing-the-Upsert</link>
				<description>
				
				&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/wheatfields/2177912522/&quot;&gt;&lt;img align=&quot;right&quot; src=&quot;/blog/images/posts/upsert.jpg&quot; border=&quot;0&quot; width=&quot;162&quot; height=&quot;204&quot; hspace=&quot;10&quot; /&gt;&lt;/a&gt;In the process of developing the contextual guidance API, I tried to push as much of the work as I could to the database. I knew that I would have to do multiple queries to check and see if a user had an existing record, when their last visit was to the application, and more. I had read some time ago about the concept of the &lt;a href=&quot;http://en.wikipedia.org/wiki/Upsert&quot;&gt;upsert&lt;/a&gt;, and thought this was a good time to put it in to practice.&lt;/p&gt;

&lt;p&gt;In many applications, you need to check to see if a record exists in a table, and do an UPDATE if a record does exist, or an INSERT if one does not exist. This is a common pattern in application development. Many developers do something like this:&lt;/p&gt;

&lt;code&gt;
Query the table to see if a record exists which matches the passed ID
IF match found {
	Run an UPDATE query
} else {
	Run an INSERT query
}
&lt;/code&gt;

&lt;p&gt;That&apos;s fine, but ultimately requires two trips to the database, or more, depending on what other conditional processing you need to do. The upsert combines all of this in to a single SQL statement. In addition, I needed to run some other database-related logic that would affect the SQL statement. If a user hadn&apos;t visited the application in more than 180 days (6 months), I wanted to treat them as a new user and delete their previous record in the log table. (You could set an &quot;isDeleted&quot; flag or delete the record, that&apos;s up to you.)&lt;/p&gt;

&lt;p&gt;My solution is as follows, and combines some conditional logic in ColdFusion with conditional logic in the SQL as well. This is for MS SQL Server, but the concept applies to pretty much any database.&lt;/p&gt;

&lt;code&gt;
&lt;!--- First check and see if a record for this user has been updated in the last 30 minutes. If so, don&apos;t do anything as that&apos;s not really a new session. ---&gt;
DECLARE @lastVisitDate datetime
set @lastVisitDate =
	(
	SELECT lastVisit
	FROM logTable
	WHERE userID = &lt;cfqueryparam cfsqltype=&quot;cf_sql_integer&quot; value=&quot;#arguments.userID#&quot; /&gt;
	AND appName = &lt;cfqueryparam cfsqltype=&quot;cf_sql_varchar&quot; value=&quot;#arguments.applicationName#&quot; /&gt;
	&lt;cfif Len(arguments.applicationSection)&gt;
		AND sectionName = &lt;cfqueryparam cfsqltype=&quot;cf_sql_varchar&quot; value=&quot;#arguments.applicationSection#&quot; /&gt;
	&lt;cfelse&gt;
		AND sectionName IS NULL
	&lt;/cfif&gt;
	AND DateDiff(n, lastVisit, getDate()) &gt; 30
	)
			
&lt;!--- If the @lastVisitDate value is not null, a record was found matching the criteria,  so we can do an update or insert, as needed. ---&gt;
IF @lastVisitDate IS NOT NULL
	BEGIN
		&lt;!--- If the user hasn&apos;t visited the app in more than 180 days, treat them as a brand-new user by deleting their record and starting fresh. ---&gt;
		IF DateDiff(d, @lastVisitDate, getDate()) &gt; 180
		     BEGIN
				DELETE FROM logTable
				WHERE userID = &lt;cfqueryparam cfsqltype=&quot;cf_sql_integer&quot; value=&quot;#arguments.userID#&quot; /&gt;
				AND appName = &lt;cfqueryparam cfsqltype=&quot;cf_sql_varchar&quot; value=&quot;#arguments.applicationName#&quot; /&gt;
				&lt;cfif Len(arguments.applicationSection)&gt;
					AND sectionName = &lt;cfqueryparam cfsqltype=&quot;cf_sql_varchar&quot; value=&quot;#arguments.applicationSection#&quot; /&gt;
				&lt;cfelse&gt;
					AND sectionName IS NULL
				&lt;/cfif&gt;
		     END
					
&lt;!--- Try the update first. If there&apos;s nothing to update, we need to do an insert instead. ---&gt;
		UPDATE contextualGuidanceLog
		SET totalVisits = totalVisits + 1,
			lastVisit = &lt;cfqueryparam cfsqltype=&quot;cf_sql_timestamp&quot; value=&quot;#CreateODBCDateTime(Now())#&quot; /&gt;,
		        previousLastVisit = (
						SELECT lastVisit FROM contextualGuidanceLog
						WHERE userID = &lt;cfqueryparam cfsqltype=&quot;cf_sql_integer&quot; value=&quot;#arguments.userID#&quot; /&gt;
						AND appName = &lt;cfqueryparam cfsqltype=&quot;cf_sql_varchar&quot; value=&quot;#arguments.applicationName#&quot; /&gt;
						&lt;cfif Len(arguments.applicationSection)&gt;
							AND sectionName = &lt;cfqueryparam cfsqltype=&quot;cf_sql_varchar&quot; value=&quot;#arguments.applicationSection#&quot; /&gt;
						&lt;cfelse&gt;
							AND sectionName IS NULL
						&lt;/cfif&gt;
						)
			WHERE userID = &lt;cfqueryparam cfsqltype=&quot;cf_sql_integer&quot; value=&quot;#arguments.userID#&quot; /&gt;
		        AND appName = &lt;cfqueryparam cfsqltype=&quot;cf_sql_varchar&quot; value=&quot;#arguments.applicationName#&quot; /&gt;
			&lt;cfif Len(arguments.applicationSection)&gt;
				AND sectionName = &lt;cfqueryparam cfsqltype=&quot;cf_sql_varchar&quot; value=&quot;#arguments.applicationSection#&quot; /&gt;
			&lt;cfelse&gt;
				AND sectionName IS NULL
			&lt;/cfif&gt;
					
		&lt;!--- If nothing was updated, then the resulting @@rowcount value will be zero. We need to do an insert in this case. ---&gt;
		IF @@rowcount = 0
			BEGIN
				INSERT INTO contextualGuidanceLog (
					userID,
					appName
					&lt;cfif Len(arguments.applicationSection)&gt;, sectionName&lt;/cfif&gt;
					)
					&lt;!--- totalVisits, lastVisit and previousLastVisit have defaults created in the table by the db ---&gt;
					VALUES (
						&lt;cfqueryparam cfsqltype=&quot;cf_sql_integer&quot; value=&quot;#arguments.userID#&quot; /&gt;,
						&lt;cfqueryparam cfsqltype=&quot;cf_sql_varchar&quot; value=&quot;#arguments.applicationName#&quot; /&gt;
						&lt;cfif Len(arguments.applicationSection)&gt;
								, &lt;cfqueryparam cfsqltype=&quot;cf_sql_varchar&quot; value=&quot;#arguments.applicationSection#&quot; /&gt;
						&lt;/cfif&gt;
					)
		      END
	END &lt;!--- End the &quot;IF @lastVisitDate IS NOT NULL&quot; IF ---&gt;
&lt;/code&gt;

&lt;p&gt;This may look a bit complex, but the key thing here is the UPDATE followed by the IF @@rowcount = 0 statement. If no records were updated (meaning there was no record to match the passed values), then we do an insert. This is just like our original logic, except we&apos;re doing everything in one query, rather than two. Because I also needed to check the last time a record for this person was updated and make sure we&apos;re not updating it more than once every 30 minutes, I combined 3 potential &amp;lt;cfquery&amp;gt; calls in to a single one.&lt;/p&gt;

&lt;p&gt;There&apos;s one issue, though, that I&apos;m not too happy with:&lt;/p&gt;

&lt;p&gt;I realize that I&apos;m repeating a bunch of code to generate the WHERE clause in these SELECT statements. I can&apos;t generate this text dynamically as a string and then &amp;lt;cfoutput&amp;gt; the WHERE clause because I&apos;m using &amp;lt;cfqueryparam&amp;gt;, as I damn well better be. I guess I could build a dynamic string and then wrap it in the Evaluate() function, but that seems pretty ugly to me (and may not work because of how CF&apos;s engine parses the query text and does the binding to the values in a &amp;lt;cfqueryparam&amp;gt; tag). Though I guess using Evaluate() isn&apos;t any uglier than the repeated code for the WHERE statement.&lt;/p&gt;

&lt;p&gt;I like the upsert approach. I&apos;ll be using it from here on out in these situations. If anyone has any suggestions about the repeated WHERE clause code, I&apos;d love to hear them!&lt;/p&gt; 
				</description>
				
				<category>Software Development</category>				
				
				<category>ColdFusion</category>				
				
				<pubDate>Wed, 21 May 2008 11:24:00-0400</pubDate>
				<guid>http://www.iterateme.com/blog/index.cfm/2008/5/21/Doing-the-Upsert</guid>
				
			</item>
			
			<item>
				<title>Wrap Up on the Contextual Guidance API</title>
				<link>http://www.iterateme.com/blog/index.cfm/2008/5/14/Wrap-Up-on-the-Contextual-Guidance-API</link>
				<description>
				
				&lt;p&gt;Given all the &lt;a href=&quot;&quot;&gt;background&lt;/a&gt; &lt;a href=&quot;&quot;&gt;thought&lt;/a&gt; I&apos;ve done on the contextual guidance API, it was a breeze to implement. Planning before coding really does pay off!&lt;/p&gt;

&lt;p&gt;The table I&apos;m using to store the data for the tool looks like this:&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;/blog/images/posts/contextualGuidanceLog.png&quot; border=&quot;0&quot; width=&quot;274&quot; height=&quot;149&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As you can see, I&apos;ve simplified things and haven&apos;t gone the route of more advanced, multivariate analysis on usage patterns for a users within an application. I certainly could have, but given that determining a user&apos;s experience level with an application is an act of generalization and not a precise science, this seemed right. Or maybe I&apos;m lazy, or like things simple, or both.&lt;/p&gt;

&lt;p&gt;In addition to a totalVisits value, I&apos;m storing two date values per user, per application, per section of the application (if that&apos;s passed). This allows me to place some context on the user&apos;s activity within the application. Instead of just saying &amp;quot;oh, well, they haven&apos;t visited this application in 30 days, they should be given the beginner materials again,&amp;quot; I can instead say &amp;quot;Well if they haven&apos;t visited in more than 30 days, but less than 90, and their total visits were greater than 50, give them the intermediate materials because they probably remember some of what&apos;s going on here.&amp;quot; Again, in an ideal setup, I should look at not only the number of visits (or visits per section), but average visits over periods of time, the length of breaks between visits, &lt;em&gt;and&lt;/em&gt; the exact actions they took within the application to provide them with highly specific contextual guidance. I think that for my users and my applications, being able to look at their activity within sections of a complex application given a rudimentary temporal context will be just fine. If anything, this simpler version of the logic will result in a more consistent display of help/guidance as the user moves from beginner to intermediate user to expert. When you try to get super-specific about guessing what a user is trying to do and provide help each step of the way, you are in danger of ending up with &lt;a href=&quot;http://en.wikipedia.org/wiki/Office_Assistant&quot;&gt;Clippy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There will be one more related post about the API. It has to do with the magic of &lt;a href=&quot;http://en.wikipedia.org/wiki/Upsert&quot;&gt;upserts&lt;/a&gt; and how I thought moving some business logic in to the query itself would save me code, but may not have.&lt;/p&gt; 
				</description>
				
				<category>Software Development</category>				
				
				<pubDate>Wed, 14 May 2008 15:49:00-0400</pubDate>
				<guid>http://www.iterateme.com/blog/index.cfm/2008/5/14/Wrap-Up-on-the-Contextual-Guidance-API</guid>
				
			</item>
			
			<item>
				<title>The Logic of the Contextual Guidance API</title>
				<link>http://www.iterateme.com/blog/index.cfm/2008/5/13/The-Logic-of-the-Contextual-Guidance-API</link>
				<description>
				
				&lt;p&gt;In my &lt;a href=&quot;http://www.iterateme.com/blog/index.cfm/2008/5/9/Getting-Users-Up-to-Speed-But-Not-Getting-in-Their-Way&quot;&gt;last post&lt;/a&gt;, I provided background on this project, and why it&apos;s useful to be able to provide users with help that fits their experience with the application. I&apos;d like to shift now to looking at the business logic that would make this happen.&lt;/p&gt;

&lt;p&gt;I&apos;ve already covered the &lt;a href=&quot;http://www.iterateme.com/blog/index.cfm/2008/5/9/Getting-Users-Up-to-Speed-But-Not-Getting-in-Their-Way&quot;&gt;method signature for this very simple API&lt;/a&gt;, but how does the API know to return a value of &amp;quot;beginner,&amp;quot; &amp;quot;intermediate,&amp;quot; or &amp;quot;advanced,&amp;quot;? To make this determination, we have to think beyond a simple, reductive value. I could certainly write something simple to say that &amp;quot;If someone has logged in to the app more than 20 times, they&apos;ve got to be an intermediate user.&amp;quot; That&apos;s easy, but misleading.&lt;/p&gt;

&lt;p&gt;People tend to forget things. I work in academia, and work here is highly cyclical. There&apos;s a flurry of activity at the start of each academic term, and the place is a ghost town in the months of May and June (well, faculty and students can&apos;t be found. Staff is working as hard as ever). Faculty and TAs working on courses tend to do a lot of work in a concentrated period of time, then walk away and don&apos;t look back until the next time they work on a course. I think that many users are the same way: they get what they need to get done ASAP, then walk away without a look back until the next time they need to use the app. There are exceptions, of course (email clients, social networking and financial sites come to mind). Most of the time, though, a user will need to use your application for a little bit and then come back to it only when needed again. In this away time, users forget a whole lot of stuff. Humans are creatures of habit and need reinforcement to retain processes. If someone uses your application for two weeks and then doesn&apos;t use it again for eight months, they&apos;re going to have forgotten how to do things. They won&apos;t be starting entirely from scratch, as, ideally, bits and pieces of how the application works will come back to them, but they&apos;ll definitely need a refresher.&lt;/p&gt;

&lt;p&gt;The contextual guidance API needs to take simple forgetfulness into account. We can&apos;t just say &amp;quot;If someone has logged in to the app more than 20 times, they&apos;ve got to be an intermediate user.&amp;quot; We have to take into account time &amp;mdash; specifically, the time between their last visit and their current one. But we can&apos;t stop there. What if they visited our app a lot nine months ago, but then came back to it for the first time yesterday. Are they still an intermediate user? Have they remembered all the basic stuff that they needed to remember? Probably not. So we need to look a bit at their history and factor that into our decision.&lt;/p&gt;

&lt;p&gt;One possible version of the business logic would work as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Store a record of a request for a page in the app
&lt;ul&gt;
&lt;li&gt;Insert if it&apos;s a new user&lt;/li&gt;
&lt;li&gt;Update if it&apos;s an existing user&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Look at two stored values: lastVisit and totalVisits&lt;/li&gt;
&lt;li&gt;Run a simple decision tree based on these values (see below for discussion)&lt;/li&gt;
&lt;li&gt;Return &amp;quot;beginner,&amp;quot; &amp;quot;intermediate,&amp;quot; or &amp;quot;advanced,&amp;quot; as appropriate.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So what would the decision tree look like? There are a number of ways of approaching this, but I plan to say something like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If lastVisit &lt; 14 days and totalVisits &lt; 10  ===&gt; new&lt;/li&gt;
&lt;li&gt;If lastVisit &lt; 14 days and totalVisits between 10 and 25  ===&gt; intermediate&lt;/li&gt;
&lt;li&gt;If lastVisit &lt; 14 days and totalVisits &gt; 50  ===&gt; new&lt;/li&gt;
&lt;li&gt;If lastVisit &gt; 14 days and totalVisits &lt; 50  ===&gt; intermediate&lt;/li&gt;
&lt;li&gt;If lastVisit &gt; 30 days and totalVisits &lt; 75  ===&gt; intermediate&lt;/li&gt;
&lt;li&gt;If lastVisit &gt; 180 days ===&gt; new&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are lots of choices you can make here in terms of the &amp;quot;rules&amp;quot; for determining someone&apos;s experience with an application. But we&apos;re only making decisions on two pieces of data. It&apos;s useful, as Edward Tufte might say, to be multivariate. We need to factor in previous visits to the application and not just look at the lastVisit value. What if someone&apos;s lastVisit was yesterday, their totalVisits was 64, but the previous visit before yesterday was 9 months ago? Should they really still be labeled an &amp;quot;intermediate&amp;quot; user even though they haven&apos;t been using the app for more than a single day in the past nine months?&lt;/p&gt;

&lt;p&gt;Beyond examining simple date values, we could also look at the amount of time the user spent working on the app in the past few days. &amp;quot;The amount of time&amp;quot; is always a highly flawed piece of data on the Web, as a user can sit on a Web page for hours but not do anything during that time. Instead of tracking hours, minutes, and seconds, we can look at the number (or even kind) of requests a user is making in our application and factor that in. You could even go so far as to weight certain, difficult tasks more than others. I&apos;m not going to go quite that far, but it&apos;s another option. Looking at all the requests a user made and not just their number of logins can help determine if they&apos;re really using the app, or just browsing.&lt;/p&gt;

&lt;p&gt;What about in-house staff or &amp;quot;experts&amp;quot;? Should they be a part of this decision tree, or should they always receive the &amp;quot;advanced&amp;quot; view? That&apos;s probably outside of the scope of this simple API, as the application that&apos;s calling this API can decide if the user is an expert and always return &amp;quot;advanced,&amp;quot; if appropriate.&lt;/p&gt;

&lt;p&gt;So that&apos;s a look at the business logic of the contextual guidance API. Next up will be a look at the (simple) database table structure, and some sample code in ColdFusion, my development language of choice.&lt;/p&gt; 
				</description>
				
				<category>Software Development</category>				
				
				<pubDate>Tue, 13 May 2008 13:59:00-0400</pubDate>
				<guid>http://www.iterateme.com/blog/index.cfm/2008/5/13/The-Logic-of-the-Contextual-Guidance-API</guid>
				
			</item>
			</channel></rss>