Google Hack-a-thon Seattle

Google's HQ in Seattle, WA

Google's HQ in Seattle, WA

My first trip to Seattle has been fun so far… although getting here wasn’t the easiest thing in the world…

I missed my first flight out of Dallas, pushing my arrival time from 2:51pm WA time to 10:30pm.  Ouch!

But, now that I’ve arrived I’ve fallen in love.  This city just exudes energy.  Sitting in a coffee shop near Google’s Seattle HQ, I’ve heard 4 pitches to potential investors over one cup of coffee.  I’m staying on the south side of the harbor and I decided to walk the 4 miles to Google this morning.  It was one of the most refreshing experiences I’ve had in a long time… Everyone here is biking or walking to work… the scene reminds me of a hipper, more urban Boulder with a little New England flair.

I’m planning on looking for a house boat on the way back to my hotel… :)

Nice Mention in MIT’s Technology Review

Brave New Fiction was mentioned in an article for MIT’s Technology Review… thanks Erica!

Software developer Brit Gardner, cofounder of Dallas-based Figaro Interactive, tested App Engine’s capabilities by beginning work on a demo application soon after the service came out. Though he didn’t know Python, the programming language App Engine requires, he says he was able to build his application in the space of a few days. Gardner says that he sees App Engine as significantly different from Amazon Web Services, in that it’s a framework for application devel, rather than merely a place to rent processing and storage ­capacity. He says that his site isn’t close to hitting Google’s page-view and storage limits, and he doubts that many other sites will be, either, since there are a lot of sites out there and only so many users.

We’ll be in Seattle on the 28th for the Google Hackathon working on new features for the site and generally hob-knobbing with other Google Geeks.  You should join us.

PhoneGap - Native iPhone Apps running your HTML/JS/CSS

Brit ran across something huge yesterday - PhoneGap

The idea behind PhoneGap is basically to allow developers to create a native iPhone application that pushes thru to the web application of their choice… some of the iPhone SDK is available via javascript.

This is a great way to get an iPhone app developed without having reinvent the wheel in Objective-C.  Who want’s to write 30 lines of code just to display a map anyway?

iPhone Design Template

Teehan+lax just posted an iPhone mockup design kit psd file that contains almost everything you’d ever need to put together a good lookup design to land that much need funding for your iPhone killer app.  Now if Adobe would just get around to implementing Objective-C we wouldn’t need the iPhone SDK at all…

Lack of Updates

Between taking care of my now neutered puppy and having to deal with all of the pipes bursting in my house, updates have been less frequent than usual.  So - here’s a quick update on what’s going on in my world:

  • Figaro Interactive is now a contributing member in the Apache Foundation - thanks to a project full of geocoding Brit threw together a CouchDB script for storing Google Geocoded JSON data and it is now included in the CouchDB wiki
  • Brit’s also posted a nice review of Mint.com - a financial service that he got me into that’s really helping stretch out the paychecks (and help save up for that vacation to Greece next year)
  • Figaro will be going to Seattle for the Google Hackathon and Penny Arcade Expo - first time for me to spend any time in Seattle - looking forward to the rain and the coffee.  Hit us up if you’re going to be there… we really want to meet some App Engine developers.  Also - App Engine docs for download - gotta love it.
  • Watched my hero, Brett Favre, play his first preseason game as a Jet… looked young and decisive.  Really hate to see him in green and white but it’s better than purple and yellow.
  • While couped up with the puppy I’ve been watching a lot of (bad) TV… interesting facts:
  1. The former lead singer of Presidents on the United States of America is now an adult film composer - didn’t even think they used composers in porn movies… shows how many I’ve watched (can’t find his alt name for a link… but he said so on VH1’s 100 Best Songs of the ’90’s so it must be true).
  2. Krist Novoselic (former Nirvana bassist) is now a politician - an interesting move for a former grunge rocker
  3. Bobbly Flay never wins throw downs… is it rigged or does he just suck?  Guess you can’t really go to someone else turf and tell them that they aren’t that great and still get them to sign a release.
  4. Way to go Michael Phelps - although it’s ridicuolous how meaningless world records feel this year… I think all of the atheletes should go back to swimming trucks and mustaches.

Scalable Tagging System in CakePHP

Tag clouds are a great way to allow users to navigate/search through your site but if you don’t design your application correctly from the ground up they can become a serious nightmare.

So - here’s my solution for creating a scalable tagging system in CakePHP (using MySQL in this instance but the theory applies to any other DB… yes… even you PostGRE’ers)

My example is a cookbook of recipes.

Most people that attempt a tagging system the first time around just go for a HABTM relationship - A recipe has and belongs to many tags.  So - you have you “recipes”, “tags”, and “recipes_tags” tables… all you have to do to find your tags is:

  1.  
  2. $this->Tag->find(‘all’);
  3.  

And to find what tags go with what recipes (assuming you setup your models correctly) is:

  1. id(int)
  2. tag(varchar)
  3. count(int)
  4. created(datetime)
  5. modified(datetime)

I pretty much always add fields for “created” and “modified” and set them to datetime - Cake fills them in automatically and it can be useful sometimes to have that history (you never know when a client wants to see something organized by the date they were added to the system - kinda sucks not to capture that info). Also - always, always, always create an “id” field that’s a unique, auto-incrementing, primary key for EVERY table… don’t call it something silly like uid or user or anything stupid like that. It’s just best practices. Period.

But, I digress;

So - your “recipes” table should look something like this:

  1. id(int)
  2. title(varchar)
  3. description(text)
  4. ingredients(text)
  5. method(text)
  6. tags(text)
  7. created(datetime)
  8. modified(datetime)

Notice that the “tags” field here is a text field - this is where we are going to store the tags, as written, by the user as one big block of text.

So - whenever a user creates a recipe we’re going to save all of the pertinent data to the database and then run a function called generate_tags:

  1.  
  2. function generate_tags($id=null)
  3. {
  4.    //get recipes by $id
  5.    $recipe = $this->Recipe->findById($id);
  6.          
  7.    //get all tags in the db
  8.    $tagsOld = $this->Tag->find(‘all’);
  9.          
  10.    $tagsOldArray = array();
  11.    $tagsOldArrayValues = array();
  12.          
  13.         //loop thru tags in db and create an array like so: $tag = array (’id’=>$id,’count’=>$count)
  14.    foreach($tagsOld as $key => $values)
  15.    {
  16.    $tagsOldArray[$values[‘Tag’][‘tag’]] = array(‘id’=>$values[‘Tag’][‘id’],‘count’=>$values[‘Tag’][‘count’]) ;
  17.    }
  18.             
  19.    $tagsArray = explode(‘,’,str_replace(‘, ‘,‘,’,$recipe[‘Recipe’][‘tags’]));
  20.    foreach($tagsArray as $tag)
  21.    {
  22.    $tags[] = $tag;
  23.    }
  24.             
  25.    $countArray = array_count_values($tags);
  26.          
  27.    $tagsOldArrayValues = array_keys($tagsOldArray);
  28.  
  29.    foreach($countArray as $tag => $count)
  30.    {                          
  31.         if(in_array($tag, $tagsOldArrayValues) == true)
  32.         {
  33.              $this->Tag->create();
  34.         $this->Tag->query(‘INSERT INTO `tags` (`tag`) VALUES (\’.$tag.\’) ON DUPLICATE KEY UPDATE `count` = `count`+1′);
  35.          } else {
  36.         $this->Tag->create();
  37.         $this->Tag->saveField(‘tag’,$tag);
  38.         $this->Tag->saveField(‘count’,$count);
  39.          }
  40.    }
  41. }
  42.  

What’s going on here? Well - first we find the recipe that you’re editing (or just inserted). Then we get all of the tags in the db. We foreach through the $tagsOldArray to format the array so that you have a nested array for each tag that contains the tag’s id and current count. We then explode the $tagsArray (the tags that are stored as plain text for the recipe at hand). We loop through the $tagsArray and then count the values of the keys. We then use array_keys to return the keys of $tagsOldArray which is used to determine whether or not a tag is already in the database. If it is in the array we execute the following query:

  1. $this->Tag->query(‘INSERT INTO `tags` (`tag`) VALUES (\’`.$tag.`\’) ON DUPLICATE KEY UPDATE `count` = `count`+1′);

This updates the count of the tag value by 1. If the tag is in the array we insert the tag and count.

There’s probably a much more elegant way to do all of this - maybe one of these days I’ll pair this code down (I threw it together tonight for a project - and looking at it now I can see some obvious redundancy… but alas there’s not enough time in the world to optimize code and actually launch a website…).

But the theory is sound…

Now it’s your turn to play along - we have to remember to do is decrement the `Tag`.`count` for all tags associated to a recipe if a user deletes that recipe… and we have to update the counts for any tags a user edits when they edit a recipe… Not as big a deal as it sounds…

My next post will focus on the view for a tag cloud using this setup.