<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en">

    <title type="text">Viget Extend : The Development Lab</title>

    <subtitle type="text">Development Blog: Viget Labs:</subtitle>
    <link rel="alternate" type="text/html" href="http://www.viget.com/extend/" />
    
    <updated>2009-11-05T20:02:05Z</updated>
    <rights>Copyright (c) 2009, Matt Swasey</rights>
    <generator uri="http://expressionengine.com/" version="1.6.2">ExpressionEngine</generator>
    <id>tag:viget.com,2009:11:05</id>


    <link rel="self" href="http://feeds.feedburner.com/VigetExtend" type="application/atom+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry>
      <title>Provisioning &amp; Deploying a LAMP Wordpress Stack with Sprinkle and Capistrano</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/MePxKNC3__4/" />
      <id>tag:viget.com,2009:extend/4.1802</id>
      <published>2009-11-05T16:37:00Z</published>
      <updated>2009-11-05T20:02:05Z</updated>
      <author>
                        <name>Matt Swasey, Web Developer</name>
                        <email>matt.swasey@viget.com</email>
            <uri>http://www.viget.com/about/team/mswasey</uri>      </author>

      <category term="Tips and Tricks" scheme="http://www.viget.com/inspire/category/tips_and_tricks/" label="Tips and Tricks" />
      <content type="html">


                 &lt;p&gt;Recently I had to provision a number of slices for use as LAMP stacks running &lt;a href="http://wordpress.org"&gt;Wordpress&lt;/a&gt; installs.  Creating a LAMP stack is not exactly difficult but it's also not that fun, so I decided to use &lt;a href="http://github.com/crafterm/sprinkle"&gt;Sprinkle&lt;/a&gt; and &lt;a href="http://www.capify.org/index.php/Capistrano"&gt;Capistrano&lt;/a&gt; to aid in my task.&lt;/p&gt;

&lt;p&gt;In the end, I had a Sprinkle recipe and Capistrano script that saved me a lot of time.  Here's what I came up with and how I used it.&lt;/p&gt;

                 &lt;h3&gt;Provisioning&lt;/h3&gt;

&lt;p&gt;After creating your slice / vps and adding a user with sudo privileges for yourself, clone the lamp-sprinkle repository I've created on Github and edit the contained deploy.rb file:&lt;/p&gt;

&lt;pre&gt;
  git clone git://github.com/mig/lamp-sprinkle.git
  cd lamp-sprinkle/
  
  // edit deploy.rb changing:
  role :app, "host.example.com"
  set :user, "username"
&lt;/pre&gt;

&lt;p&gt;Then, issue the Sprinkle command and point it at the lamp recipe:&lt;/p&gt;

&lt;pre&gt;
  sprinkle -c -s lamp.rb
&lt;/pre&gt;

&lt;p&gt;When the script is done running, you should have a fully functioning LAMP stack running on your slice, ready for your Wordpress or any other PHP application.&lt;/p&gt;

&lt;h3&gt;Deploying&lt;/h3&gt;

&lt;p&gt;Having used Capistrano with version control for a while now, I couldn't bring myself to deploy any manner of web application using a method like straight (s)ftp.  I went searching for people deploying PHP applications with Capistrano and found &lt;a href="http://whomwah.com/2009/02/01/deploying-wordpress-to-slicehost-using-capistrano-and-git/"&gt;Duncan's post&lt;/a&gt; on doing just that.&lt;/p&gt;

&lt;p&gt;Assuming you've got your wordpress install in a git repository, place this &lt;a href="http://gist.github.com/227325"&gt;Capfile&lt;/a&gt; in your local working copy.&lt;/p&gt;

&lt;p&gt;Now just run the normal Capistrano deployment commands:&lt;/p&gt;

&lt;pre&gt;
  cap deploy:setup
  cap deploy
&lt;/pre&gt;

&lt;p&gt;All the normal rules apply here, your deploy user will need write permission to the deploy_to directory, and you will need an apache vhost file in your /etc/apache/sites-available turned on.&lt;/p&gt;

&lt;h3&gt;Other Ideas&lt;/h3&gt;

&lt;p&gt;You could take these two scripts and run with them in different directions if desired.  The Sprinkle script could go inside your wordpress repo, use the Capistrano information in the Capfile, and contain code to configure your vhost file for you.  Since I was provisioning a couple slices at the same time, I decided to go with the above, more general approach.&lt;/p&gt;

&lt;p&gt;If you've found a nicer approach to provisioning LAMP stacks or deploying PHP applications, let me know in the comments.&lt;/p&gt;

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=MePxKNC3__4:vUYesFuflMs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=MePxKNC3__4:vUYesFuflMs:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=MePxKNC3__4:vUYesFuflMs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=MePxKNC3__4:vUYesFuflMs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=MePxKNC3__4:vUYesFuflMs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=MePxKNC3__4:vUYesFuflMs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/MePxKNC3__4" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/provisioning-deploying-a-lamp-wordpress-stack-with-sprinkle-and-capistrano/</feedburner:origLink></entry>

    <entry>
      <title>(re)-Introducing simple_importer</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/UualiaOzTzk/" />
      <id>tag:viget.com,2009:extend/4.1782</id>
      <published>2009-10-24T18:32:01Z</published>
      <updated>2009-10-26T13:42:08Z</updated>
      <author>
                        <name>Justin Marney, Web Developer</name>
                        <email>justin.marney@viget.com</email>
            <uri>http://www.viget.com/about/team/jmarney</uri>      </author>

      <category term="General" scheme="http://www.viget.com/inspire/category/general/" label="General" />
      <content type="html">


                 &lt;p&gt;simple_importer has existed for some time as a lowly little gem that made it easy to create CSV import scripts using the Ruby CSV library. The API was usable but wasn't nearly as "simple" as it could be. Motivated by our upcoming Hackday event, &lt;a href="http://www.meetup.com/rubyhacknight/calendar/11696332/"&gt;Intro to Ruby Metaprogramming&lt;/a&gt;, I decided to rewrite simple_importer using some Ruby metaprogramming techniques. The end result is a gem that makes CSV import tasks easy to create and manage, and hopefully provides some real-world examples of basic Ruby metaprogramming.&lt;/p&gt;                 &lt;p&gt;The basic use case starts with defining importers using a small &lt;a href="http://www.martinfowler.com/bliki/DomainSpecificLanguage.html"&gt;internal DSL&lt;/a&gt;. Each importer has a name, a csv file, and a block of code that is used to process each row in the file. The row instance that is passed into the block is a &lt;a href="http://gemcutter.org/gems/fastercsv"&gt;fastercsv&lt;/a&gt; row and all of the &lt;a href="http://fastercsv.rubyforge.org/classes/FasterCSV.html#M000018"&gt;fastercsv configuration options&lt;/a&gt; are available.&lt;/p&gt;

&lt;pre name="code" class="brush: ruby;"&gt;
importer :items do
  file 'items.csv'

  foreach do |row|
    Item.create(:name =&gt; row[:name])
  end
end
&lt;/pre&gt;

&lt;p&gt;Once you have created an importer, save it into a directory named importers. This directory can be located in the same directory as your Rakefile, lib/importers or app/importers. Next, pull in the simple_importer rake tasks by adding the following line to your Rakefile.&lt;/p&gt;

&lt;pre name="code" class="brush: ruby;"&gt;
require 'simple_importer/tasks'
&lt;/pre&gt;

&lt;p&gt;Now, when you do a &lt;code&gt;rake -T simple_importer&lt;/code&gt; you'll see a rake task for each importer as well as a rake task that will run all of the importers.&lt;/p&gt;

&lt;p&gt;Pretty simple. Although, simple_importer does have a few other neat features such as before callbacks and multiple file processing capabilities. Be sure to check out the &lt;a href="http://github.com/vigetlabs/simple_importer"&gt;documentation&lt;/a&gt; which has plenty of examples. You can grab the gem from &lt;a href="http://gemcutter.org/gems/simple_importer"&gt;gemcutter&lt;/a&gt;, or check out the code on &lt;a href="http://github.com/vigetlabs/simple_importer"&gt;github&lt;/a&gt;.&lt;/p&gt;

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=UualiaOzTzk:O3ISa7hH-hI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=UualiaOzTzk:O3ISa7hH-hI:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=UualiaOzTzk:O3ISa7hH-hI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=UualiaOzTzk:O3ISa7hH-hI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=UualiaOzTzk:O3ISa7hH-hI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=UualiaOzTzk:O3ISa7hH-hI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/UualiaOzTzk" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/re-introducing-simple-importer/</feedburner:origLink></entry>

    <entry>
      <title>NoSQL Misconceptions</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/tPMtznDcT6Y/" />
      <id>tag:viget.com,2009:extend/4.1773</id>
      <published>2009-10-21T13:00:00Z</published>
      <updated>2009-10-21T14:04:33Z</updated>
      <author>
                        <name>Ben Scofield, Technology Director</name>
                        <email>ben.scofield@viget.com</email>
            <uri>http://www.viget.com/about/team/bscofield</uri>      </author>

      <category term="Trends" scheme="http://www.viget.com/inspire/category/trends/" label="Trends" />
      <content type="html">


                 &lt;p&gt;I wanted to clear up a couple of misconceptions about NoSQL that I've seen much too often lately (what can I say – I watch the &lt;a href="http://search.twitter.com/search?q=nosql"&gt;Twitter results&lt;/a&gt; for 'nosql' obsessively). &lt;/p&gt;

&lt;h3&gt;Scalability/Performance&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;NoSQL is just about scalability and/or performance.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is a particularly attractive claim for the traditionalists because it allows for the hope that these alternatives could be made obsolete in the future by making your RDBMS of choice faster or more scalable.&lt;/p&gt;

&lt;p&gt;Unfortunately (for the traditionalist), there's a lot more to NoSQL than just performance and scaling. Most importantly (for me, at least) is that NoSQL DBs often provide better substrates for modeling business domains. I've spent more than two years struggling to map just part of the comic book business onto MySQL, for instance, where something like a graph database would be a vastly better fit.&lt;/p&gt;

&lt;h3&gt;Database Types&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;NoSQL is just document databases, or key-value stores, or ...&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most of the anti-NoSQL articles I've seen have addressed only document-oriented databases or key-value stores (though recently, column-oriented databases have started to show up as well). Good arguments can be made against each of those solutions for specific circumstances, but those are arguments against a specific type of storage engine. The problem with pointing to those articles as rebutting the utility of NoSQL in general is that the label is much broader than traditionalists usually understand.&lt;/p&gt;

&lt;p&gt;"NoSQL" covers a vast set of applications, from &lt;a href="http://code.google.com/p/redis/"&gt;Redis&lt;/a&gt; all the way up to &lt;a href="http://neo4j.org/"&gt;Neo4J&lt;/a&gt;. Any argument that shows that, say, document-oriented databases fail in a set of situations may very well not apply to key-value stores or graph databases, and the further arguments required to make those cases are rarely (if ever) provided.&lt;/p&gt;

&lt;h3&gt;FriendFeed &amp;amp; MySQL&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;I can do NoSQL just as well in a relational database.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well, sure, you can (and FriendFeed did, apparently) – but you shouldn't. I could roll my own relations in &lt;a href="http://www.mongodb.org/display/DOCS/Home"&gt;MongoDB&lt;/a&gt;, but that doesn't make it a good idea. Different applications are good for different things; relational databases are great for relational data, but why would you want to use them for non-relational data? &lt;/p&gt;

&lt;h3&gt;Never SQL&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;NoSQL is a wholesale rejection of relational databases.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Happily, this claim is becoming less common; many proponents of NoSQL have softened their rhetoric, and the traditionalists have become a little less defensive. It seems that we're moving towards a pluralistic approach to storing our data, and that's a good thing. I've &lt;a href="http://benscofield.com/2009/09/polyglot-persistence/"&gt;suggested&lt;/a&gt; 'polyglot persistence' for this approach (though I didn't &lt;a href="http://www.infoq.com/news/2009/07/leberknight-polyglot-persistence"&gt;coin the term&lt;/a&gt;), but I also like &lt;a href="http://twitter.com/ezmobius"&gt;Ezra Zygmuntowicz&lt;/a&gt;'s 'LessSQL' as a label, too.&lt;/p&gt;
                 

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=tPMtznDcT6Y:9aRBs2g4qBc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=tPMtznDcT6Y:9aRBs2g4qBc:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=tPMtznDcT6Y:9aRBs2g4qBc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=tPMtznDcT6Y:9aRBs2g4qBc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=tPMtznDcT6Y:9aRBs2g4qBc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=tPMtznDcT6Y:9aRBs2g4qBc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/tPMtznDcT6Y" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/nosql-misconceptions/</feedburner:origLink></entry>

    <entry>
      <title>My Tools of the Trade</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/G_jpdASyDpc/" />
      <id>tag:viget.com,2009:extend/4.1769</id>
      <published>2009-10-15T14:00:00Z</published>
      <updated>2009-10-15T14:32:36Z</updated>
      <author>
                        <name>Clinton R. Nixon, Development Director</name>
                        <email>clinton.nixon@viget.com</email>
            <uri>http://www.viget.com/about/team/cnixon</uri>      </author>

      <category term="Tools of the Trade" scheme="http://www.viget.com/inspire/category/tools-of-the-trade/" label="Tools of the Trade" />
      <content type="html">


                 &lt;p&gt;Inspired by &lt;a href="http://afreshcup.com/2009/10/11/my-tools-of-the-trade-2009/"&gt;Mike Gunderloy&amp;#8217;s tools of the trade post&lt;/a&gt;, I made a list of what I use every day for development. My tools don&amp;#8217;t necessarily reflect what every developer at Viget uses.&lt;/p&gt;


	&lt;h3&gt;Hardware&lt;/h3&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;2009 MacBook Pro 13&amp;#8221;&lt;/strong&gt;, 2.53 GHz, 4 GB of memory. This machine is a screaming demon of speed and fury. I&amp;#8217;m meticulous about keeping junk that it doesn&amp;#8217;t need off of it. I love my laptop, although I do wish I had 8 GB of memory in it. Maybe I&amp;#8217;ll get the upgrade for its birthday present.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;20&amp;#8221; Dell 2000FP monitor.&lt;/strong&gt; It works. It seems giant to me, but I imagine I&amp;#8217;d love a bigger one even more. I&amp;#8217;ve had my eye on &lt;a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16824254026"&gt;this 28 inch beauty&lt;/a&gt; for a while.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;MacAlly ICEkey keyboard&lt;/strong&gt; and &lt;strong&gt;Logitech &lt;span class="caps"&gt;MX518&lt;/span&gt; mouse.&lt;/strong&gt; Both of these are amazing. I have the same setup at work and at home. The ICEkey is my favorite keyboard I&amp;#8217;ve ever used.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;Development software&lt;/h3&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Mac &lt;span class="caps"&gt;OS X 10&lt;/span&gt;.6 Snow Leopard.&lt;/strong&gt; Pure joy.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;Ruby Enterprise Edition 1.8.7.&lt;/strong&gt; It&amp;#8217;s what I use on my servers, and I like to develop in a similar environment.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;&lt;a href="http://github.com/mxcl/homebrew"&gt;Homebrew packaging system&lt;/a&gt;.&lt;/strong&gt; I used MacPorts for a long time, and was a big proponent, but the ease of adding new packages to this won me over quickly. Max, the project head, is great about accepting patches.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;&lt;a href="http://macromates.com/"&gt;TextMate&lt;/a&gt;.&lt;/strong&gt; Big surprise, I know. There&amp;#8217;s a reason it&amp;#8217;s so beloved in the Mac development community.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;&lt;a href="http://www.netbeans.org/"&gt;NetBeans&lt;/a&gt;.&lt;/strong&gt; I&amp;#8217;m a wishy-washy person when it comes to my editing environment, so I switch from TextMate to NetBeans often. It&amp;#8217;s an excellent &lt;span class="caps"&gt;IDE&lt;/span&gt; for multiple languages, and gets better with every release. If I have to work on anything that isn&amp;#8217;t Ruby, I usually use this. If it felt a little snappier and had a little better usability, I&amp;#8217;d probably use this for all my code.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;Git&lt;/strong&gt; and &lt;strong&gt;&lt;a href="http://gitx.frim.nl/"&gt;GitX&lt;/a&gt;&lt;/strong&gt;. Git&amp;#8217;s my version control system of choice. I mainly use it from the command line, but when I need to do some visualization, I pull out GitX.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;Mozilla Firefox.&lt;/strong&gt; It&amp;#8217;s my development browser. For casual browsing, I use Safari, as it&amp;#8217;s way faster. I was a Firefox-only user for a long time, but frustrations about speed and lack of customizable keybindings has pushed me into Safari&amp;#8217;s arms.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;Other software&lt;/h3&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Backblaze.&lt;/strong&gt; I use this for constant off-site backups. I&amp;#8217;d link to them, but they have an awful auto-starting movie on their homepage. Instead, &lt;a href="http://blog.backblaze.com/2009/09/01/petabytes-on-a-budget-how-to-build-cheap-cloud-storage/"&gt;check out this blog post about their storage pods&lt;/a&gt;.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;&lt;a href="http://hiveminder.com/"&gt;Hiveminder&lt;/a&gt;.&lt;/strong&gt; This is a great task management system. My favorite parts are the command-line client and IM interface.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;&lt;a href="http://notational.net/"&gt;Notational Velocity&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="http://www.simplenoteapp.com/"&gt;SimpleNote&lt;/a&gt;&lt;/strong&gt;. Notational Velocity&amp;#8217;s a great super-fast note taking application for &lt;span class="caps"&gt;OS X&lt;/span&gt;, and SimpleNote&amp;#8217;s the same for the iPhone. I &lt;a href="http://billyd.net/post/204970320/simple-notes-that-sync-minus-the-stink"&gt;keep them in sync with a Perl script&lt;/a&gt;, so I have my notes everywhere.&lt;/li&gt;
		&lt;li&gt;I like to keep everything I can online and off my computer, so along with Hiveminder and SimpleNote, I use Gmail for both home and work email, &lt;strong&gt;&lt;a href="http://delicious.com/"&gt;Delicious&lt;/a&gt;&lt;/strong&gt; for bookmarking and making groups of links, and &lt;strong&gt;&lt;a href="http://www.instapaper.com/u"&gt;Instapaper&lt;/a&gt;&lt;/strong&gt; for things to read on the can or while waiting in line. I use &lt;strong&gt;&lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="http://getdropbox.com"&gt;Dropbox&lt;/a&gt;&lt;/strong&gt; to keep all my projects off my computer and accessible.&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;&lt;a href="http://feedafever.com/"&gt;Fever&lt;/a&gt;&lt;/strong&gt; is my &lt;span class="caps"&gt;RSS&lt;/span&gt; reader of choice. There&amp;#8217;s too many high-noise feeds with sporadic great content out there to read them all. Fever&amp;#8217;s Hot List makes it way easier to sift through the cruft.&lt;/li&gt;
		&lt;li&gt;To control my desktop, I use a combination of &lt;strong&gt;&lt;a href="http://www.obdev.at/products/launchbar/index.html"&gt;LaunchBar&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href="http://www.heliumfoot.com/mercurymover/"&gt;MercuryMover&lt;/a&gt;&lt;/strong&gt;, and &lt;strong&gt;&lt;a href="http://www.irradiatedsoftware.com/sizeup/"&gt;SizeUp&lt;/a&gt;.&lt;/strong&gt; I can launch anything, do many file manipulations, and move my windows around without leaving the keyboard. LaunchBar&amp;#8217;s also great for giving me a global kill ring.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;Tell Me What You&amp;#8217;re Using&lt;/h3&gt;


	&lt;p&gt;If you&amp;#8217;ve got a tool you love, or think my toolset is weak sauce, let me know! I&amp;#8217;d love to hear about it.&lt;/p&gt;
                 

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=G_jpdASyDpc:kJKJttVV9kk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=G_jpdASyDpc:kJKJttVV9kk:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=G_jpdASyDpc:kJKJttVV9kk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=G_jpdASyDpc:kJKJttVV9kk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=G_jpdASyDpc:kJKJttVV9kk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=G_jpdASyDpc:kJKJttVV9kk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/G_jpdASyDpc" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/my-tools-of-the-trade/</feedburner:origLink></entry>

    <entry>
      <title>Deploying the git way</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/jcIdhUqBg08/" />
      <id>tag:viget.com,2009:extend/4.1770</id>
      <published>2009-10-14T14:30:00Z</published>
      <updated>2009-10-14T15:28:15Z</updated>
      <author>
                        <name>Brian Landau, Web Developer</name>
                        <email>brian.landau@viget.com</email>
                  </author>

      <category term="Tips and Tricks" scheme="http://www.viget.com/inspire/category/tips_and_tricks/" label="Tips and Tricks" />
      <content type="html">


                 &lt;p&gt;Let&amp;#8217;s start with this: Git is mind-blowingly amazing &lt;strong&gt;and&lt;/strong&gt; simple. We&amp;#8217;ll get back to this later.&lt;/p&gt;

&lt;p&gt;Moving on though, a while back I was combing through my feed reader and found a post that leapt up at me: &lt;a href="http://github.com/blog/470-deployment-script-spring-cleaning"&gt;Deployment Script Spring Cleaning by Chris Wanstrath over at Github&lt;/a&gt;. It amazed me that no one had thought of doing this before. That is, using git as the deployment strategy for Capistrano.&lt;/p&gt;

&lt;p&gt;A few weeks later I was preparing to get &lt;a href="http://connectasketch.com/"&gt;Connect-A-Sketch&lt;/a&gt; production ready (it&amp;#8217;s in a private beta and you should &lt;a href="http://bit.ly/cas-invites" title="Request a Connect-A-Sketch Invite"&gt;sign-up&lt;/a&gt; if you haven&amp;#8217;t yet), and the git deployment strategy jumped into my head. To reiterate what&amp;#8217;s so great about using git, instead of rsync with git or any of the other options: it&amp;#8217;s fast, lightweight, and can handle all the rollbacks itself with no need for timestamped directories.&lt;/p&gt;
                 &lt;h3 id="the_reflog_rollback"&gt;The Reflog Rollback&lt;/h3&gt;

&lt;p&gt;So, I forked &lt;a href="http://gist.github.com/162444"&gt;defunkt&amp;#8217;s gist&lt;/a&gt;, and got to work polishing it up for Connect-A-Sketch. The first thing I noticed (as did a few others who commented on the original blog post) his rollback command only rolled back to the previous commit (via the ref name &amp;#8220;&lt;code&gt;HEAD^&lt;/code&gt;&amp;#8221;). What we really want here is to rollback to the commit that we had previously deployed to. As it turns out there&amp;#8217;s a ref name for that &amp;#8220;&lt;code&gt;HEAD@{1}&lt;/code&gt;&amp;#8221;. So, we just replace &amp;#8220;&lt;code&gt;HEAD^&lt;/code&gt;&amp;#8221; with that, and we&amp;#8217;re all good right? Nope, because we forgot about the edge-case where we want to keep rolling back one after the other, and this can&amp;#8217;t handle that. That&amp;#8217;s how Capistrano normally works and so our new deployment strategy should work the same.&lt;/p&gt;

&lt;p&gt;Well, if you didn&amp;#8217;t know, as I didn&amp;#8217;t, the &amp;#8220;&lt;code&gt;HEAD@{1}&lt;/code&gt;&amp;#8221; ref name works because git tracks all the commits that HEAD has pointed to in the &lt;code&gt;reflog&lt;/code&gt; (this is a really helpful feature that most other version control systems just don&amp;#8217;t do). The deploy script uses &lt;code&gt;git reset&lt;/code&gt; to force git to set the &lt;code&gt;HEAD&lt;/code&gt; to a specific commit not moving through each commit or doing a rebase, or any other modifications to the &lt;code&gt;HEAD&lt;/code&gt; &lt;code&gt;reflog&lt;/code&gt;. But when we reset to &amp;#8220;&lt;code&gt;HEAD@{1}&lt;/code&gt;&amp;#8221; that is added to the reflog, it doesn&amp;#8217;t just pop off the last ref and move &lt;code&gt;HEAD&lt;/code&gt; back (and don&amp;#8217;t get me wrong this is what git should do, it&amp;#8217;s just not what we want to do in our particular case). So we need to pop off what we don&amp;#8217;t need from the reflog so &amp;#8220;&lt;code&gt;HEAD@{1}&lt;/code&gt;&amp;#8221; will point to the correct commit now.&lt;/p&gt;

&lt;p&gt;Lucky for us git version 1.5.6.6 and later have the ability to remove items from the &lt;code&gt;HEAD&lt;/code&gt; reflog and correctly rewrite the reflog so everything still works correctly internally. The command to do this is &lt;code&gt;git reflog delete --rewrite &amp;lt;ref&amp;gt;&lt;/code&gt; (see what I mean about mind-blowing!), by using this in our deploy script we can cleanup the reflog so we can continue to rollback one after another as much as we want. &lt;/p&gt;

&lt;h3 id="cap_compatibility"&gt;Cap Compatibility&lt;/h3&gt;

&lt;p&gt;Capistrano and various cap extensions and plugins expect the releases directory and its subdirectories to exist, as well as identifiers for the current and previous versions to be present. The default values for these variables won’t be set correctly given we have no “releases” directory, so we need to make some changes to keep everything compatible.&lt;/p&gt;

&lt;p&gt;First, we want to make sure our migrations are run in the correct directory. By default it will run it in the &amp;#8220;&lt;code&gt;current_release&lt;/code&gt;&amp;#8221; directory, which is the last directory in the &amp;#8220;releases&amp;#8221; directory. We want it to use the &amp;#8220;current&amp;#8221; directory, to do that we add this line:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;set :migrate_target, :current
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, we want to make sure our deploy script sets the correct values for the various directory variables. To do this we add the following lines to our deploy script:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;set(:latest_release)  { fetch(:current_path) }
set(:release_path)    { fetch(:current_path) }
set(:current_release) { fetch(:current_path) }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, we need to make sure that the correct version identifier is supplied to the various revision variables:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;set(:current_revision)  { capture("cd #{current_path}; git rev-parse --short HEAD").strip }
set(:latest_revision)   { capture("cd #{current_path}; git rev-parse --short HEAD").strip }
set(:previous_revision) { capture("cd #{current_path}; git rev-parse --short HEAD@{1}").strip }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With all that in place (along with a few other minor changes and additions), we have a &lt;a href="http://gist.github.com/176754"&gt;git based deployment strategy&lt;/a&gt; that&amp;#8217;s totally compatible and works just the way we expect Capistrano to work.&lt;/p&gt;

&lt;p&gt;The complete deployment script can be found here: &lt;a href="http://gist.github.com/176754"&gt;http://gist.github.com/176754&lt;/a&gt;&lt;/p&gt;


      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=jcIdhUqBg08:RD3_E1KQbq0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=jcIdhUqBg08:RD3_E1KQbq0:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=jcIdhUqBg08:RD3_E1KQbq0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=jcIdhUqBg08:RD3_E1KQbq0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=jcIdhUqBg08:RD3_E1KQbq0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=jcIdhUqBg08:RD3_E1KQbq0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/jcIdhUqBg08" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/deploying-the-git-way/</feedburner:origLink></entry>

    <entry>
      <title>Developer Day Boulder Wrapup</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/FP4UEV1Y7mc/" />
      <id>tag:viget.com,2009:extend/4.1766</id>
      <published>2009-10-12T09:31:00Z</published>
      <updated>2009-10-12T14:48:40Z</updated>
      <author>
                        <name>Ben Scofield, Technology Director</name>
                        <email>ben.scofield@viget.com</email>
            <uri>http://www.viget.com/about/team/bscofield</uri>      </author>

      <category term="Events" scheme="http://www.viget.com/inspire/category/events/" label="Events" />
      <content type="html">


                 &lt;p&gt;Neither snow nor rain nor heat nor gloom of night stays these developers from the swift completion of their appointed conference. As it so happened, we experienced two of those obstacles at &lt;a href="http://developer-day.com/events/2009-boulder.html"&gt;Developer Day Boulder&lt;/a&gt; this past weekend – Boulder got its first snowfall of the year the night before, and the &lt;a href="http://techstars.org"&gt;TechStars&lt;/a&gt; bunker got extremely warm as the day progressed (in seeming defiance of the sub-freezing temperatures outside).&lt;/p&gt;

&lt;p&gt;We had great attendance despite the difficult conditions, and those who made it enjoyed the event a great deal. &lt;a href="http://chadfowler.com"&gt;Chad Fowler&lt;/a&gt; started us off with a discussion of creating a remarkable life, and (judging from the tweets I saw fly by) inspired a number of the listeners to take more control of their experiences. &lt;/p&gt;

&lt;p&gt;&lt;a href="http://percious.com/blog"&gt;Chris Perkins&lt;/a&gt; followed Chad, and gave us a thorough introduction to &lt;a href="http://turbogears.org/"&gt;TurboGears&lt;/a&gt; and the state of the Python web community. From there, we moved on to &lt;a href="http://robsanheim.com"&gt;Rob Sanheim&lt;/a&gt;'s talk about the cloud, and I saw my first ever live-deploy (live-coding is so last year). &lt;a href="http://copiousfreetime.org/"&gt;Jeremy Hinegardner&lt;/a&gt; then closed out the morning session by discussing a number of tools that work well in mixed-language environments.&lt;/p&gt;

&lt;p&gt;After lunch, we had a great series of lightning talks. David Eisinger premiered his Introduction to Ruby and Mid-90s Hip Hop for the public, Jason Turner showed off &lt;a href="http://www.chaiscript.com/"&gt;ChaiScript&lt;/a&gt;, Ben Reubenstein talked about donating time and talent to worthy causes, Bobby Wilson railed against the current state of templating systems in Ruby, Jess Martin describe the One True Way of CSS, and I talked a little bit about how the comics industry is difficult to model in a relational database.&lt;/p&gt;

&lt;p&gt;The afternoon session then continued with &lt;a href="http://davideisinger.com"&gt;David Eisinger&lt;/a&gt;, back up to explore email as an interface. &lt;a href="http://riteofcoding.blogspot.com/"&gt;Derek Chen-Becker&lt;/a&gt; was next up, with an introduction to &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt; and a brief demo of Lift, the Scala web framework. We then shifted to the mobile and desktop worlds, with &lt;a href="http://bill.dudney.net/roller/bill/"&gt;Bill Dudney&lt;/a&gt; and a talk about CoreAnimation. Finally, &lt;a href="http://mindviewinc.com"&gt;Bruce Eckel&lt;/a&gt; closed us out with his perspective of the evolution of features in C++, Java, and Python.&lt;/p&gt;

&lt;p&gt;All in all, this was another successful Developer Day, and we're excited to start planning for 2010. If you'd like to see us come to your area and showcase the various developer communities, feel free to leave a comment here or email me at &lt;a href="mailto:bscofield@developer-day.com"&gt;bscofield@developer-day.com&lt;/a&gt;. Viva la Developer Day!&lt;/p&gt;

* Note: We'll be posting the speakers' slides to their &lt;a href="http://speakerrate.com/events/199"&gt;SpeakerRate&lt;/a&gt; pages and to the Developer Day Boulder page as we get them in.
                 

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=FP4UEV1Y7mc:CY1FGAiXa_U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=FP4UEV1Y7mc:CY1FGAiXa_U:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=FP4UEV1Y7mc:CY1FGAiXa_U:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=FP4UEV1Y7mc:CY1FGAiXa_U:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=FP4UEV1Y7mc:CY1FGAiXa_U:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=FP4UEV1Y7mc:CY1FGAiXa_U:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/FP4UEV1Y7mc" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/developer-day-boulder-wrapup/</feedburner:origLink></entry>

    <entry>
      <title>Wrapping Rails Session Hash: Follow Up</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/In-Jys9fa7g/" />
      <id>tag:viget.com,2009:extend/4.1764</id>
      <published>2009-10-08T14:03:00Z</published>
      <updated>2009-10-08T15:48:20Z</updated>
      <author>
                        <name>Matt Swasey, Web Developer</name>
                        <email>matt.swasey@viget.com</email>
            <uri>http://www.viget.com/about/team/mswasey</uri>      </author>

      <category term="Tips and Tricks" scheme="http://www.viget.com/inspire/category/tips_and_tricks/" label="Tips and Tricks" />
      <content type="html">


                 &lt;p&gt;The other week I wrote about &lt;a href="http://www.viget.com/extend/wrapping-rails-session-hash/"&gt;wrapping your Rails session variables in current_object&lt;/a&gt; methods.  There is, however, a performance related bug in line 5 of the code I posted:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
class ApplicationController &amp;lt; ActionController::Base  
  helper_method :current_account  
    
  def current_account  
    @current_account ||= Account.find_by_id(session[:current_account_id])  
  end  
  
  def current_account=(account)  
    session[:current_account_id] = account.try(:id)  
  end  
end 
&lt;/pre&gt;

&lt;p&gt;If session[:current_account_id] is nil, current_account will make a useless database query each time it is called.  This would happen if you are calling current_account on a public page while a user has yet to log in.&lt;/p&gt;

&lt;p&gt;We can fix this in the following way:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
...
def current_account
  if session[:current_account_id]
    @current_account ||= Account.find_by_id(session[:current_account_id])
  end
end
...
&lt;/pre&gt;

&lt;p&gt;The above code will only evaluate @current_account if session[:current_account_id] has been set, otherwise it will return nil without hitting the database.  Once session[:current_account_id] is set, it will hit the database a single time, memoize the result in @current_account, and return @current_account for the duration of the Rails request cycle.  This should help take some load off the database.&lt;/p&gt;

&lt;p&gt;If anyone has an even simpler solution, please let me know in the comments!&lt;/p&gt;                 

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=In-Jys9fa7g:pLVHTLcUcTY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=In-Jys9fa7g:pLVHTLcUcTY:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=In-Jys9fa7g:pLVHTLcUcTY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=In-Jys9fa7g:pLVHTLcUcTY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=In-Jys9fa7g:pLVHTLcUcTY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=In-Jys9fa7g:pLVHTLcUcTY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/In-Jys9fa7g" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/wrapping-rails-session-hash-follow-up/</feedburner:origLink></entry>

    <entry>
      <title>Database Taxonomy</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/EzahfEHbQyQ/" />
      <id>tag:viget.com,2009:extend/4.1751</id>
      <published>2009-09-30T10:30:00Z</published>
      <updated>2009-09-30T12:28:25Z</updated>
      <author>
                        <name>Ben Scofield, Technology Director</name>
                        <email>ben.scofield@viget.com</email>
            <uri>http://www.viget.com/about/team/bscofield</uri>      </author>

      <category term="General" scheme="http://www.viget.com/inspire/category/general/" label="General" />
      <content type="html">


                 &lt;p&gt;In my &lt;a href="http://speakerrate.com/talks/1447"&gt;domain modeling/alternative database talk&lt;/a&gt;, I usually spend some time talking about taxonomy in biology. It's a fascinating field, with a lot of interesting tangents (ligers and tigons and pluots, oh my!), but in the presentation I focus on how difficult it can be to model in a standard relational schema. I think there's another set of lessons that people interested in databases can draw from taxonomy, however, and that's a way of looking at how databases are related.&lt;/p&gt;
                 &lt;h3&gt;Similarity&lt;/h3&gt;

&lt;p&gt;There are two main techniques in taxonomy for classifying things. Numerical taxonomy is the practice of grouping by similarity - dogs are more similar to bears than they are to cats, so dogs and bears fall into the same suborder (Carniformia, versus Feliformia for cats).&lt;/p&gt;

&lt;p&gt;As it turns out, we can group databases by similarity, too. Many lists already do this at a &lt;a href="http://internetmindmap.com/database_software"&gt;macro level&lt;/a&gt;, but they don't do it systematically. I think the right approach here is to identify some axis, and plot the choices along it. Here's an example where the axis is degree of relationality the database provides (with just a subset of databases, of course):&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.viget.com/uploads/image/by-relation.jpg" alt="Databases by relationality" /&gt;&lt;/p&gt;

&lt;p&gt;On the other hand, we might also try grouping them based on the degree to which they require data to follow a pre-built schema:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.viget.com/uploads/image/by-schema.jpg" alt="Databases by schematicness" /&gt;&lt;/p&gt;

&lt;p&gt;The big changes between the relationality and schema rankings are the move of graph databases (which are schemaless both within individual nodes &lt;em&gt;and&lt;/em&gt; for nodes' relationships), the swap of document-oriented and column-oriented databases (which, granted, may just be an opinion), and Oracle's move within relational databases (based mostly on its support for object storage, which is very close to document storage).&lt;/p&gt;

&lt;h3&gt;Descent&lt;/h3&gt;

&lt;p&gt;The other main technique in biological taxonomy is cladistics, where relationships between things are identified based on common evolutionary descent. In other words, humans are more closely related to chimps than to lemurs because the common ancestor of chimps and humans occurred more recently than the common ancestor of humans and lemurs (but I bet that common ancestor was darn cute).&lt;/p&gt;

&lt;p&gt;In biology, cladistics presents some obstacles – we can't actually go back in time and see the divergence of species, though we've gotten really good at reconstructing lineages based on rates of mutation and the like. With databases, however, this is a lot easier. Heck, half the time it just takes a quick visit to Wikipedia, or maybe an email to the core team for the application. &lt;/p&gt;

&lt;p&gt;Regardless of how the history is constructed, however, these trees can provide interesting and useful information. For instance, knowing the genealogy of Cassandra gives you an excellent idea of the sorts of situations for which it is designed:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.viget.com/uploads/image/cladistics.jpg" alt="Databases by descent" /&gt;&lt;/p&gt;

&lt;p&gt;Doing a full cladistic breakdown of the database landscape is beyond the scope of this article (or of any one person with a job, I think), but I welcome comments and suggestions for relationships!&lt;/p&gt;


      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=EzahfEHbQyQ:ffenpNPqeHc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=EzahfEHbQyQ:ffenpNPqeHc:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=EzahfEHbQyQ:ffenpNPqeHc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=EzahfEHbQyQ:ffenpNPqeHc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=EzahfEHbQyQ:ffenpNPqeHc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=EzahfEHbQyQ:ffenpNPqeHc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/EzahfEHbQyQ" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/database-taxonomy/</feedburner:origLink></entry>

    <entry>
      <title>Using ruby-debug to Find Those Hard-To-Reach Places (bugs)</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/hgrUB-xIv4k/" />
      <id>tag:viget.com,2009:extend/4.1753</id>
      <published>2009-09-29T17:23:01Z</published>
      <updated>2009-09-29T21:18:18Z</updated>
      <author>
                        <name>Matt Swasey, Web Developer</name>
                        <email>matt.swasey@viget.com</email>
            <uri>http://www.viget.com/about/team/mswasey</uri>      </author>

      <category term="Tools of the Trade" scheme="http://www.viget.com/inspire/category/tools-of-the-trade/" label="Tools of the Trade" />
      <content type="html">


                 &lt;p&gt;I've been writing Rails applications for a little over two years now, but only recently has ruby-debug been added to my tool belt.  Since then, I've been using it almost every week and have found it super useful.&lt;/p&gt;

&lt;p&gt;If you take five minutes to learn the six commands I'll provide for you here, I promise you won't regret it.&lt;/p&gt;
                 &lt;h3&gt;The Scenario&lt;/h3&gt;

&lt;p&gt;I was working with binarylogic's fantastic &lt;a href="http://github.com/binarylogic/searchlogic"&gt;searchlogic&lt;/a&gt; gem in a project recently.  I couldn't figure out why mysql "ORDER" parameters were not being produced by searchlogic's search method when chained off of a named scope.  For example:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
class Order &amp;lt; ActiveRecord::Base
  named_scope :active, 
              :conditions =&gt; {:state =&gt; "active"}, 
              :order =&gt; "delivery_date DESC"
end
&lt;/pre&gt;

&lt;p&gt;Using just this named scope, the DB log would reflect this:&lt;/p&gt;
&lt;pre&gt;
SELECT * FROM "orders" WHERE ("orders"."state" = 'active') ORDER BY delivery_date DESC
&lt;/pre&gt;

&lt;p&gt;That looks like we would expect.  However, when executing a command like this:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;
Order.active.search(:state_is =&gt; "onhold").ascend_by_delivery_date
&lt;/pre&gt;

&lt;p&gt;Noting the DB logs, we see this:&lt;/p&gt;
&lt;pre&gt;
SELECT * FROM "orders" WHERE ((orders.state = 'onhold') AND ("orders"."state" = 'active')) ORDER BY delivery_date DESC
&lt;/pre&gt;

&lt;p&gt;Notice that our two states are joined with an AND (that's cool), but check out the "ORDER BY" clause.  It still reflects a descending order for delivery_date &amp;ndash; not what we wanted at all.&lt;/p&gt;

&lt;p&gt;So how do we figure out what's going on here?  We could write some tests, but I'm afraid that those tests might just confirm what we already know.  There is a bug somewhere, but where?&lt;/p&gt;

&lt;h3&gt;Setup&lt;/h3&gt;

&lt;p&gt;There are many ways to go about this.  The one I came up with could be clever or could just be a hack. I like to create a rake task that invokes the debugger right before the problem line of code, so I created lib/tasks/debug.rake and added this to it:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
namespace :debug do
  require 'ruby-debug'
  
  desc "debug named_scope order issues"
  task :named_scope_issues =&gt; :environment do
    debugger
    Order.active.search(:state_is =&gt; "onhold").ascend_by_delivery_date
  end
end
&lt;/pre&gt;

&lt;p&gt;Then in terminal:&lt;/p&gt;
&lt;pre&gt;
$ rake debug:named_scope_issues
&lt;/pre&gt;

&lt;p&gt;This will dump us into a debug session.&lt;/p&gt;

&lt;h3&gt;ruby-debug&lt;/h3&gt;

&lt;p&gt;What you will see will look similar to this:&lt;/p&gt;

&lt;pre&gt;
rake debug:named_scope_issues 
(in /Users/mig/Desktop/store)
/Users/mig/Desktop/store/lib/tasks/debug.rake:7
Order.active.search(:state_is =&gt; "onhold").ascend_by_delivery_date
(rdb:1) where
--&gt; #0 at line /Users/mig/Desktop/store/lib/tasks/debug.rake:7
Warning: saved frames may be incomplete; compare with caller(0).
(rdb:1)
&lt;/pre&gt;

&lt;p&gt;From here we have a ton of commands at our disposal, the most important I've found are: &lt;strong&gt;help&lt;/strong&gt;, &lt;strong&gt;step&lt;/strong&gt;, &lt;strong&gt;next&lt;/strong&gt;, &lt;strong&gt;list&lt;/strong&gt;, and &lt;strong&gt;var local&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;help&lt;/h4&gt;
&lt;p&gt;Help will give you a run-down on all the other commands available to you, easy enough.&lt;/p&gt;

&lt;pre&gt;
(rdb:1) help
ruby-debug help v0.10.3
Type 'help &lt;command-name&gt;' for help on a specific command

Available commands:
backtrace  delete   enable  help    next  quit     show    trace    
break      disable  eval    info    p     reload   source  undisplay
catch      display  exit    irb     pp    restart  step    up       
condition  down     finish  list    ps    save     thread  var      
continue   edit     frame   method  putl  set      tmate   where    

(rdb:1) 
&lt;/pre&gt;

&lt;h4&gt;step &amp;amp; next&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;step&lt;/strong&gt; is where you can get down into the nitty gritty goings-on of the code, it will 'step' into the first method it encounters on its current line.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;next&lt;/strong&gt; is like step, only it will evaluate the current line of code without stepping into the methods within, and simply drop down the next line of code in the current method.&lt;/p&gt;

&lt;h4&gt;list&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;list&lt;/strong&gt; will print the current line of code the debugger is waiting to evaluate, along with the preceding and following five lines.&lt;/p&gt;

&lt;p&gt;Here we are buried within some named_scope logic:&lt;/p&gt;
&lt;pre&gt;
(rdb:1) list
[169, 178] in /Users/mig/Desktop/store/vendor/rails/activerecord/lib/active_record/named_scope.rb
   169        private
   170        def method_missing(method, *args, &amp;block)
   171          if scopes.include?(method)
   172            scopes[method].call(self, *args)
   173          else
=&gt; 174            with_scope({:find =&gt; proxy_options, :create =&gt; proxy_options[:conditions].is_a?(Hash) ?  proxy_options[:conditions] : {}}, :reverse_merge) do
   175              method = :new if method == :build
   176              if current_scoped_methods_when_defined &amp;&amp; !scoped_methods.include?(current_scoped_methods_when_defined)
   177                with_scope current_scoped_methods_when_defined do
   178                  proxy_scope.send(method, *args, &amp;block)
(rdb:1)
&lt;/pre&gt;

&lt;p&gt;&lt;i&gt;The =&gt; mark indicates the current line (174)&lt;/i&gt;&lt;/p&gt;

&lt;h4&gt;var local&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;var local&lt;/strong&gt; is perhaps the most useful of all the debugger commands for me, it will give a value dump of all the local variables.  I keep an eye on this every few lines to detect when variable values have changed.&lt;/p&gt;

&lt;p&gt;For example, if we called 'var local' on the previous line, we would get this:&lt;/p&gt;

&lt;pre&gt;
(rdb:1) var local
  args =&gt; [{:state_is=&gt;"onhold"}]
  block =&gt; nil
  method =&gt; :search
(rdb:1) 
&lt;/pre&gt;

&lt;p&gt;Ahh, we can see that we've passed the evaluation of the 'active' scope, and are now evaluating the scope that search() is creating.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;You might be thinking that this is a pretty tedious process, and it often is, but for the bugs buried deep within code it's sometimes a good way to go.&lt;/p&gt;

&lt;p&gt;I won't take you though the entire debug session here, as it would take a couple screens, and people would probably lose interest.  I will say however, that the bug was &lt;strong&gt;not&lt;/strong&gt; in searchlogic's code, but in Rails itself.&lt;/p&gt;

&lt;p&gt;Here is a simple example to demonstrate:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
class Order &lt; ActiveRecord::Base
  named_scope :by_delivery, :order =&gt; "delivery_date DESC"
  named_scope :by_creation, :order =&gt; "created_at ASC"
end
&lt;/pre&gt;

&lt;p&gt;Calling:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;
Order.by_delivery.by_creation
&lt;/pre&gt;

&lt;p&gt;Would produce:&lt;/p&gt;

&lt;pre&gt;
SELECT * FROM "orders" ORDER BY delivery_date DESC
&lt;/pre&gt;

&lt;p&gt;Hmm...&lt;/p&gt;

&lt;p&gt;In the end, the issue was a bug in Rails itself, but this process allowed me to gain a better understanding of how the tools and libraries I use interact with one another. Try giving ruby-debug a whirl in your next project.&lt;/p&gt;

&lt;p&gt;Here is a link to the Rails &lt;a href="https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2253-named_scope-and-nested-order-clauses"&gt;Lighthouse ticket&lt;/a&gt; describing this bug.&lt;/p&gt;

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=hgrUB-xIv4k:oOnotl1wlNk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=hgrUB-xIv4k:oOnotl1wlNk:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=hgrUB-xIv4k:oOnotl1wlNk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=hgrUB-xIv4k:oOnotl1wlNk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=hgrUB-xIv4k:oOnotl1wlNk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=hgrUB-xIv4k:oOnotl1wlNk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/hgrUB-xIv4k" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/using-ruby-debug-to-find-those-hard-to-reach-places-bugs/</feedburner:origLink></entry>

    <entry>
      <title>Hackday: Effective Testing for Rails</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/yZpwc3E2wwI/" />
      <id>tag:viget.com,2009:extend/4.1747</id>
      <published>2009-09-28T19:01:00Z</published>
      <updated>2009-09-29T00:32:02Z</updated>
      <author>
                        <name>Patrick Reagan, Development Director</name>
                        <email>patrick.reagan@viget.com</email>
            <uri>http://www.viget.com/about/team/preagan</uri>      </author>

      <category term="Events" scheme="http://www.viget.com/inspire/category/events/" label="Events" />
      <category term="Ruby on Rails" scheme="http://www.viget.com/inspire/category/ruby_on_rails/" label="Ruby on Rails" />
      <content type="html">


                 &lt;p&gt;This past Saturday we hosted the &lt;a href="http://www.meetup.com/rubyhacknight/calendar/11340056/"&gt;second Hackday&lt;/a&gt; at the Viget Labs office (&lt;a href="http://www.flickr.com/photos/viget/sets/72157622461248276/"&gt;photos&lt;/a&gt;).  For this event, Matt and I focused on the tools and techniques for testing that we often use when developing Rails applications.  Since the Hackday format is one of collaborative teaching and discussion, we decided to build a micro-app from scratch during a pair-programming session.&lt;/p&gt;

&lt;img src="http://farm4.static.flickr.com/3533/3956480459_b8d69288f6.jpg" alt="Pairing" /&gt;

&lt;p&gt;The topic for the day was a logical progression from our &lt;a href="http://www.viget.com/extend/hackday-recap/"&gt;previous event on controller refactoring&lt;/a&gt; as testing is a critical component of any reliable refactoring activity.  We spent some time covering the standard testing facilities in Rails and went on to discuss mocking, stubbing, object factories, and other testing libraries for use in Ruby and Rails projects.&lt;/p&gt;

The three-hour timeframe was sufficient to scratch the surface of these topics, but didn't allow us to get too deep in any one area.  In order to bridge the gap between what we covered during the day and the final application, we've made the full application code and tests &lt;a href="http://github.com/mig/outtolunch"&gt;available on GitHub&lt;/a&gt;.  We've also provided a &lt;a href="http://github.com/mig/outtolunch/blob/master/README.md"&gt;list of links&lt;/a&gt; to some of the tools we discussed during the day.

&lt;p&gt;Thanks to everyone who came out to the event &amp;ndash; we hope to see you all at the &lt;a href="http://www.meetup.com/rubyhacknight/calendar/11332322/"&gt;next Hack Night&lt;/a&gt;.&lt;/p&gt;                 

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=yZpwc3E2wwI:9fT8e0uMXTc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=yZpwc3E2wwI:9fT8e0uMXTc:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=yZpwc3E2wwI:9fT8e0uMXTc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=yZpwc3E2wwI:9fT8e0uMXTc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=yZpwc3E2wwI:9fT8e0uMXTc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=yZpwc3E2wwI:9fT8e0uMXTc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/yZpwc3E2wwI" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/hackday-effective-testing-for-rails/</feedburner:origLink></entry>

    <entry>
      <title>North Carolina jQuery Camp Recap</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/y39mmbHBhw4/" />
      <id>tag:viget.com,2009:extend/4.1736</id>
      <published>2009-09-21T17:03:00Z</published>
      <updated>2009-09-21T18:49:01Z</updated>
      <author>
                        <name>Brian Landau, Web Developer</name>
                        <email>brian.landau@viget.com</email>
                  </author>

      <category term="Events" scheme="http://www.viget.com/inspire/category/events/" label="Events" />
      <content type="html">


                 &lt;p&gt;This Saturday Viget South hosted NC jQuery Camp &amp;lsquo;09 which was organized by &lt;a href="http://blog.rebeccamurphey.com/"&gt;Rebecca Murphey&lt;/a&gt;. The day started off at 10AM with the group making a list of possible presentation topics in typical BarCamp style.&lt;/p&gt;
&lt;p&gt;Since some of the attendees were new to jQuery Rebecca did a little jQuery 101 with them while &lt;a href="http://blog.nemikor.com/"&gt;Scott Gonzalez&lt;/a&gt; went over creating stateful plugins.&lt;/p&gt;
&lt;p&gt;Scott explained that all the jQuery UI widgets and interactions are based off of a &lt;a href="http://docs.jquery.com/UI/Developer_Guide#The_widget_factory"&gt;widget module&lt;/a&gt;. Using &lt;code&gt;$.widget&lt;/code&gt; you can easily create your own stateful jQuery plugin. Given that there are a number of use-cases for this style of plugin I&amp;rsquo;m making sure to keep this in mind for the next time I need to whip up a jQuery plugin.&lt;/p&gt;
&lt;p&gt;Next, I took the floor and did an overview of &lt;a href="http://vigetlabs.github.com/jmapping/" title="jMapping Documentation"&gt;jMapping&lt;/a&gt;, how it came to be and the code behind it. I transitioned from that into giving an overview of using &lt;a href="http://github.com/nkallen/screw-unit/"&gt;Screw.Unit&lt;/a&gt; and &lt;a href="http://github.com/andykent/smoke"&gt;Smoke&lt;/a&gt; to unit test your jQuery code.&lt;/p&gt;
&lt;p&gt;Following me, our own &lt;a href="http://www.viget.com/about/team/deisinger"&gt;David Eisinger&lt;/a&gt; captivated everyone with his talk on Perceived Performance. He&amp;rsquo;s given this a couple of times before but he added something special this time by showing us the jQuery code that runs his whole presentation, &lt;a href="http://github.com/dce/dbdb/blob/master/public/javascripts/jquery.jquinote.js"&gt;jQuinote&lt;/a&gt;. There&amp;rsquo;s a decent amount of JS wizardry going on there and it was interesting to see how it all works.&lt;/p&gt;
&lt;p&gt;After lunch we were treated to Rebecca&amp;rsquo;s talk on organizing your code with object literals. This lead into a group discussion on code organization and the possibility of using &lt;a href="http://docs.jquery.com/Namespaced_Events" title="Namespaced Events - jQuery JavaScript Library"&gt;jQuery custom events&lt;/a&gt; to also organize your code. While I&amp;rsquo;m not sold on using custom events for code organization, you should definitely look at them if you&amp;rsquo;re developing a plugin because they make it very easy to add hooks into your code.&lt;/p&gt;
&lt;p&gt;Rounding out the afternoon a number of people came up for a &amp;ldquo;Show &amp;amp; Tell&amp;rdquo; session where they presented some code and/or functionality they&amp;rsquo;d written for a recent project. This included our own &lt;a href="http://www.viget.com/about/team/cnixon"&gt;Clinton Nixon&lt;/a&gt; along with &lt;a href="http://seancribbs.com/"&gt;Sean Cribbs&lt;/a&gt; of &lt;a href="http://radiantcms.org/"&gt;Radiant&lt;/a&gt; and &lt;a href="http://lowdownapp.com/"&gt;Lowdown&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, Scott came back up to give us a little jQuery UI 101. He went over all of the various effects, widgets and interactions. He educated us on &lt;a href="http://jquery-ui.googlecode.com/svn/trunk/demos/effect/easing.html" title="jQuery UI Effects - Effect Easing"&gt;all the &amp;ldquo;easings&amp;rdquo; available&lt;/a&gt; for the effects. Previously, I didn&amp;rsquo;t know so many were bundled with jQuery UI. He then treated us to a preview of the positioning plugin that's going to be released in conjunction with the new jQuery plugin repository that&amp;rsquo;s in the works.&lt;/p&gt;
&lt;p&gt;The positioning plugin is very impressive and I can&amp;rsquo;t wait for it to be released. It allows you to position an element in relation to another element via a very easy to use API:&lt;/p&gt;
&lt;pre name="code" class="javascript"&gt;$("#some-element").position({
  my: "left top",
  at: "left center",
  of: "#target-element"
});
&lt;/pre&gt;
&lt;p&gt;While still a work in progress &lt;a href="http://jquery-ui.googlecode.com/svn/trunk/ui/jquery.ui.position.js"&gt;source code for the position plugin&lt;/a&gt;, an &lt;a href="http://jquery-ui.googlecode.com/svn/trunk/demos/position/default.html" title="jQuery UI Position - Default functionality"&gt;initial example&lt;/a&gt;, and some &lt;a href="http://docs.jquery.com/UI/Position" title="UI/Utility/Position - jQuery JavaScript Library"&gt;documentation&lt;/a&gt; are all available.&lt;/p&gt;
&lt;p&gt;Throughout the day everyone had great conversations with other jQuery/JS developers about best-practices, favorite plugins, and new solutions to tough problems. It was a great event and we&amp;rsquo;re encouraged to &lt;a href="http://blog.rebeccamurphey.com/2009/09/19/inaugural-north-carolina-jquery-camp/"&gt;hear that Rebecca is considering organizing another event sometime early next year&lt;/a&gt;. Hope to see some of you next time!&lt;/p&gt;                 

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=y39mmbHBhw4:vAJReTJbVUE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=y39mmbHBhw4:vAJReTJbVUE:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=y39mmbHBhw4:vAJReTJbVUE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=y39mmbHBhw4:vAJReTJbVUE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=y39mmbHBhw4:vAJReTJbVUE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=y39mmbHBhw4:vAJReTJbVUE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/y39mmbHBhw4" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/north-carolina-jquery-camp-recap/</feedburner:origLink></entry>

    <entry>
      <title>Keep Your Friends Close, But Your Test Data Closer</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/ea995syefbw/" />
      <id>tag:viget.com,2009:extend/4.1733</id>
      <published>2009-09-18T17:38:00Z</published>
      <updated>2009-09-18T19:03:02Z</updated>
      <author>
                        <name>Patrick Reagan, Development Director</name>
                        <email>patrick.reagan@viget.com</email>
            <uri>http://www.viget.com/about/team/preagan</uri>      </author>

      <category term="Opinions/Reviews" scheme="http://www.viget.com/inspire/category/opinions_reviews/" label="Opinions/Reviews" />
      <category term="Ruby on Rails" scheme="http://www.viget.com/inspire/category/ruby_on_rails/" label="Ruby on Rails" />
      <category term="Tips and Tricks" scheme="http://www.viget.com/inspire/category/tips_and_tricks/" label="Tips and Tricks" />
      <content type="html">


                 &lt;p&gt;Like any Rails developer, you've been indoctrinated into the cult of DRY and are constantly removing duplication whenever you can as you add new functionality to your application.  Refactoring is an important part of the development process and improves the maintainability and understandability of your application's code.&lt;/p&gt;
&lt;p&gt;While this is good practice for production code, the tests in your application can benefit from refactoring as well.  Often, it is the setup phase of the unit testing cycle where you will encounter the most duplication.  The following example was extracted from &lt;a href="http://tweetsoffury.com/" title="Tweets of Fury"&gt;Tweets of Fury&lt;/a&gt; (go play now, I'll wait) &amp;ndash; I'm using both &lt;a href="http://github.com/thoughtbot/shoulda" title="thoughtbot's shoulda at master - GitHub"&gt;Shoulda&lt;/a&gt; and &lt;a href="http://github.com/jnunemaker/matchy" title="jnunemaker's matchy at master - GitHub"&gt;Matchy&lt;/a&gt; for the tests:&lt;/p&gt;                 &lt;pre&gt;context "An instance of the Round class" do
  should "know that there hasn't been a response from the challenger" do
    user   = Factory(:user)
    battle = Factory(:battle, :challenger =&amp;gt; user)
    weapon = Factory(:weapon)
    
    round  = battle.rounds.create!(:challenger_weapon =&amp;gt; nil, :opponent_weapon =&amp;gt; weapon)
    
    round.response_from?(user).should be(false)
  end

  should "know that the challenger has responded" do
    user   = Factory(:user)
    battle = Factory(:battle, :challenger =&amp;gt; user)
    weapon = Factory(:weapon)

    round  = battle.rounds.create!(:challenger_weapon =&amp;gt; weapon, :opponent_weapon =&amp;gt; nil)

    round.response_from?(user).should be(true)
  end
end
&lt;/pre&gt;
&lt;p&gt;A quick refactoring might result in moving the duplication into the setup:&lt;/p&gt;
&lt;pre&gt;context "An instance of the Round class" do
  setup do
    @user   = Factory(:user)
    @battle = Factory(:battle, :challenger =&amp;gt; @user)
    @weapon = Factory(:weapon)
  end
  
  ...
  
end
&lt;/pre&gt;
&lt;p&gt;The tests can now become more focused once the setup code has been extracted:&lt;/p&gt;
&lt;pre&gt;should "know that there hasn't been a response from the challenger" do
  round = @battle.rounds.create!(:opponent_weapon =&amp;gt; @weapon)
  round.response_from?(@user).should be(false)
end

should "know that the challenger has responded" do
  round = @battle.rounds.create!(:challenger_weapon =&amp;gt; @weapon)
  round.response_from?(@user).should be(true)
end
&lt;/pre&gt;
&lt;p&gt;Better, but not quite what I want.  I've removed the "noise" and can now better focus on the code under test, but it presents me with another issue: the setup that I need to perform is missing some information that is important to keep within the test itself.  I want it to be clear to anyone reading either of these tests that the user is the challenger in this particular battle, especially as I continue to add tests for this model.&lt;/p&gt;
&lt;p&gt;In order to make this state apparent and remove duplication, I created a helper method that handles the task of setting up the data for a round:&lt;/p&gt;
&lt;pre&gt;class RoundTest &amp;lt; ActiveSupport::TestCase
  def create_round_with_battle(round_options = {}, battle_options = {})
    ...
  end
end
&lt;/pre&gt;
&lt;p&gt;The implementation isn't particularly important &amp;ndash; what it allows me to do is keep the important setup data within my tests:&lt;/p&gt;
&lt;pre&gt;context "An instance of the Round class with a challenger" do
  setup { @challenger = Factory(:user) }

  should "know that there hasn't been a response from the challenger" do
    round = create_round_with_battle({:weapon_for =&amp;gt; :opponent}, {:challenger =&amp;gt; @challenger})
    round.response_from?(@challenger).should be(false)
  end

  should "know that the challenger has responded" do
    round = create_round_with_battle({:weapon_for =&amp;gt; :challenger}, {:challenger =&amp;gt; @challenger})
    round.response_from?(@challenger).should be(true)
  end
end
&lt;/pre&gt;
&lt;p&gt;To me, this strikes the proper balance.  It gives me only the context I need while still giving me the required control over the initial state of the object under test.  At this point, it may be tempting to tuck the &lt;tt&gt;create_round_with_battle&lt;/tt&gt; method into &lt;tt&gt;test_helper.rb&lt;/tt&gt;, but you should resist that urge.  This method is only needed in this test, so it should remain here.&lt;/p&gt;

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=ea995syefbw:29IRpjzIY8k:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=ea995syefbw:29IRpjzIY8k:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=ea995syefbw:29IRpjzIY8k:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=ea995syefbw:29IRpjzIY8k:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=ea995syefbw:29IRpjzIY8k:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=ea995syefbw:29IRpjzIY8k:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/ea995syefbw" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/keep-your-friends-close-but-your-test-data-closer/</feedburner:origLink></entry>

    <entry>
      <title>Getting Started with MongoDB &amp; MongoMapper</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/WBUh-nPFlWs/" />
      <id>tag:viget.com,2009:extend/4.1731</id>
      <published>2009-09-17T09:00:00Z</published>
      <updated>2009-09-15T20:14:17Z</updated>
      <author>
                        <name>Clinton R. Nixon, Development Director</name>
                        <email>clinton.nixon@viget.com</email>
            <uri>http://www.viget.com/about/team/cnixon</uri>      </author>

      <category term="Opinions/Reviews" scheme="http://www.viget.com/inspire/category/opinions_reviews/" label="Opinions/Reviews" />
      <category term="Ruby on Rails" scheme="http://www.viget.com/inspire/category/ruby_on_rails/" label="Ruby on Rails" />
      <category term="Trends" scheme="http://www.viget.com/inspire/category/trends/" label="Trends" />
      <content type="html">


                 &lt;p&gt;As part of our &lt;a href="http://www.viget.com/extend/introducing-the-nosql-series/"&gt;NoSQL exploration&lt;/a&gt;, I&amp;rsquo;ve spent some time lately with &lt;a href="http://www.mongodb.org/display/DOCS/Home"&gt;MongoDB&lt;/a&gt;. MongoDB bills itself as a &amp;ldquo;schema-free document-oriented database.&amp;rdquo; In using MongoDB, I&amp;rsquo;ve found it to be an easy transition from RDBMS&amp;rsquo;s because of the way it organizes document-based data. Here&amp;rsquo;s the basics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MongoDB has collections of data, not tables.&lt;/strong&gt; Unlike &lt;a href="http://couchdb.apache.org/"&gt;CouchDB&lt;/a&gt;, which is also a document-oriented DB, Mongo has namespaces for data. These are schema-less, so any data could go in each namespace. In my practice, I&amp;rsquo;ve persisted objects of one class into each collection, not unlike ActiveRecord with MySQL or any other RDBMS.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MongoDB has indexes&lt;/strong&gt;. Even though each collection has no schema, you can still index the data in a collection based off a field. Not all documents in a collection have to have this field.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MongoDB has a query language and query profiling.&lt;/strong&gt; While you can use JavaScript to search through a collection, like CouchDB, you also have access to a rich query language that can filter based on fields, like SQL, and filter based on the contents of embedded documents, which proves to be totally freaking awesome. Instead of a complex join, you can query for all documents in the posts collection that have an embedded comment in the last month.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;                 &lt;p&gt;Given the similarities between MongoDB and a relational database, you&amp;rsquo;d think it would be easy to use in Ruby in place of ActiveRecord, and you&amp;rsquo;d be right. John Nunemaker has created &lt;a href="http://github.com/jnunemaker/mongomapper"&gt;a gem called MongoMapper&lt;/a&gt; to work as an object mapper to MongoDB. Using MongoMapper, you can create model classes like so:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;class Book
  include MongoMapper::Document

  key :title, String, :required =&amp;gt; true
  key :author, String
  key :published_at, Date
  key :user_id, String
  timestamps! # HECK YES

  belongs_to :user
  many :chapters
end  
&lt;/pre&gt;
&lt;p&gt;You&amp;rsquo;ll note several things here. Keys are defined in the model, like in a DataMapper model, although they aren&amp;rsquo;t defining a schema, only a mapping for this particular model. (If the difference seems subtle, that&amp;rsquo;s because it is: MongoMapper in many ways lets you treat MongoDB as a relational DB.) The keys can be typecast as I&amp;rsquo;ve done, although they don&amp;rsquo;t have to be. I&amp;rsquo;ve defined relationships to other models, and MongoMapper is smart about this. In the case of &lt;code&gt;many :chapters&lt;/code&gt;, it looks to see if the &lt;code&gt;Chapter&lt;/code&gt; class is embeddable. If so, it will embed &lt;code&gt;Chapter&lt;/code&gt; documents in my &lt;code&gt;Book&lt;/code&gt; document. If not, it will store them in their own collection.&lt;/p&gt;
&lt;p&gt;Just because MongoMapper defines a document with keys, you don&amp;rsquo;t have to stick to the keys. Because collections are schema-less, you can add new attributes at will, like in this example:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;book = Book.new(:title =&amp;gt; "Moby Dick 2")
# =&amp;gt; #&amp;lt;Book _id: , title: Moby Dick 2, author: &amp;gt;

book.author = "Dan Brown"
book.update_attributes(:author =&amp;gt; "J.K. Rowling", 
                       :isbn =&amp;gt; '1-2345-6789-0', 
                       :amazon_score =&amp;gt; 1.25)
book.save

book = Book.find_by_title("Moby Dick 2")
# =&amp;gt; #&amp;lt;Book _id: 4aafe487477a51f0e8000002, 
#         title: Moby Dick 2, 
#         author: J.K. Rowling, 
#         isbn: 1-2345-6789-0, 
#         amazon_score: 1.25&amp;gt; 
&lt;/pre&gt;
&lt;p&gt;You can see that I can set keys defined in the class with setters, but I can set any attribute through &lt;code&gt;update_attributes&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;MongoMapper&amp;rsquo;s API is roughly equivalent to ActiveRecord&amp;rsquo;s, allowing you to use in a Rails application with little difficulty. The only things I&amp;rsquo;ve had to do are define &lt;code&gt;human_name&lt;/code&gt; on model classes and define &lt;code&gt;new_record?&lt;/code&gt; on embedded documents.&lt;/p&gt;
&lt;p&gt;The only other thing you need to know to get started with MongoMapper is how to tell it what database to use. All you have to do is set &lt;code&gt;MongoMapper.connection&lt;/code&gt; and &lt;code&gt;MongoMapper.database&lt;/code&gt;. In &lt;a href="http://github.com/crnixon/wordbadger"&gt;my sample Rails app&lt;/a&gt;, I&amp;rsquo;ve put a file in &lt;code&gt;config/initializers/&lt;/code&gt; that looks like this:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;db_config = YAML::load(File.read(RAILS_ROOT + "/config/database.yml"))

if db_config[Rails.env] &amp;amp;&amp;amp; 
db_config[Rails.env]['adapter'] == 'mongodb'
  mongo = db_config[Rails.env]
  MongoMapper.connection = Mongo::Connection.new(mongo['hostname'])
  MongoMapper.database = mongo['database']
end
&lt;/pre&gt;
&lt;p&gt;You can see my &lt;a href="http://github.com/crnixon/wordbadger/blob/master/config/database.yml"&gt;&lt;code&gt;database.yml&lt;/code&gt;&lt;/a&gt; file for more information on setup or check out &lt;a href="http://gist.github.com/181842"&gt;Ben Scofield&amp;rsquo;s Rails template for MongoMapper&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That should get you started! I&amp;rsquo;ve really enjoyed using MongoDB so far. For further information, checkout the &lt;a href="http://github.com/mongodb/mongo-ruby-driver"&gt;MongoDB Ruby driver code&lt;/a&gt;, the &lt;a href="http://github.com/jnunemaker/mongomapper"&gt;MongoMapper code&lt;/a&gt;, and &lt;a href="http://github.com/crnixon/wordbadger"&gt;the code for my sample app&lt;/a&gt; on GitHub, and look out for more upcoming posts about how we&amp;rsquo;ve used MongoDB.&lt;/p&gt;

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=WBUh-nPFlWs:RWF-ax7iPG4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=WBUh-nPFlWs:RWF-ax7iPG4:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=WBUh-nPFlWs:RWF-ax7iPG4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=WBUh-nPFlWs:RWF-ax7iPG4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=WBUh-nPFlWs:RWF-ax7iPG4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=WBUh-nPFlWs:RWF-ax7iPG4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/WBUh-nPFlWs" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/getting-started-with-mongodb-mongomapper/</feedburner:origLink></entry>

    <entry>
      <title>Wrapping Rails Session Hash</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/l9luDV-5dx8/" />
      <id>tag:viget.com,2009:extend/4.1726</id>
      <published>2009-09-16T18:42:00Z</published>
      <updated>2009-09-17T14:05:01Z</updated>
      <author>
                        <name>Matt Swasey, Web Developer</name>
                        <email>matt.swasey@viget.com</email>
            <uri>http://www.viget.com/about/team/mswasey</uri>      </author>

      <category term="General" scheme="http://www.viget.com/inspire/category/general/" label="General" />
      <content type="html">


                 &lt;p&gt;
  The best way to use session data in Rails is sometimes a bit elusive.  One technique I see from time to time is using a before_filter to pull data from the session, and store it in an instance variable.
&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;class AccountsController &amp;lt; ApplicationController
  before_filter :find_account
  
  ...
  
  def find_account
    @account = Account.find(session[:account_id])
  end
end
&lt;/pre&gt;
&lt;p&gt;The problem here is that the more places you start using the @account instance variable, the more confusing it gets.  Suppose we wanted to reuse this before_filter, and so we move find_account to our ApplicationController.  This would further obscure the location where the instance variable is being set.&lt;/p&gt;
&lt;p&gt;
  Another drawback to using a before_filter is having to tediously define where you want the filter to run or not-to-run (using skip_before_filter).  It would be nice if we could have that data only where we really needed it without worrying about declaring which actions have access to session data and which don't.
&lt;/p&gt;
&lt;h3&gt;A Better Approach&lt;/h3&gt;
&lt;p&gt;A pattern I like to use when working with sessions in rails is wrapping session variables in getter and setter current_object methods.  I picked this up a while ago while using RestfulAuthentication, I've found since that I use it in almost every project.  Observe...&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;class ApplicationController &amp;lt; ActionController::Base
  helper_method :current_account
  
  def current_account
    @current_account ||= Account.find_by_id(session[:current_account_id])
  end

  def current_account=(account)
    session[:current_account_id] = account.try(:id)
  end
end
&lt;/pre&gt;
&lt;p&gt;I am using find_by_id(id) because it returns a nil value when the
  record is not found rather than an exception, which is what is
  returned from an unsuccessful find(id).  Keep this in mind, as you
  may prefer to throw an exception over a silent failure.&lt;/p&gt;
&lt;p&gt; Using the conditional assignment method in our getter allows us to lazily load database records.  It's also worth noting that the current_account method always returns a model instance, we only store the record's id in the actual session.  This keeps our session data as small as possible.&lt;/p&gt;
&lt;p&gt;
  I've declared these methods as helper methods inside the ApplicationController so that I can use them in my controllers and views alike.  I find a call to 'current_account' in the view is easier to understand than an instance variable that is set somewhere other than the view's corresponding controller action.
&lt;/p&gt;
&lt;p&gt;Notice the use of &lt;a href="http://github.com/rails/rails/blob/95dfcc4f3c4bda74efe220e6dd5a11f58f29a501/activesupport/lib/active_support/core_ext/try.rb#L25"&gt;Object#try&lt;/a&gt; when calling id on the account
  argument passed to current_account=.  Using Object#try in this situation allows us to set session[:current_account_id] to nil using the same current_account=
  setter method.  This is often seen in logout actions:&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;class SessionsController &amp;lt; ApplicationController
  ...
  def destroy
    self.current_account = nil
    redirect_to root_path
  end
end
&lt;/pre&gt;
&lt;h3&gt;A Gotcha&lt;/h3&gt;
&lt;p&gt;Remember to prepend the setter method with 'self' when using it in your controllers, else Ruby will make a local variable assignment to 'current_account' the variable, which is different from 'current_account=' the method.  Obvious, perhaps, but it trips me up from time to time.&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;class AccountsController
  def create
    self.current_account = Account.find(params[:id])
    ...
  end
  ...
end
&lt;/pre&gt;
&lt;p&gt;If anyone has other nice ways of handling session variables in Rails, let me know in the comments!&lt;/p&gt;                 

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=l9luDV-5dx8:rQxq1xM1E6k:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=l9luDV-5dx8:rQxq1xM1E6k:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=l9luDV-5dx8:rQxq1xM1E6k:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=l9luDV-5dx8:rQxq1xM1E6k:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=l9luDV-5dx8:rQxq1xM1E6k:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=l9luDV-5dx8:rQxq1xM1E6k:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/l9luDV-5dx8" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/wrapping-rails-session-hash/</feedburner:origLink></entry>

    <entry>
      <title>Viget Devs Storm Chicago</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/G4LjXcX0HMo/" />
      <id>tag:viget.com,2009:extend/4.1732</id>
      <published>2009-09-16T00:58:00Z</published>
      <updated>2009-09-16T02:01:59Z</updated>
      <author>
                        <name>David Eisinger, Web Developer</name>
                        <email>david.eisinger@viget.com</email>
            <uri>http://www.viget.com/about/team/deisinger</uri>      </author>

      <category term="Events" scheme="http://www.viget.com/inspire/category/events/" label="Events" />
      <content type="html">


                 &lt;p&gt;&lt;a href="http://www.flickr.com/photos/laffy4k/53100874/"&gt;&lt;img align="right" src="http://farm1.static.flickr.com/28/53100874_f605bd5f42_m.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This past weekend, Ben and I travelled to Chicago to speak at &lt;a href="http://windycityrails.org/"&gt;Windy City Rails&lt;/a&gt;. It was a great conference; highlights included &lt;a href="http://www.deanwampler.com/"&gt;Dean Wampler&lt;/a&gt;&amp;rsquo;s discussion of functional programming in Ruby, &lt;a href="http://www.railsprescriptions.com/"&gt;Noel Rappin&lt;/a&gt;&amp;rsquo;s talk on handling difficult-to-test portions of your applications, and our own &lt;a href="http://www.viget.com/about/team/bscofield"&gt;Ben Scofield&lt;/a&gt;&amp;rsquo;s very polished presentation about modeling difficult domains. This was the second time I&amp;rsquo;d seen &lt;a href="http://yehudakatz.com/"&gt;Yeduda Katz&lt;/a&gt;&amp;rsquo;s keynote on the history and future of the Rails framework, and that the talk has come so far in the last three months says promising things for the progress of Rails 3.&lt;/p&gt;
&lt;p&gt;Speaking at Windy City Rails was just as much an excuse to hang out in Chicago as it was a chance to share knowledge with the Ruby community. We knocked out the major &lt;a href="http://www.portillos.com/"&gt;food&lt;/a&gt; &lt;a href="http://www.loumalnatis.com/"&gt;groups&lt;/a&gt; on the first day, and I set aside a few days after the conference to wander the city. Big thanks to the conference organizers and attendees. Videos of all of the talks will be appearing on the &lt;a href="http://windycityrails.org/"&gt;conference website&lt;/a&gt; soon.&lt;/p&gt;                 

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=G4LjXcX0HMo:rHth0V3TIAE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=G4LjXcX0HMo:rHth0V3TIAE:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=G4LjXcX0HMo:rHth0V3TIAE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=G4LjXcX0HMo:rHth0V3TIAE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=G4LjXcX0HMo:rHth0V3TIAE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=G4LjXcX0HMo:rHth0V3TIAE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/G4LjXcX0HMo" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/viget-devs-storm-chicago/</feedburner:origLink></entry>

    <entry>
      <title>Herding Developers</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/sa9SeZMhoV0/" />
      <id>tag:viget.com,2009:extend/4.1723</id>
      <published>2009-09-10T11:00:00Z</published>
      <updated>2009-09-09T13:56:14Z</updated>
      <author>
                        <name>Ben Scofield, Technology Director</name>
                        <email>ben.scofield@viget.com</email>
            <uri>http://www.viget.com/about/team/bscofield</uri>      </author>

      <category term="Events" scheme="http://www.viget.com/inspire/category/events/" label="Events" />
      <content type="html">


                 &lt;p&gt;&lt;a href="http://developer-day.com/"&gt;Developer Day&lt;/a&gt;&amp;nbsp;has taken the east coast by storm, with great receptions in&amp;nbsp;&lt;a href="http://developer-day.com/events/2009-durham.html"&gt;Durham&lt;/a&gt;,&amp;nbsp;&lt;a href="http://developer-day.com/events/2009-dc.html"&gt;DC&lt;/a&gt;, and&amp;nbsp;&lt;a href="http://developer-day.com/events/2009-boston.html"&gt;Boston&lt;/a&gt;&amp;nbsp;(check&amp;nbsp;&lt;a href="http://speakerrate.com/series/46-developer-day"&gt;SpeakerRate&lt;/a&gt;&amp;nbsp;for all the details). As we reflected on the next steps, then, the natural progression was to move west &amp;ndash; so that's what we're d
&lt;script src="http://www.viget.com/ee-system/scripts/tiny_mce/themes/advanced/langs/en.js" type="text/javascript"&gt;&lt;/script&gt;
oing. On October 10th, Developer Day will be thundering into Boulder, Colorado (home of&amp;nbsp;&lt;a href="http://www.techstars.org/"&gt;TechStars&lt;/a&gt;,&amp;nbsp;and a number of exciting companies and startups).&amp;nbsp;&lt;/p&gt;
&lt;p&gt;We've started to finalize &lt;a href="http://developer-day.com/events/2009-boulder.html"&gt;the program&lt;/a&gt;, and so far it looks great. There's a huge pool of developer talent in Colorado, and we're aiming to pull in as much of it as we can to speak at the event.&lt;/p&gt;
&lt;p&gt;If you'll be anywhere near Boulder around October 10th, you should definitely plan to attend &amp;ndash; early bird registration is only $50, which will get you a full day of great talks, smart people to chat with, breakfast, lunch, &lt;strong&gt;and &lt;/strong&gt;a t-shirt. Who could resist that deal? &lt;a href="http://developer-day.com/events/2009-boulder.html"&gt;Register today&lt;/a&gt;!&lt;/p&gt;                 

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=sa9SeZMhoV0:YYVo7hLy6pk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=sa9SeZMhoV0:YYVo7hLy6pk:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=sa9SeZMhoV0:YYVo7hLy6pk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=sa9SeZMhoV0:YYVo7hLy6pk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=sa9SeZMhoV0:YYVo7hLy6pk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=sa9SeZMhoV0:YYVo7hLy6pk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/sa9SeZMhoV0" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/herding-developers/</feedburner:origLink></entry>

    <entry>
      <title>Coming Soon: The NoSQL Series</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/TYlC1EXUj1c/" />
      <id>tag:viget.com,2009:extend/4.1718</id>
      <published>2009-09-02T11:00:00Z</published>
      <updated>2009-09-02T02:02:16Z</updated>
      <author>
                        <name>Ben Scofield, Technology Director</name>
                        <email>ben.scofield@viget.com</email>
            <uri>http://www.viget.com/about/team/bscofield</uri>      </author>

      <category term="Introducing" scheme="http://www.viget.com/inspire/category/introducing/" label="Introducing" />
      <content type="html">


                 &lt;p&gt;We're always excited about new trends here at Viget, and the most recent phenomenon that's caught our attention is &lt;a href="http://en.wikipedia.org/wiki/Nosql"&gt;NoSQL&lt;/a&gt; - the reaction against traditional relational databases like &lt;a href="http://www.mysql.com/"&gt;MySQL&lt;/a&gt;. The movement has been characterized by an explosion of interest in key-value stores, document-oriented databases, and other (mostly non-relational) alternatives for data storage. Several of the developers here in the Labs have been &lt;a href="http://github.com/tpitale/mongolytics/tree/master"&gt;experimenting&lt;/a&gt; with these emerging systems, and over the next few weeks, we'll be posting our thoughts. &lt;/p&gt;
&lt;p&gt;We'll show examples of situations in which, say, &lt;a href="http://www.mongodb.org/display/DOCS/Home"&gt;MongoDB&lt;/a&gt; works particularly well - and we'll also show situations in which you're much better off staying with something more traditional. In fact, that's the conclusion we've drawn from the whole thing: just as many different programming languages can coexist, with each being useful for some particular set of problems, many different databases can coexist - with each being useful for some particular set of domains. Even more interesting to me, though, is the set of complex domains that can be best served with &lt;em&gt;multiple&lt;/em&gt; database systems... Hey, if &lt;a href="http://twitter.com/"&gt;Twitter&lt;/a&gt; can rely on &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt; and &lt;a href="http://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt;, why can't we build an application with MySQL on top of &lt;a href="http://couchdb.apache.org/"&gt;CouchDB&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;In the course of this series, we'd love to hear your feedback - how are you using these alternatives to traditional databases? Have you abandoned &lt;a href="http://www.postgresql.org/"&gt;Postgres&lt;/a&gt; to &lt;a href="http://tokyocabinet.sourceforge.net/"&gt;Tokyo Cabinet&lt;/a&gt;, or tested with &lt;a href="http://neo4j.org/"&gt;Neo4j&lt;/a&gt;? How are they working for you?&lt;/p&gt;
&lt;p&gt;Look for the first post in the series next week!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;                 

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=TYlC1EXUj1c:GHlZGQcSYDs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=TYlC1EXUj1c:GHlZGQcSYDs:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=TYlC1EXUj1c:GHlZGQcSYDs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=TYlC1EXUj1c:GHlZGQcSYDs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=TYlC1EXUj1c:GHlZGQcSYDs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=TYlC1EXUj1c:GHlZGQcSYDs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/TYlC1EXUj1c" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/introducing-the-nosql-series/</feedburner:origLink></entry>

    <entry>
      <title>Prototyping Java-Processing in Ruby-Processing</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/loVgYMGb3Z0/" />
      <id>tag:viget.com,2009:extend/4.1714</id>
      <published>2009-08-28T17:53:00Z</published>
      <updated>2009-08-28T20:55:42Z</updated>
      <author>
                        <name>Justin Marney, Web Developer</name>
                        <email>justin.marney@viget.com</email>
            <uri>http://www.viget.com/about/team/jmarney</uri>      </author>

      <category term="General" scheme="http://www.viget.com/inspire/category/general/" label="General" />
      <content type="html">


                 &lt;p&gt;It's no secret that I spend copious amounts of free time trying to create art with my laptop.  Not too long ago I gave a talk on &lt;a href="http://sorescode.com/2009/6/2/monome-lily"&gt;using Lily and the Monome to generate algorithmic music&lt;/a&gt;.  More recently, I've been obsessed with learning &lt;a href="http://processing.org"&gt;Processing&lt;/a&gt;, an animation and interaction programming language.  It has the capability to generate both algorithmic music and visualizations and it runs on the JVM so it's quite fast and portable.  The language itself provides a huge library of functions that serve as abstractions to the intricate and tedious world of graphics programming in Java.  That said, it isn't really its own language per se.  At the end of the day, coding in Processing is coding in Java.  Fortunately, &lt;a href="http://ashkenas.com/"&gt;Jeremy Ashkenas&lt;/a&gt; has created a JRuby interface to the Processing API called &lt;a href="http://github.com/jashkenas/ruby-processing/"&gt;ruby-processing&lt;/a&gt;.  I've been using both, together, at the &lt;em&gt;same time&lt;/em&gt; to help improve both my Ruby code and my Java code.&lt;/p&gt;                 &lt;h2&gt;The Concept&lt;/h2&gt;
&lt;p&gt;The Java based version of Processing runs faster than ruby-processing and this is no surprise as there is an inherent performance cost when translating Ruby to Java.  On the other hand, I can code faster in Ruby.  I've been combining these two forces and prototyping my Processing applications in ruby-processing and then porting them to Processing.  Along the way I've realized that this technique is a powerful aid in understanding object-oriented fundamentals.  It has also increased my appreciation of Ruby as it demonstrates how features of the language map to Java code structures with surprisingly less syntax and greater flexibility.&lt;/p&gt;
&lt;h2&gt;Examples&lt;/h2&gt;
&lt;p&gt;Here's an example based on a Processing simulation I've been working on.  My simulation is based on &lt;a href="http://vimeo.com/135862"&gt;this video&lt;/a&gt;, by Robert Hodgin who blogs at &lt;a href="http://flight404.com"&gt;flight404&lt;/a&gt;.  We'll look at a small subset of the app for demonstration purposes.&lt;/p&gt;
&lt;h3&gt;Modules and Base Classes&lt;/h3&gt;
&lt;pre name="code" class="ruby"&gt; module Movable
  def move; end
end
class Magnetism
  attr_accessor :particles
  def act; end
end
class Gravity
  include Movable
  attr_accessor :particles
  def act; end
end
class Particle
  include Movable
end
&lt;/pre&gt;
&lt;p&gt;A little explanation is in order here.  Magnetism takes a collection of Movables and applies a magnetic field equation in &lt;code&gt;Magnetism#act&lt;/code&gt;.  Gravity does the same thing except it uses a gravitational equation.  Here we see that instances of Particle and Gravity are both Movables.  I wanted to be able to have a bunch of small magnetized particles influenced by gravity, as well as a handful of gravitational objects that were magnetized with respect to each other.  Watch &lt;a href="http://vimeo.com/135862"&gt;the flight404 video&lt;/a&gt; if that isn't totally clear.&lt;/p&gt;
&lt;p&gt;My Java solution is essentially the opposite of what I talked about in an older blog post, &lt;a href="http://www.viget.com/extend/inheritance-is-unlikely/"&gt;Inheritance is Unlikely&lt;/a&gt;.  I created a Movable base class that Gravity and Particle inherit from.  Inside &lt;code&gt;Magnetism#act&lt;/code&gt; I cast the objects in the particle collection to the type Movable.&lt;/p&gt;
&lt;h3&gt;Duck Typing and Interfaces&lt;/h3&gt;
&lt;pre name="code" class="ruby"&gt; class Particles
  def display
    particles.each do |p|
      p.display
    end
  end
  def move
    particles.each do |p|
      p.move
    end
  end
 end
&lt;/pre&gt;
&lt;p&gt;While Particle and Gravity instances get their movement behavior from the Movable module, they both implement different display behavior.  Particles, which is the particle collection class, contains an array of instances that respond to both &lt;code&gt;#display&lt;/code&gt; and &lt;code&gt;#move&lt;/code&gt; messages.  My goal was to use this as a collection for both Particle and Gravity instances.  In Ruby, this happens automatically.  As long as the instance &lt;code&gt;p&lt;/code&gt; passed into the &lt;code&gt;#each&lt;/code&gt; block responds to &lt;code&gt;#move&lt;/code&gt; or &lt;code&gt;#act&lt;/code&gt; I should be able to use these delegation methods without any trouble.&lt;/p&gt;
&lt;pre name="code" class="ruby"&gt;interface IDisplayable {
  void display();
}

class Gravity extends Movable implements IDisplayable {
  void display() {
  }
}

class Particle extends Movable implements IDisplayable {
  void display() {
  }
}

class Particles {
  void display() {
    for(int i = 0; i &amp;lt; particles.size(); i++) {
      IDisplayable p = (IDisplayable)particles.get(i);
      p.display();
    }
  }
}
&lt;/pre&gt;
&lt;p&gt;In Java, the solution is a bit more tricky, at least for a Java novice such as myself.  I created an IDisplayable interface that defined the display method signature and made Gravity and Particle implement that interface.  This particular approach helps concretize the idea that adding public methods to a Ruby object implicitly builds an interface.  The duck typed nature of Ruby somewhat hides this aspect but in porting to Java the concept of interfaces becomes explicit.&lt;/p&gt;
&lt;h2&gt;Lessons&lt;/h2&gt;
&lt;p&gt;Clearly, these two examples aren't groundbreaking but the value of this approach is in the actual practice.  Looking at your Ruby code and thinking about what various interfaces your objects conform to will help you model more flexible and reusable classes.  In the event your end goal is flexible Java code, prototyping a class hierarchy in Ruby can help you build in the flexibility of Ruby without having to mess with explicit interfaces until everything is working the way you want.  Processing itself is a great environment to try out something like this as the boiler-plate overhead of creating a running Java application is well hidden within the Processing internals.&lt;/p&gt;

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=loVgYMGb3Z0:94b3U751hkQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=loVgYMGb3Z0:94b3U751hkQ:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=loVgYMGb3Z0:94b3U751hkQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=loVgYMGb3Z0:94b3U751hkQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=loVgYMGb3Z0:94b3U751hkQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=loVgYMGb3Z0:94b3U751hkQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/loVgYMGb3Z0" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/prototyping-java-processing-in-ruby-processing/</feedburner:origLink></entry>

    <entry>
      <title>Regarding Recent Events</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/Ho40Fql1-AI/" />
      <id>tag:viget.com,2009:extend/4.1692</id>
      <published>2009-08-17T12:30:00Z</published>
      <updated>2009-08-17T11:19:54Z</updated>
      <author>
                        <name>Ben Scofield, Technology Director</name>
                        <email>ben.scofield@viget.com</email>
            <uri>http://www.viget.com/about/team/bscofield</uri>      </author>

      <category term="Events" scheme="http://www.viget.com/inspire/category/events/" label="Events" />
      <content type="html">


                 &lt;p&gt;We&amp;rsquo;ve been busy little event organizers here at Viget lately, with a couple of iPhone Hack Days (one at each office) and Developer Day Boston all coming in the last several weeks. In case you missed &amp;lsquo;em, here&amp;rsquo;s how things went down.&lt;/p&gt;
&lt;h3&gt;iPhone Hack Days&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ve been seeing a lot of interest in iPhone development, both from clients and from developers - and there is a flurry of activity going on in the framework space, with &lt;a href="http://www.rhomobile.com/"&gt;Rhomobile&lt;/a&gt;, &lt;a href="http://phonegap.com/"&gt;PhoneGap&lt;/a&gt;, &lt;a href="http://www.appcelerator.com/"&gt;Titanium&lt;/a&gt;, and more all competing to make iPhone development easier. It made perfect sense, then, for me to run a couple of half-day-ish workshops on the platform, both introducing Objective-C and the process for creating native apps (and walking people through the code for my own application in the process), and digging in deeper to a couple of the frameworks.&lt;/p&gt;
&lt;p&gt;At the HQ Hack Day, we just had Viget developers (and a lone UX guy) working, but we had a ton of fun. For the Durham version, we invited in a few local developers to bring in people with diverse backgrounds and interests. Brent Collier &lt;a href="http://www.brentmc79.com/posts/iphone-hack-day-at-viget-labs"&gt;posted his thoughts&lt;/a&gt; about the event, and we got some nice comments on Twitter, as well:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://twitter.com/brentmc79"&gt;@brentmc79&lt;/a&gt; At Viget Labs hacking around with some iPhone development... &lt;a href="http://yfrog.com/2rnhij"&gt;http://yfrog.com/2rnhij&lt;/a&gt; - &lt;a href="http://twitter.com/brentmc79/statuses/3166859487"&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://twitter.com/rmurphey"&gt;@rmurphey&lt;/a&gt; great day at iphone dev camp &lt;a href="http://twitter.com/viget"&gt;@viget&lt;/a&gt; -- obj c ugh. titanium and phonegap ftw. - &lt;a href="http://twitter.com/rmurphey/statuses/3169622876"&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://twitter.com/brianjlandau"&gt;@brianjlandau&lt;/a&gt; Learning a ton about iPhone development with all the &lt;a href="http://twitter.com/viget"&gt;@viget&lt;/a&gt; south devs from &lt;a href="http://twitter.com/bscofield"&gt;@bscofield&lt;/a&gt; - &lt;a href="http://twitter.com/brianjlandau/statuses/3167190227"&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Developer Day Boston&lt;/h3&gt;
&lt;p&gt;On August 15th, I was up in Boston along with Jess Martin and Stuart Halloway from &lt;a href="http://thinkrelevance.com"&gt;Relevance&lt;/a&gt; to organize (and speak) at our first Developer Day outside of DC and Durham. We were fortunate to have the help of &lt;a href="http://thoughtbot.com"&gt;thoughtbot&lt;/a&gt; and &lt;a href="http://microsoft.com"&gt;Microsoft&lt;/a&gt; (which allowed us to hold the event in an amazing space at their &lt;a href="http://microsoftcambridge.com/"&gt;NERD Center&lt;/a&gt;), and with all of that we had a great time. People learned about &lt;a href="http://speakerrate.com/talks/1318-understanding-javascript-testing"&gt;JavaScript testing&lt;/a&gt; from &lt;a href="http://ejohn.org/"&gt;John Resig&lt;/a&gt;, about the &lt;a href="http://speakerrate.com/talks/1316-an-introduction-to-css-2-1-css-3"&gt;wonders of CSS 2.1 and 3&lt;/a&gt; from &lt;a href="http://marcamos.com/"&gt;Marc Amos&lt;/a&gt;, about &lt;a href="http://speakerrate.com/talks/1317-enjoy-your-version-control"&gt;git&lt;/a&gt; from &lt;a href="http://gitready.com/"&gt;Nick Quaranto&lt;/a&gt;, and &lt;a href="http://speakerrate.com/events/157-developer-day-boston"&gt;more&lt;/a&gt; - check out some of the comments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://twitter.com/vandrijevik"&gt;@vandrijevik&lt;/a&gt; @thoughtbot's flutie is sexay! Enjoying &lt;a href="http://twitter.com/croaky"&gt;@croaky&lt;/a&gt;'s talk and demo of heroku-suspenders. &lt;a href="http://twitter.com/#search?q=%23developer_day"&gt;#developer_day&lt;/a&gt; - &lt;a href="http://twitter.com/vandrijevik/statuses/3328547380"&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://twitter.com/wrycoder"&gt;@wrycoder&lt;/a&gt; Compelling pitch for document databases by &lt;a href="http://twitter.com/bscofield"&gt;@bscofield&lt;/a&gt;. Relationships as first class objects. May even check out some comics. &lt;a href="http://twitter.com/#search?q=%23developer_day"&gt;#developer_day&lt;/a&gt;  - &lt;a href="http://twitter.com/wrycoder/statuses/3329379990"&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://twitter.com/phildarnowsky"&gt;@PhilDarnowsky&lt;/a&gt; Continuous Integration: writing better applications by harnessing the power of shame. &lt;a href="http://twitter.com/#search?q=%23developer_day"&gt;#developer_day&lt;/a&gt; - &lt;a href="http://twitter.com/PhilDarnowsky/statuses/3329531344"&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://twitter.com/sarahjchipps"&gt;@SaraJChipps&lt;/a&gt; &lt;a href="http://twitter.com/lostintangent"&gt;@LostInTangent&lt;/a&gt; right now I'm learning about box-shadow it's freakin rockstar. css 3 stuff. &lt;a href="http://twitter.com/#search?q=%23developer_day"&gt;#developer_day&lt;/a&gt; - &lt;a href="http://twitter.com/SaraJChipps/statuses/3330943660"&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://twitter.com/croaky"&gt;@Croaky&lt;/a&gt; microsoft mvc framework looking sharp these days. rails-like, cheaper tools than The Old Days, includes jQuery. &lt;a href="http://twitter.com/#search?q=%23developer_day"&gt;#developer_day&lt;/a&gt; - &lt;a href="http://twitter.com/Croaky/statuses/3331853851"&gt;link &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://twitter.com/marcamos"&gt;@marcamos&lt;/a&gt; Just heard about the Selenium plugin for Firefox, via &lt;a href="http://twitter.com/jeresig"&gt;@jeresig&lt;/a&gt;, here at &lt;a href="http://twitter.com/#search?q=%23developer_day"&gt;#developer_day&lt;/a&gt;. I'm in love. - &lt;a href="http://twitter.com/marcamos/statuses/3333569320"&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://twitter.com/csspixel"&gt;@csspixel&lt;/a&gt; &lt;a href="http://twitter.com/#search?q=%23developer_day"&gt;#developer_day&lt;/a&gt; was awesome. Met some great people. - &lt;a href="http://twitter.com/csspixel/statuses/3336455370"&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://twitter.com/rkalajian"&gt;@rkalajian&lt;/a&gt; I'm finally home. &lt;a href="http://twitter.com/#search?q=%23developer_day"&gt;#developer_day&lt;/a&gt; kicked ass. Met some great people, listened to great talks. Can't wait for next year. - &lt;a href="http://twitter.com/rkalajian/statuses/3336518881"&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Every Developer Day adds a little something to the previous ones, and Boston was no exception. We started videotaping talks, and after some review we&amp;rsquo;re hoping to post them publicly. This is also the first Day where we had shirts for the attendees - take a look!&lt;/p&gt;
&lt;p&gt;&lt;img alt="Developer Day Boston shirt" height="225" src="http://www.viget.com/uploads/image/dev-day-shirt.jpg" width="300" /&gt;&lt;br /&gt;Plans for the next Developer Day are underway, so keep watching the &lt;a href="http://developer-day.com"&gt;web site&lt;/a&gt; for details - and a new design, coming &lt;em&gt;very&lt;/em&gt; soon.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;                 

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=Ho40Fql1-AI:Adp7dEbzFbM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=Ho40Fql1-AI:Adp7dEbzFbM:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=Ho40Fql1-AI:Adp7dEbzFbM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=Ho40Fql1-AI:Adp7dEbzFbM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=Ho40Fql1-AI:Adp7dEbzFbM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=Ho40Fql1-AI:Adp7dEbzFbM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/Ho40Fql1-AI" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/regarding-recent-events/</feedburner:origLink></entry>

    <entry>
      <title>Materialize Views in the Rails Application Layer</title>
      <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/VigetExtend/~3/Nz3KaIBFc1E/" />
      <id>tag:viget.com,2009:extend/4.1677</id>
      <published>2009-08-11T18:04:00Z</published>
      <updated>2009-08-11T19:24:39Z</updated>
      <author>
                        <name>Tony Pitale, Web Developer</name>
                        <email>tony.pitale@viget.com</email>
            <uri>http://t.pitale.com</uri>      </author>

      <category term="General" scheme="http://www.viget.com/inspire/category/general/" label="General" />
      <content type="html">


                 &lt;p&gt;
  In my &lt;a href="http://www.viget.com/extend/rails-nested-has-many-through-with-sql-views/"&gt;previous post&lt;/a&gt; I
  talked about how we used a VIEW to act as an auto-updating join between our Group and Entry tables on
  &lt;a href="http://feedstitch.com"&gt;FeedStitch&lt;/a&gt;. After the changes were made there was a concern that as the
  view grew there would be a significant slowdown in selecting rows.
&lt;/p&gt;
&lt;h3&gt;Identifying our Problem&lt;/h3&gt;
&lt;p&gt;
  In general, the results of running EXPLAIN on the VIEW we have set up is that, in order to find a row, the VIEW
  must be sequentially scanned. This is telling in two ways. First, sequential scans are pretty much the single
  least efficient way to find a row (unless you're lucky and it's the first row). And second, without indexes,
  this is the only way to find a row. The primary drawback in using views is that they lack the ability to have
  indexes, as the data isn't really persisted as we see it.
&lt;/p&gt;
&lt;h3&gt;Moving Forward&lt;/h3&gt;
&lt;p&gt;
  The answer to our index problem may be solved with something called "View Materialization". Simply, the view,
  which contains a complex SELECT would be stored in a table which can be indexed as needed. Sounds simple, right?
&lt;/p&gt;
&lt;h3&gt;The Tricky Parts&lt;/h3&gt;
&lt;p&gt;
  Unfortunately, as with any caching mechanism, this one must be expired and updated as the data changes, to keep
  it fresh. To do this at the database level requires functions and triggers, often a complex task.
&lt;/p&gt;
&lt;h3&gt;The Simplest Thing That Works&lt;/h3&gt;
&lt;p&gt;
  Fortunately, in Rails, or with any ORM, we have a sensible place to put this sort of logic. And, with a little
  SQL written, we can refresh our materialized view with a semblance of ease. The two benefits to this are simplicity
  and ease of maintenance.
&lt;/p&gt;
&lt;p&gt;
  It takes a little bit of planning, but the first thing to do is to understand at what points the data in the VIEW
  will change. In our case, when we run a rolling update to fetch new feeds we can invalidate and re-materialize
  the entire thing. This is not very efficient in and of itself. However, it is simple (call destroy_all, only one
  SELECT) and does what it needs to do. Given that this only happens every few hours or so, this is a feasible option.
&lt;/p&gt;
&lt;p&gt;
  An even better solution would be to invalidate (delete) a portion of the materialized view and only SELECT a
  changed subset. This is better because, at least in our case, we never truly need to re-materialize the entire
  VIEW. In fact, we never really need to delete any records besides the subset we're working with.
&lt;/p&gt;
&lt;h3&gt;A Little Setup&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;
  ALTER VIEW group_entries RENAME TO group_entries_view; -- Or recreate the view in MySQL
  CREATE TABLE group_entries AS SELECT * FROM group_entries_view;
  ALTER TABLE group_entries ADD PRIMARY KEY (group_id, entry_id);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Updating the Table&lt;/h3&gt;
&lt;p&gt;
  We currently have a VIEW which selects a &lt;em&gt;group_id&lt;/em&gt; and an &lt;em&gt;entry_id&lt;/em&gt;. FeedStitch's updater fetches
  new entries for a group. Once done, the VIEW will hold an updated set of &lt;em&gt;entry_ids&lt;/em&gt; for the &lt;em&gt;group_id&lt;/em&gt;
  we are working with. This must then be materialized into a table. First we delete the rows give the group_id then
  we INSERT new rows from our VIEW:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
  GroupEntry.connection.execute &amp;lt;&amp;lt;-EOSQL
    BEGIN;
    DELETE FROM group_entries WHERE group_id = 1;
    INSERT INTO group_entries SELECT * FROM group_entries_view WHERE group_id = 1;
    COMMIT;
  EOSQL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  Though not always applicable to performance issues, materialized views can be useful way to cache frequently
  selected data. This simple method by which to materialize a view and update from within our application code
  gives us this functionality in a more accessible, flexible way.
&lt;/p&gt;                 

      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=Nz3KaIBFc1E:764BHb2a51U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=Nz3KaIBFc1E:764BHb2a51U:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=Nz3KaIBFc1E:764BHb2a51U:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=Nz3KaIBFc1E:764BHb2a51U:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VigetExtend?a=Nz3KaIBFc1E:764BHb2a51U:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VigetExtend?i=Nz3KaIBFc1E:764BHb2a51U:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VigetExtend/~4/Nz3KaIBFc1E" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.viget.com/extend/materialize-views-in-the-rails-application-layer/</feedburner:origLink></entry>


</feed>
