<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>James Yu</title>
 <link href="http://www.jamesyu.org/atom.xml" rel="self"/>
 <link href="http://www.jamesyu.org/"/>
 <updated>2013-08-18T12:07:01-07:00</updated>
 <id>http://www.jamesyu.org/</id>
 <author>
   <name>James Yu</name>
 </author>

 
 <entry>
   <title>Staring at Zero</title>
   <link href="http://www.jamesyu.org/2013/06/13/staring-at-zero/"/>
   <updated>2013-06-13T13:32:36-07:00</updated>
   <id>http://www.jamesyu.org/2013/06/13/staring-at-zero</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/zero.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Seeing Parse &lt;a href=&quot;http://techcrunch.com/2013/06/12/facebook-parse-2/&quot;&gt;reach 100,000 apps&lt;/a&gt; is humbling.&lt;/p&gt;

&lt;p&gt;Everything starts from zero. I remember the early days when we would measure the number of apps that used us on a daily basis, and then write that number big and bold on a white board.&lt;/p&gt;

&lt;p&gt;This meant that for many days, we would look up from our desks and be faced with a big fat zero. Nothing motivates you more than zero.&lt;/p&gt;

&lt;p&gt;That summer, we coded as fast and as hard as we could.&lt;/p&gt;

&lt;p&gt;I recall when the number hit 2. Wow! 2 apps used us! People actually found our service useful. As the weeks and months went by, that number slowly went up. From single digits to double, then to triple and beyond.&lt;/p&gt;

&lt;p&gt;Eventually, we stopped writing the number on the board and instead sent out an internal daily email with various important stats. Waking up to that email is still the most motivating part of my day.&lt;/p&gt;

&lt;p&gt;So, my suggestion for when you're starting any project: write your daily number down. Seeing the number in ink and not pixels is much more visceral. You'll find yourself looking up once in a while, motivated to changing that number.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>The importance of startup momentum</title>
   <link href="http://www.jamesyu.org/2012/11/29/the-importance-of-startup-momentum/"/>
   <updated>2012-11-29T12:32:36-08:00</updated>
   <id>http://www.jamesyu.org/2012/11/29/the-importance-of-startup-momentum</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/momentum.png&quot; /&gt;&lt;/p&gt;


&lt;p&gt;A startup just had its big launch. The fundraising is over and the champagne has been poured. For some, this is the great beginning. But, for others, it's the zenith.&lt;/p&gt;

&lt;p&gt;The problem?&lt;/p&gt;

&lt;p&gt;Momentum is easy to lose, especially after a big adrenaline rush.&lt;/p&gt;

&lt;p&gt;Momentum is that invisible force that makes it easy to execute when things are moving, and difficult to get anything done in a languishing environment. The problem is that the natural resting state of companies (and really, anything) is to lose momentum. You have to actively work to maintain momentum.&lt;/p&gt;

&lt;p&gt;On Y Combinator's &lt;a href=&quot;http://www.ycombinator.com&quot;&gt;homepage&lt;/a&gt;, Paul Graham emphasizes that the program doesn't end on demo day. A network of support continues throughout the life of each company.&lt;/p&gt;

&lt;p&gt;But, there's an underlying message: just because the dinners have ended doesn't mean you should stop working hard! Building a company isn't a 3 month affair.&lt;/p&gt;

&lt;p&gt;Demo day is only a passing milestone--the important work is when you build on the foundation to create a sustainable business after the launch dust settles. Many startups, even the most hyped ones, sputter after launch. They fail to achieve the momentum necessary to carry the ball forward. And this is a shame, because many of these companies haven't even had time to test their business hypothesis.&lt;/p&gt;

&lt;p&gt;So, how do you maintain momentum?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Don't pin everything on one moment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's a red flag when companies place too much importance on a single event like a launch, partnership, or funding. These have significance, but, by themselves, they do not equal success.&lt;/p&gt;

&lt;p&gt;A string of these events, coupled with sustaining a culture of execution leads to success. After hitting a milestone, your eyes should already be fixed on the next one.&lt;/p&gt;

&lt;p&gt;After a successful demo day, my co-founders and I at &lt;a href=&quot;https://www.parse.com&quot;&gt;Parse&lt;/a&gt; were already looking ahead to the next big milestones in the months after. There was no time to waste.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Set both short and long term goals&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Setting and achieving goals is crucial. There are always goals for your company to achieve, and to get there, you need action. You need to set achievable short term goals alongside big goals.&lt;/p&gt;

&lt;p&gt;Hitting small goals gives you the momentum to hit other small goals. Soon, you'll find that you're well on your way to hitting the big goals.&lt;/p&gt;

&lt;p&gt;Some people find it difficult to set a timeline for goals, simply because life doesn't hand you a timeline on a silver platter. So, set artificial deadlines! You'll be surprised by how much the simple act of circling a date will motivate you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Don't get complacent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reid Hoffman compares building a startup to jumping off a cliff without a parachute while building a plane. If you get complacent, you'll hit the ground hard. Every startup is trying to prove a business model. Every day, you should be working hard to achieve that proof.&lt;/p&gt;

&lt;p&gt;Getting lazy after a big launch is like relaxing after assembling only one wing. You still need to assemble the other wing! Not to mention the engines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Build a culture of doers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When momentum is lost, there usually isn't one person at fault. Every single person contributes to how well a company executes. The key is to be a doer and hire people who are doers.&lt;/p&gt;

&lt;p&gt;These are people that will be able to conquer any task. Even if the task is outside their wheelhouse or seemingly insurmountable.&lt;/p&gt;

&lt;p&gt;In the end, building a startup is hard work. Momentum is the flow needed to launch and vet your product in the market.&lt;/p&gt;

&lt;p&gt;Don't lose your momentum!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We're also hiring at Parse. &lt;a href=&quot;https://www.parse.com/jobs&quot;&gt;Check out our jobs page&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Do everything. Then hire.</title>
   <link href="http://www.jamesyu.org/2012/11/23/do-everything-then-hire/"/>
   <updated>2012-11-23T12:32:36-08:00</updated>
   <id>http://www.jamesyu.org/2012/11/23/do-everything-then-hire</id>
   <content type="html">&lt;div style=&quot;float:right; padding: 0 0 20px 20px;&quot;&gt;
     &lt;img src=&quot;/images/do_everything.jpg&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;When starting a company, it's essential that you get involved in every aspect of the business. This is true whether you're a hacker, designer, or MBA. No exceptions.&lt;/p&gt;

&lt;p&gt;The obvious reason for this is that getting your hands dirty will force you to understand all parts of your business, and eventually, your industry. This is knowledge that will give you key business insights, paying dividends down the road.&lt;/p&gt;

&lt;p&gt;But, the equally important reason for doing everything is that it will enable you to hire the right people to expand your business.&lt;/p&gt;

&lt;p&gt;Lots of people will tell you to only focus on &quot;high leverage&quot; activities&amp;mdash;things that are strictly in your wheelhouse. Delegate everything else. While this is true as you scale, it's a grave mistake when starting out.&lt;/p&gt;

&lt;p&gt;How do you hire A+ people if you have no idea what their jobs entail? And after hiring them, how would you evaluate their work? The most sure-fire way is to understand the skill from a firsthand perspective.&lt;/p&gt;

&lt;p&gt;Now, I'm not saying that hackers should spend copious amounts of time attempting to make world class logos in Adobe Illustrator, or that designers should pick up a computer science book and attempt to code a scalable distributed database from scratch.&lt;/p&gt;

&lt;p&gt;What I'm advocating is that entrepreneurs should obtain a baseline working knowledge of each business segment.&lt;/p&gt;

&lt;p&gt;To do this quickly, there are three aspects to focus on:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Techniques&lt;/strong&gt;&lt;br/&gt;
What techniques do people employ to execute on a skill? For example, designers employ storyboards, wireframes, and mockups. Engineers understand data structures, do code reviews, and thoroughly test their code. Marketers understand lead generation, funnel analysis, and know how to segment an audience to reach them more effectively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools&lt;/strong&gt;&lt;br /&gt;
Tools are the way people execute a technique. Learn how these tools are used and how they fit into daily workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Results&lt;/strong&gt;&lt;br/&gt;
Most importantly, study great work. Google for it. Talk to people who are in the field. If you want to understand design, find some great works that are admired. For marketing, seek out successful campaigns from other companies. Always ask yourself: what makes this good?&lt;/p&gt;

&lt;p&gt;The best time to gain firsthand experience is when your company is small. Don't waste the opportunity to gain insights from doing something outside of your comfort zone. In the beginning, it's okay to do work that doesn't scale.&lt;/p&gt;

&lt;p&gt;So, the next time you need to balance the books, try doing it yourself. If you need a new layout for your blog, try fiddling with some HTML to make it work. Need to run a marketing event? Just try doing it. Don't be scared of making mistakes. Mistakes are how you learn.&lt;/p&gt;

&lt;p&gt;And only once you learn can you effectively scale.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Startups should think big and start small</title>
   <link href="http://www.jamesyu.org/2012/11/18/startups-should-think-big-and-start-small/"/>
   <updated>2012-11-18T12:32:36-08:00</updated>
   <id>http://www.jamesyu.org/2012/11/18/startups-should-think-big-and-start-small</id>
   <content type="html">&lt;p&gt;Every so often, I meet an entrepreneur who has big ideas for their startup but who never seems to get anything done. It's a pattern that I see in smart people who haven't had experience building real world products.&lt;/p&gt;

&lt;p&gt;&quot;It's gonna be huge! Revolutionary is only the beginning of how you would describe it.&quot;&lt;/p&gt;

&lt;p&gt;This is when they launch into their vision. And it is a grand vision, full of moving parts and exclamations. Their excitement is contagious.&lt;/p&gt;

&lt;p&gt;A few months later, I'll have another chat with them only to discover that they're overwhelmed and nothing concrete has happened. The problem is that they're thinking big but failing to start small.&lt;/p&gt;

&lt;p&gt;Repeat after me: big things start small!&lt;/p&gt;

&lt;p&gt;If you try to tackle too much in the beginning, you'll get overwhelmed. Not only that, but you'll lose precious time optimizing your product with too little data. This is, after all, the main reason you should always start with a &lt;a href=&quot;http://en.wikipedia.org/wiki/Minimum_viable_product&quot;&gt;minimum viable product&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You need to be able to shift decisively from brainstorm mode into execution mode. It's fine to pontificate about the big world changing vision. But, at some point, you need to clear the cruft and make a beeline to launch, then iterate quickly with real customers.&lt;/p&gt;

&lt;p&gt;People are always surprised that &lt;a href=&quot;https://www.parse.com&quot;&gt;Parse&lt;/a&gt; was started with a simple landing page to gather user feedback. And, when we launched the beta, it was an iOS and Android SDK that let you save structured data. There weren't user accounts, social integration, or other features that we have now.&lt;/p&gt;

&lt;p&gt;Our goal is to be the foundational platform for all mobile apps. However, we started off small, with a focus on the core of what was valuable. We iterated with our users to add everything that you see today. If we had built all the things in the beginning, we would not have had the benefit of the wisdom we gained each step of the way.&lt;/p&gt;

&lt;p&gt;In essence: think big and start small. Make a concrete plan with small milestones that roll up into a grander vision. Without that, you risk never shipping at all.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Converting CloudEdit from Backbone to Parse in 5 minutes</title>
   <link href="http://www.jamesyu.org/2012/05/20/converting-cloudedit-from-backbone-to-parse/"/>
   <updated>2012-05-20T13:32:36-07:00</updated>
   <id>http://www.jamesyu.org/2012/05/20/converting-cloudedit-from-backbone-to-parse</id>
   <content type="html">&lt;p&gt;In &lt;a href=&quot;http://www.jamesyu.org/2011/01/27/cloudedit-a-backbone-js-tutorial-by-example/&quot;&gt;Part 1&lt;/a&gt; and &lt;a href=&quot;http://www.jamesyu.org/2011/02/09/backbone.js-tutorial-with-rails-part-2/&quot;&gt;Part 2&lt;/a&gt; of the CloudEdit Backbone tutorials, I showed you how to create a simple Backbone app using Rails. Now, I'll show you how to get rid of the Rails server entirely and convert CloudEdit into a Parse app using the &lt;a href=&quot;https://www.parse.com/docs/js_guide&quot;&gt;Parse JavaScript SDK&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As usual, you can follow along with the &lt;a href=&quot;https://github.com/hungrylabs/CloudEditParse&quot;&gt;codebase on GitHub&lt;/a&gt; and &lt;a href=&quot;http://www.jamesyu.org/parse/CloudEdit/&quot;&gt;view the live app here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;Look Ma, No Servers!&lt;/h4&gt;


&lt;p&gt;My team and I at Parse have worked hard to create a platform that lets developers avoid having to think about or code anything on the server-side. You'll notice that the codebase is just a static HTML5 app. You can easily throw this behind Nginx or even host it directly on AWS. Before embarking on this tutorial, you can &lt;a href=&quot;https://www.parse.com&quot;&gt;sign up for a free account on Parse&lt;/a&gt; and have your app keys ready.&lt;/p&gt;

&lt;p&gt;You can think of the Parse JavaScript SDK as completing the other half of Backbone: &lt;b&gt;data persistence&lt;/b&gt;. Backbone doesn't provide anything out of the box to store your data. Parse solves this (usually messy) half of the equation transparently. What you'll see is that everything will Just Work&amp;trade; without any server code.&lt;/p&gt;

&lt;h4&gt;From Backbone to Parse&lt;/h4&gt;


&lt;p&gt;The Parse JavaScript SDK is based on the Backbone codebase, and the core &lt;code&gt;Parse.Object&lt;/code&gt; and &lt;code&gt;Parse.Collection&lt;/code&gt; classes are compatible with Backbone Models and Collections. This tutorial is a step-by-step guide on how to convert CloudEdit to use Parse. There are also &lt;a href=&quot;https://www.parse.com/docs/js_guide#convert&quot;&gt;general conversion instructions on the Parse documentation page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h4&gt;Directory Structure&lt;/h4&gt;


&lt;p&gt;The structure for the HTML5 is extremely simple since the whole site is static. We've reduced down to two main directories, with a similar hierarchy in the &lt;code&gt;js&lt;/code&gt; directory:&lt;/p&gt;

&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;index.html
stylesheets/
js/
    application.js
    controllers/
        documents.js
    models/
        document.js
    views/
        show.js
        index.js
        notice.js&lt;/code&gt;
&lt;/pre&gt;


&lt;br /&gt;




&lt;h4&gt;Converting the Document Model&lt;/h4&gt;


&lt;p&gt;CloudEdit lets users create simple documents that have a title and body, and that are immediately publicly editable. To convert the document Backbone model to Parse, we simply replace the classes appropriately and specify a Parse &lt;code&gt;className&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// The old Backbone Model&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Document&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Backbone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;documents&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;charAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// The new Parse Object&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Document&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Document&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;br /&gt;


&lt;p&gt;And that's it. Notice that we can get rid of the notion of urls entirely and reduce the model to be backed by a named class on Parse.&lt;/p&gt;

&lt;h4&gt;Converting the Collection&lt;/h4&gt;


&lt;p&gt;Converting the collection is just as easy:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Old Backbone Collection&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Collections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Backbone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/documents&amp;#39;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// New Parse Collection&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Collections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Document&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;br /&gt;


&lt;p&gt;Again, we simply get rid of the &lt;code&gt;url&lt;/code&gt; attribute and point the collection over to the new Parse Object class. Everything just works the same.&lt;/p&gt;

&lt;p&gt;But, it turns out we can get rid of the collection class altogether. Since it's such a simple collection, we can automatically create an instance of this collection from a &lt;code&gt;Parse.Query&lt;/code&gt;. Here's how we do it:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;limit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;descending&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;createdAt&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;br /&gt;


&lt;p&gt;We create a query to get all documents and limit it to 50 documents. We then generate the proper collection using the &lt;code&gt;collection&lt;/code&gt; method.&lt;/p&gt;

&lt;h4&gt;Views and Controllers&lt;/h4&gt;


&lt;p&gt;We don't have to do anything major to convert the Backbone views and controllers, since they don't involve the data models.&lt;/p&gt;

&lt;p&gt;As for the templates, I converted from the original JST templates over to underscore templates directly in index.html. Also, I combined various Rails templates to make index.html. You could also simply copy and paste the rendered output directly to create the index page.&lt;/p&gt;

&lt;h4&gt;Initializing Parse&lt;/h4&gt;


&lt;p&gt;There's one last thing we need to do, and that is to initialize the Parse SDK with your application keys:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;YOUR_APP_ID&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;YOUR_JAVASCRIPT_KEY&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;br /&gt;


&lt;p&gt;We also create a user automatically for each client by generating a username and password. This is crucial for security. You can read more about &lt;a href=&quot;https://parse.com/docs/js_guide#users-security&quot;&gt;security and ACLs in the guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And, that's it. You can check out the &lt;a href=&quot;http://www.jamesyu.org/parse/CloudEdit/&quot;&gt;fully functioning app here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;Backbone Apps Without Servers&lt;/h4&gt;


&lt;p&gt;With Parse, we're hoping to usher in an age of apps without servers. Or, at least, without servers that you as the developer have to worry about. What's great is that by following this guide, you'll be able to convert your existing Backbone apps to Parse with ease.&lt;/p&gt;

&lt;p&gt;And, this is just the beginning. Read the &lt;a href=&quot;https://www.parse.com/docs/js_guide&quot;&gt;full documentation&lt;/a&gt; to learn about user authentication, security, queries, geopoints, and much more.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Double Down</title>
   <link href="http://www.jamesyu.org/2012/01/13/double-down/"/>
   <updated>2012-01-13T12:32:36-08:00</updated>
   <id>http://www.jamesyu.org/2012/01/13/double-down</id>
   <content type="html">&lt;p&gt;People always quote the platitude &quot;the only thing you have control of is how hard you work.&quot; But, ask most people what they thought were the big factors in the success of people they know, and you'll get a combination of timing and hard work.&lt;/p&gt;

&lt;p&gt;I argue that along with hard work, you need to know when to double down. You need to be able to recognize that moment in time when something just clicks. The lightbulb goes off. The stars align.&lt;/p&gt;

&lt;p&gt;The problem is, many people who get confronted with this moment are at once excited and scared. There is a fear of not being able to accept the upcoming challenge and succeed. The fear of letting yourself down in the face of good opportunity. You then start to make excuses like &quot;oh, I'll just put it off for now, I'm sure I'll get another opportunity like this when I'm more prepared.&quot;&lt;/p&gt;

&lt;p&gt;News flash: opportunities don't just come knocking. When it appears, you need to seize it. When I feel myself having doubts, I always ask &quot;what is the worse that could happen?&quot; The answer 99% of the time is: not much.&lt;/p&gt;

&lt;p&gt;The key to success (both in business and in life) is the ability to know when to double down. People often talk about trusting your gut to make judgements when situations are bad. However, too little is said about trusting your gut to sense when good opportunities arise.&lt;/p&gt;

&lt;p&gt;When they do arise, you need to execute, and execute with as much effort as you can.&lt;/p&gt;

&lt;p&gt;This is how great things are made.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Hone the Core of Your Product</title>
   <link href="http://www.jamesyu.org/2012/01/06/hone-the-core-of-your-product/"/>
   <updated>2012-01-06T12:32:36-08:00</updated>
   <id>http://www.jamesyu.org/2012/01/06/hone-the-core-of-your-product</id>
   <content type="html">&lt;p&gt;Every product has a core&amp;mdash;a feature that is the heart and soul. Everything else is secondary and is supported by the core. The product would not exist without the core.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.parse.com&quot;&gt;Parse&lt;/a&gt; =&gt; remote object storage&lt;br/&gt;
DropBox =&gt; files&lt;br/&gt;
Facebook =&gt; friends&lt;br /&gt;
Netflix =&gt; movies&lt;br /&gt;
YouTube =&gt; videos&lt;br /&gt;
WordPress =&gt; blogs&lt;/p&gt;

&lt;p&gt;Successful products and startups hone and keep a tight focus on the core of their product. This may sound obvious, but it's something that a lot of failed startups forget as the product matures and the core gets occluded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Make sure the core is valuable&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a product grows and adds more features, the core is at risk of becoming sidelined. Keep the core the core of your product. This is a fine balancing act, because rich features on top of the core can make the product better.&lt;/p&gt;

&lt;p&gt;From a UX perspective, The key is to avoid complicating core user flows. For example, uploading a YouTube video shouldn't require that you understand video annotations.&lt;/p&gt;

&lt;p&gt;Most likely, 100% of your users will come to use the core. Don't make them think about any other features until they've mastered the core.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Maximize the value that the core provides&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most users will use your product just for the core feature. If it doesn't provide that much value, then it's time to rethink your product. A user shouldn't have to understand every feature of your product for it to be valuable.&lt;/p&gt;

&lt;p&gt;A great product is one where users are happy just using the core.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Onboard users slowly, especially for complicated products&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I do a lot of thinking about this because &lt;a href=&quot;https://www.parse.com&quot;&gt;Parse&lt;/a&gt; is a developer platform, which is inherently more complicated than your average consumer product.&lt;/p&gt;

&lt;p&gt;The way to onboard users for platforms is to have a quickstart flow that teaches users how to use the core. Nothing else.&lt;/p&gt;

&lt;p&gt;For Parse, which provides an SDK to add backend features to your mobile app, the core is saving a single object from a mobile app. The quickstart flow methodically guides the user to the point where they can save an object. If you're a mobile dev, &lt;a href=&quot;https://www.parse.com/users/new&quot;&gt;sign up&lt;/a&gt; and check it out.&lt;/p&gt;

&lt;p&gt;Even though Parse offers much more, it makes no sense to clutter the flow for new users. When you're new, you need to learn the core, then slowly digest the rest of the features.&lt;/p&gt;

&lt;p&gt;This is important for consumer products, and crucial for developer products. You can apply this to any kind of product.&lt;/p&gt;

&lt;p&gt;Are you building a new document editor? Your onboarding should get users to write a few sentences and save a document. Nothing else. I took this to the extreme with &lt;a href=&quot;http://www.quietwrite.com&quot;&gt;QuietWrite&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Are you building a photo sharing site? Your onboarding should have users upload a single photo, then show it to them with a success message. Nothing else. Instagram did a great job at this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Give users feedback as they complete tasks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A successful product is one that constantly teaches users how to use it. At the end of the Parse quickstart guide, we have a button that lets users test whether they've successfully saved an object. We give direct feedback, and users can immediately course correct if they've made a wrong turn.&lt;/p&gt;

&lt;p&gt;This gives users the confidence that they understand the core feature of your product. From there, they'll be able to explore everything else, and hopefully become a power user.&lt;/p&gt;

&lt;p&gt;At the end of the day, a product that is trying to be too many things at once is going to just confuse users. People want products that solve specific problems well. And the best way to do this is to focus on core features and teach users how to use them. Everything else is secondary.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Things I Learned Building a Company in 2011</title>
   <link href="http://www.jamesyu.org/2011/12/31/learning-from-2011/"/>
   <updated>2011-12-31T12:32:36-08:00</updated>
   <id>http://www.jamesyu.org/2011/12/31/learning-from-2011</id>
   <content type="html">&lt;p&gt;It would be an understatement to say that 2011 was a packed year for me.
In one year, I&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Left my job&lt;/li&gt;
&lt;li&gt;Started &lt;a href=&quot;https://www.parse.com&quot;&gt;a company&lt;/a&gt; (Psst.. &lt;a href=&quot;https://www.parse.com/jobs&quot;&gt;we're hiring&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Made it into &lt;a href=&quot;http://www.ycombinator.com&quot;&gt;Y Combinator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Raised funding&lt;/li&gt;
&lt;li&gt;Got married to the &lt;a href=&quot;http://www.twitter.com/joeywan&quot;&gt;most beautiful girl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Turned 30&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;It was a year of action. I barely had time to think. It was always go-time. And, I feel particularly lucky to be alive. This was probably my best year ever.&lt;/p&gt;

&lt;p&gt;Throughout, I tried to write down the things that I've learned. So, here they are, in no particular order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Everyone is flying by the seat of their pants&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No one knows exactly what's going to happen. No plan ever goes perfectly. If people say they do, they're lying. Everyone is winging it to some degree. This is especially true at the very beginning of a company. This is when ideas are raw and untested.&lt;/p&gt;

&lt;p&gt;The key is to continually learn from the pant flying, and don't be afraid to course correct. And most of all, you need to be okay with uncertainty.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pay attention to market signals&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The best products are the ones that are literally pulled out of a company. These products solve hair-on-fire problems that affect a big market. Building a startup is finding this type of product: one that will fly off the shelves.&lt;/p&gt;

&lt;p&gt;If you're currently building a product, you're looking for feedback from customers like &quot;Oh my god, where were you 2 years ago? This solves a huge problem for me. I want to pay tou now.&quot; If instead, you're only getting &quot;That's cool&quot;, then it's time to worry. You need to get to &quot;Oh my god&quot; as soon as possible.&lt;/p&gt;

&lt;p&gt;Keep talking to customers and iterating.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Product marketing is minimizing the time to WOW&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a potential customer is evaluating your product, you literally have seconds before they bounce. You need to minimize the time from when they first see your product, to when they exclaim in their head: &quot;I understand this, and WOW do I need this.&quot;&lt;/p&gt;

&lt;p&gt;Also, instead of listing what features your product has, you need to communicate what problems it actually solves for your customers. Rob Fitzpatrick has a great article on how &lt;a href=&quot;http://thestartuptoolkit.com/blog/2011/12/abstraction-makes-us-stupid-at-business/&quot;&gt;abstractions make us stupid&lt;/a&gt;. Remove the abstractions, and your product will communicate more clearly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content is king&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Rand Fishkin says this &lt;a href=&quot;http://hackersandfounders.tv/RDmt/rand-fishkin-inbound-marketing-for-startups/&quot;&gt;much better than I do&lt;/a&gt;. A strong marketing strategy is one that is centered around organic and shareable content, rather than interruption style marketing like ads.&lt;/p&gt;

&lt;p&gt;People on the web don't like interruptions. But, you'll be praised if you're adding something to the ecosystem of knowledge. Just make that knowledge relevant to your product.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build custom dashboards&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&quot;You make what you measure.&quot;&lt;/p&gt;

&lt;p&gt;No analytics solution is going to be as fully integrated as a custom solution you roll. If you have the resources, make your own dashboards that show your most important metrics. This is different for all companies. The act of creating these dashboards can itself be an enlightening exercise.&lt;/p&gt;

&lt;p&gt;The main dashboard should only the top 3 metrics. Nothing more. Put this dashboard on a big screen and refer to it often. As you go through the day, think constantly about these metrics as you make decisions.&lt;/p&gt;

&lt;p&gt;Of course, you can use Google Analytics, MixPanel, and other solutions. But use these in conjunction with your own dashboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do if for passion and fun&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is an oft repeated meme, but it's worth repeating. If you're building a company just because you want to get rich, it will show in your product.&lt;/p&gt;

&lt;p&gt;Do it because you believe in what you're building. Do it because you love building things that other people use. Do it because you think the world will be a better place.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>On Being an Early Startup Employee, and a Farewell</title>
   <link href="http://www.jamesyu.org/2011/03/10/on-being-an-early-employee-at-a-startup-and-a-farewell/"/>
   <updated>2011-03-10T12:32:36-08:00</updated>
   <id>http://www.jamesyu.org/2011/03/10/on-being-an-early-employee-at-a-startup-and-a-farewell</id>
   <content type="html">&lt;p&gt;I was one of the first hires at &lt;a href=&quot;http://www.scribd.com/&quot;&gt;Scribd&lt;/a&gt;, the social publishing site that garners over 100 million visits per month. My journey as a fruitful early startup employee has lasted over 3 and half years, and this Friday, that journey comes to an end. I will soon be pursuing my dreams of starting my own company.&lt;/p&gt;

&lt;p&gt;It's hard to put in words the amount of experience an early employee gets at a fast moving technology startup. My time at Scribd wasn't just another job &amp;mdash; it was a kaleidoscopic learning experience spanning all aspects of business and technology. For those of you weighing the benefits of an MBA program: join a startup instead. You'll not only learn about real world business problems, you'll also execute them in the real world with smart and passionate people.&lt;/p&gt;

&lt;p&gt;In essence, there isn't much difference between what you do and what the founders do. Everyone is furiously iterating on the product, making the user base happy, and growing revenue.&lt;/p&gt;

&lt;p&gt;If you're the kind of person that likes to make an impact and learn faster than you've ever learned before, being an early startup employee may be an ideal job. The following are some of the highlights of my experience.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/joeywan/3123936811/in/photostream/&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3255/3123936811_d8b4870844_z.jpg&quot; /&gt;&lt;/a&gt;&lt;br/&gt;
&lt;small&gt;Jared, Trip, Tikhon, and I at the 2008 Scribd Holiday Party (photo by &lt;a href=&quot;http://www.flickr.com/photos/joeywan&quot;&gt;joeywan&lt;/a&gt;)&lt;/small&gt;&lt;/p&gt;

&lt;h4&gt;Millions of Hats&lt;/h4&gt;


&lt;p&gt;I still recall the night before my first day at Scribd. We had just gotten our first office space in downtown San Francisco, and Trip Adler, one of the founders, called me up to see if I could help put together some office chairs. Of course, I happily obliged. There we were on a Sunday night, the CEO and I assembling chairs for the new office. We didn't get very far, and quickly realized that we had better things to do with our time and hired someone from Craigslist the next day. The point though, was that were ready to roll up our sleeves and get anything done that was necessary.&lt;/p&gt;

&lt;p&gt;Eventually, I did much more than assemble a few chairs. In my time at Scribd, I have managed to work on (in no particular order): backend and frontend Ruby on Rails development, UX design, graphic design, A/B testing, user testing, viral marketing, SEO, ad optimization, database query wrangling, Facebook app development, localization, large scale redesigns, managing a team and probably a dozen more things I don't remember.&lt;/p&gt;

&lt;p&gt;And typically, many of the projects I took on had some component where I had little or no experience with. I found myself going from &quot;I don't know how to do X&quot; to &quot;Well okay, that isn't too hard&quot; to &quot;I have something working, let's try it in production.&quot; This kind of fast and fearless execution with little bureaucracy is exhilarating. It's an experience that you will rarely find at larger companies.&lt;/p&gt;

&lt;h4&gt;Fast Iteration and Big Changes&lt;/h4&gt;


&lt;p&gt;One of the big advantages of a startup is its ability to change strategies overnight, and execute on those changes almost immediately. Startups aim to shorten the time between the inception of an idea to deploying it in production. In doing so, they are able to iterate quickly and out-maneuver competitors.&lt;/p&gt;

&lt;p&gt;This is exemplified by the handful of major site redesigns that I've been involved with at Scribd. It's not trivial to redesign a site as large as Scribd, but with our fantastically focused team, we were able to pull off radical changes while keeping the site stable and also measuring the impact on business metrics. Many times, we literally transformed and finessed every page on the site.&lt;/p&gt;

&lt;p&gt;Here's a fun timelapse of me slinging some frontend work that was shot over 4 hours during our first major redesign (we were neck deep in execution mode at the time, and that day was probably one of the most productive days in my life; shortly thereafter, we launched a totally rebranded site from the ground up):&lt;/p&gt;

&lt;iframe title=&quot;YouTube video player&quot; width=&quot;680&quot; height=&quot;390&quot; src=&quot;http://www.youtube.com/embed/q_4SBfKRsng&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;


&lt;br/&gt;&lt;br/&gt;


&lt;p&gt;And here's a quick timelapse of the code development at Scribd, using &lt;a href=&quot;http://code.google.com/p/codeswarm/&quot;&gt;code swarm&lt;/a&gt; to visualize the git commits over time:&lt;/p&gt;

&lt;iframe src=&quot;http://player.vimeo.com/video/9404957?portrait=0&quot; width=&quot;680&quot; height=&quot;413&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;


&lt;br/&gt;&lt;br/&gt;


&lt;p&gt;More recently, we converted all our documents from Flash to a new HTML5 format that we built from scratch. This was a radical change to the most important pages on our site that was enacted over a short period of time. The end result was a dramatic improvement to the user experience that blew our users away.&lt;/p&gt;

&lt;h4&gt;Big Impact&lt;/h4&gt;


&lt;p&gt;The right startup environment allows you to be super productive and make a big impact. On a site like Scribd, developers push features that affect literally millions of people a day. In other words, the user-to-developer ratio is extremely high.&lt;/p&gt;

&lt;p&gt;However, maintaining this high ratio is meaningless if developers aren't empowered to push changes to the product. At Scribd, we deploy code daily. Sometimes, small features are launched; while other times, huge site-wide changes are pushed. There isn't any hand holding from superiors when these deploys go out. Is the feature ready, tested, and does what it's supposed to do? Does it also make the site better? Then let's deploy! In fact, the title of our Campfire room at Scribd is &quot;Working hard to make Scribd better!&quot;&lt;/p&gt;

&lt;p&gt;This brings us to the most important quality that enables impact: trust. Without trust, employees aren't empowered. And without empowerment, there can be no impact. Needless to say, Scribd puts a lot of trust on its employees.&lt;/p&gt;

&lt;p&gt;This is exactly the reason why startup hiring is difficult: the amount of trust required in the candidate is magnitudes above that of large companies. In fact, the difficulty factor is inversely proportional to the number of employees in the company. When you're only one of a handful of employees, you have a big influence on the company, for better or for worse.&lt;/p&gt;

&lt;h4&gt;The People&lt;/h4&gt;


&lt;p&gt;The people make the startup. At a well-oiled startup, they are passionate, hard working, and sincere about improving the business. There really is no other way for such a tight knit group to be successful.&lt;/p&gt;

&lt;p&gt;The biggest part of Scribd I'll miss is the people. The relationships that I've forged while working in the trenches building great products are unparalleled. Over the past few years, I have collaborated with a wide range of smart and passionate people to create the site that Scribd is today, and I'm proud of it.&lt;/p&gt;

&lt;p&gt;Coincidentally, &lt;strong&gt;Scribd is hiring&lt;/strong&gt;! So if you're looking for a fast paced environment working on one of the largest sites on the planet with a boatload of awesome, smart, and passionate people, check out their &lt;a href=&quot;http://www.scribd.com/jobs&quot;&gt;job page for open positions&lt;/a&gt;. There will be big things happening at Scribd in the near future, so it's the perfect time to join in on the action.&lt;/p&gt;

&lt;p&gt;Feel free to contact me if you have more questions about my experience at Scribd.&lt;/p&gt;

&lt;h4&gt;Farewell and The Future&lt;/h4&gt;


&lt;p&gt;And with that, I am saying farewell to my Scribd friends and the company that taught me an immense amount about running a web startup. I will be starting a new venture, and will have more to share about that soon.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Progressive Signup</title>
   <link href="http://www.jamesyu.org/2011/02/16/progressive-signup/"/>
   <updated>2011-02-16T22:21:13-08:00</updated>
   <id>http://www.jamesyu.org/2011/02/16/progressive-signup</id>
   <content type="html">&lt;p&gt;&lt;em&gt;This article originally appeared on the &lt;a href=&quot;http://www.quietwrite.com/users/quietwrite&quot;&gt;QuietWrite Blog&lt;/a&gt;. I'm reposting it here because it may be of interest to my readers.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At &lt;a href=&quot;http://www.quietwrite.com/&quot;&gt;QuietWrite&lt;/a&gt;, we have a philosophy about the user signup process that we call &lt;strong&gt;Progressive Signup&lt;/strong&gt;. Basically, we eschew the typical signup wall for a more gradual process over a longer period of time. As the user plays with our product, we gently prod them at certain checkpoints to give us more info. This results in a better and more natural user experience.&lt;/p&gt;

&lt;p&gt;Think of Progressive Signup as being similar to visiting an electronics store to buy a TV. What you expect is to be able to walk into the store, peruse their selection, play around with some of their floor models, and then begin the process of deciding on the best TV for your needs. After making a decision, you walk up to the cash register and hand over your credit card and credentials to make the purchase.&lt;/p&gt;

&lt;p&gt;Throughout all this, you didn't really have to pause to think about &quot;signing up.&quot; You did what was natural: progress at your own pace with the goal of leaving with a TV.&lt;/p&gt;

&lt;p&gt;Now imagine that your visit to the store were more like the traditional signup model, where you're presented a long signup form before you can do any member activities on the site. This would mean that before you could even enter the store and play with their products, you would have to hand over your credit card and fill out a long survey form with your personal information. I don't know about you, but I would probably turn around and head for another store that doesn't have such costly entrance procedures.&lt;/p&gt;

&lt;p&gt;As we design websites, we need to keep this simple brick and mortar example in mind: don't force the user to jump through hoops just to play with your product! You have enough to worry about with just getting the word out about your new website. When a user lands on your homepage for the first time, the last thing you want is to create barriers between them and your core product. Remember, &lt;a href=&quot;http://mixergy.com/paul-graham-design/&quot;&gt;users are poised over the back button&lt;/a&gt;, just waiting to leave your site if it isn't compelling.&lt;/p&gt;

&lt;p&gt;But how do you decide on the checkpoints for Progressive Signup? Bokardo has a great article about keeping &lt;a href=&quot;http://bokardo.com/archives/creating-engaged-and-passionate-users-part-1/&quot;&gt;user lifecycles&lt;/a&gt; in mind. As the user transitions from being Unaware to a Passionate user, we should gather information about the user in proportion to their passion. If the passion-to-information ratio is too low, we risk losing the user altogether.&lt;/p&gt;

&lt;p&gt;At QuietWrite, we've sectioned off the various stages of user signup like so:&lt;/p&gt;

&lt;h4&gt;1. New User&lt;/h4&gt;


&lt;p&gt;When a new user lands on the homepage, we show a big button with some quick bullet points explaining the benefits of QuietWrite. When the user clicks the big button, we immediately drop them into our editor, which is the core value of our site. No signup information is necessary to edit and save writings on QuietWrite. We cookie the user so they can still access their writings at a later time, even if they give no further information.&lt;/p&gt;

&lt;h4&gt;2. Invested User&lt;/h4&gt;


&lt;p&gt;As soon as a new user starts writing, we show an email and password field in the header, with a quick note saying they can signup in order to ensure that they can access their writings later. After the user decides that our product is worth it, they give us their email and a password. Note that there is always a good reason for a user to give information, and we emphasize it here by saying an email and password combination is a much more reliable way to retrieve your writings than with a cookie, which can get lost.&lt;/p&gt;

&lt;h4&gt;3. Publishing User&lt;/h4&gt;


&lt;p&gt;Currently, the final stage of our user lifecycle ends with the user publishing their writing. Right now, publishing isn't the core of QuietWrite, so a user with many writings that starts publishing is using our product to the full extent. When a user publishes their first writing, we prompt them to give a display name, which will better identify them to visitors. We could have done that at step 2, but it wasn't necessary.&lt;/p&gt;

&lt;p&gt;By partitioning the signup process like so, getting information from the user feels less like a chore, and more natural. We've seen a lot of engagement from users that would never have played with our editor if we had a big signup wall in the beginning.&lt;/p&gt;

&lt;p&gt;The biggest thing to keep in mind when designing a Progressive Signup process on your site is to ask: what is the minimal amount of information we need from the user in order for them to progress to the next step. Many times, you'll be surprised how little you need.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update: Luke Wroblewski also has some &lt;a href=&quot;http://www.lukew.com/ff/entry.asp?1128&quot;&gt;great thoughts on this here, with respect to Twitter's redesigned signup flow&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Backbone.js Tutorial with Rails Part 2</title>
   <link href="http://www.jamesyu.org/2011/02/09/backbone.js-tutorial-with-rails-part-2/"/>
   <updated>2011-02-09T00:04:13-08:00</updated>
   <id>http://www.jamesyu.org/2011/02/09/backbone.js-tutorial-with-rails-part-2</id>
   <content type="html">&lt;div class=&quot;promo&quot;&gt;
  If you like Backbone, &lt;strong&gt;you'll love Parse&lt;/strong&gt;. Read &lt;a href=&quot;http://www.jamesyu.org/2012/05/20/converting-cloudedit-from-backbone-to-parse/&quot;&gt;Part 3 of this tutorial where I show you how to convert the CloudEdit app to use Parse without any server-side Rails code at all&lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;In &lt;a href=&quot;http://www.jamesyu.org/2011/01/27/cloudedit-a-backbone-js-tutorial-by-example/&quot;&gt;Part 1 of the CloudEdit Backbone.js Tutorial&lt;/a&gt;, we developed a basic Rails application using &lt;a href=&quot;http://documentcloud.github.com/backbone/&quot;&gt;Backbone.js&lt;/a&gt; that lets users create and edit documents in the cloud. Now, in Part 2, we'll do some refactoring to clean up parts of the app and make things more readable and maintainable.&lt;/p&gt;

&lt;p&gt;Specifically, we'll be doing the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Backbone Collections.&lt;/li&gt;
&lt;li&gt;Use Underscore templating.&lt;/li&gt;
&lt;li&gt;Use event binding to refresh views.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This update won't change anything in the UI: it's simply some housekeeping to tidy up the code.&lt;/p&gt;

&lt;p&gt;As always, you can follow along with the &lt;a href=&quot;https://github.com/jamesyu/CloudEdit&quot;&gt;CloudEdit GitHub repo&lt;/a&gt;, and also play with the &lt;a href=&quot;http://cloudedit.jamesyu.org&quot;&gt;live app here&lt;/a&gt;. They both have been updated to reflect this part of the tutorial.&lt;/p&gt;

&lt;h4&gt;Backbone Collections&lt;/h4&gt;


&lt;p&gt;As you may remember in Part 1, we loaded the list of documents for the &lt;code&gt;documents#index&lt;/code&gt; action via a call to &lt;code&gt;$.getJSON&lt;/code&gt;, and then instantiated all the documents in an array. But, we can provide a better abstraction by defining a Backbone Collection as follows:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Collections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Backbone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/documents&amp;#39;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;em&gt;public/javascripts/collections/documents.js&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's pretty simple: we tell the collection that it should hold the &lt;code&gt;Document&lt;/code&gt; model (via the model attribute), and that the resource to fetch the documents from the server is located at &lt;code&gt;/documents&lt;/code&gt;. Also notice that I'm organizing collections in the same way as the MVC components: the definition is located under the &lt;code&gt;App.Collections&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Now, we can update the &lt;code&gt;documents#index&lt;/code&gt; action in the Backbone controller as follows:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Controllers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Backbone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// ... snip ...&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Collections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Views&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;documents&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Error loading documents.&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// ... snip ...&lt;/span&gt;
    
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;em&gt;public/javascripts/controllers/documents.js&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All we did was instantiate a new instance of the &lt;code&gt;Documents&lt;/code&gt; collection, and then call fetch with a success callback that passes the collection to the &lt;code&gt;App.Views.Index&lt;/code&gt; view. We didn't even need to change any Rails code: the original RESTful &lt;code&gt;/documents&lt;/code&gt; action is identical.&lt;/p&gt;

&lt;h4&gt;Underscore Templates&lt;/h4&gt;


&lt;p&gt;Previously, we built up our views using string concatenation. I did this so that we could focus on Backbone.js itself, and not any particular templating language.&lt;/p&gt;

&lt;p&gt;However, for anything more than trivial views, string concatenation is a maintenance nightmare. Luckily, &lt;a href=&quot;Jammit&quot;&gt;http://documentcloud.github.com/jammit/&lt;/a&gt; provides an easy integration with &lt;a href=&quot;Underscore&quot;&gt;http://documentcloud.github.com/underscore/&lt;/a&gt; templates, which are powerful and very similar to ERb.&lt;/p&gt;

&lt;h5&gt;.jst Files&lt;/h5&gt;


&lt;p&gt;Jammit expects your javascript templates (or JST) to live alongside your regular ERb templates as &lt;code&gt;.jst&lt;/code&gt; files. It will package up the templates into a global &lt;code&gt;JST&lt;/code&gt; object that you can use to render your templates into strings. To make Jammit aware of these files, I simply added an entry for &lt;code&gt;app/views/**/*.jst&lt;/code&gt; in my &lt;code&gt;app&lt;/code&gt; package in &lt;code&gt;assets.yml&lt;/code&gt;.&lt;/p&gt;

&lt;h5&gt;Convert the Views&lt;/h5&gt;


&lt;p&gt;Next, we need to convert our views to Underscore templates. This is the fun part, since we get to see the ugly jumble of strings turn into beautiful templates.&lt;/p&gt;

&lt;p&gt;Let's first convert the strings in the &lt;code&gt;App.Views.Edit&lt;/code&gt; view into the &lt;code&gt;document.jst&lt;/code&gt; template. This would turn the following code:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;lt;form&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;label for=&amp;#39;title&amp;#39;&amp;gt;Title&amp;lt;/label&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;input name=&amp;#39;title&amp;#39; type=&amp;#39;text&amp;#39; /&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;label for=&amp;#39;body&amp;#39;&amp;gt;Body&amp;lt;/label&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;textarea name=&amp;#39;body&amp;#39;&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;escape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/textarea&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;submitText&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Create&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Save&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;button&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;submitText&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/button&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/form&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;br /&gt;


&lt;p&gt;into:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;form&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Title&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;title&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;text&amp;#39;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Body&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;&lt;/span&gt;%= model.get(&amp;#39;body&amp;#39;) %&amp;gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
    
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;button&amp;gt;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;&lt;/span&gt;%= model.isNew() ? &amp;#39;Create&amp;#39; : &amp;#39;Save&amp;#39; %&amp;gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;em&gt;app/views/documents/document.jst&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you're familiar with ERb templates, this is pretty straightforward. Basically, the template now uses the &lt;code&gt;model&lt;/code&gt; object that is passed in to fill in all the data. The call to render this template is:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;JST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;br/&gt;


&lt;p&gt;No more complicated string concatenation!&lt;/p&gt;

&lt;p&gt;Now let's convert the strings in &lt;code&gt;App.Views.Index&lt;/code&gt; into the &lt;code&gt;documents_collection.jst&lt;/code&gt; template. This turns:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;h3&amp;gt;&amp;lt;a href=&amp;#39;#new&amp;#39;&amp;gt;Create New&amp;lt;/a&amp;gt;&amp;lt;/h3&amp;gt;&amp;lt;ul&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#39;#documents/&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;#39;&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;escape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/ul&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;h3&amp;gt;No documents! &amp;lt;a href=&amp;#39;#new&amp;#39;&amp;gt;Create one&amp;lt;/a&amp;gt;&amp;lt;/h3&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;br /&gt;


&lt;p&gt;into:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;&lt;/span&gt;% if(collection.models.length &amp;gt; 0) { %&amp;gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h3&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;#new&amp;#39;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Create New&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&amp;lt;/h3&amp;gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;&amp;lt;&lt;/span&gt;% collection.each(function(item) { %&amp;gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;#documents/&amp;lt;%= item.id %&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;&lt;/span&gt;%= item.escape(&amp;#39;title&amp;#39;) %&amp;gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;&amp;lt;&lt;/span&gt;% }); %&amp;gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;&amp;lt;&lt;/span&gt;% } else { %&amp;gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;No documents! &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;#new&amp;#39;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Create one&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;&amp;lt;&lt;/span&gt;% } %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;em&gt;app/views/documents/documents_collection.jst&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Similar to the &lt;code&gt;document.jst&lt;/code&gt; template, this template derives all its data from the &lt;code&gt;collection&lt;/code&gt; object that is passed in. We would render it like:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;JST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;documents_collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;br /&gt;


&lt;p&gt;If you take a look at the &lt;code&gt;App.Views.Edit&lt;/code&gt; and &lt;code&gt;App.Views.Index&lt;/code&gt; models, they are now significantly simpler after moving the HTML out.&lt;/p&gt;

&lt;h4&gt;Model Event Binding&lt;/h4&gt;


&lt;p&gt;One last minor cleanup that we'll do is to avoid calling &lt;code&gt;render&lt;/code&gt; in the &lt;code&gt;save&lt;/code&gt; method of &lt;code&gt;App.Views.Edit&lt;/code&gt;. Instead, we'll bind the &lt;code&gt;render&lt;/code&gt; call to any model changes, like so:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Views&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Edit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Backbone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;View&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    
&lt;span class=&quot;c1&quot;&gt;// ... snip ...&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bindAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;render&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;change&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ... snip ...&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;br /&gt;


&lt;p&gt;Now, whenever the &lt;code&gt;document&lt;/code&gt; model changes, the view will be re-rendered. This ensures that the view will always stay up-to-date with the model, no matter what piece of code happens to change it. This is actually fundamental to the philosophy of Backbone, which is to separate the model data from the controllers and views.&lt;/p&gt;

&lt;h4&gt;Conclusion&lt;/h4&gt;


&lt;p&gt;Let's take a look at the updated directory structure after these changes:&lt;/p&gt;

&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;app/
    controllers/
        documents_controller.rb
    models/
        document.rb
    views/
        home/
            index.html.erb
        documents/
            document.jst
            documents_collection.jst
public/
    javascripts/
        application.js
        collections/
            documents.js
        controllers/
            documents.js
        models/
            document.js
        views/
            show.js
            index.js
            notice.js&lt;/code&gt;
&lt;/pre&gt;


&lt;br /&gt;


&lt;p&gt;We added two items: the .jst files, and the Backbone collections folder. Overall, the structure is still nicely organized, and its easy to see at a glance how everything connects.&lt;/p&gt;

&lt;p&gt;After this update, we have a robust base that we can powerfully extend with more features. What you'll discover is that with Backbone, you avoid a lot of churn that is usually present in persisting data and view fragments in a javascript heavy Rails application. There is now a logical place for all client-side code.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;&quot;&gt;In Part 3, learn about how to convert CloudEdit from Rails to Parse, so you don't need to do any server side coding at all&lt;/a&gt;!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Empathetic Product Discovery for Hackers</title>
   <link href="http://www.jamesyu.org/2011/02/08/empathetic-product-development-for-hackers/"/>
   <updated>2011-02-08T00:00:27-08:00</updated>
   <id>http://www.jamesyu.org/2011/02/08/empathetic-product-development-for-hackers</id>
   <content type="html">&lt;p&gt;Hackers tend to look inward. It's only natural: we spend our days thinking about intricate, abstract pieces of code. In order to focus on these concepts, your mind has to do away with distractions. You have to buckle down and think about the problem as it relates to your perspective, and how you're going to solve it. Notice the word &lt;em&gt;you&lt;/em&gt; shows up a lot.&lt;/p&gt;

&lt;p&gt;But if you're a hacker that wants to brainstorm the next big consumer product idea, an inward-facing thought process is exactly what you don't want. It can lead to products that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Are built only for yourself, and thus, never really delivers value to real users.&lt;/li&gt;
&lt;li&gt;Miss out on a significant market because you discounted it entirely.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;The root problem is a lack of empathy. Without the ability to empathize with potential users, there's little chance that you'll discover the right product.&lt;/p&gt;

&lt;p&gt;Empathy is defined as &quot;the capacity to recognize and, to some extent, share feelings that are being experienced by another semi-sentient being.&quot; So, &lt;em&gt;empathetic product discovery&lt;/em&gt; is simply learning through other people's experiences in order to discover potential solutions to their problems.&lt;/p&gt;

&lt;h4&gt;It's Stupid&lt;/h4&gt;


&lt;p&gt;Too often, I see hackers dismiss phenomena that occur outside of their world, like in popular culture or world news. A lot of times, they'll say &quot;it's stupid.&quot; They feel like they're above it.&lt;/p&gt;

&lt;p&gt;This is foolish. When a lot of people suddenly give attention to something, that's usually the sign of an opportunity.&lt;/p&gt;

&lt;p&gt;The question you need to ask yourself is: why is this important to people?&lt;/p&gt;

&lt;p&gt;If I had dismissed the whole Gap logo redesign debacle, I wouldn't have come up with &lt;a href=&quot;http://www.jamesyu.org/2010/10/09/how-my-gap-logo-app-became-viral/&quot;&gt;Make Your Own Gap Logo&lt;/a&gt;. Nor would I have seen the opportunity with &lt;a href=&quot;http://www.jamesyu.org/2011/01/27/zodiac-hacking-a-small-seo-experiment/&quot;&gt;Did My Zodiac Change&lt;/a&gt;. These two projects may be small (and trite), but they're examples that highlight how important it is to keep your ear to the ground.&lt;/p&gt;

&lt;h4&gt;Putting Yourself in Their World&lt;/h4&gt;


&lt;p&gt;By now, it's cliché in the hacker-turned-product-guru community to talk about &quot;putting yourself in someone else's shoes&quot;. I want to take this a step further and say that you need not be afraid to put yourself in someone else's world. Furthermore, you should be seeking out opportunities to get an inside view from the people around you.&lt;/p&gt;

&lt;p&gt;This means that the next time your little cousin talks about his favorite video games, you should listen to him for once. What kinds of games does he like? Why does he like it?&lt;/p&gt;

&lt;p&gt;The same goes for your girlfriend. When she starts to talk about Sex and the City, ask her why it's such a phenomenon, and why she identifies with the show.&lt;/p&gt;

&lt;p&gt;You'll be surprised at what you'll learn.&lt;/p&gt;

&lt;p&gt;Take life as one big opportunity to learn about other people's thoughts and desires. Innovative product builders are always listening and analyzing the world around them. This is the key to anticipating business opportunities.&lt;/p&gt;

&lt;h4&gt;Problems = Ideas&lt;/h4&gt;


&lt;p&gt;Most good ideas come from people's problems.&lt;/p&gt;

&lt;p&gt;Ideally, you would have potential customers line up and have leisurely discussions with you about how they use the web, and what problems they're having. But these days, it's relatively easy to do this research without leaving your living room.&lt;/p&gt;

&lt;p&gt;For example, are you planning on building a photo sharing app? Take a look at how people are currently sharing their photos on Twitter, Facebook, and other sites. Start identifying patterns and problem points. Specifically, look for users who are complaining about specific issues, or are trying to jury-rig a complicated solution to a problem using tools that aren't quite doing the job. This is usually a sign of an opportunity.&lt;/p&gt;

&lt;p&gt;For &lt;a href=&quot;http://www.quietwrite.com/&quot;&gt;QuietWrite&lt;/a&gt;, I was inspired by the growing movement against cluttered interfaces. I also looked at products like WriteRoom and Ommwriter, and how they were able to strike a nerve with productivity oriented users. But I also noticed that these products were all offline &amp;mdash; so QuietWrite was born out of the convenience of having your data in the cloud combined with an interface for minimalists.&lt;/p&gt;

&lt;h4&gt;Don't Cover Your Ears!&lt;/h4&gt;


&lt;p&gt;To summarize, the big points behind empathetic product discovery are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't cover your ears! This is especially true when you're talking to people who are very unlike yourself. Try to understand their point of view.&lt;/li&gt;
&lt;li&gt;Research the pain points people are having. A lot of data is already in the social web.&lt;/li&gt;
&lt;li&gt;Find patterns of complaining and jury-rigging tools to uncover potential product ideas.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;em&gt;Did you like this post? If so, you might be interested in reading &lt;a href=&quot;http://www.jamesyu.org/2010/10/09/how-my-gap-logo-app-became-viral/&quot;&gt;How My Gap Logo App Became Viral&lt;/a&gt; and &lt;a href=&quot;http://www.jamesyu.org/2011/01/27/zodiac-hacking-a-small-seo-experiment/&quot;&gt;Zodiac Hacking: An Accidental SEO Experiment&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Introducing Gmailr: A Javascript API for Gmail</title>
   <link href="http://www.jamesyu.org/2011/02/05/introducing-gmailr-an-unofficial-javscript-api-for-gmail/"/>
   <updated>2011-02-05T13:27:59-08:00</updated>
   <id>http://www.jamesyu.org/2011/02/05/introducing-gmailr-an-unofficial-javscript-api-for-gmail</id>
   <content type="html">&lt;p&gt;I'm happy to announce that I've decided to open source &lt;a href=&quot;https://github.com/jamesyu/gmailr&quot;&gt;Gmailr&lt;/a&gt;, a Javascript API for Gmail. It's the code that is used to run one of my pet projects, &lt;a href=&quot;http://www.0boxer.com/&quot;&gt;0Boxer&lt;/a&gt;, which is an extension for Gmail that turns organizing your inbox into a game.&lt;/p&gt;

&lt;p&gt;A few days ago, the 10,000th user signed up for 0Boxer, so I figured this would be a great time to share some of the code that makes the realtime gaming mechanics possible. Go ahead, &lt;a href=&quot;https://github.com/jamesyu/gmailr&quot;&gt;grab the code&lt;/a&gt; and play with it, make your own extensions and apps, and improve it!&lt;/p&gt;

&lt;h4&gt;A Thorny Road&lt;/h4&gt;


&lt;p&gt;Developing the code behind Gmailr was fraught with frustration and dead ends. There is no currently supported official javascript API for Gmail. There was a &lt;a href=&quot;http://code.google.com/p/gmail-greasemonkey/&quot;&gt;greasemonkey script&lt;/a&gt; that was released a few years ago, but is now broken, with no plans from the Gmail team to fix it.&lt;/p&gt;

&lt;p&gt;Also, no one else (as far as I know) has released any kind of frontend API for Gmail. And, in order for my app to work, I needed access to the various user actions in the UI &amp;mdash; the &lt;a href=&quot;http://code.google.com/apis/gmail/&quot;&gt;backend APIs&lt;/a&gt; weren't going to cut it. So, I was stuck writing my own library from scratch.&lt;/p&gt;

&lt;p&gt;But this was no easy task. Gmail runs its code through the &lt;a href=&quot;http://code.google.com/closure/compiler/&quot;&gt;closure compiler&lt;/a&gt;, thereby obfuscating everything. On top of that, Gmail is probably one of the most sophisticated javascript apps out there. Needless to say, I am now intimately familiar with the various DOM elements that make up the Gmail interface, as well as how the data is transported.&lt;/p&gt;

&lt;h4&gt;A Call to Stop Duplicating Risky Work&lt;/h4&gt;


&lt;p&gt;I had the chance to actually speak with some people on the Gmail team. Basically, they are reluctant to release any kind of javascript API, for fear of making Gmail slow (ironically, I find Gmail already pretty slow these days). There is no hope in the near future for an official javascript API.&lt;/p&gt;

&lt;p&gt;And yet, there are many companies, like &lt;a href=&quot;http://rapportive.com/&quot;&gt;Rapportive&lt;/a&gt;, &lt;a href=&quot;http://www.baydin.com/&quot;&gt;Baydin&lt;/a&gt;, and &lt;a href=&quot;http://www.unsubscribe.com&quot;&gt;Unsubscribe.com&lt;/a&gt; that build their own APIs. They're all building out complex APIs with similar functionality, that can all break independently if Gmail decides to significantly change their app structure (which they inevitably will).&lt;/p&gt;

&lt;p&gt;What we really need is for many people to come together and build out a robust and easy-to-use javascript API for Gmail that is shared across many extensions and applications. This is my hope for Gmailr.&lt;/p&gt;

&lt;p&gt;Right now, Gmailr is pretty barebones. There are a lot of missing features. However, it has been used for the past half year at 0Boxer, serving thousands of active extension users per week. What I'm hoping for is that developers will improve Gmailr, and over time, it will be the robust API that many developers will find useful.&lt;/p&gt;

&lt;p&gt;And maybe, if we get enough apps built on top of it, the Gmail team will take notice.&lt;/p&gt;

&lt;h4&gt;The API&lt;/h4&gt;


&lt;p&gt;The architecture of Gmailr and the process of reverse engineering Gmail probably deserves its own blog post. For now, I'll just show you a quick code snippet of what using Gmailr looks like. If you want more details, &lt;a href=&quot;https://github.com/jamesyu/gmailr&quot;&gt;head on over to the GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A typical use case looks like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;Gmailr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;archive&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Wow, you just archived &amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39; emails! Great job!&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;br&gt;


&lt;p&gt;Basically, this will show a nice annoying message to the user everytime they archive email. The call to &lt;code&gt;init&lt;/code&gt; does a bunch of work to bootstrap the Gmailr API. After that, there is a callback that passes in the API object, which provides the Gmailr API methods.&lt;/p&gt;

&lt;p&gt;Let's say you want to insert some custom DOM elements. That's easy:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;Gmailr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;insertTop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;div id=&amp;#39;my_div&amp;#39;&amp;gt;Hello World!&amp;lt;/div&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;insertCss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/path/to/my/css&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;




&lt;br&gt;


&lt;p&gt;This will insert a div on the top of the Gmail API, and also inject your own CSS. You can use this to add new features to Gmail.&lt;/p&gt;

&lt;h4&gt;The Future&lt;/h4&gt;


&lt;p&gt;I don't have much time these days to devote to Gmailr. What I'm hoping for is to pass the torch to other developers to improve upon the seedlings. In particular, here are some ways to improve it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expose methods that allow insertion of UI elements into various places in Gmail, like the sidebar.&lt;/li&gt;
&lt;li&gt;Improve the reliability of the API, taking into account the various weird states that Gmail can get into.&lt;/li&gt;
&lt;li&gt;Add capabilities to read the contents and metadata of emails received, sent, and interacted with.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;If you want to get in touch, please contact me at jamesjacobyu -AT- gmail.com.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Did you like this post? If so, you might like reading &lt;a href=&quot;http://www.jamesyu.org/2011/02/08/empathetic-product-development-for-hackers/&quot;&gt;Empathetic Product Development for Hackers&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>CloudEdit: A Backbone.js Tutorial with Rails (Part 1)</title>
   <link href="http://www.jamesyu.org/2011/01/27/cloudedit-a-backbone-js-tutorial-by-example/"/>
   <updated>2011-01-27T23:37:29-08:00</updated>
   <id>http://www.jamesyu.org/2011/01/27/cloudedit-a-backbone-js-tutorial-by-example</id>
   <content type="html">&lt;div class=&quot;promo&quot;&gt;
  If you like Backbone, &lt;strong&gt;you'll love Parse&lt;/strong&gt;. Read &lt;a href=&quot;http://www.jamesyu.org/2012/05/20/converting-cloudedit-from-backbone-to-parse/&quot;&gt;Part 3 of this tutorial where I show you how to convert the CloudEdit app to use Parse without any server-side Rails code at all&lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href=&quot;http://documentcloud.github.com/backbone/&quot;&gt;Backbone.js&lt;/a&gt; is a javascript MVC framework, and is the newest addition to my frontend toolbox. What's great is that &lt;a href=&quot;http://www.documentcloud.org&quot;&gt;DocumentCloud&lt;/a&gt;, the team that released it, is actively developing and using the framework, making it better everyday. I'm currently using it in various projects, including &lt;a href=&quot;http://www.quietwrite.com&quot;&gt;QuietWrite&lt;/a&gt;, a javascript-heavy document editing service.&lt;/p&gt;

&lt;p&gt;The major advantage of Backbone is that it's simple, lightweight, and gets out of your way, but provides just enough structure to organize large javascript projects.&lt;/p&gt;

&lt;p&gt;In this tutorial, I'll go over the code for &lt;a href=&quot;http://cloudedit.jamesyu.org/&quot;&gt;CloudEdit&lt;/a&gt;, an example Backbone.js app backed with Rails that outlines some basic patterns that I've used successfully in my Rails Backbone projects. I'll start by describing the spec for the app, and then detail how the models, controllers, and views hook up. This tutorial assumes you already have some basic knowledge about Rails &amp;mdash; I'll be focusing mainly on the Backbone.js concepts.&lt;/p&gt;

&lt;p&gt;You can grab all the code for the example app in the &lt;a href=&quot;https://github.com/jamesyu/CloudEdit&quot;&gt;GitHub repo&lt;/a&gt;. You can also play around with a &lt;a href=&quot;http://cloudedit.jamesyu.org/&quot;&gt;live version of CloudEdit here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;The Spec&lt;/h4&gt;


&lt;p&gt;CloudEdit is an extremely simple document editing app. Here are the specs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users should see a list of the latest documents. To edit, the user clicks the document in the list.&lt;/li&gt;
&lt;li&gt;Users should be able to edit documents with a title and body, and should be able to save their edits to the server.&lt;/li&gt;
&lt;li&gt;Users should be able to create new documents.&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;Directory Structure&lt;/h4&gt;


&lt;p&gt;First, let's get the directory structure organized. For our Rails project, we have the usual MVC directory structure underneath the &lt;code&gt;apps&lt;/code&gt; directory. For the Backbone files, I like to create another set of MVC directories underneath the javascript directory:&lt;/p&gt;

&lt;pre class=&quot;highlight&quot;&gt;
&lt;code&gt;app/
    controllers/
        documents_controller.rb
    models/
        document.rb
    views/
        home/
            index.html.erb
public/
    javascripts/
        application.js
        controllers/
            documents.js
        models/
            document.js
        views/
            show.js
            index.js
            notice.js&lt;/code&gt;
&lt;/pre&gt;


&lt;br /&gt;


&lt;p&gt;Notice how the MVC directories mirror the Rails MVC directories.&lt;/p&gt;

&lt;p&gt;I like to use &lt;a href=&quot;http://documentcloud.github.com/jammit/&quot;&gt;Jammit&lt;/a&gt; to deliver and package the CSS and Javascript files. It also allows you to specify load ordering. So, for example, you can tell it to load all the vendor javascript files before loading the application specific files.&lt;/p&gt;

&lt;p&gt;Let's first go through all the Backbone related code, and then tackle the Rails code (which is much simpler).&lt;/p&gt;

&lt;h4&gt;Backbone Models&lt;/h4&gt;


&lt;p&gt;We only have one model: the Document. It has a &lt;code&gt;title&lt;/code&gt; and a &lt;code&gt;body&lt;/code&gt; attribute. But take note that you don't actually need to specify that in the Backbone model: they're populated by JSON data, either from the server or from the client.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Document&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Backbone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;documents&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;charAt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;em&gt;public/javascripts/models/document.js&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The only method defined is the &lt;code&gt;url&lt;/code&gt; method, which tells Backbone the URL to persist the &lt;code&gt;Document&lt;/code&gt; model when calling &lt;code&gt;save()&lt;/code&gt; or &lt;code&gt;destroy()&lt;/code&gt;. In this case, it's a pretty typical Rails RESTful model: if it's a new unsaved model, then it should POST to &lt;code&gt;/documents&lt;/code&gt; for a CREATE action, and if it's not new, then it should POST to &lt;code&gt;/documents/id&lt;/code&gt; for an UPDATE action.&lt;/p&gt;

&lt;h4&gt;Backbone Controllers&lt;/h4&gt;


&lt;p&gt;There's 3 actions in our app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Index: Show a list of documents.&lt;/li&gt;
&lt;li&gt;Edit: Shows a specific document ready to be edited and saved to the server.&lt;/li&gt;
&lt;li&gt;New: Shows a blank document ready to be created and saved to the server.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Note that these match up with the RESTful pages we would expect from a Document resource. You certainly don't have to organize it this way, but I find that it really helps to have your Backbone structure follow a RESTful pattern.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Controllers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Backbone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;routes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;documents/:id&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;            &lt;span class=&quot;s2&quot;&gt;&amp;quot;edit&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;                         &lt;span class=&quot;s2&quot;&gt;&amp;quot;index&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;new&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;                      &lt;span class=&quot;s2&quot;&gt;&amp;quot;newDoc&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Views&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Edit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Could not find that document.&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
                &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;#&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getJSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;/documents&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Views&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;documents&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Error loading documents.&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;newDoc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Views&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Edit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;em&gt;public/javascripts/controllers/documents.js&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There's a lot going on here, so let's tackle it piece by piece.&lt;/p&gt;

&lt;h5&gt;Naming&lt;/h5&gt;


&lt;p&gt;I like to organize my Backbone controller and views under &lt;code&gt;App.Controllers&lt;/code&gt; and &lt;code&gt;App.Views&lt;/code&gt;, respectfully. This helps to disambiguate all the object names, especially at the time of instantiation. Thus, our documents controller is &lt;code&gt;App.Controllers.Documents&lt;/code&gt;.&lt;/p&gt;

&lt;h5&gt;Routes&lt;/h5&gt;


&lt;p&gt;The controller expects you to define routes for each action in your app. In our case, we have the 3 routes we talked about earlier, specified as a javascript object mapping from the url hash structure to the method that is invoked. So, for example, when the user goes to &lt;code&gt;/#documents/3&lt;/code&gt;, it will show the edit page for the document with id 3.&lt;/p&gt;

&lt;h5&gt;Methods&lt;/h5&gt;


&lt;p&gt;The rule that I use for controller methods is that they should only do 3 things: (1) get the data from the server to populate the models, (2) process that data for the views, and (3) instantiate the views.&lt;/p&gt;

&lt;p&gt;For example, in our &lt;code&gt;index&lt;/code&gt; method, we make an ajax JSON call to the Documents#index action on the server to get a list of documents. Then, we iterate through the list and instantiate a Document model for each of the JSON data. Finally, we instantiate the App.Views.Index view with the array of models.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;edit&lt;/code&gt; method is equally simple: it instantiates the Document with the given id, and then fetches the data for it from the server. Upon success, we instantiate the &lt;code&gt;App.Views.Edit&lt;/code&gt; view.&lt;/p&gt;

&lt;p&gt;Just like with Rails controllers, it is best to keep them skinny. You should delegate most of the complications to the views and models.&lt;/p&gt;

&lt;h4&gt;The Main App Object&lt;/h4&gt;


&lt;p&gt;Now that we have the controller setup, let's actually get our App up and running. The root route for the Rails server will serve up the following HTML, which our Backbone app will use as its scaffolding:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;#&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;CloudEdit&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;A Backbone.js Rails Example by James Yu&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;notice&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;app&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;em&gt;app/views/home/index.html.erb&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The #notice and #app div elements will be used by the app as a scaffold for the UI.&lt;/p&gt;

&lt;p&gt;The main App object itself is dead simple:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;Views&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;Controllers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Controllers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;Backbone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;history&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;em&gt;public/javascripts/application.js&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The two main things to take note is the instantiation of the Documents controller, and the call to the &lt;code&gt;Backbone.history.start()&lt;/code&gt;. These combined will kick off the necessary listeners to make the hash routing work.&lt;/p&gt;

&lt;h4&gt;Backbone Views&lt;/h4&gt;


&lt;p&gt;Now that we have the plumbing done, let's work on the views, which is the actual user facing interface.&lt;/p&gt;

&lt;p&gt;For the purposes of this tutorial, I'll use simple string concatenation in my views. Of course, for more complicated apps, I would highly suggest using a templating framework like &lt;a href=&quot;http://api.jquery.com/category/plugins/templates/&quot;&gt;jQuery templates&lt;/a&gt; or &lt;a href=&quot;http://aefxx.com/jquery-plugins/jqote/&quot;&gt;jQote&lt;/a&gt;.&lt;/p&gt;

&lt;h5&gt;Index&lt;/h5&gt;




&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Views&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Backbone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;View&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;h3&amp;gt;&amp;lt;a href=&amp;#39;#new&amp;#39;&amp;gt;Create New&amp;lt;/a&amp;gt;&amp;lt;/h3&amp;gt;&amp;lt;ul&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#39;#documents/&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;#39;&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;escape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/ul&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;h3&amp;gt;No documents! &amp;lt;a href=&amp;#39;#new&amp;#39;&amp;gt;Create one&amp;lt;/a&amp;gt;&amp;lt;/h3&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;#app&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;em&gt;public/javascripts/views/index.js&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This view accepts a list of documents, and simply lists them out with links to edit each of the documents. I want to highlight a few things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Backbone automatically (and conveniently) captures the hash passed to the initialization of the object, and sticks it into &lt;code&gt;this.options&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The only method really required by the views is &lt;code&gt;render&lt;/code&gt;, and you can do anything you want to render the view. In this case, all we do is some string concatenation, and stick it into the &lt;code&gt;#app&lt;/code&gt; div element.&lt;/li&gt;
&lt;li&gt;I like to call &lt;code&gt;render&lt;/code&gt; immediately at the end of &lt;code&gt;initialize&lt;/code&gt;. What this means is that as soon as you instantiate the view object, it gets rendered.&lt;/li&gt;
&lt;li&gt;Note that there is no event delegation specified. The links to each document is handled automatically by the controller by simply specifying the right hash url to the Edit action. Backbone's History object automatically handles routing the clicks to the Edit action. This greatly simplifies views which usually have a million events flying around just to do routing correctly.&lt;/li&gt;
&lt;/ol&gt;


&lt;h5&gt;Edit/New&lt;/h5&gt;




&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Views&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Edit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Backbone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;View&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;events&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;submit form&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;save&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Successfully created!&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Saved!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;[name=title]&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;[name=body]&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Views&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Notice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
                
                &lt;span class=&quot;nx&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;delegateEvents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

                &lt;span class=&quot;nx&quot;&gt;Backbone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;history&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;saveLocation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;documents/&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Views&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
        
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;lt;form&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;label for=&amp;#39;title&amp;#39;&amp;gt;Title&amp;lt;/label&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;input name=&amp;#39;title&amp;#39; type=&amp;#39;text&amp;#39; /&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        
        &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;label for=&amp;#39;body&amp;#39;&amp;gt;Body&amp;lt;/label&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;textarea name=&amp;#39;body&amp;#39;&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;escape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/textarea&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;submitText&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Create&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Save&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        
        &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;button&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;submitText&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/button&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/form&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;#app&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;[name=title]&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// use val, for security reasons&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;em&gt;public/javascripts/views/edit.js&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I decided to collapse both the Edit and New views into one view: the Edit view. Basically, when a Document is passed in that is newly instantiated (and hasn't been persisted to the server), it acts like a New view, otherwise, it's an Edit view.&lt;/p&gt;

&lt;p&gt;The instantiate-and-render pattern is similar to that of the Index view. The new thing that we see here is the event delegation model. Here's how it works:&lt;/p&gt;

&lt;p&gt;If you specify an event key on the view object, Backbone will automatically delegate the events. The key to each event is in the form &quot;event selector&quot;. In our example, Backbone automatically binds the &lt;code&gt;save&lt;/code&gt; method to the form's &lt;code&gt;submit&lt;/code&gt; event. This is a very handy shortcut that allows you to organize and peruse events in view easily.&lt;/p&gt;

&lt;p&gt;The final thing I want to point out is the &lt;code&gt;save&lt;/code&gt; method, which really bears to fruit the power of Backbone. Unlike normal &lt;code&gt;save&lt;/code&gt; routines, you don't have to jump through hoops to remember how to persist your data. All of that is already specified in your model. So, all we do is call &lt;code&gt;save&lt;/code&gt; on the Document model (with the parameters taken from the title and body form elements), and we're done!&lt;/p&gt;

&lt;h4&gt;Rails&lt;/h4&gt;


&lt;p&gt;The great thing about using Backbone is that it makes your server side code very clean. The main meat of it is simply controllers that pass back JSON data to the client via XHR.&lt;/p&gt;

&lt;h5&gt;Document Model&lt;/h5&gt;




&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Document&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;attr_accessible&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;to_json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:only&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;em&gt;app/models/document.rb&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The Document model is simple, and only contains a &lt;code&gt;body&lt;/code&gt; and &lt;code&gt;title&lt;/code&gt; attribute (along with timestamps). One thing to note is that I specifically set &lt;code&gt;body&lt;/code&gt; and &lt;code&gt;title&lt;/code&gt; to be the only attributes that can be mass assigned, and also specifically set which attributes should be returned when calling &lt;code&gt;to_json&lt;/code&gt;. Both of these are for security reasons (you don't want to client to be able to set or receive attributes they don't need).&lt;/p&gt;

&lt;h5&gt;Documents Controller&lt;/h5&gt;




&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DocumentsController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ApplicationController&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;show&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create!&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update_attributes!&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;em&gt;app/controllers/documents_controller.rb&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As you see, the Rails controller is dead simple: 4 RESTful actions that return data via JSON. No views and no instance variables. This is RESTful design at its finest!&lt;/p&gt;

&lt;h4&gt;Conclusion and Part 2&lt;/h4&gt;


&lt;p&gt;Backbone.js really introduces a new kind of data flow for Rails apps. Instead of data flowing like this:&lt;/p&gt;

&lt;p&gt;Rails Model =&gt; Rails Controller =&gt; Rails View&lt;/p&gt;

&lt;p&gt;It now flows like this:&lt;/p&gt;

&lt;p&gt;Rails Model =&gt; Rails Controller =&gt; Backbone Model =&gt; Backbone Controller =&gt; Backbone View&lt;/p&gt;

&lt;p&gt;What I've found is that overall, Backbone.js makes it really simple to create highly responsive Javascript heavy applications.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read on with &lt;a href=&quot;http://www.jamesyu.org/2011/02/09/backbone.js-tutorial-with-rails-part-2/&quot;&gt;Part 2 of the Backbone.js and Rails Tutorial&lt;/a&gt;, where we'll work with Backbone Collections add Underscore templates.&lt;/em&gt; and &lt;a href=&quot;http://www.jamesyu.org/2012/05/20/converting-cloudedit-from-backbone-to-parse/&quot;&gt;Part 3 where I show how to convert CloudEdit to use Parse and get rid of the Rails code entirely&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Zodiac Hacking: An Accidental SEO Experiment</title>
   <link href="http://www.jamesyu.org/2011/01/27/zodiac-hacking-a-small-seo-experiment/"/>
   <updated>2011-01-27T22:55:41-08:00</updated>
   <id>http://www.jamesyu.org/2011/01/27/zodiac-hacking-a-small-seo-experiment</id>
   <content type="html">&lt;p&gt;Around January 12, 2011, news was quickly spreading about a &lt;a href=&quot;http://gawker.com/5732115/your-zodiac-sign-may-have-changed&quot;&gt;potential change to the Zodiac system&lt;/a&gt;. Apparently, Parke Kunkle, an astronomer from Minneapolis, asserted that the Earth's axis has shifted over the past 2,000 years, resulting in a potential change to the Zodiac signs.&lt;/p&gt;

&lt;p&gt;I didn't know much (or cared) about the Zodiac. But, this was a hot button issue that got a ton of people riled up. When there's such intense attention on a topic, my first instinct is to look for potential app ideas that could go viral. I launched a &lt;a href=&quot;http://www.jamesyu.org/2010/10/09/how-my-gap-logo-app-became-viral/&quot;&gt;parody Gap logo maker&lt;/a&gt; a few months back which took off on the coattails of the news of the horribly designed logo.&lt;/p&gt;

&lt;h4&gt;The Idea&lt;/h4&gt;


&lt;p&gt;The first thing I did was do some simple queries for &quot;zodiac&quot; and related keywords. Most of the top sites on the SERPs were timing out or simply returning errors. This was my first real clue that there was a lot of interest, and that there was massive traffic surrounding all things Zodiac.&lt;/p&gt;

&lt;p&gt;But why did people care? It was simple: people's Zodiac signs may have changed. And to the people who put weight in their daily horoscopes, this was a Big Deal. All the articles about the Zodiac change listed a table of the old Zodiac dates, and a table with the altered new dates.&lt;/p&gt;

&lt;p&gt;But there was no site that simply told you what new Zodiac sign you were.&lt;/p&gt;

&lt;p&gt;This was it: I could build a simple app that lets users enter their birthdate, and then tell them if their sign changed, and what that new sign is.&lt;/p&gt;

&lt;h4&gt;Implementation&lt;/h4&gt;


&lt;p&gt;I kept the implementation as dead simple as possible: just a static HTML file with some javascript. The site functionality was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ask the user to enter their birthdate.&lt;/li&gt;
&lt;li&gt;Show a nice message saying whether their sign changed, and what that new sign was.&lt;/li&gt;
&lt;li&gt;Let them tweet out a message about their new sign.&lt;/li&gt;
&lt;li&gt;Some ads for a little revenue.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I built it in about an hour, and the result is at &lt;a href=&quot;http://www.didmyzodiacchange.com&quot;&gt;http://www.didmyzodiacchange.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update: Bemmu asks: But how did you get the site noticed initially?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I didn't do anything besides send it to a dozen friends and told them to like it and tweet it. It got picked up into the realtime widget almost immediately. This probably was a factor in getting the site up so high in the SERPs.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;Results&lt;/h4&gt;


&lt;p&gt;The results surprised me.&lt;/p&gt;

&lt;p&gt;I thought this would be another viral winner, driven by Facebook likes and Tweets. But instead, the majority came from unexpected Google traffic.&lt;/p&gt;

&lt;p&gt;On the morning of January 14th, my site got above the fold for the search term &quot;zodiac change&quot;, which resulted in this traffic:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/zodiac.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;My speculation is that my site was riding a &quot;freshness bump&quot; due to two reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zodiac was the topic of the day, and new material on Zodiac changes were being ranked very high.&lt;/li&gt;
&lt;li&gt;My site was new and had fresh content that was extremely relevant.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I was pretty excited, because not only was the search volume relatively high, but I was seeing CTRs on my ads of up to 2-3% at a $5 CPM. Take note: the horoscopes industry is very lucrative.&lt;/p&gt;

&lt;p&gt;However, by 11am, Google had already started bumping me back down to the second page for &quot;zodiac change&quot;, and the traffic immediately died. I got another bump back to the first page around 2pm, but only for about 20 minutes.&lt;/p&gt;

&lt;p&gt;Over the next week or so, the site bounced around the 1st and 2nd SERPs, and finally rested on the 3rd page where it is now. The traffic to the site now is minuscule.&lt;/p&gt;

&lt;p&gt;In the end I learned a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google values fresh and relevant content, and will give you a bump up because of it.&lt;/li&gt;
&lt;li&gt;You'll also get a good amount of traffic from their &quot;realtime&quot; results widget.&lt;/li&gt;
&lt;li&gt;After the bump, I speculate that sites get properly &quot;reindexed.&quot; In order to maintain high SERP position, you'll need to do the usual hard work of providing quality and consistent content.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;All in all, it was a fun experiment.&lt;/p&gt;

&lt;p&gt;And by the way, I'm still a Sagittarius.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>My New Jekyll Blog</title>
   <link href="http://www.jamesyu.org/2011/01/26/my-new-jekyll-blog/"/>
   <updated>2011-01-26T18:59:35-08:00</updated>
   <id>http://www.jamesyu.org/2011/01/26/my-new-jekyll-blog</id>
   <content type="html">&lt;p&gt;It's been quite a while since I've rebooted my blog. So, I present to you the latest incarnation. I decided to finally migrate from a self-hosted WordPress blog to &lt;a href=&quot;https://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt;, a Ruby-based static site generator.&lt;/p&gt;

&lt;p&gt;In my opinion, blogs should really be a set of static files, since each post is create once, and updated rarely. This has several benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scaling is easy. Serving static files is trivial.&lt;/li&gt;
&lt;li&gt;Highly secure. There is no app to hack.&lt;/li&gt;
&lt;li&gt;Everything is stored as plaintext, which neatly side steps any legacy format issues.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;And finally, having my blog as simple text files (flavored with &lt;a href=&quot;http://daringfireball.net/projects/markdown/syntax&quot;&gt;Markdown&lt;/a&gt;) makes the minimalist in me very happy.&lt;/p&gt;

&lt;p&gt;If you want to get started with Jekyll, I highly recommend the &lt;a href=&quot;http://paulstamatiou.com/how-to-wordpress-to-jekyll&quot;&gt;exhaustive guide written by Paul Stamatiou&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I've also shared my &lt;a href=&quot;https://github.com/jamesyu/jamesyu_jekyll_template&quot;&gt;Jekyll blog template&lt;/a&gt; on GitHub. Go ahead and use and modify it for your own purposes.&lt;/p&gt;

&lt;h4&gt;A Throwback&lt;/h4&gt;


&lt;p&gt;There's actually been a lot of chatter around static site generation with tools like Jekyll and &lt;a href=&quot;http://cloudhead.io/toto&quot;&gt;toto&lt;/a&gt;. But this is nothing new. I remember launching my first blog back in the late 90s as static files, and then moving to an early version of MovableType which required static regeneration whenever you created a new post.&lt;/p&gt;

&lt;p&gt;It's funny how old tech re-emerges again as a response to over-complication.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>How My Gap Logo App Became Viral</title>
   <link href="http://www.jamesyu.org/2010/10/09/how-my-gap-logo-app-became-viral/"/>
   <updated>2010-10-09T00:00:00-07:00</updated>
   <id>http://www.jamesyu.org/2010/10/09/how-my-gap-logo-app-became-viral</id>
   <content type="html">&lt;p&gt;It's been a fun ride over the past couple days. I launched &lt;a href=&quot;http://www.makeyourowngaplogo.com/&quot;&gt;Make Your Own Gap Logo&lt;/a&gt; (MYOGL) a few days ago, and it has since gone viral, receiving over 100,000 page views, and almost 10,000 logos made so far. This is the story of a viral news-based app and the frantic journey that launched it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;October 4th, 2010: The News&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;New hits the wire that Gap is rebranding with a new logo. In a sea of rebranding stories, why did this get so much attention? In short, (1) because Gap hasn't changed their logo in over 40 years, and (2) because the new logo is terrible: Helvetica paired up with a puzzling gradient square, something a first year design student would come up with.&lt;/p&gt;

&lt;p&gt;I was in disbelief. Did some intern mess up and leak a joke logo that was being passed around internally at Gap? I even mocked up a &lt;a href=&quot;http://img.skitch.com/20101006-tt33u3gbxfgnwyi8k57h3crbgh.jpg&quot;&gt;version of the logo using only Powerpoint&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;October 5th, 2010: The Idea&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Gap logo story is still blowing up. People all over the web are creating parodies and suggesting better versions of the logo. Someone even created the &lt;a href=&quot;http://www.twitter.com/gaplogo&quot;&gt;@GapLogo&lt;/a&gt; Twitter account.&lt;/p&gt;

&lt;p&gt;I remember the distinct moment when I knew that I had to make an app that lets people create and share their own logos. It was around 9pm, and I was sitting on my couch while my fiance was dozing comfortably beside me. I shot up like a bullet the instant the idea culminated. It was one of those ideas that I knew would go viral: (1) it capitalized on a popular news story, (2) people are getting more opinionated about design and logos, and (3) it allows people to be creative and funny at the new logo's expense.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Designing and Building the App&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I allowed myself only 2 hours to create the app from start to finish. A restricted time limit would force me to focus on only what was necessary for the app, and to keep it simple and fun. I'm a strong believer in iterating fast and pushing out a minumum viable design.&lt;/p&gt;

&lt;p&gt;For the next 2 hours, I worked as fast as humanly possible, cobbling up a quick design in Fireworks and coding it in Rails. The following are some decisions and specs for the MVP:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;It should allow the user to create a logo, and each logo should have a permalink that is easily shareable.&lt;/li&gt;
    &lt;li&gt;The generated logo should look very similar to the new Gap logo. With the word  &quot;Gap&quot;, it should be indistinguishable from the original.&lt;/li&gt;
    &lt;li&gt;The site should include Facebook and Twitter buttons.&lt;/li&gt;
    &lt;li&gt;It doesn't have to generate an image. (in short, I just didn't want to deal with ImageMagick. The logo is so simple that it's trivial to create an HTML version of it.)&lt;/li&gt;
    &lt;li&gt;The user should be able to edit the logo and create it inline as soon as they hit the homepage.&lt;/li&gt;
    &lt;li&gt;The site doesn't have to make money, it's just for fun. So, focus on the fun.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;By midnight, I had a functional version up and running, and I pushed out to the new domain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Marketing the App&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I knew that I didn't have to market my app too strongly, because as soon as a handful of users shared their logos, I knew it would take off. What I did was identify all the bloggers that mentioned the Gap redesign and email them the site, and also left a comment on their blog post with the site.&lt;/p&gt;

&lt;p&gt;At around 2am, I decided to call it a night, and climbed into my bed and promptly woke up my fiance to show her the site. She thought I was crazy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;October 6th, 2010: Virality&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I woke up with a start at about 8:30am. I install &lt;a href=&quot;http://www.chartbeat.com/&quot;&gt;Chartbeat&lt;/a&gt; on all my apps (it's the best way to keep a pulse on quickly changing traffic patterns). The first thing I did was grab my iPad and check Chartbeat, and saw only about 5 concurrent users on MYOGL. So, I decided to doze off for another 15 minutes.&lt;/p&gt;

&lt;p&gt;After dozing, I checked Chartbeat again. Now it was at about 11 users. I kept staring at it, and suddenly it jumped to 23, then 33. 30 seconds later, it was at 70, with the majority of referrals coming from Facebook and Twitter. This was it!&lt;/p&gt;

&lt;p&gt;I literally ran downstairs to my laptop to keep checking on the progress. 30 minutes later, I was seeing about 200 concurrent users, and the Tweets about MYOGL were coming at about one every 3 seconds. Facebook and Twitter's referrals dwarfed all the blogs that covered my app, proving that this app was driven all by virality (one of the my first to actually be a purely viral app).&lt;/p&gt;

&lt;p&gt;For the most part the app was done: I didn't need to add anything to it, and it drove its own virality. I kept a pulse on the traffic for the rest of the day, and it peaked at about 700 concurrent users in Chartbeat.&lt;/p&gt;

&lt;p&gt;Funny enough, there was another app called &lt;a href=&quot;http://www.craplogo.me&quot;&gt;Crap Logo&lt;/a&gt; that also let users create their own Gap parody logos (theres is image based). We both launch at about the same time, but it seemed like they had a slight headstart in hitting virality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Iterations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next night, I added a few more features to the site: a Top page (that shows the most popular logos made) and a Random button. The Random button proved to be very sticky.&lt;/p&gt;

&lt;p&gt;I even had a hair brained scheme to monetize the site by selling Tshirts with parody logos using Zazzle, but that didn't work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Post Mortem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first day saw about 100,000 pageviews, with about 20,000 visitors. Over 6000 logos were created, and the Top page really did reflect the collective sentiment of what people thought. The Top logo created is &quot;Crap.&quot;&lt;/p&gt;

&lt;p&gt;I even got mentioned on a &lt;a href=&quot;http://blogs.forbes.com/velocity/2010/10/07/new-gap-logo-hated-by-many-company-turns-to-crowdsourcing-tactics/?boxes=Homepagechannels&quot;&gt;Forbes Blog article about the Gap redesign&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So why did this app take off? I think that it involved the following factors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The news was big. People hated the new logo.&lt;/li&gt;
&lt;li&gt;The general public is becoming more design conscious, especially about logos and rebranding. People love to give their opinions on designs, more now than at any time in the past.&lt;/li&gt;
&lt;li&gt;The app was fun, and gave users a feeling of creating their own parody. People love to share the clever things they come up with, and this app was all about that.&lt;/li&gt;
&lt;li&gt;The Facebook Like button was key. Most of my traffic was from Facebook. A blog even mentioned the fact that another designer &quot;liked&quot; the app as a point of interest.&lt;/li&gt;
&lt;li&gt;The app was launched fast. If I had waited even a half a day longer to push it out, I don't think it would have gone as viral as it did.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;All in all, I had a blast launching this fun little app. I view it almost more as an art piece that crowdsourced people's sentiments about a newsworthy topic. For now, I'm calling the app a success and leaving it as that.&lt;/p&gt;

&lt;p&gt;I did, however, throw a Google ad on the site, and it's looking like it'll pay for a few Gap shirts a month.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Tips for the Digital Traveler in Italy</title>
   <link href="http://www.jamesyu.org/2010/05/31/tips-for-the-digital-traveler-in-italy/"/>
   <updated>2010-05-31T00:00:00-07:00</updated>
   <id>http://www.jamesyu.org/2010/05/31/tips-for-the-digital-traveler-in-italy</id>
   <content type="html">&lt;p align=&quot;center&quot;&gt;&lt;a href=&quot;http://www.flickr.com/photos/jamesyu/4635611391/&quot; title=&quot;Golden Hour in Bologna by jamesjyu, on Flickr&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3371/4635611391_87d3aa18db.jpg&quot; width=&quot;500&quot; height=&quot;333&quot; alt=&quot;Golden Hour in Bologna&quot; /&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;After traveling in Italy for the past two weeks, I learned a lot about how digital devices and various other tools can help with travel logistics. This was the first big international trip where I made a significant effort to use digital tools; it's stunning how much easier it is to get oriented when you're not only relying on static offline tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jailbroken iPhone&lt;/strong&gt;
All of Italy (and most of Europe) is blanketed in fast 3G, making the iPhone one of the most useful tools. You'll need to jailbreak your iPhone first. &lt;a href=&quot;http://www.iclarified.com/jailbreak/iphone3g/firmware.php&quot;&gt;iClarified&lt;/a&gt; is the easiest way to do this.&lt;/p&gt;

&lt;p&gt;After landing in Italy, all you need to do is go to a local wireless provider and get a prepaid SIM card with data plan, which will run you around ‚Ç¨15. I went with &lt;a href=&quot;http://www.tim.it/consumer/homepage.do&quot;&gt;TIM&lt;/a&gt;, which provided 3GB of free data and great coverage even in the most rural areas of Italy. I also hear good things about &lt;a href=&quot;http://vodafone.it/&quot;&gt;Vodafone&lt;/a&gt; and Wind.&lt;/p&gt;

&lt;p&gt;Once you get this setup, you'll also be able to tether your iPhone 3G connection to your other devices. This is useful since many hotels in Italy still charge highway robbery fees for WiFi. If you have an iPad without 3G, you can grab the &lt;a href=&quot;http://www.wired.com/gadgetlab/2010/05/miwi-jailbreak-app/&quot;&gt;MiWi&lt;/a&gt; app to create a WiFi hotspot using your iPhone. As far as I know, this is the only way to share your internet connection from your iPhone to your iPad.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evernote&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I made heavy use of &lt;a href=&quot;http://www.evernote.com/&quot;&gt;Evernote&lt;/a&gt; throughout the entire trip. It's the perfect tool to throw all those random bits of information like receipts, reservations, and itineraries. It's also an easy way to share information between your iPad, iPhone, and laptop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Language Apps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In bigger urban areas like Florence and Rome, you can get by with English. But, in smaller towns like Bologna, you'll have more problems. It's a good idea to get the basic phrases down, and rely on a full dictionary for more difficult situations.&lt;/p&gt;

&lt;p&gt;I recommend these two apps for Italian:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href=&quot;http://itunes.apple.com/us/app/italian-phrase-book/id313611245?mt=8&quot;&gt;Italian Phrase Book&lt;/a&gt;&lt;/em&gt; - The best &quot;phrase book&quot; app. It allows you to easily build phrases for various different situations, with clear audio pronunciations.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href=&quot;http://itunes.apple.com/us/app/wordroll-ei-italian-english/id292396100?mt=8&quot;&gt;WordRoll Italian/English Translation Dictionary&lt;/a&gt;&lt;/em&gt; - Quick and easy to use It/Eng dictionary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google My Maps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google My Maps is the best way to create and manage itinerary of places. You can access it by going to &lt;a href=&quot;http://maps.google.com&quot;&gt;http://maps.google.com&lt;/a&gt; and clicking on &quot;My Maps&quot;. The UI isn't the most intuitive, but I've found it's really the best way to manage a bunch of locations you want to see. Also, it's the best app to  get a &quot;feeling&quot; for a place, especially since you can easily see nearby places, zoom into street view, and add google search results to your maps.&lt;/p&gt;

&lt;p&gt;Once you make your map, you can access your map on the iPhone by going to &lt;a href=&quot;http://my-maps.appspot.com/&quot;&gt;http://my-maps.appspot.com/&lt;/a&gt;. This is a 3rd party solution, since Google doesn't yet offer a native solution. From here, you will be able to browse all your maps, and see all your mapped points at once in the Google Maps interface on the iPhone. Very handy.&lt;/p&gt;

&lt;p&gt;Using this, I was able to easily navigate the streets of Rome and Milan. And trust me, the streets can get very hairy, with many street names ending and starting at the most unpredictable places.&lt;/p&gt;

&lt;p&gt;Here is a list of my maps that I've created:
&lt;a href=&quot;http://maps.google.com/maps/ms?ie=UTF8&amp;hl=en&amp;msa=0&amp;msid=118207183003398270068.00048649d38d1e3091751&amp;z=11&quot;&gt;Milan&lt;/a&gt;
&lt;a href=&quot;http://maps.google.com/maps/ms?ie=UTF8&amp;hl=en&amp;msa=0&amp;msid=118207183003398270068.0004864a14be78fc5c24b&amp;z=15&quot;&gt;Florence&lt;/a&gt;
&lt;a href=&quot;http://maps.google.com/maps/ms?ie=UTF8&amp;hl=en&amp;msa=0&amp;msid=118207183003398270068.0004863108e8554f046ef&amp;z=13&quot;&gt;Bologna&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TripAdvisor&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yelp may rule the roost for reviews in the US, but &lt;a href=&quot;http://www.tripadvisor.com/&quot;&gt;TripAdvisor&lt;/a&gt; is king internationally. As always, you should take reviews with a grain of salt, but I've found TripAdvisor to be pretty reliable, especially for hotels and restaurants.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Food Books&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Okay, so these aren't digital, but if you're into food, and want to taste &lt;a href=&quot;http://jamesyu.org/2010/05/31/eating-in-italy/&quot;&gt;traditional Italian cuisine&lt;/a&gt;, I suggest taking a look at &lt;a href=&quot;http://www.amazon.com/Osterie-Locande-DItalia-Traditional-Places/dp/8884991218/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1275336378&amp;sr=8-1&quot;&gt;L'Osteria Italia&lt;/a&gt; and Fred Plotkin's &lt;a href=&quot;http://www.amazon.com/Italy-Gourmet-Traveler-Fred-Plotkin/dp/190686831X/ref=sr_1_3?ie=UTF8&amp;s=books&amp;qid=1275336432&amp;sr=1-3&quot;&gt;Italy for the Gourmet Traveler&lt;/a&gt;. Many people don't know that it's actually easy to eat &lt;em&gt;badly&lt;/em&gt; in Italy by falling into tourist traps.&lt;/p&gt;

&lt;p&gt;Understand the food, the traditions, and prepare a list of restaurant options before heading out! The last thing you want to do is to duck into a restaurant that cooks Americanized Italian food just because you were to hungry to look for anything else.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Eating in Italy</title>
   <link href="http://www.jamesyu.org/2010/05/31/eating-in-italy/"/>
   <updated>2010-05-31T00:00:00-07:00</updated>
   <id>http://www.jamesyu.org/2010/05/31/eating-in-italy</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/jamesyu/4619346593/in/set-72157624061403428/&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4059/4619346593_c5071166cf.jpg&quot;&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;I spent the last two weeks traveling through Italy, eating my way through various provinces. Along the way, I was floored by the quality of food Italians enjoy. You can &lt;a href=&quot;http://www.flickr.com/photos/jamesyu/sets/72157624061403428/&quot;&gt;check out my photoset to see a glimpse&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Eating in Italy is both liberating and intoxicating.&lt;/p&gt;

&lt;p&gt;Americans are afraid of food. We scrutinize our diets, contemplating levels of saturated fats and questioning the origins of every ingredient. Italians simply eat. And eating simply is eating better.&lt;/p&gt;

&lt;p&gt;Italian food is the most loved food in the world. Whether you're in New York or Norway, you'll find people dining on some form of spaghetti or pizza. There are three factors to the success of Italian food: freshness and locality, simplicity, and umami. Yes, I'm using a Japanese concept to describe an old world European cuisine. I'll explain soon.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Freshness and Locality&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you eat in Italy, you are eating locally. The Italians have an unparalleled level of respect for their ingredients. Each morsel of produce encountered is the best it can be.&lt;/p&gt;

&lt;p&gt;During my trip, I've tasted impossibly sweet tomatoes, deeply savory slices of prociutto, and rich creamy scoops of gelato. Each bite was bittersweet, because no matter how you slice it, Italian produce is just better than the rest of the world. The produce in California, arguably the best in America, even pales in comparison.&lt;/p&gt;

&lt;p&gt;So what's the secret? Some say it's the air, others say it's the water. Italy is just naturally the best place to grow many types of produce. Whether it's tomatoes from Napoli, milk and cream from Emilgio-Romagna cows, or olives from the Amalfi coast, Italian cuisine has an advantage even before heating up the skillet.&lt;/p&gt;

&lt;p&gt;But more important than the quality of the local ingredients is the Italian philosophy of eating fresh and local. Chefs in Italy are fiercely dedicated to using local, fresh, and in-season ingredients. Through this commitment, the foundation of Italian cuisine is firmly rooted in quality. This is the reason why simple dishes like bruschetta are sublime when the ingredients are right, and disastrously dull when they are not.&lt;/p&gt;

&lt;p&gt;Italian chefs, wherever they are, will turn to using local ingredients. One thing to remember is that even the tomato, which we strongly associate with Italian cuisine, originated from the New World. Only after pioneers brought back the plant did Italians incorporate it into their cuisine. It turns out tomatoes grow exceedingly well in the Italian climate. It's a real testament to the Italian philosophy of incorporating local ingredients that grow well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simplicity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Italian food is simple. It's an honest cuisine that let's the produce and ingredients shine. You'll be surprised to learn that a lot of Italian dishes only comprise of three or four ingredients. Bruschetta is tomatoes, olive oil, garlic and bread. Bolognese sauce is chopped root vegetables, beef, pork, and wine, slowly simmered.&lt;/p&gt;

&lt;p&gt;In the US, we like to overcomplicate Italian food. We overstuff, oversauce, and overdo classic Italian recipes. For example, a typical lasagna in the US explodes with thick layers of mozzarella, meat, sauce, and other random ingredients.&lt;/p&gt;

&lt;p&gt;In contrast, the classic Bolognese lasagna is comprised of Bolognese sauce, bechemel sauce, spinach sheet pasta, and parmesan cheese. Each layer contains a balanced and spare amount of these ingredients. Italian chefs understand that one component of a dish should not drown out all the other flavors. After tasting how delicate a lasagna could be, all the other versions I've tasted before felt heavy and overburdened.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Umami&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Italians are masters at lacing their food with umami, the delicious savory fifth taste that is associated with the presence of glutamates. This is different from MSG, which is basically artifically injecting glutamates into foods.&lt;/p&gt;

&lt;p&gt;The foundational Italian ingredients naturally contain very high levels of umami: ripe tomatoes, parmesan reggiano, prosciutto, porcini mushrooms, ragu. The aging process in parmesan reggiano in particular produces one of the highest levels of glutamates found in any naturally made ingredient. This is the reason why parmesan is a staple in pantries across the world.&lt;/p&gt;

&lt;p&gt;With this trifecta, there is no surprise that Italian food is revered, eaten, and imitated across the world. It is said that Italians, even at their poorest, eat better than the richest countries in the world.&lt;/p&gt;

&lt;p&gt;After my trip, I'm hoping to emulate as much of their philosophy as possible. You don't need to be in Italy to cook great Italian food. You just need to remember to use the freshest ingredients around you to create an honest meal. Any Italian grandmother would approve of that.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Foursquare is my Location Memory</title>
   <link href="http://www.jamesyu.org/2009/04/15/foursquare-is-my-location-memory/"/>
   <updated>2009-04-15T00:00:00-07:00</updated>
   <id>http://www.jamesyu.org/2009/04/15/foursquare-is-my-location-memory</id>
   <content type="html">&lt;p&gt;This past weekend, my credit card was declined at various venues. It turns out, there was a fraudulent charge made on my card.&lt;/p&gt;

&lt;p&gt;The problem with verifying fraudulent charges is that they make you do it over the phone. All online access to your account is locked. This can make it difficult to remember exactly which charge you made, especially if you're the kind of person who forgets the various places you've been in the past few days. A lot of context is lost.&lt;/p&gt;

&lt;p&gt;As I was on the phone, trying to remember exactly what I did, I remembered my &lt;a href=&quot;http://playfoursquare.com/&quot;&gt;foursquare&lt;/a&gt; account. Foursquare is a fun little location aware app I recently started really getting into. They make it a game to check-in online whenever you arrive at a new venue.&lt;/p&gt;

&lt;p&gt;With the &lt;a href=&quot;http://playfoursquare.com/history&quot;&gt;super secret check-in history page&lt;/a&gt;, I had in hand all the places I've been in the past few days, and could easily spot the fraudulent charges.&lt;/p&gt;

&lt;p&gt;In essence, foursquare has now become my very accurate location memory. There are definitely fun social aspects about using the service, but what I find compelling is that diligent users of location aware services like foursquare will find lots of situations where location data is a logistical gold mine.&lt;/p&gt;

&lt;p&gt;Now, if I only I can figure who's been making those big online retail purchases.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Why Table Tennis is a Great Hacker Sport</title>
   <link href="http://www.jamesyu.org/2009/01/11/why-table-tennis-is-a-great-hacker-sport/"/>
   <updated>2009-01-11T00:00:00-08:00</updated>
   <id>http://www.jamesyu.org/2009/01/11/why-table-tennis-is-a-great-hacker-sport</id>
   <content type="html">&lt;p&gt;I've recently been getting really into table tennis, a sport I've played for most of my life, but never seriously. My father taught me when I was just tall enough to reach the table, and I was hooked ever since.&lt;/p&gt;

&lt;p&gt;As I began to study table tennis (or more casually, ping pong) in depth, I realized it's one of the best sports for hackers. Here's why.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Table tennis is easy to install in any office&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Just order a table, some balls, and few paddles and you're in business. No complicated setup is necessary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Table tennis exercises the brain&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A simple game of table tennis works wonders for the reflexes and brain. The ball moves fast, and &lt;a href=&quot;http://www.nytimes.com/2008/04/05/business/05pursuits.html&quot;&gt;studies have shown that the game keeps your brain sharp&lt;/a&gt;. It's also especially refreshing to play a fast reaction after a complex coding session, and can get your mind to drift off of a problem long enough to work out the solution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Table tennis is strategy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Table tennis is one of the few sports that has a wide variety of play styles. Just like programmers have various languages to choose from, there is a multitude of table tennis playing styles. And, just like programming languages, these styles are continuously evolving. Throughout the decades, many styles of play have had their moment in the limelight.&lt;/p&gt;

&lt;p&gt;It's really up to you &lt;a href=&quot;http://en.wikipedia.org/wiki/Table_tennis_styles&quot;&gt;how you'd like to play&lt;/a&gt;. Maybe you're an aggressive player that uses the handshake grip. Or, maybe you're an attacker that uses the Japanese penhold grip, utilizing extremely fast footwork. Or, maybe you're a defensive lobber (a rare type, but perhaps you program in Haskell? Don't think lobbing works? Witness the power of the lob below.)&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;object width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/IILXzEmt9kM&amp;hl=en&amp;fs=1&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;http://www.youtube.com/v/IILXzEmt9kM&amp;hl=en&amp;fs=1&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/p&gt;


&lt;p&gt;There really is an essence of &quot;hacking&quot; in table tennis as well. Each style has particular strengths and weaknesses. Much of the challenge is to discover your opponents' weaknesses and change the way you play to exploit them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Table tennis doesn't require you to be in super tip-top shape, but it'll get you in shape&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Table tennis is an easy sport to pick up (but as the cliche goes: very difficult to master). Most importantly, for casual games, you don't need to be super athletic to play. This encourages everybody in the office to get involved, no matter how fit your are.&lt;/p&gt;

&lt;p&gt;On the flip side, the game does offer the rare chance for many hackers to exercise during the day. A game is ideal for any hacker who has been sitting in a chair for the past 4 hours. Get up and move around. A healthy hacker is a productive hacker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Table tennis is social&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A game of table tennis encourages conversations, especially if you play doubles. It's a good way to get the team together and participate in something fun and interactive after a day of staring at a lifeless screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. It's just damn fun.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go out there and get a table, &lt;a href=&quot;http://en.wikipedia.org/wiki/Table_tennis#Game_play&quot;&gt;review the rules&lt;/a&gt;, and start playing. Trust me, it'll boost productivity.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>A Guide for Your First Usability Test</title>
   <link href="http://www.jamesyu.org/2008/12/14/guide-for-your-first-usability-test/"/>
   <updated>2008-12-14T00:00:00-08:00</updated>
   <id>http://www.jamesyu.org/2008/12/14/guide-for-your-first-usability-test</id>
   <content type="html">&lt;p&gt;Usability testing is an essential tool in any product life cycle, especially at startups, where you live and die by your product. It is the most effective technique to get real user data on how they are using and assessing your product--in real life. If the product stake holders are not already bought into user testing, you need to convince them, now. Usability tests are cheap, and have the potential to save development time, money, and headaches down the road.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Determine Your &lt;a href=&quot;http://www.usability.gov/analyze/personas.html&quot;&gt;Personas&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're doing a startup, you should already have a good sense of who uses your site. Is it the normal internet user? Is it business people who are internet savvy? Is it your grandma? Make sure you pin down all the potential user personas before going any further.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Recruit Testees from Craigslist&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Depending on your location, Craigslist has a rich ecosystem of people willing to give their time for usability tests. Here is a sample text I usually post:&lt;/p&gt;

&lt;blockquote&gt;
We are a company creating an online consumer product that needs people for usability testing. The test will be no longer than 1 hour, and we'll pay you $35 for your time. Easy money!

Requirements:

&lt;em&gt;List your demographic requirements here&lt;/em&gt;

We are located at &lt;em&gt;LOCATION&lt;/em&gt;, and we'll be conducting the tests on &lt;em&gt;DATES&lt;/em&gt;. If you qualify, and are interested, please reply with the following information:

- Name
- Date and hours of availability
- How much experience you have with internet sites, specifically searching the internet
- How many hours a day you spend on the internet
- The industry in which you work 
&lt;/blockquote&gt;


&lt;p&gt;Be as specific as possible with your requirements. You can always widen them later if you don't get enough responses. In the San Francisco Bay Area, I received about 20 responses in the first day, most of them eager to help out and that fit our personas. Avoid putting any information about your company or website, as you want the testees to see your site for the first time during your test.&lt;/p&gt;

&lt;p&gt;If Craigslist isn't popular in your area, I suggest just grabbing some people from your local coffee shop. You'll be surprised by people's enthusiasm when they know they can help improve a product.&lt;/p&gt;

&lt;p&gt;For your first battery of usability tests, take two days and block out 4 hours on each day, and try to set up times with 8 people. Some of them will invariably cancel or flake out, but, that's okay, since you really &lt;a href=&quot;http://www.useit.com/alertbox/20000319.html&quot;&gt;only need about 5 people to have an effective test&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Prepare Your List of Tasks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I highly suggest picking up &lt;a href=&quot;http://www.amazon.com/gp/product/0321344758?ie=UTF8&amp;tag=buzzshout-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0321344758&quot;&gt;Don't Make Me Think&lt;/a&gt;, which is a great introduction to web usability and usability testing. It's short, and chock full of practical information.&lt;/p&gt;

&lt;p&gt;Now, write down all the user tasks that are crucial to your site. This may be the signup flow, or the upload pictures flow, or the browse profiles flow. The point is, you should be testing flows that are most important to your business objectives.&lt;/p&gt;

&lt;p&gt;Remember that testees will take much longer than expected to complete the tasks. It's easy to lose sight of this, but as the founder or member of the product team, you're an expert at using your product. Testees have &lt;strong&gt;never&lt;/strong&gt; seen your site before, and they'll have to figure it out all on the fly. Try to limit your first set of tests to 4 or 5 tasks.&lt;/p&gt;

&lt;p&gt;Your list of tasks should be derived directly from the user flows on your site. It's best for each task to have a very specific objective for the user with a plausible story behind it. For example, a task on YouTube might be: &quot;You're sitting at home relaxing with a friend, and you're looking for videos of lolcats. You land on the YouTube homepage. Now, I want you to go and find some funny cat videos.&quot; The more realistic the imagery you put into the testee's mind, the more comfortable and natural they will be at completing the task.&lt;/p&gt;

&lt;p&gt;Try as best you can to make these tasks funnel the user to do one type of action. Of course, you may not be able to avoid multiple paths--just be sure to take into account all them in your task list. In example above, the user might use the search functionality on YouTube, or, they may simply browse by category.&lt;/p&gt;

&lt;p&gt;Make a spreadsheet with each tab being a separate task, and list each step of each task on a separate row. This makes taking notes easier during the test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Download &lt;a href=&quot;http://silverbackapp.com/&quot;&gt;Silverback&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Seriously, &lt;a href=&quot;http://silverbackapp.com/&quot;&gt;Silverback&lt;/a&gt; is the easiest and slickest video and screen capturing tool for usability testing. It captures the screen while also capturing the video from iSight and puts this all into the same video on export. You'll be able to review the videos without missing a single thing the testee did during each task.&lt;/p&gt;

&lt;p&gt;At $50, it's cheap.&lt;/p&gt;

&lt;p&gt;If you're worried that Silverback is Mac only, and your application must be tested in Windows, you should be able to run Parallels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Conduct the Test&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You will need two people: one to take notes and one to direct the user to do the tasks. Here are some simple guidelines:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;Make the testee as comfortable as possible. The less comfortable they are, the less likely the user will respond realistically to your site.&lt;/li&gt;
&lt;li&gt;Many testees are nervous. Tell the testee that they are not being tested, rather, it is the product that is being tested.&lt;/li&gt;
&lt;li&gt;Ask the testee to speak out loud during the session, explaining what they are thinking at all times.&lt;/li&gt;
&lt;li&gt;When the testee first sees the site, ask them about what they think the site is. This is the best moment to get their genuine first impressions.&lt;/li&gt;
&lt;li&gt;Start off with an open ended task that allows the testee to explore the site on their own.&lt;/li&gt;
&lt;li&gt;Tell the testee to do each step of the task, but never tell the them &lt;strong&gt;how&lt;/strong&gt; to do each step. This is by far the hardest part of usability testing. Remember: you need to let the testee struggle, or else the pain points in your product won't reveal themselves. If, after about a minute or two, they still have no idea, ask them, &quot;Is there anything in particular you are looking for?&quot;. If it's a total no-go, mark the step as FAIL, and simply point to whatever the solution is and ask, &quot;What about this option/checkbox/button/etc?&quot; Note their response.&lt;/li&gt;
&lt;li&gt;When taking notes, no detail is too small. Observe everything the testee does -- did they click on the image that was not hyperlinked? Did they frown when their upload aborted without a message? Were the confused by the order of things in a dropdown menu? It's the little nuances that will tell you the problem areas in your application.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;strong&gt;6. Post Mortem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There's no point in usability testing if you don't analyze the results and make action items. Gather the team and go over the notes and videos. Everyone will probably be surprised by the number of small and big problems overlooked when designing the product.&lt;/p&gt;

&lt;p&gt;Typically, the solutions to the problems seen in usability testing are obvious and easy to implement. Be decisive and move forward quickly.&lt;/p&gt;

&lt;p&gt;I suggest doing usability tests periodically (once every few months) as you actively develop your product. Typically, there are no shortage of features and flows to test on your site, and it's best to catch usability problems early.&lt;/p&gt;

&lt;p&gt;I hope this post will encourage you to do your first usability test. A lot of people tend to dismiss conducting usability tests, saying, &quot;I know exactly what the user wants in the design.&quot; But, the fact is, in most cases, you're &lt;strong&gt;not&lt;/strong&gt; the target demographic, and your intuition about the design is vastly different than the average joe. It's much better to have empirical evidence that users are responding well to your site, rather than falling back on your own gut feeling.&lt;/p&gt;

&lt;p&gt;UPDATED 12/14/08: Thanks goes to Ron from &lt;a href=&quot;http://www.designperspectives.com/&quot;&gt;Design Perspectives&lt;/a&gt; for his awesome feedback on this post.&lt;/p&gt;
</content>
 </entry>
 
 
</feed>