<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Jaanus Kase, jaanuskase.com</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/" />
    <link rel="self" type="application/atom+xml" href="http://www.jaanuskase.com/en/atom.xml" />
   <id>tag:www.jaanuskase.com,2010:/en//1</id>
    <link rel="service.post" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1" title="Jaanus Kase, jaanuskase.com" />
    <updated>2010-03-03T07:35:03Z</updated>
    <subtitle>Advertising. Technology. Media. Usability. Skype. People. Security. Language. Culture. Government. Privacy. Ergonomics. Communication.</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.23-en</generator>
 

<entry>
    <title>Say hello to Crème, the new iPhone Twitter app</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/2010/03/say_hello_to_creme_the_new_iph.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=3840" title="Say hello to Crème, the new iPhone Twitter app" />
    <id>tag:www.jaanuskase.com,2010:/en//1.3840</id>
    
    <published>2010-03-03T07:27:36Z</published>
    <updated>2010-03-03T07:35:03Z</updated>
    
    <summary>A few weeks back, I was searching for closed beta testers. The app was fairly well developed by then, but the beta was immensely useful in clarifying some interaction approaches and ironing out the final bugs. The app is now...</summary>
    <author>
        <name>Jaanus</name>
        <uri>http://www.jaanuskase.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jaanuskase.com/en/">
        <![CDATA[<p>A few weeks back, I was searching for <a href="http://www.jaanuskase.com/en/2010/02/come_join_the_closed_beta_for.html">closed beta testers</a>. The app was fairly well developed by then, but the beta was immensely useful in clarifying some interaction approaches and ironing out the final bugs.</p>

<p>The app is now done and has been submitted to the app store. So, say hello to Crème, the new iPhone Twitter app. See more info at <a href="http://cremeapp.com">cremeapp.com.</a></p>

<p>There&#8217;s so much more to post. I&#8217;m really happy that the project is done now, I think it came out quite well. But, of course, a lot of the features are missing still, and I&#8217;m already planning next versions.</p>

<p>For now, you can check out <a href="http://cremeapp.com">cremeapp.com</a> for some nice screenshots and feature overview, and <a href="http://twitter.com/cremeapp">follow @cremeapp</a> to hear more about when it will be available on the App Store.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Come join the closed beta for my iPhone Twitter client</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/2010/02/come_join_the_closed_beta_for.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=3838" title="Come join the closed beta for my iPhone Twitter client" />
    <id>tag:www.jaanuskase.com,2010:/en//1.3838</id>
    
    <published>2010-02-13T06:01:16Z</published>
    <updated>2010-02-15T04:00:08Z</updated>
    
    <summary>[ Update: wow, I got great response. So, if you haven&#8217;t responded already, then&#8230; you may still contact me, but I may add you in a later round. Or just direct you to the app store for the complete version...</summary>
    <author>
        <name>Jaanus</name>
        <uri>http://www.jaanuskase.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jaanuskase.com/en/">
        <![CDATA[<p><em>[ Update: wow, I got great response. So, if you haven&#8217;t responded already, then&#8230; you may still contact me, but I may add you in a later round. Or just direct you to the app store for the complete version soon. <img src="http://download.skype.com/share/emoticons/0100-smile.png" alt=":)" /> Thanks to all who have responded thus far. ]</em></p>

<p>For some nights and weekends, I&#8217;ve been working on a yet unnamed/unbranded iPhone Twitter client app. I&#8217;ve looked at all the existing ones and I think I have some new things to contribute to the scene in terms of the UI, interaction and the overall experience.</p>

<p>I&#8217;m now starting a closed/private beta. To join, you need to have an iPhone (vanilla and jailbroken are both fine) and use Twitter at any level. You also need to have some imagination and patience because parts of the software are still broken or need some work. But, the app is not just a raw piece of rock any more. You can see the outline of the final thing, it&#8217;s starting to shape up and just needs lots of sandpaper&#8212;and your help, both in terms of technical testing and UI/interaction feedback. The goals of the test are to get to a good place with the technical quality of the app, and make sure the interaction is solid.</p>

<p>If you&#8217;re interested, contact me through some private channel (email, Skype chat) this weekend (Feb 13-14&#8230; happy Valentine <img src="http://download.skype.com/share/emoticons/0100-smile.png" alt=":)" /> ) to get set up. We&#8217;re going to use Google Wave (remember? Wave? Not Buzz. Wave.) as the collaboration tool. If you haven&#8217;t used Wave before, it will be an interesting experience from that perspective too.</p>

<p>Your main benefit will be participating in the test with me and a fun bunch of other people, and witnessing the app coming together. The final app will sell for a few dollars, and all the testers will get it for free. There&#8217;s no other material compensation. The beer, though, will be on me the next time we meet.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>An example iPhone Twitter app with OAuth authentication</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/2010/01/an_example_iphone_twitter_app.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=3837" title="An example iPhone Twitter app with OAuth authentication" />
    <id>tag:www.jaanuskase.com,2010:/en//1.3837</id>
    
    <published>2010-01-18T03:10:28Z</published>
    <updated>2010-01-18T03:22:37Z</updated>
    
    <summary>As a companion to my post on how OAuth works with Twitter, I thought I&#8217;d write another OAuth client for my own needs. There are several OAuth Objective-C libraries out there, and I am using some code from one of...</summary>
    <author>
        <name>Jaanus</name>
        <uri>http://www.jaanuskase.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jaanuskase.com/en/">
        <![CDATA[<p>As a companion to <a href="http://www.jaanuskase.com/en/2010/01/understanding_the_guts_of_twit.html">my post on how OAuth works with Twitter</a>, I thought I&#8217;d write another OAuth client for my own needs. There are several OAuth Objective-C libraries out there, and I am using some code from one of them, <a href="http://code.google.com/p/oauthconsumer/">OAuthConsumer</a>. But I did not like that the libraries overload existing classes like NSURL or some Twitter libraries. I like to put my app together of fairly loosely coupled pieces, and the OAuth piece should only do OAuth, and not much else. So, I wrote my own.</p>

<h2>Get it</h2>

<p><a href="http://github.com/jaanus/PlainOAuth">Get it from GitHub.</a></p>
]]>
        <![CDATA[<h2>Example iPhone app</h2>

<p>As part of the example, I also put together a very simple iPhone app that just lets you sign in to OAuth with Twitter and lets you post an update. I tried to showcase how logging in works, and how to handle things like user deauthorizing your app etc in a reasonable way.</p>

<p>The focus of this app is much more on the architecture than the UI; the UI is just the simplest I could put together to accomplish the purpose.</p>

<p>Here is the screenshot walkthrough.</p>

<p><img alt="Picture 5 twtr iphone.png" src="http://www.jaanuskase.com/en/Picture%205%20twtr%20iphone.png" width="414" height="770"  /></p>

<p><img alt="Picture 6 twtr iphone.png" src="http://www.jaanuskase.com/en/Picture%206%20twtr%20iphone.png" width="414" height="770"  /></p>

<p><img alt="Picture 7 twtr iphone.png" src="http://www.jaanuskase.com/en/Picture%207%20twtr%20iphone.png" width="414" height="770"  /></p>

<p><img alt="Picture 8 twtr iphone.png" src="http://www.jaanuskase.com/en/Picture%208%20twtr%20iphone.png" width="414" height="770"  /></p>

<p><img alt="Picture 8 twtr iphone plus.png" src="http://www.jaanuskase.com/en/Picture%208%20twtr%20iphone%20plus.png" width="414"  /></p>

<p><img alt="Picture 9 twtr iphone.png" src="http://www.jaanuskase.com/en/Picture%209%20twtr%20iphone.png" width="414" height="770"  /></p>

<p><img alt="Picture 10 twtr iphone.png" src="http://www.jaanuskase.com/en/Picture%2010%20twtr%20iphone.png" width="414" height="770"  /></p>

<p><img alt="Picture 11 twtr iphone.png" src="http://www.jaanuskase.com/en/Picture%2011%20twtr%20iphone.png" width="414" height="770" /></p>

<p>It is not great that the user goes away from the app and to the browser. But, I could not imagine how to fit the viewable PIN, PIN entry field and keyboard into the UI in a reasonable way, so I did not even try.</p>

<p>It wouldn&#8217;t be so bad if the PIN could be copy-pasted in a reasonable way. But, since the PIN is seven digits, iPhone tries to  be helpful and thinks that it is a phone number. By tapping on it, it lets you call the PIN, but not copy it. (It actually is possible to copy if you play around with your finger.)</p>

<p>I don&#8217;t know what would be a good experience. Can Twitter construct some mini-PIN display that still works for a UIWebView within an app? Or can they provide an iPhone-optimized web UI for /authorize and/or just disable the phone number recognition (not sure if you can do it by some WebKit smartness)? Sending user off to browser is surely the cleanest solution from the security perspective, as you don&#8217;t capture their credentials within the context of your app.</p>
]]>
    </content>
</entry>

<entry>
    <title>Understanding the guts of Twitter&apos;s OAuth for client apps</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/2010/01/understanding_the_guts_of_twit.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=3836" title="Understanding the guts of Twitter's OAuth for client apps" />
    <id>tag:www.jaanuskase.com,2010:/en//1.3836</id>
    
    <published>2010-01-18T02:53:16Z</published>
    <updated>2010-01-18T03:20:46Z</updated>
    
    <summary>In November 2009 at Web 2.0 Expo in New York, someone from Twitter said that they will be phasing out Basic Authentication for their API in favor of OAuth some time in 2010. (This may or may not be 100%...</summary>
    <author>
        <name>Jaanus</name>
        <uri>http://www.jaanuskase.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jaanuskase.com/en/">
        <![CDATA[<p>In November 2009 at Web 2.0 Expo in New York, someone from Twitter said that they will be phasing out Basic Authentication for their API in favor of OAuth some time in 2010. (This may or may not be 100% correct; I remember reading/seeing this but could not find the reference.) But regardless of what exactly they said, it is clear that they are moving towards OAuth, as are many other providers.</p>

<p>So, I decided the time has come for me to learn more about OAuth, and specifically how to work with Twitter API using it, instead of HTTP Basic Authentication. I found some shortcomings in existing docs and thought to write a post.</p>

<p>This post is for you if you:</p>

<ul>
<li>know how HTTP works on a general level: e.g you know what&#8217;s a request header.</li>
<li>kinda sorta know what OAuth is and does even if you haven&#8217;t developed for it before; if not, read e.g <a href="http://en.wikipedia.org/wiki/OAuth">Wikipedia</a> or <a href="http://hueniverse.com/oauth/">Beginner&#8217;s Guide to OAuth</a>.</li>
<li>want to understand how the protocol works for client apps on the barebones/wire level, instead of just using a client library.</li>
</ul>
]]>
        <![CDATA[<h2>Starting with existing docs</h2>

<p>Let&#8217;s see what resources there are today to learn about OAuth:</p>

<ul>
<li><a href="http://hueniverse.com/oauth/">Beginner&#8217;s Guide to OAuth</a></li>
<li><a href="http://www.slideshare.net/Blaine/oauth-presentation">Blaine Cook&#8217;s presentation</a></li>
<li><a href="http://apiwiki.twitter.com/OAuth-FAQ">Twitter API wiki OAuth FAQ</a> and <a href="http://apiwiki.twitter.com/Authentication">authentication guide</a></li>
<li><a href="http://oauth.net/core/1.0a/">oauth.net spec 1.0a</a> and <a href="http://tools.ietf.org/html/draft-hammer-oauth-08">the RFC draft (newer than spec)</a></li>
</ul>

<p>Some of these were somewhat helpful, but there wasn&#8217;t one single guide that satisfied me. The RFC is probably the most accurate as reference material, but it is very dense and hard to parse/follow if you are starting out. Terminology has also changed over time, and the RFC points out the mapping between &#8220;old&#8221; and &#8220;new&#8221; terms.</p>

<p>What I find most helpful when working with a new HTTP-based protocol is to examine what &#8220;goes on the wire&#8221; and what comes back. There are some examples in the above, but they are not one coherent story. The examples are also generic, and not specific to Twitter, which is what I was interested in. So here we go&#8230; an introductory OAuth session in three (+1) steps.</p>

<h2>0. Register your app with Twitter</h2>

<p>Go to <a href="http://twitter.com/oauth_clients">Twitter OAuth clients</a> and register your app. Select &#8220;Client&#8221; as the app type. You will get two very important pieces of information: &#8220;consumer key&#8221; and &#8220;consumer secret.&#8221; You will use them below. RFC calls these &#8220;client credentials.&#8221; (Confused about terminology yet?)</p>

<h2>1. Request temporary credentials from Twitter</h2>

<p>You will now issue a HTTP GET request to the following URL:</p>

<pre><code>https://twitter.com/oauth/request_token
</code></pre>

<p>(Twitter actually uses HTTP throughout the examples on their site, but HTTPS is better for security and works fine.)</p>

<p>It is a simple GET request, but as part of it, you include the following HTTP header:</p>

<pre><code>Authorization: OAuth realm="", oauth_nonce="92673243246",
oauth_timestamp="12642432725", oauth_consumer_key="9874239869",
oauth_signature_method="HMAC-SHA1", oauth_version="1.0",
oauth_signature="l%2FXBqib2y423432LCYwby3kCk%3D"
</code></pre>

<p>Whoa. What?</p>

<p>Yes, that&#8217;s basically how OAuth works. It is otherwise like simple HTTP, but you just include this special header in all your requests. (It should all be one line, it has linebreaks above just for readability.) So. Let&#8217;s talk about this header. (There are other ways to do this besides the header, but RFC section 3.5 says header is preferred anyway, so we will just use the header.)</p>

<p>You see it has a bunch of fields. Here&#8217;s what they should be:</p>

<ul>
<li>realm: &#8220;&#8221; is fine for Twitter</li>
<li>oauth_nonce: a unique value. I myself use sha1(timestamp || str(random)), i.e current timestamp concatenated with a random string. Anything should be fine as long as it is unique string. Keep it alphanumeric or hex for simplicity.</li>
<li>oauth_timestamp: current UNIX timestamp, seconds since epoch (Jan 1 1970).</li>
<li>oauth_consumer_key: what you got from Twitter.</li>
<li>oauth_signature_method: just use HMAC-SHA1. There are other methods, but I won&#8217;t talk about them.</li>
<li>oauth_version: just use &#8220;1.0.&#8221;</li>
<li>oauth_signature: this is a signature calculated across a set of fields in a very specific way, so let&#8217;s talk about that.</li>
</ul>

<h3>OAuth signature and the signature base string</h3>

<p>OAuth headers need to include a signature. It is calculated thus:</p>

<pre><code>signature = base64(hmac-sha1(signature_base_string, signature_key))
</code></pre>

<p>So, there is some hmac-sha1 function that takes two things as input: a base string and a key. It signs the base string with the key and returns a signature. The output value must be base64-encoded. Treat these functions as black boxes, just find a hmac-sha1 and base64 implementation and use those, they are standard.</p>

<p>Let&#8217;s talk about the key first. The key is defined thus (&#8220;||&#8221; means concatenation):</p>

<pre><code>signature_key = consumer_secret || "&amp;" || token_secret
</code></pre>

<p>&#8220;But I don&#8217;t have a token_secret by this point?&#8221; Correct, you don&#8217;t. So if the consumer secret was &#8220;abcd&#8221;, your signature key in this stage is &#8220;abcd&amp;&#8221;.</p>

<p>Now, let&#8217;s talk about the base string. Here is an example base string.</p>

<pre><code>GET&amp;https%3A%2F%2Ftwitter.com%2Foauth%2Frequest_token&amp;oauth_consumer_key
%3D1rB94WF54ayRvryLQIZ01A%26oauth_nonce%3D92676946%26
oauth_signature_method%3DHMAC-SHA1%26
oauth_timestamp%3D1263777725%26oauth_version%3D1.0
</code></pre>

<p>Again, it should all be one long string without linebreaks.</p>

<p>The algorithm to calculate the signature base string is:</p>

<pre><code>signature_base_string = HTTP_METHOD || "&amp;" || urlencode(normalized_url)
    || "&amp;" || urlencode(parameters_string)
parameters_string = join(sorted_urlencoded_parameter_keypairs, '&amp;')
</code></pre>

<p>In English:</p>

<ol>
<li>Take the request parameter keypairs. These are your GET or POST key/value pairs. We don&#8217;t have any in this first example. In addition, you have a set of core fields that are included, which you can see above.</li>
<li>Sort the keypairs alphabetically by key, merge them into a big string &#8220;key1=value1&amp;key2=value2&#8221;, where the keys and values are URL-encoded. (RFC specifies a specific method of URL-encoding; see <a href="http://tools.ietf.org/html/draft-hammer-oauth-08#section-3.6">section 3.6</a>.)</li>
<li>Construct the base string by merging the HTTP method, normalized URL, and URL-encoded whole parameter string into the base string. This means that for some parameter keys/values, you will see double URL-encoding: first the individual value was encoded, and then the result got encoded again due to the whole parameter string being encoded.</li>
</ol>

<p>OK&#8230; so, let&#8217;s go back to where we were. We have managed to construct a signature base string, and have signed it. We have put together the OAuth Authorization header. We fired off the GET request. At this point, one of two things will happen.</p>

<p>First, you may get a &#8220;401 Not Authorized&#8221; response from Twitter. It is helpful to examine the response body for more detail. It will say something like &#8220;Invalid signature&#8221; or &#8220;Invalid / expired nonce.&#8221; Use this knowledge to fix what you were doing. I had lots of trouble to get the base string and signature calculation right. Don&#8217;t forget that the signature key always contains &#8220;&amp;&#8221;. And Twitter really does make sure that nonces are not reused: if you send the same correctly constructed request twice with the same nonce, then the first one will be successful, but the second one will fail.</p>

<p>Let&#8217;s say you did everything correctly. In this case, you will get a 200 OK, and the response body will be:</p>

<pre><code>oauth_token=lLUrf57ghMfIt24173AgJiSUHjTbT
EdNRqOqQFz5Pk&amp;oauth_token_secret=5K60EOjryJVtiC
NkwoEteTQkGhMkrwFsEMs&amp;oauth_callback_confirmed=true
</code></pre>

<p>Aha! Now we are getting somewhere. Capture and save the oauth_token and oauth_token_secret values; you&#8217;ll need them soon. Disregard oauth_callback_confirmed; since you are a client app, there are no callbacks.</p>

<h2>1.5 Redirecting user to obtain the PIN</h2>

<p>Next, you need to redirect the user to this URL in their browsers:</p>

<pre><code>https://twitter.com/oauth/authorize?oauth_token=Bo2bmtiydaKScpMqzIsEWuZuG2x8
</code></pre>

<p>Where the token value is, of course, the one that you got from Twitter just a second ago.</p>

<p>The users will then go through these screens:</p>

<p><img alt="Picture 3.png" src="http://www.jaanuskase.com/en/Picture%203.png" width="500" height="321" /></p>

<p><img alt="Picture 4 twtr.png" src="http://www.jaanuskase.com/en/Picture%204%20twtr.png" width="500" height="321" /></p>

<p>They will come back to your app with the PIN, and will expect to input or copypaste it somewhere. Let&#8217;s see what happens after they do that.</p>

<h2>2. Obtaining an access token from Twitter</h2>

<p>You now have your consumer key and secret, token and token secret (which are temporary by this point), and the PIN that the user input (in the spec terms this is &#8220;verifier&#8221;). You now make the following HTTP GET request:</p>

<pre><code>https://twitter.com/oauth/access_token
</code></pre>

<p>The header should be something like:</p>

<pre><code>Authorization: OAuth realm="", oauth_nonce="926534246",
oauth_timestamp="1890725", oauth_consumer_key="9874239869",
oauth_signature_method="HMAC-SHA1", oauth_version="1.0",
oauth_signature="l%2FXBqib2y422LCYwby3kCk%3D",
oauth_token="31242343232", oauth_verifier="8689612"
</code></pre>

<p>The signature base string is something like:</p>

<pre><code>GET&amp;https%3A%2F%2Ftwitter.com%2Foauth%2Faccess_token&amp;
oauth_consumer_key%3D1rB94WF54ayRvryLQIZ01A%26oauth_nonce%3D
86345093%26oauth_signature_method%3DHMAC-SHA1%26
oauth_timestamp%3D1263780501%26oauth_token%3D
Bo2d2oZewAyOHstF5bmtiydaKScpMqzIsEWuZuG2x8%26
oauth_verifier%3D2383255%26oauth_version%3D1.0
</code></pre>

<p>This is actually very similar to what we did above. Only three changes:</p>

<ul>
<li>The URL is https://twitter.com/oauth/access_token.</li>
<li>The header and base string contain two new parameters, oauth_verifier (user-entered PIN) and oauth_token (what you got from Twitter as response to previous request).</li>
<li>Remember how signature key is calculated: signature_key = consumer_secret || &#8220;&amp;&#8221; || token_secret. You had both of these by this point, so the key was something like &#8220;abc123&amp;456cde.&#8221;</li>
</ul>

<p>(The <a href="http://apiwiki.twitter.com/Twitter-REST-API-Method:-oauth-access_token">Twitter API wiki</a> says that the method for this call should be POST. I am not sure why, but as empirically shown, GET works just fine.)</p>

<p>The outcome is one of two things. Either &#8220;401 Not Authorized,&#8221; in which case it is again time to debug. But if all is well, Twitter responds with 200 OK and the following body:</p>

<pre><code>oauth_token=103393708-XKheKolp4P775W8Ejr1DQ
Z82AciwFOicaRg6hw1Y&amp;oauth_token_secret=vRaADq6
v7vUZ90fisaIF2jqJZW29pKVS8vLKMUb
f3k&amp;user_id=103393708&amp;screen_name=exampleuser
</code></pre>

<p>Cool! If you get by this point, you have done the bulk of the work and are pretty much done. As you see, we got four things back from Twitter:</p>

<ul>
<li>user_id and screen_name. These are the identifiers for the user who signed in. Note that you haven&#8217;t actually asked the user for anything in your app; you just get the userid and screenname like this back from Twitter. You can now save and use them.</li>
<li>oauth_token and oauth_token_secret. Here is the confusing part: these parameters are called the same as they were before, but they mean an entirely different thing. These are now AUTHORIZED, which means that you will now use these to make further requests. Throw away the previous oauth_token and secret, and keep these new ones. In RFC terms, these are &#8220;access token and secret.&#8221;</li>
</ul>

<h2>3. Making further requests</h2>

<p>You would do the above steps only once per user in your app. They would authenticate once, and then forget about it. Now you will continue to make Twitter API requests. Let&#8217;s look at a simple example of updating status. Say you POST to this URL:</p>

<pre><code>https://twitter.com/statuses/update.json
</code></pre>

<p>And your post body (parameters encoded in a standard way) is:</p>

<pre><code>status=hello+world
</code></pre>

<p>Your header would be:</p>

<pre><code>Authorization: OAuth realm="", oauth_nonce="926534246",
oauth_timestamp="1890345", oauth_consumer_key="9874239869",
oauth_signature_method="HMAC-SHA1", oauth_version="1.0",
oauth_signature="l%2FXBqib242y422LCYwby3kCk%3D",
oauth_token="31242343232", status="hello%20world"
</code></pre>

<p>And the signature base string would be:</p>

<pre><code>POST&amp;https%3A%2F%2Ftwitter.com%2F1%2Fstatuses
%2Fupdate.json&amp;oauth_consumer_key%3D1rB7654ayRvr
yLQIZ01A%26oauth_nonce%3D45586507%26oauth_
signature_method%3DHMAC-SHA1%26oauth_
timestamp%3D1263781497%26oauth_token%3D1033
93708-XKheKolp4P775W8Ejr4234246hw1Y%26o
auth_version%3D1.0%26status%3Dhello%2520world
</code></pre>

<p>Note the new &#8220;status&#8221; field, and how it may be differently encoded in the POST body and in the signature base string. It is in the end since the keys were alphabetically sorted.</p>

<p>Phew&#8230; that&#8217;s it.</p>

<h2>A note on debugging</h2>

<p>The above may be difficult to debug in your client app. One strategy that I found extremely helpful was to use curl. Here is how you would do the curl request for the above status update example:</p>

<pre><code>curl -v -X POST -H 'Authorization: OAuth realm=""
oauth_nonce=... etc' -d "status=hello world"
https://twitter.com/statuses/update.json
</code></pre>

<p>So, in your client app, you would generate this header, but not actually run the request. Remember that nonces need to be unique; you can only run the request once with the same nonce value; changing it arbitrarily would invalidate the signature. So, just generate and print the header from your client app, and try to curl it, and see what you get back. The -v flag ensures you see plenty of debug info.</p>

<h2>Acknowledgements</h2>

<p><a href="http://github.com/joshthecoder/tweepy">Tweepy</a> is a great Twitter API implementation in Python. I used it to debug the protocol, just inserting print statements in relevant places, letting me trace what went on the wire and what came back.</p>

<h2>See also</h2>

<p><a href="http://www.jaanuskase.com/en/2010/01/an_example_iphone_twitter_app.html">Here&#8217;s another post</a> about my OAuth implementation in Objective-C that also has an example iPhone app.</p>
]]>
    </content>
</entry>

<entry>
    <title>My bad iPhone 3GS purchasing experience</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/2010/01/my_bad_iphone_3gs_purchasing_e.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=3835" title="My bad iPhone 3GS purchasing experience" />
    <id>tag:www.jaanuskase.com,2010:/en//1.3835</id>
    
    <published>2010-01-06T04:03:28Z</published>
    <updated>2010-01-06T04:04:03Z</updated>
    
    <summary>Today, I thought I&#8217;ll buy an iPhone 3GS. I somehow broke the headphone connector on my old one, and it was annoyingly slow. I like the new features too, like better camera. So, why not. First, I went to a...</summary>
    <author>
        <name>Jaanus</name>
        <uri>http://www.jaanuskase.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jaanuskase.com/en/">
        <![CDATA[<p>Today, I thought I&#8217;ll buy an iPhone 3GS. I somehow broke the headphone connector on my old one, and it was annoyingly slow. I like the new features too, like better camera. So, why not.</p>

<p>First, I went to a nearby AT&amp;T store. They had the phone, but they said I can only buy it with AppleCare. (Rushing ahead, the Apple Store people told me this is a lie.) But I didn&#8217;t feel like arguing with them, so I went to Apple Store instead.</p>
]]>
        <![CDATA[<p>There, I first had to go through some sort of pre-activation on the computer, and then we were almost done&#8230; or so I thought. Not so fast. The sales people brought me a phone and activated it, but the phone remained in the &#8220;activating, no service, please wait&#8221; state.</p>

<p>Managers of various capacity came by to look. They thought maybe the SIM in the phone is bad, so they exchanged the phone for a new one. Same thing. Everybody was very friendly, but obviously distressed at the same time because me and them had to put up with AT&amp;T not activating the phone in a timely manner.</p>

<p>They said that maybe something is up with my service plan and I should go to AT&amp;T to check it out since it is a network-related issue. (Reminds me of a &#8220;Mac vs PC&#8221; ad where the PC is calling various help lines in vain.) Luckily, there was an AT&amp;T store nearby&#8230; except that it would close in a few minutes. But I made it in time.</p>

<p>The AT&amp;T people were upset with the Apple People who had sent me to AT&amp;T with a phone that says &#8220;no service.&#8221; This shouldn&#8217;t happen, they figured. Maybe.</p>

<p>AT&amp;T gave me a new SIM and one of the more competent people looked at their computers and said there is a &#8220;network delay&#8221; of 2 hours. Whatever that means. They said that I could just go home and my phone with the new SIM would be activated later. Which is true. But then again, the first 3GS that I bought would probably have woken up the same way.</p>

<p>So, the final verdict is that there was some AT&amp;T network delay that gave me and Apple Store people a bad iPhone 3GS buying/selling experience.</p>

<p>On a side note, the Apple Store retail staff always used to have some sort of custom PDA for mobile sales processing. Today I saw that they have replaced it with iPod Touch in a custom enclosure that contains barcode and credit card readers. Dogfood, eh. I mentioned this to the salesperson and he said he was very happy about the Touch and the sales app. Which indeed looked pretty slick.</p>
]]>
    </content>
</entry>

<entry>
    <title>Twitter read/unread state, campaigns, and priority contacts</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/2009/12/twitter_readunread_state_campa.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=3832" title="Twitter read/unread state, campaigns, and priority contacts" />
    <id>tag:www.jaanuskase.com,2009:/en//1.3832</id>
    
    <published>2009-12-01T21:24:36Z</published>
    <updated>2009-12-02T03:17:42Z</updated>
    
    <summary>Twitter is interesting because it is a new protocol. In connection with that, I&#8217;ve recently thought about three things that illustrate the questions it goes through as it grows. Maintaining read/unread state (Mentioned it previously, but it was so low...</summary>
    <author>
        <name>Jaanus</name>
        <uri>http://www.jaanuskase.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jaanuskase.com/en/">
        <![CDATA[<p>Twitter is interesting because <a href="http://ycombinator.com/rfs3.html">it is a new protocol</a>. In connection with that, I&#8217;ve recently thought about three things that illustrate the questions it goes through as it grows.</p>

<h2>Maintaining read/unread state</h2>

<p>(<a href="http://www.jaanuskase.com/en/2009/11/on_google_wave_and_how_skype_c.html">Mentioned it previously</a>, but it was so low nobody got to it, hence this new post.)</p>

<p>&#8230; or, more precisely, this is about maintaining &#8220;last read&#8221; position in your Twitter stream. I don&#8217;t think people will want to selectively mark stuff read and unread as you&#8217;d do with, say, email. But it is important to keep a pointer to what I&#8217;ve seen, so that it would be easy for me to tell the new stuff from old.</p>

<p>(Aside: read/unread would be one way to mark stuff as &#8220;to read later.&#8221; Currently, some people <a href="http://twitter.com/ppmotskula/status/5657313930">use favorites for this.</a> Not a bad idea. But neither favorites nor read/unread are really for this purpose. Maybe we need something yet new&#8230;)</p>

<p>Currently, clients do this on their own, but do not share this data. For example, Tweetie exists on both my desktop and iPhone, but I still see the same messages twice. Nevermind other clients or Twitter.com itself.</p>

<p>One solution would be to create a third-party site to offer this as a service to clients. I don&#8217;t know what their business would be, but you can imagine clients sharing this data. And it can be with or without authentication. With, it&#8217;s secure but annoying. Without, you could find some downsides in privacy, but you could package the data up and offer it to the community. Who reads what and when? Is this sort of metadata privacy-intrusive? I don&#8217;t know. I myself wouldn&#8217;t care. (If I was more agile, I&#8217;d have the service running by now, it&#8217;s a few simple calls&#8230; basically setLastRead(user,lastReadId) and getLastRead(user) and that&#8217;s it.)</p>

<p>But really, this should be part of Twitter API, similarly to how your IMAP email, Skype Chat and Google Wave can keep track of what you&#8217;ve seen and what&#8217;s new.</p>
]]>
        <![CDATA[<h2>Product vs platform</h2>

<p><a href="http://blog.twitter.com/2009/12/aids-is-preventable-and-treatable.html">Today&#8217;s campaign</a> was interesting. Some tweets are shown red on Twitter.com based on certain criteria, but this does not come through to any clients.</p>

<p>This illustrates the tension between Twitter being an end-user product and a platform. As a product, you can promote any cause you want. As a platform, you should be content-neutral and removed from any such activities. Furthermore, you should be predictable and not repurpose users&#8217; content in ways that are not agreed upon. Maybe I am all against the red color, why are you forcing it upon me? Maybe I was using #red hashtag as &#8220;Rocket Engine Designers&#8221; and don&#8217;t care about your initiative?</p>

<h2>Priority contacts</h2>

<p><a href="http://share.skype.com/sites/en/2009/11/how_the_internet_makes_intimac.html">Here&#8217;s a great video.</a> Currently, Twitter contact lists are flat. If you&#8217;re like me with a few hundred contacts, you miss a lot of the activity. And for some of it, it&#8217;s OK: some people are more entertainment/ephemeral value and it&#8217;s OK to not see everything. For some, though, I really care about what they have to say, and would like to prioritize them to always come through. Current Twitter API typically gives you 200 messages at a time: I&#8217;d like to tune it so that I&#8217;d rather miss some tweets from the ephemeral people than be shown everything.</p>

<p>You could repurpose lists so that you could make a special list with your priority contacts, but here&#8217;s the thing: I don&#8217;t want my priority contacts to be public. This would reveal connections and interests beyond what I care to disclose.</p>

<p>This sounds like something that could start as a client feature and later graduate to the API if it&#8217;s really valuable. Hmh, where&#8217;s that pet project of mine&#8230; everybody must have their own Twitter client, right?</p>
]]>
    </content>
</entry>

<entry>
    <title>Why you shouldn&apos;t trust Google Wave: it&apos;s broken</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/2009/11/why_you_shouldnt_trust_google.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=3830" title="Why you shouldn't trust Google Wave: it's broken" />
    <id>tag:www.jaanuskase.com,2009:/en//1.3830</id>
    
    <published>2009-11-27T06:10:40Z</published>
    <updated>2009-11-27T06:23:54Z</updated>
    
    <summary>I couldn&#8217;t fit this in the post about Skype Chat vs Google Wave, so here&#8217;s my biggest gripe with Wave. It has many UI flaws, but those are just minor glitches that I can live with. The biggest flaw is...</summary>
    <author>
        <name>Jaanus</name>
        <uri>http://www.jaanuskase.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jaanuskase.com/en/">
        <![CDATA[<p>I couldn&#8217;t fit this in the <a href="http://www.jaanuskase.com/en/2009/11/on_google_wave_and_how_skype_c.html">post about Skype Chat vs Google Wave</a>, so here&#8217;s my biggest gripe with Wave.</p>

<p>It has many UI flaws, but those are just minor glitches that I can live with. The biggest flaw is that some Waves can simply break. There&#8217;s one in particular where some member attempted to do something with a plugin. After that &#8220;something&#8221;, the wave is simply BROKEN for EVERYONE and the content is inaccessible. When we try to access the Wave, everyone gets this message:</p>

<p><a href="http://www.jaanuskase.com/en/Picture%201.png"><img alt="Picture 1.png" src="http://www.jaanuskase.com/en/assets_c/2009/11/Picture 1-thumb-500x59-175.png" width="500" height="59" /></a></p>

<p>This is data loss, and not acceptable. (Yes, I have submitted a response and reloaded many times.) So, my approach is that you cannot yet trust Google Wave and better be careful what you put there. I will change this when they either fix a wave or explain that this is an irrecoverable problem and how they make sure it won&#8217;t happen again. Until then, watch out with your waves.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>On Google Wave, and how we made Skype Chat</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/2009/11/on_google_wave_and_how_skype_c.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=3829" title="On Google Wave, and how we made Skype Chat" />
    <id>tag:www.jaanuskase.com,2009:/en//1.3829</id>
    
    <published>2009-11-27T06:07:54Z</published>
    <updated>2009-11-27T16:23:35Z</updated>
    
    <summary>Google Wave looked interesting when it was first presented. I was looking forward to getting on to it. And I was intrigued by the actual interface when I got the invite a few months ago. I was intrigued because it...</summary>
    <author>
        <name>Jaanus</name>
        <uri>http://www.jaanuskase.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jaanuskase.com/en/">
        <![CDATA[<p>Google Wave looked interesting when it was first presented. I was looking forward to getting on to it. And I was intrigued by the actual interface when I got the invite a few months ago.</p>

<p>I was intrigued because it was a déjà vu from five years ago to me. It was the time when I was challenged with leading the effort to <a href="http://www.jaanuskase.com/works/skype-group-chat/">design Skype chat</a> to support multiple people. I now thought a five year anniversary is fitting to document this part of Internet history. And furthermore, enough time has gone by to make sure that this doesn&#8217;t contain any proprietary info or doesn&#8217;t hurt anybody. A lot has changed with Skype chat and conversations, and I mostly wasn&#8217;t a part of the later changes. I can&#8217;t really explain the more recent work. I can only discuss how it came to be.</p>

<p>So, it was somewhere in 2004 and Skype realized they need to revamp their text chat/conversation system. Skype actually had one from the very beginning, but it was one-to-one and not very nice. It did support the basic concept of queueing messages that is extensively used today as well; that is, you could write a message to someone regardless of whether they were online or not, and it would be delivered the next time you would both be online. True to Skype&#8217;s serverless architecture, the message would simply be queued in your computer.</p>
]]>
        <![CDATA[<p>That was nice, but not enough. We needed to support multiple people, as was evidenced by our own itch of using Jabber for internal work conversations until chat came to be. It did an OK, but not great, job. It set a bar for us to cross.</p>

<p>I was tasked with leading the project, and I take credit for the most important interaction design decisions, right or wrong. I actually consider Skype Chat my most important interaction design work to date of everything that I have done, though I didn&#8217;t know what I was doing was called interaction design. We called it just &#8220;project management.&#8221; I had great help, though, from <a href="http://kika.trip.ee">Kristjan</a>, <a href="http://www.zilmer.com">Priidu</a>, <a href="http://www.mare.ee/indrek/">Indrek</a> and other Skype staff, who we spent a lot of time with at the whiteboard, arguing through things.</p>

<p>Here are some of the most important questions and decisions we went through. This is reconstructed from memory, and is all years old, so forgive me for possible occasional misrepresentation, and fix it in comments.</p>

<h2>What is the goal?</h2>

<p>It was somewhat similar to Wave. We set out to &#8220;fix the email problem&#8221;, and provide a convenient group collaboration tool that would first and foremost support our own organization of many adhoc groups coming and going, but being fairly limited in size (the first chat size limit was 50 people I think, later boosted to 150). We looked at SMS, IRC, email, Jabber groupchat, Internet chatrooms, and other modes of such communication available at the time.</p>

<p>We were more limited in scope that Wave, though, since we didn&#8217;t try to solve the communication and document problems together. What Wave is trying to do is to say that the same &#8220;room&#8221; can serve as both discussion and document. The jury is still out there whether this works. At Skype, we limited our approach to only consider communication, and not really look at the document/wiki aspect. We figured we&#8217;d solve the document aspect by providing a convenient file transfer capability integrated with the chat.</p>

<h2>What&#8217;s the content model vis-a-vis people coming and going? What happens when you close the window?</h2>

<p>This was the most important question to me. Is it synchronous or asynchronous? Is it like email, where you get everything delivered at the time of your choosing? Or is it like IRC, where you only get the stuff that happened while you were connected with your client, and miss out on the rest? (Nevermind that there are now IRC log-bots that capture and share everything, as that is a different experience from actually participating.)</p>

<p>I chose to make chats persistent because that is how teams work in an organization. A team tends to be consistent over time, and it is in the interest of the team that everybody is constantly filled in and knows the same information. So, closing the chat window in the GUI should not disconnect you from the chat. Neither should turning off your computer and later turning it on again; you should still get all the messages. More on this below in &#8220;multiple devices.&#8221;</p>

<p>If closing a window keeps you in a chat, what does this mean for alerts if you get a new message? How about if you minimized a window? What notifications will you get? I don&#8217;t remember all the details, but we spent some time to generate quite an elaborate alert policy. Today, if you look at the alerts/notifications in your Skype preferences, you&#8217;ll find all the settings there.</p>

<p>But if closing the window does not take you away from the chat, how do you actually exit one? Or are you stuck in all your chats forever? No, you are not. We just made &#8220;leave chat&#8221; an explicit user action. There&#8217;s a button for it.</p>

<h2>Are chats public or invite-only? How do you get in a chat and what do you see then?</h2>

<p>I spoke about leaving a chat, but how about getting to a chat in the first place? We made chats private and invite-only. The only way for you to get in a chat was if someone added you to it. That could happen in two ways: either you started a 1:1 chat and expanded it to multiple people later, or you explicitly started a chat with multiple people. I don&#8217;t have data, but I&#8217;m quite sure that &#8220;1:1 first, expand later&#8221; is 99.9% of the use.</p>

<p>If you are added to a chat, do you see the whole history or only from that point onwards? I decided that each member sees only what&#8217;s posted during the time that they are a member of a chat. Again, this was to support our own use, but it also just feels more natural to eliminate historic cruft. You may be added to a team chat that may be two years old. What they spoke a while back may be irrelevant to you, and they may actively not want you to see it. If it&#8217;s important, someone will copypaste you the relevant parts of earlier discussion. I made it this way because it resembles how human groups naturally work.</p>

<p>Note that this is a major difference from Wave. If you are added to a Wave, you see everything from the beginning of times, and can play it back bit for bit, seeing all the edits. I&#8217;m not saying it&#8217;s wrong, and it definitely has its advantages in their wiki/document model. Time will tell how it works out.</p>

<p>Aside: later, there were public chats in Skype. And even in private chats, there&#8217;s a permission scheme so some people can kick others out under some conditions. But I won&#8217;t write about it because I&#8217;m not sure what&#8217;s the status or future of public chats, and the permissions are complex. We borrowed some functions from IRC: type &#8220;/help&#8221; to see the commands, including permission-related, that are available to you in any Skype chat.</p>

<h2>How will multiple devices/computers work?</h2>

<p>This was a very interesting question, and we diverged from what most of the popular IM systems did at the time. In client-server-based systems like MSN, AIM, Yahoo Messenger, ICQ etc, only one client per username could be connected at the time. If you connected with AIM from computer A, and then from computer B, computer A got disconnected at the moment you connected from B. I don&#8217;t know why that was the common practice in the industry. Maybe it was about message routing complexity, or security, or who knows what.</p>

<p>Skype&#8217;s architecture, though, was more complex than simple client-server. Everybody was a client and a server at the same time. What would &#8220;one client at a time&#8221; even mean? It would have created more problems than it would have solved. So, we realized that what were dealing with was not a messaging problem, but more of a distributed database problem. And through some brilliant engineering by <a href="http://www.mare.ee/indrek/">Indrek</a>, we created a system based on &#8220;synchronizing&#8221;. That is, each device signed in with a particular username has a local database of all chats, and when (re)connected to the Skype network, synchronizes the chats with the &#8220;Skype cloud&#8221;, posting messages created locally, and retrieves new ones from the cloud.</p>

<p>It sounds complex, and it is. Initially it was quite buggy, but over time, I think it has worked remarkably well. I myself use Skype across multiple devices and overall it works really great. I absolutely think it was the right decision as I could foresee Skype being used across multiple computers and other devices. Extrapolate this approach to the iPhone version and you see what I mean.</p>

<p>I have not looked at Wave protocol guts, but it feels that our design and implementation was/is fairly similar to the gist of Wave federation, except that Wave is more complex, spanning multiple servers, networks and who knows what else. But all in all, you have a collection of waves, and in those, you post messages locally and retrieve remote ones, and it works quite nicely already today, e.g across multiple browsers.</p>

<p>One important thing that Skype and Wave do right, but that&#8217;s completely broken in Twitter, is the distribution of metadata, and in particular read/unread states. In Skype, we synchronize not only message content, but also the read/unread state, and Wave does the same. But in Twitter, it highly annoys me that there is no facility to synchronize read/unread state, and I have to read the same tweets ten times across different clients and devices.</p>

<p>Interestingly, email can work using both models. The &#8220;old MSN/AIM etc&#8221; is POP3 where content is downloaded to client and deleted from cloud, and the new Skype/Wave model is IMAP. (Though these days, probably very few people use POP3 or realize the difference.)</p>

<div class="splitter"></div>

<p>So there; that&#8217;s some of the thinking that went into Skype Chat that continues to serve the global Skype community. I&#8217;m extremely proud of it and as I said, it&#8217;s one of my most important works to date. I don&#8217;t know what&#8217;s next for it; I do know that Skype&#8217;s &#8220;conversations&#8221; pitch that they practiced around Windows version 4 has much of the same goals that Wave tries to achieve, with perhaps voice and video other added goodies. We&#8217;ll see what comes next.</p>
]]>
    </content>
</entry>

<entry>
    <title>Why I like Flash Catalyst more than Expression Blend for interactive wireframe prototyping</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/2009/11/why_i_like_flash_catalyst_more.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=3828" title="Why I like Flash Catalyst more than Expression Blend for interactive wireframe prototyping" />
    <id>tag:www.jaanuskase.com,2009:/en//1.3828</id>
    
    <published>2009-11-24T02:47:07Z</published>
    <updated>2009-11-24T03:05:32Z</updated>
    
    <summary>I sometimes build &#8220;interactive wireframes.&#8221; These are screens that you can click through, to explore main parts of navigation in some app. And you could also construct them in higher fidelity to get a feel for the final app, before...</summary>
    <author>
        <name>Jaanus</name>
        <uri>http://www.jaanuskase.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jaanuskase.com/en/">
        <![CDATA[<p>I sometimes build &#8220;interactive wireframes.&#8221; These are screens that you can click through, to explore main parts of navigation in some app. And you could also construct them in higher fidelity to get a feel for the final app, before actually engineering it.</p>

<p>Two previous players on the market were <a href="http://www.irise.com">iRise</a> and <a href="http://www.axure.com/">Axure</a>, but I didn&#8217;t need it so much that I would have cared to invest in them. But recently Microsoft and Adobe have entered this market with <a href="http://www.microsoft.com/expression/products/Blend_Overview.aspx">Expression Blend</a> and <a href="http://labs.adobe.com/technologies/flashcatalyst/">Flash Catalyst</a>.</p>
]]>
        <![CDATA[<p>I know EB and FC are not 100% equivalent products, but they are roughly in the same space for the purposes of this post, which is, creating interactive prototypes. Flex may be familiar to some; EB is roughly the same tool as Flex (with better prototyping capabilities), whereas FC is more focused on interaction design and one layer above Flex. It still builds Flex applications in the end and if you want, you can monkey around in Flex code if you know what you are doing, <a href="http://forums.adobe.com/thread/484695">like I needed to do</a>.</p>

<p>I have used Flash Catalyst to build a medium-complexity prototype, but I can&#8217;t post it here, sorry, proprietary. But I did do a very simple example project which illustrates why I like FC more. I made a very dumb project in both: an application that has two views. And in the first view, there is a button; click the button, and a transition happens to the second view. As simple as can be, but plenty to get your feet wet in the tool.</p>

<p>Here are the screenshots of developing this application in Expression Blend/Sketchflow, and Flash Catalyst.</p>

<p><a href="http://www.jaanuskase.com/en/Capture.PNG"><img alt="Capture.PNG" src="http://www.jaanuskase.com/en/assets_c/2009/11/Capture-thumb-500x399-171.png" width="500" height="399"  /></a></p>

<p><a href="http://www.jaanuskase.com/en/Picture%204.png"><img alt="Picture 4.png" src="http://www.jaanuskase.com/en/assets_c/2009/11/Picture 4-thumb-500x301-173.png" width="500" height="301"  /></a></p>

<p>My first reaction to the EB view was &#8220;whoa, what exploded here?&#8221; Look at all these controls. I am sure they are all useful and necessary, but all these controls feel like I had accidentally detonated something and they just flew all over the screen. Somewhat difficult to get around. See also <a href="http://www.brandonwalkin.com/blog/2009/08/10/managing-ui-complexity/">Brandon Walkin from a while ago about managing complexity, especially the &#8220;Alignment &amp; Visual Hierarchy&#8221; section.</a></p>

<p>Flash Catalyst feels much more welcoming. Granted, some of the functions don&#8217;t work that well since the product is not even out of beta yet; for example, text engine needs improvements (although it has got better in beta 2, compared to beta 1). But even with all these missing things, I feel much more welcome in Catalyst. It is a more focused tool and I feel it is easy to get around.</p>

<p>This is definitely unscientific and biased. I have used Adobe tools much more than Microsoft Expression, so maybe I am just used to them. And I do not know how well these tools fare for complex prototypes; it may very well be that EB can handle complex things better. This is just my first run impression.</p>
]]>
    </content>
</entry>

<entry>
    <title>New Apple Store in NYC Upper West Side</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/2009/11/new_apple_store_in_nyc_upper_w.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=3827" title="New Apple Store in NYC Upper West Side" />
    <id>tag:www.jaanuskase.com,2009:/en//1.3827</id>
    
    <published>2009-11-15T04:57:47Z</published>
    <updated>2009-11-15T05:05:48Z</updated>
    
    <summary>I went to the new Apple store opening. Made it there around 10:15am, saw a few hundred people in line. Not a big fan of standing in line, so I went across the street to kill a few hours by...</summary>
    <author>
        <name>Jaanus</name>
        <uri>http://www.jaanuskase.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jaanuskase.com/en/">
        <![CDATA[<p>I went to the <a href="http://www.apple.com/retail/upperwestside/">new Apple store</a> opening. Made it there around 10:15am, saw a few hundred people in line.</p>

<p><a href="http://www.flickr.com/photos/jaanus/4105066112/" title="PB140010 by Jaanus1, on Flickr"><img src="http://farm3.static.flickr.com/2506/4105066112_6d83b26e1b.jpg" width="500" height="375" alt="PB140010" /></a></p>

<p><a href="http://www.flickr.com/photos/jaanus/4104303979/" title="PB140021 by Jaanus1, on Flickr"><img src="http://farm3.static.flickr.com/2734/4104303979_b92b262455.jpg" width="500" height="375" alt="PB140021" /></a></p>

<p>Not a big fan of standing in line, so I went across the street to kill a few hours by seeing a movie instead. (&#8220;2012.&#8221; Don&#8217;t go. Terrible.) Came back, the line was gone, got in. Crowded, but shoppable.</p>

<p>I really like the first floor. It&#8217;s unusually high for a retail place. Feels more like an art gallery or something. You don&#8217;t see the ceiling on these pics.</p>

<p><a href="http://www.flickr.com/photos/jaanus/4104304591/" title="PB140026 by Jaanus1, on Flickr"><img src="http://farm3.static.flickr.com/2676/4104304591_a8b02eab8a.jpg" width="500" height="375" alt="PB140026" /></a></p>

<p><a href="http://www.flickr.com/photos/jaanus/4105070520/" title="PB140028 by Jaanus1, on Flickr"><img src="http://farm3.static.flickr.com/2539/4105070520_e5da36e6fb.jpg" width="500" height="375" alt="PB140028" /></a></p>

<p><a href="http://www.flickr.com/photos/jaanus/4104305905/" title="PB140029 by Jaanus1, on Flickr"><img src="http://farm3.static.flickr.com/2746/4104305905_41a7c9cdcc.jpg" width="500" height="375" alt="PB140029" /></a></p>

<p>From the outside, it&#8217;s less impressive than 5th Ave, no cube or such. But the inside is really quite something.</p>

<p>Lower floor is blah, simple Apple shopping, same as other stores.</p>

<p><a href="http://www.flickr.com/photos/jaanus/sets/72157622805255664/">More pictures.</a></p>
]]>
        

    </content>
</entry>

<entry>
    <title>A new face to this site</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/2009/11/a_new_face_to_this_site.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=3826" title="A new face to this site" />
    <id>tag:www.jaanuskase.com,2009:/en//1.3826</id>
    
    <published>2009-11-10T01:45:28Z</published>
    <updated>2009-11-10T01:49:15Z</updated>
    
    <summary>If you&#8217;re following me over RSS, come check out the site. I just published my new design. The old design was just about two years old now. I needed a refreshment, and some parts were just plain ugly. There was...</summary>
    <author>
        <name>Jaanus</name>
        <uri>http://www.jaanuskase.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jaanuskase.com/en/">
        <![CDATA[<p>If you&#8217;re following me over RSS, come check out <a href="http://www.jaanuskase.com/">the site</a>. I just published my new design.</p>

<p>The old design was just about two years old now. I needed a refreshment, and some parts were just plain ugly. There was also too much clutter in the sidebar. Many thanks to <a href="http://zilmer.com/">Priidu</a> who helped me with some ideas and nudging along the way.</p>

<h3>Content changes</h3>

<p>Along with the new layout, I also published information about two projects that haven&#8217;t been out there yet.</p>

<p>First, <a href="http://www.jaanuskase.com/works/skype-group-chat/">Skype group chat</a>. I take credit for largely designing its behavior in 2004, just about five years ago. I didn&#8217;t know at the time that I was doing interaction design, but that&#8217;s exactly what it was. It was interesting to revisit this experience, in light of Google Wave and all these new things. As an example, we did an interface where elements appear and disappear based on mouse hover. I see the same behavior in iTunes 9 for song preview playing. I&#8217;m not saying there is a connection between the two, but it&#8217;s interesting to see how such interface concepts mature and evolve across products.</p>
]]>
        <![CDATA[<p>Second, the <a href="http://www.jaanuskase.com/works/restroom-status-indicator/">restroom status indicator</a>. I did this about a year ago, to explore how to bridge my two interests of electronics and UI technology. The outcome was pretty neat, I hope to do more of such hardware prototyping projects.</p>

<h3>Comments</h3>

<p>One thing that also changed is the comment system on this site. I am now using <a href="http://www.disqus.com">Disqus</a> instead of Movable Type built in features. THey have better features, and my own comments were a pain to maintain well. The old comments may or may not be migrated.</p>

<p>Comment system switching illustrate the evolution of identity and content on the Internet for me. On one hand, you could argue that anything that&#8217;s been put up should remain there forever. On the other hand, things have a lifecycle. They are born, they live, and they die. I don&#8217;t have an expectation that my comments will be up there forever, and neither do I guarantee anything to you if you are posting on my site. It may remain, or it may not.</p>

<p>Disappearing content? Or even disappearing identities? It used to sound terrible to me until I saw <a href="http://www.zephoria.org">danah boyd&#8217;s</a> writeup on teen IM identities. Can&#8217;t locate the exact post, but her point was that whereas adult identities in the form of IM, email addresses etc tend to be fairly stable, some teenagers tend to often switch to new identities on IM systems and just completely abandon the old ones, and that&#8217;s perfectly normal for them.</p>

<p>Commenting should now be much more convenient here than it used to be. You can do it anonymously or reuse any of your existing identities. Leave me a note if you find something broken.</p>
]]>
    </content>
</entry>

<entry>
    <title>Apple TV, games, and iPhone</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/2009/11/apple_tv_games_and_iphone.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=3341" title="Apple TV, games, and iPhone" />
    <id>tag:www.jaanuskase.com,2009:/en//1.3341</id>
    
    <published>2009-11-03T17:14:54Z</published>
    <updated>2009-11-03T17:24:12Z</updated>
    
    <summary>Here&#8217;s a piece on Apple TV. Interesting bit: &#8230; there&#8217;s no way you&#8217;re going to have games where the input is a little five-button Apple Remote, or anything else connected by IR. Apple already has a great gaming controller. It...</summary>
    <author>
        <name>Jaanus</name>
        <uri>http://www.jaanuskase.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jaanuskase.com/en/">
        <![CDATA[<p><a href="http://daringfireball.net/2009/10/regarding_apple_tv">Here&#8217;s a piece on Apple TV.</a> Interesting bit:</p>

<blockquote>
  <p>&#8230; there&#8217;s no way you&#8217;re going to have games where the input is a little five-button Apple Remote, or anything else connected by IR.</p>
</blockquote>

<p>Apple already has a great gaming controller. It is called iPhone. Granted, the hardware is not as spectacular as Xbox and PS3 controllers with vibration, analog thumbsticks etc, but there is something to be said about the benefits of having a full reconfigurable touch surface for gaming. Imagine games with pinch and other multitouch gestures. I have played many games on the iPhone and it really exceeds my expectations as a gaming platform. You should not dismiss touch-based gaming until you&#8217;ve tried. I recommend Assassin&#8217;s Creed, but why not also Flight Control and other such staples.</p>

<p>So, let&#8217;s imagine that we use iPhone as controller for games that you buy on iTunes and push to your Apple TV. I can&#8217;t see anything broken with this model. It would just need one &#8220;controller app&#8221; for iPhone, that could be game-specific or generic, maybe to the point of expanding the already existing Remote app.</p>

<p>Let&#8217;s also push this further and imagine games that work on Apple TV as well as iPhone; games that keep you immersed regardless of your environment. Until now, most games are bound to a platform, but you can imagine a rich experience like Sims where the story continues on your TV when you are home, and iPhone when you are on the move. Obviously the content and angle need to be a bit different due to screen size, direct vs indirect manipulation etc, but again, there&#8217;s something worthwhile in this model.</p>

<p>With the later example, you wouldn&#8217;t even need a new app store. You could keep buying games on your iPhone as you do today, and some of those could simply be expanded if you have an Apple TV.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Fixing the iPhone&apos;s Springboard with groups</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/2009/10/fixing_the_iphones_springboard.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=3340" title="Fixing the iPhone's Springboard with groups" />
    <id>tag:www.jaanuskase.com,2009:/en//1.3340</id>
    
    <published>2009-10-22T02:48:58Z</published>
    <updated>2009-10-22T22:55:17Z</updated>
    
    <summary>There have been some interesting posts recently about the iPhone &#8220;Springboard&#8221;. I don&#8217;t know if that&#8217;s the official name, but in any case, it&#8217;s the &#8220;home&#8221; function of iPhone that lets you page through apps and launch them. I can...</summary>
    <author>
        <name>Jaanus</name>
        <uri>http://www.jaanuskase.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jaanuskase.com/en/">
        <![CDATA[<p>There have been some <a href="http://www.asktog.com/columns/080Springboard.html">interesting</a> <a href="http://userexperience.evantageconsulting.com/2009/10/aesthetics-interaction-iphone-home-screen-redesign/">posts</a> recently about the iPhone &#8220;Springboard&#8221;. I don&#8217;t know if that&#8217;s the official name, but in any case, it&#8217;s the &#8220;home&#8221; function of iPhone that lets you page through apps and launch them.</p>

<p>I can identify with the problem; I have 7 screens worth of apps and I page through them constantly. But I think the solutions proposed in the above two posts are too complicated, and I agree with Fred about why Tog&#8217;s #1-#3 solutions are not good.</p>

<p>My solution is very simple, and is around containers. We simply need containers for apps. I don&#8217;t know if they are &#8220;folders&#8221; or &#8220;playlists&#8221; or &#8220;groups&#8221;, well, let&#8217;s call them &#8220;groups&#8221; for now. iPhone tries very hard to hide the file system from the user, even though they have a complete one inside. But Apple has many groups all around the iPhone and OS X that I would call &#8220;domain-specific containers&#8221;. These would be playlists in iTunes, Events etc in iPhoto, Groups in iCal&#8230; i.e not general-purpose folders, but hierarchies for the purpose of organizing items in a particular domain. iPhone App groups fit here well.</p>
]]>
        <![CDATA[<p>So, how would this work? Here&#8217;s a simple lo-fi wireframe.</p>

<p><a href="http://www.jaanuskase.com/en/springboard.png"><img alt="springboard.png" src="http://www.jaanuskase.com/en/assets_c/2009/10/springboard-thumb-500x426-169.png" width="500" height="426"/></a></p>

<p>On the left, you see a regular iPhone view. On the right is what you see when you tap on a Group.</p>

<p>You&#8217;ll see that the four über-apps have disappeared. This is because when you are already in the context of a group, you don&#8217;t care about those; you only care about this group. </p>

<h3>Why is this a superior solution?</h3>

<p>It keeps everything about the Springboard that we already have. You still have pages, you move apps around exactly the same way, you can still search for them, you still have the four &#8220;über-apps&#8221; that are always visible etc.</p>

<p>Unlike Fred&#8217;s and Tog&#8217;s solutions that require a computer to manage them, these groups are fully manageable on the go without a computer. This is important, since I know many people (and also myself) who don&#8217;t connect the phone to the computer for an extended period of time.</p>

<p>Furthermore, managing apps is something that you do when you get the urge. Apple recognized that buying apps also falls in this category, which is why they let you buy, delete and do everything with the apps on the phone without a computer. So you have a bunch of apps and you look at them on your phone and suddenly decide &#8220;hmm, I would like these three to be in a group&#8221;. Being able to do it right then and there is superior to having to remember (or rather, forget) this for a later time when you have access to a computer.</p>

<p>The group interface is not limited to 16 apps. Similarly to Documents and Downloads stacks on OS X dock, it can change its appearance based on the number of apps: if it&#8217;s greater than 16, switch to table/list view, where the amount of apps can be endless with live filtering. (Another option: keep the magic number at 12, and keep the four über-apps in the bottom.)</p>

<h3>Scenarios</h3>

<p>Here are the things you can do.</p>

<p><strong>Moving an app to group.</strong> Just tap and hold like today, until you see apps and groups wiggle. Drag and drop an app on to a group. It goes there.</p>

<p><strong>Moving an app to parent group/back to master springboard.</strong> Tap and hold on an app while looking at a group, and either just drop it in the &#8220;Back&#8221; button; or, the &#8220;wiggle&#8221; version of Back button could be something that is more obviously a (bigger) drop target.</p>

<p><strong>Moving groups around.</strong> Fully same as apps today. Put them onto the &#8220;quick launch&#8221; zone if there is room etc.</p>

<p><strong>Creating subgroups.</strong> I don&#8217;t see it as necessary. But all the above scales for nested groups as well. Apple does not have playlists within playlists, events within events etc for a reason.</p>

<p><strong>Deleting a group.</strong> Just tap and hold for &#8220;wiggle mode&#8221;, hit the X icon in the corner of the group, and tap it. And then see some explosion animation that removes the groups and explodes the apps back to springboard.</p>

<p><strong>Move many apps to a group.</strong> See above; if you put more than X apps in a group, the group stops looking like a mini-Springboard and instead switches to table/list view. (Or, maybe a group can have multiple pages in it.)</p>

<p><strong>Creating shortcuts, one app in multiple groups.</strong> This is Tog&#8217;s #5. On one hand, shortcuts are too abstract on a filesystem level; on the other, they seem to work in domain-specific groups (iTunes playlists, iPhoto albums). I can&#8217;t think of a good way to manage this on the device, but surely you can do it in iTunes, similarly to playlists.</p>

<h3>Creating a group</h3>

<p>The only thing missing from the above is, how do you actually create a group? (Leaving aside iTunes on computer where you could do it in many ways, let&#8217;s focus only on the device for now.) Well, let&#8217;s say you are looking at an empty space on your Springboard where you&#8217;d like to see a group. So, you just tap and hold (which currently does nothing on empty space) and you get an interface for naming a group, and you name it, and voila, you have it.</p>

<p>If Apple wants to do multiple things with this gesture, they could introduce indirection through choices. I.e</p>

<ol>
<li>tap and hold on empty space</li>
<li>select &#8220;Create Group&#8221; from among the options</li>
<li>Name group</li>
<li>Done.</li>
</ol>
]]>
    </content>
</entry>

<entry>
    <title>Bank of America misses an opportunity to market online banking at its branches</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/2009/10/bank_of_america_misses_an_oppo.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=3337" title="Bank of America misses an opportunity to market online banking at its branches" />
    <id>tag:www.jaanuskase.com,2009:/en//1.3337</id>
    
    <published>2009-10-03T19:32:04Z</published>
    <updated>2009-10-03T19:32:48Z</updated>
    
    <summary>Sometimes I wire money from my Bank of America account to another country. It used to be that you had to fill a paper form at their branch to do this. A few months ago, I went to their branch...</summary>
    <author>
        <name>Jaanus</name>
        <uri>http://www.jaanuskase.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jaanuskase.com/en/">
        <![CDATA[<p>Sometimes I wire money from my Bank of America account to another country. It used to be that you had to fill a paper form at their branch to do this. A few months ago, I went to their branch and was turned away, saying that I should use their online banking to do this. Which failed&#8212;the online bank did not recognize a valid IBAN account number, so I had to go back to the office and still use the paper form.</p>

<p>Now this week, I needed to do the same. I went to my local branch and was again turned away. I insisted that I want to use their paper form because I am sick of nonworking systems, and I had seen the system not working before. But the representative told me that the system had been fixed since I last tried, and I should give it a shot. And in case I had problems, I should call the online support and they had a &#8220;dedicated team&#8221; on standby for international wire problems.</p>

<p>This was quite annoying. I am already at the office, and you are a human being. Why do you force me to go away and try a system which may or may not work, and then navigate your stupid phone system (which has a billion numbers to begin with, I don&#8217;t know which one I should call in the first place) and sit on hold for a long time to reach some person who probably isn&#8217;t empowered to do anything anyway?</p>
]]>
        <![CDATA[<p>&#8220;Well,&#8221; I said. &#8220;You have computers here at the bank branch. Could I use them for online banking to make the said transfer and see that the system works right here and now?&#8221;</p>

<p>Turns out this is forbidden. Computers are only for staff. Which to me translates to a missed opportunity. If you are trying so hard to market online banking, why not set up a computer at your branches so people could come and give it a shot right then and there, and get some basic assistance? You have computers already, setting up another one does not cost anything. And having your staff instruct people in online banking could translate to many customers turning to it.</p>

<p>Many people are less tech-savvy than me and would really appreciate this small push, instead of being driven away from the branch with a bunch of paper instructions in their hand and being forced to face online banking the first time for themselves.</p>

<p>Estonian banks are similarly big on Internet banking, but they get this right. At each bank branch in Estonia, no matter which brand, there is at least one computer set up for customer use. And if you are new to online banking, the staff is always willing to walk you through it, so that you are more confident when you leave the branch and can then use it on your own.</p>

<p>The wire transfer system had been fixed and did indeed work when I tried it later on my own. But it would have been nice to try it out right then and there at the branch, so I wouldn&#8217;t have left the branch and the staff in an annoyed state of mind.</p>
]]>
    </content>
</entry>

<entry>
    <title>Apple and Linux share the same design philosophy</title>
    <link rel="alternate" type="text/html" href="http://www.jaanuskase.com/en/2009/08/apple_and_linux_share_the_same.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.jaanuskase.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=3328" title="Apple and Linux share the same design philosophy" />
    <id>tag:www.jaanuskase.com,2009:/en//1.3328</id>
    
    <published>2009-08-23T01:43:54Z</published>
    <updated>2009-08-23T01:50:15Z</updated>
    
    <summary>I know. It sounds crazy. But hear me out. One of my favorite Master&#8217;s professors, Bonnie John, said: If there&#8217;s one thing you want to take away from your main course and your whole education, then it&#8217;s this: THE USER...</summary>
    <author>
        <name>Jaanus</name>
        <uri>http://www.jaanuskase.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.jaanuskase.com/en/">
        <![CDATA[<p>I know. It sounds crazy. But hear me out.</p>

<p>One of my favorite Master&#8217;s professors, <a href="http://www.cs.cmu.edu/~bej/">Bonnie John</a>, said:</p>

<blockquote>
  <p>If there&#8217;s one thing you want to take away from your main course and your whole education, then it&#8217;s this: THE USER IS NOT LIKE ME.</p>
</blockquote>

<p>In other words (my paraphrase): the designer is an impartial bystander who has no personal stake in the product. Their job is to study the user, their needs and their desires, and then make design decisions based on what they witnessed, while still standing aside.</p>
]]>
        <![CDATA[<p>Now, let&#8217;s compare it to what Apple and Linux say. I know, these two are antithetical. But I argue that they are antithetical not because of the philosophy, but simply because the nature of the products that they make. Linux makes &#8220;backend&#8221; stuff, while Apple makes &#8220;user-facing&#8221;/&#8221;frontend&#8221; stuff. So, they do not compete. And their philosophy is similar. Allow me to present:</p>

<p>For Apple, I refer to the <a href="http://money.cnn.com/galleries/2008/fortune/0803/gallery.jobsqna.fortune/2.html">Steve Jobs interview in Fortune:</a></p>

<blockquote>
  <p>We did iTunes because we all love music. We made what we thought was the best jukebox in iTunes. Then we all wanted to carry our whole music libraries around with us. The team worked really hard. And the reason that they worked so hard is because we all wanted one. You know? I mean, the first few hundred customers were us. &#8230; We figure out what we want. And I think we&#8217;re pretty good at having the right discipline to think through whether a lot of other people are going to want it, too.</p>
</blockquote>

<p>Now, I am sure that this is a sugar-coated version of what happens in practice. I have been in big software organizations and I KNOW that reality is more complex than that. But the complexity is just details. The above is still the guiding force.</p>

<p>As for Linux, I refer to <a href="http://en.wikipedia.org/wiki/Eric_S._Raymond">ESR&#8217;s</a> famous The Cathedral and The Bazaar:</p>

<blockquote>
  <p><a href="http://catb.org/esr/writings/cathedral-bazaar/cathedral-bazaar/ar01s02.html">Every good work of software starts by scratching a developer&#8217;s personal itch.</a></p>
</blockquote>

<p>See what I mean? I will make a rough cut and say that Apple people develop frontend and Linux folks develop backend. But what unites them is that they both have a personal vested interest that the software succeeds, because they personally care about it. Which is opposed to the view of &#8220;professional designer&#8221; and &#8220;the user is not like me&#8221;.</p>

<p>In many Apple job ads, you need to show that not only are you good at design, but that you also have the domain knowledge. In other words, if you want to design Pro Music apps, you must actually know a thing or two about music and be able to play an instrument.</p>

<p>Can a designer make good design decisions and build a brilliant product design if they are not the users? And approach it purely at a professional level, vs being the target group and having a vested interest? I think the best products are still built if you have a personal vested interest and you care. The rest is &#8220;industrial&#8221;: industry-standard and boring.</p>

<p>What do you think?</p>
]]>
    </content>
</entry>

</feed> 

