<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>bdunagan &#187; design</title>
	<atom:link href="http://www.bdunagan.com/category/design/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.bdunagan.com</link>
	<description>fill the void</description>
	<lastBuildDate>Thu, 15 Dec 2011 14:04:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Design Iterations for Dollar Clock</title>
		<link>http://www.bdunagan.com/2011/08/04/design-iterations-for-dollar-clock/</link>
		<comments>http://www.bdunagan.com/2011/08/04/design-iterations-for-dollar-clock/#comments</comments>
		<pubDate>Thu, 04 Aug 2011 09:25:46 +0000</pubDate>
		<dc:creator>bdunagan</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[dollar clock]]></category>

		<guid isPermaLink="false">http://www.bdunagan.com/?p=1313</guid>
		<description><![CDATA[I shipped Dollar Clock 1.0 more than a year ago as an experiment. I wanted to submit an app to the App Store, and my friend and I came up with tracking how much money meetings waste. To date, the free app has had several thousand downloads on iPhone and iPad, a moderate success for [...]]]></description>
			<content:encoded><![CDATA[<p>
I shipped <a href="http://www.bdunagan.com/2010/04/11/time-is-money-quantify-wasted-meetings-with-dollar-clock/">Dollar Clock 1.0</a> more than a year ago as an experiment. I wanted to submit an app to the App Store, and my friend and I came up with tracking how much money meetings waste. To date, the free app has had several thousand downloads on iPhone and iPad, a moderate success for a mediocre side project with no marketing.
</p>
<h3>1.0: Simple and Lame</h3>
<p>
The first iteration of the app was simple. That was my design goal: really simple. There were only two views: the money counting and the settings. I limited input to two pickers for people and average salary. I designed the input this way to force the user to estimate the numbers, rather than be exact. I wanted people to use the app to estimate meeting waste.
</p>
<p><img src="http://bdunagan.com/files/dollar.clock.v1.png"/></p>
<p>
The app was simple but lame. It lacked personality. Just look at it. I&#8217;m bored already. I even shipped 2.0 and 3.0, and both were such lackluster releases that I don&#8217;t remember what they included. Something about iPad support and VGA support, I think. And that&#8217;s my point. Even the developer didn&#8217;t care about the app.
</p>
<h3>4.0: Snarky and Deeper</h3>
<p>
Recently, I decided Dollar Clock needed some love. The app needed a personality. What goes with a depressing clock counting monetary waste? Interesting images and uplifting messages.
</p>
<p><img src="http://bdunagan.com/files/dollar.clock.v2.png"/></p>
<p>
I gave the app a voice. It iterates through a set of Flickr photos, each with a number of messages associated. Here are a couple examples:
</p>
<ul>
<li>You&#8217;re not special. Neither is this meeting.</li>
<li>Does someone have the notes from the pre-meeting?</li>
<li>More people make meetings less effective. Leave. It&#8217;ll help.</li>
</ul>
<p>
Furthermore, I was wrong about input. The most common request for the app is more customization for salary input. My original problem with this was complexity. I didn&#8217;t want to make the salary input hard, for people to use or for me to code. But I like this new version. People click the &#8220;Add Salary&#8221; row. They can type in number for people and a salary and save it. It&#8217;s just another salary row. Simple but flexible.
</p>
<p><img src="http://bdunagan.com/files/dollar.clock.v2.settings.png"/></p>
<p>
Dollar Clock is available on Apple&#8217;s App Store, free for iPhone and iPad. Try it out! Let me know what you think.
</p>
<p><a href="http://bit.ly/dollarclock"><img src="http://bdunagan.com/files/appstore.png"/></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.bdunagan.com/2011/08/04/design-iterations-for-dollar-clock/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>blog.data.visualize()</title>
		<link>http://www.bdunagan.com/2011/06/25/blog-data-visualize/</link>
		<comments>http://www.bdunagan.com/2011/06/25/blog-data-visualize/#comments</comments>
		<pubDate>Sat, 25 Jun 2011 19:06:24 +0000</pubDate>
		<dc:creator>bdunagan</dc:creator>
				<category><![CDATA[data]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[development]]></category>

		<guid isPermaLink="false">http://www.bdunagan.com/?p=1422</guid>
		<description><![CDATA[This blog&#8217;s sidebar got a little fancier today: sparklines! Inspired by infosthetics&#8217;s google adsense sparklines post, I&#8217;ve added a couple interesting streams of data to the sidebar, both from this website and from my iOS App Store apps. Sparklines are an excellent visualization for conveying a large amount of information in a small space. Here&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>
This blog&#8217;s sidebar got a little fancier today: sparklines!
</p>
<p><img src="http://bdunagan.com/files/sidebar.sparklines.png"/></p>
<p>
Inspired by <a href="http://infosthetics.com/archives/2006/05/google_adsense_sparklines_visualization.html">infosthetics&#8217;s google adsense sparklines post</a>, I&#8217;ve added a couple interesting streams of data to the sidebar, both from this website and from my iOS App Store apps. <a href="http://www.edwardtufte.com/bboard/q-and-a-fetch-msg?msg_id=0001OR">Sparklines</a> are an excellent visualization for conveying a large amount of information in a small space. Here&#8217;s what I display now:
</p>
<ul>
<li>site: bdunagan.com blog visits per day (Google Analytics)</li>
<li>rml: Remind Me Later downloads per day (Appfigures)</li>
<li>dc: Dollar Clock downloads per day (Appfigures)</li>
</ul>
<p>
I&#8217;ll walk through how I get the data from those sources into sparklines on my blog.
</p>
<h3>Getting the Data</h3>
<p>
First, I needed to get the data from its original location to my blog&#8217;s server, in a form Javascript could easily find and read. Using Ruby, I extract the data from its service and then write it in JSON to a local file on my web hosting server.
</p>
<p>
The site data comes from <a href="http://www.google.com/analytics/">Google Analytics</a>. Getting data from Google is a bit complicated due to its adoption of OAuth. To access Google Analytics information, I wrote a Ruby script leveraging <a href="https://github.com/vigetlabs/garb">Garb</a>, a great gem from <a href="http://www.viget.com/">Viget</a>.
</p>
<pre class="brush: ruby; title: ; notranslate">
# Require libraries.
require 'rubygems'
require 'active_support'
require 'oauth'
require 'garb'
require 'json'

class Time
  def to_js_date
    self.utc.strftime(&quot;%Y/%m/%d&quot;)
  end
end

# Setup OAuth. (See http://everburning.com/news/google-analytics-oauth-and-ruby-oh-my/.)
# Register a domain: https://www.google.com/accounts/ManageDomains.
oauth_consumer = OAuth::Consumer.new(consumer_key, consumer_secret, {:site =&gt; 'https://www.google.com', :request_token_path =&gt; '/accounts/OAuthGetRequestToken', :access_token_path =&gt; '/accounts/OAuthGetAccessToken', :authorize_path =&gt; '/accounts/OAuthAuthorizeToken'})
session = Garb::Session.new
session.access_token = OAuth::AccessToken.new(oauth_consumer, request_token, request_secret)
profile = nil
Garb::Management::Profile.all(session).each |current_profile|
  profile = current_profile if current_profile.title == site_name
end

# Visits/day over last week: bar chart
class RecentVisits
    extend Garb::Model
    metrics :visits
    dimensions :date
end

stop = Time.now
start = stop - 60*60*24*30
start_date = Time.utc(start.year, start.month, start.day - 1)
stop_date = Time.utc(stop.year, stop.month, stop.day - 1)
results = RecentVisits.results(profile, :start_date =&gt; start_date, :end_date =&gt; stop_date, :sort =&gt; :date)
visits = {}
results.each { |result| visits[Time.parse(result.date).to_js_date] = result.visits }
# Save to a file.
f = File.new(&quot;ga.txt&quot;,&quot;w&quot;)
f.write(visits.to_json)
f.close
</pre>
<p>
The app data comes from <a href="http://www.appfigures.com/">Appfigures</a>. Their API access is based on credentials, but SSL is always required. Below is the Ruby script I wrote to fetch that data.
</p>
<pre class="brush: ruby; title: ; notranslate">
# Require libraries.
require 'rubygems'
require 'time'
require 'net/http'
require 'net/https'
require 'json'

class Time
  def to_short_date
    self.utc.strftime(&quot;%Y-%m-%d&quot;)
  end

  def to_js_date
    # Safari Javascript doesn't parse to_short_date format.
    self.utc.strftime(&quot;%Y/%m/%d&quot;)
  end
end

# Set up environment.
rml_key = 'app_id'
dc_key = 'app_id'
rml_data = {}
dc_data = {}
af_response = nil
day_length = 86400
stop = Time.now
start = stop - 60*60*24*30
start_date = Time.utc(start.year, start.month, start.day - 1)
stop_date = Time.utc(stop.year, stop.month, stop.day - 1)

# Prepopulate dates to ensure range. Appfigures's API is not great about including every day.
current_date = start_date
while current_date &lt;= stop_date
  rml_data[current_date.to_js_date] = 0
  current_date += day_length
end
current_date = start_date
while current_date &lt;= stop_date
  dc_data[current_date.to_js_date] = 0
  current_date += day_length
end

# Fetch data from Appfigures.
http=Net::HTTP.new('api.appfigures.com', 443)
http.use_ssl = true
http.start() {|http|
	req = Net::HTTP::Get.new(&quot;/v1/sales/apps+dates/#{start_date.to_short_date}/#{stop_date.to_short_date}/&quot;)
	req.basic_auth 'username', 'password'
	response = http.request(req)
	af_response = response.body
}
af_data = JSON.parse(af_response)

# Parse data.
af_data[dc_key].keys.sort.each { |date| dc_data[Time.parse(date).to_js_date] = af_data[dc_key][date]['app_downloads'] }
af_data[rml_key].keys.sort.each { |date| rml_data[Time.parse(date).to_js_date] = af_data[rml_key][date]['app_downloads'] }

# Write to files.
f = File.new('dc.txt','w')
f.write(dc_data.to_json)
f.close
f = File.new('rml.txt','w')
f.write(rml_data.to_json)
f.close
</pre>
<h3>Displaying the Data</h3>
<p>
Second, I needed to visualize the data. I&#8217;ve been looking for a lightweight graphing library ever since I wrote my post about <a href="http://www.bdunagan.com/2010/05/12/measuring-design-changes/">measuring design changes</a>. For that chart, I used Excel and <a href="http://flyingmeat.com/acorn/">Acorn</a>. It was slow, painful, and manual. No fun at all.
</p>
<p>
I asked a friend at LinkedIn for recommendations, and he pointed me to <a href="http://raphaeljs.com/">Raphael</a>, an excellent open source tool written in Javascript. I used a higher-level version of the tool called <a href="http://g.raphaeljs.com/">gRaphael</a>.
</p>
<p>
Infosthetics&#8217;s sparklines used color to give context to the data: black bars for weekdays this month, dark gray bars for weekends this month, light gray bars for weekdays last month, and a single red bar for today. Small but data-rich. I tried to bring a little of that context to my sidebar&#8217;s sparklines by coloring the weekends in red but the weekdays in gray. Below is the Javascript code that reads the generated text files and creates the graphs:
</p>
<pre class="brush: jscript; title: ; notranslate">
&lt;script type=&quot;text/javascript&quot;&gt;
window.onload = function () {
// Include the following scripts in the header:
// * raphael-min.js
// * g.raphael-min.js
// * g.bar-min.js

// Add hover functions.
var fin = function () { this.flag = r.g.popup(this.bar.x, this.bar.y, this.bar.value || &quot;0&quot;).insertBefore(this); };
var fout = function () { this.flag.animate({opacity: 0}, 60, function () {this.remove();}); };

// Getting Data: fetch data from local files and separate into weekdays and weekends to allow grey/red bars in sparklines.

// Get cached GA data.
var ga_xhr = new XMLHttpRequest();
ga_xhr.open('GET', '/files/ga.txt', false);
ga_xhr.send(null);
var ga_response = ga_xhr.responseText;
var ga_data = JSON.parse(ga_response);
var ga_dates = [];
for (var ga_key in ga_data) { ga_dates.push(ga_key); }
ga_dates = ga_dates.sort();
var ga_weekday_values = [];
var ga_weekend_values = [];
for (var ga_dates_key in ga_dates) {
    var ga_key = ga_dates[ga_dates_key];
    var key_date = new Date(ga_key);
    var key_day = key_date.getDay();
    if (key_day == 0 || key_day == 6) {
        ga_weekday_values.push(&quot;&quot;);
        ga_weekend_values.push(ga_data[ga_key]);
    }
    else {
        ga_weekday_values.push(ga_data[ga_key]);
        ga_weekend_values.push(&quot;&quot;);
    }
}

// Get cached RML data.
var rml_xhr = new XMLHttpRequest();
rml_xhr.open('GET', '/files/rml.txt', false);
rml_xhr.send(null);
var rml_response = rml_xhr.responseText;
var rml_data = JSON.parse(rml_response);
var rml_dates = [];
for (var rml_key in rml_data) { rml_dates.push(rml_key); }
rml_dates = rml_dates.sort();
var rml_weekday_values = [];
var rml_weekend_values = [];
for (var rml_dates_key in rml_dates) {
    var rml_key = rml_dates[rml_dates_key];
    var key_date = new Date(rml_key);
    var key_day = key_date.getDay();
    if (key_day == 0 || key_day == 6) {
        rml_weekday_values.push(&quot;&quot;);
        rml_weekend_values.push(rml_data[rml_key]);
    }
    else {
        rml_weekday_values.push(rml_data[rml_key]);
        rml_weekend_values.push(&quot;&quot;);
    }
}

// Get cached DC data.
var dc_xhr = new XMLHttpRequest();
dc_xhr.open('GET', '/files/dc.txt', false);
dc_xhr.send(null);
var dc_response = dc_xhr.responseText;
var dc_data = JSON.parse(dc_response);
var dc_dates = [];
for (var dc_key in dc_data) { dc_dates.push(dc_key); }
dc_dates = dc_dates.sort();
var dc_weekday_values = [];
var dc_weekend_values = [];
for (var dc_dates_key in dc_dates) {
    var dc_key = dc_dates[dc_dates_key];
    var key_date = new Date(dc_key);
    var key_day = key_date.getDay();
    if (key_day == 0 || key_day == 6) {
        dc_weekday_values.push(&quot;&quot;);
        dc_weekend_values.push(dc_data[dc_key]);
    }
    else {
        dc_weekday_values.push(dc_data[dc_key]);
        dc_weekend_values.push(&quot;&quot;);
    }
}

// Graph GA sparkline with gRaphael.
var r = Raphael(&quot;gadata&quot;);
var chart = r.g.barchart(10, 10, 160, 50, [ga_weekday_values, ga_weekend_values], {stacked: true});
chart.bars[0].attr({&quot;fill&quot;: &quot;#666&quot;});
chart.bars[1].attr({&quot;fill&quot;: &quot;#CD0000&quot;});
chart.hover(fin, fout);

// Graph RML sparkline with gRaphael.
var r = Raphael(&quot;rmldata&quot;);
var chart = r.g.barchart(10, 10, 160, 50, [rml_weekday_values, rml_weekend_values], {stacked: true});
chart.bars[0].attr({&quot;fill&quot;: &quot;#666&quot;});
chart.bars[1].attr({&quot;fill&quot;: &quot;#CD0000&quot;});
chart.hover(fin, fout);

// Graph DC sparkline with gRaphael.
var r = Raphael(&quot;dcdata&quot;);
var chart = r.g.barchart(10, 10, 160, 50, [dc_weekday_values, dc_weekend_values], {stacked: true});
chart.bars[0].attr({&quot;fill&quot;: &quot;#666&quot;});
chart.bars[1].attr({&quot;fill&quot;: &quot;#CD0000&quot;});
chart.hover(fin, fout);
}
&lt;/script&gt;
</pre>
<p>These scripts are also available through my <a href="https://github.com/bdunagan/codebucket/tree/master/data">GitHub repository</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bdunagan.com/2011/06/25/blog-data-visualize/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Developers: Just Handle It</title>
		<link>http://www.bdunagan.com/2011/06/19/developers-just-handle-it/</link>
		<comments>http://www.bdunagan.com/2011/06/19/developers-just-handle-it/#comments</comments>
		<pubDate>Sun, 19 Jun 2011 16:43:01 +0000</pubDate>
		<dc:creator>bdunagan</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[development]]></category>

		<guid isPermaLink="false">http://www.bdunagan.com/?p=1329</guid>
		<description><![CDATA[I&#8217;ve talked about thinking like the user. I&#8217;ve talked about feeling for the user. But honestly, developers aren&#8217;t users. Especially when it comes to their own apps. Developers know exactly how their apps work. They wrote it. They made a hundred decisions that led to their app&#8217;s user experience. Why would they encounter problems with [...]]]></description>
			<content:encoded><![CDATA[<p>
I&#8217;ve talked about <a href="http://www.bdunagan.com/2009/12/24/you-are-a-user/">thinking like the user</a>. I&#8217;ve talked about <a href="http://www.bdunagan.com/2010/06/15/dont-make-users-feel-bad/">feeling for the user</a>. But honestly, developers aren&#8217;t users. Especially when it comes to their own apps. Developers know exactly how their apps work. They wrote it. They made a hundred decisions that led to their app&#8217;s user experience. Why would they encounter problems with their own <a href="http://en.wikipedia.org/wiki/Mental_model">mental model</a>? But users inevitably will. My advice: just handle it. Developers should listen to their users and transparently handle other mental models.
</p>
<h3>Remind Me Later</h3>
<p><img src="http://bdunagan.com/files/rml_dock_icon.png"/></p>
<p>
Remind Me Later had this problem. When people downloaded the app from the Mac App Store, the app went to their <tt>/Applications</tt> folder, and its icon was added to their dock. So, the user clicked the dock icon. Remind Me Later&#8217;s dialog appeared, because on launch, I show the dialog. However, some users associated the dock icon click with the dialog&#8217;s appearance, because they didn&#8217;t notice the menu bar icon appear. People complained.
</p>
<p>
My first pass at a solution was a pulsing menu bar icon. When someone clicked the dock icon to launch the app, the app&#8217;s menu bar icon pulsed blue four times. I thought people would notice this. Wrong. People still complained.
</p>
<p>
My second pass acknowledged the root problem. Some people don&#8217;t understand the dock. They don&#8217;t get the menu bar. They just want the stupid dialog to appear. The first click on the dock icon makes the dialog appear; that means the second click should. Luckily, Cocoa&#8217;s <tt>NSApplication</tt> provides that exact delegate method:
</p>
<pre class="brush: objc; title: ; notranslate">
# NSApplication method
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag;
</pre>
<p>
Now in Remind Me Later, clicking the dock icon makes the dialog appear. Every time.
</p>
<h3>LaunchBar, Alfred, and QuickCursor</h3>
<p><img src="http://bdunagan.com/files/quick_cursor_dock_icon.png"/></p>
<p>
I&#8217;m not alone in coming to this conclusion either. Those popular productivity apps, <a href="http://www.obdev.at/products/launchbar/">LaunchBar</a> and <a href="http://www.alfredapp.com/">Alfred</a>, both support that interaction. Click on the dock icon; the main window appears, every time. However, I&#8217;ll bet both of them added that workflow <i>after</i> someone complained. On the other hand, <a href="http://www.hogbaysoftware.com/products/quickcursor">QuickCursor</a> provides no help when I click the dock icon. The first click puts the icon in the menu bar, but I might not notice that. The second click does nothing. (Keep in mind that QuickCursor is a brilliant app, along with the rest of Jesse Grosjean&#8217;s <a href="http://www.hogbaysoftware.com/">Hog Bay</a> portfolio. This post was written in WriteRoom.) Every dock icon click should open the menu in the menu bar. That interaction should help the user associate the menu bar icon with the app.
</p>
<h3>Jing</h3>
<p><img src="http://bdunagan.com/files/jing_dock_icon.png"/></p>
<p>
<a href="http://www.techsmith.com/jing/">Jing</a> takes a different approach. When I click on the dock icon a second time, it pops up this explanatory message. Yes, it&#8217;s better than nothing. But no, it&#8217;s not great. Why not just trigger the menu in the menu bar? Or the &#8220;Capture&#8221; action? <a href="http://www.techsmith.com/">TechSmith</a> produces great software, so I find it strange to find such an odd workflow from them. Show the user; don&#8217;t tell the user.
</p>
<p><img src="http://bdunagan.com/files/jing_popup.png"/></p>
<p>
So, developers, just handle it. Because your mental model isn&#8217;t the only mental model.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bdunagan.com/2011/06/19/developers-just-handle-it/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Iterating to iCloud</title>
		<link>http://www.bdunagan.com/2011/06/13/iterating-to-icloud/</link>
		<comments>http://www.bdunagan.com/2011/06/13/iterating-to-icloud/#comments</comments>
		<pubDate>Mon, 13 Jun 2011 12:06:11 +0000</pubDate>
		<dc:creator>bdunagan</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[ideas]]></category>

		<guid isPermaLink="false">http://www.bdunagan.com/?p=1298</guid>
		<description><![CDATA[In the week leading up to Apple&#8217;s WWDC keynote last Monday, everyone seemed convinced that Apple&#8217;s big announcement, iCloud, would be a cloud-based streaming service. (In fact, NPR reported that after the event before amending the article.) But music streaming would be such an odd service from Apple. They make money on hardware. All their [...]]]></description>
			<content:encoded><![CDATA[<p><img style="float:left; margin:0px 6px 6px 0px;" src="http://bdunagan.com/files/icloud.png"/></p>
<p>
In the week leading up to Apple&#8217;s WWDC keynote last Monday, everyone seemed convinced that Apple&#8217;s big announcement, iCloud, would be a <a href="http://www.appleinsider.com/articles/11/04/21/apples_cloud_based_itunes_music_streaming_service_is_completed_report.html">cloud-based streaming service</a>. (In fact, <a href="http://www.npr.org/blogs/therecord/2011/06/07/137005359/apple-announces-icloud-streaming-music-service">NPR reported that</a> <i>after</i> the event before amending the article.) But music streaming would be such an odd service from Apple. They make money on hardware. All their other businesses fuel their hardware business. How would music streaming fit into that story?
</p>
<p>
As it turned out, iCloud is not music streaming. It&#8217;s a wish list of features to fix what&#8217;s broken about iOS. Think about it from Apple&#8217;s perspective. Their online service has never been a success. <a href="http://en.wikipedia.org/wiki/MobileMe">MobileMe</a> offers an excellent interface to mail, contacts, calendar, and photos; iDisk has never been exceptional; Find My iPhone was their first hit because it leveraged their unique hardware. But at $99/year, only Apple fanboys (like me) and a minority of non-techies opted to pay for the bundle of services. MobileMe just wasn&#8217;t very compelling compared to the multitude of free services from Google, Yahoo, and Microsoft. In that respect, MobileMe was a fresh coat of paint on .Mac, but the underlying business simply wasn&#8217;t exceptional.
</p>
<p>
I wonder if Apple&#8217;s executives sat down last year to brainstorm a better online service. You can imagine the sort of wish list they would come up with. Anyone who owns an iPhone or iPod understands the frustrations with syncing.
</p>
<ul>
<li>sync app data between devices, because I don&#8217;t want to start Angry Birds over again</li>
<li>sync music between devices, because I forget to plug my iPhone into my computer</li>
<li>sync and backup magically, because I don&#8217;t own a computer</li>
<li>include MobileMe for free</li>
<li>in fact, make the whole service free at some level</li>
</ul>
<p>
Out of these frustrations, you can see a service forming. It would be a massive service but a compelling one. The iOS ecosystem has been hampered by its own success, and this service would solve many of its current problems and fuel further growth. And that&#8217;s the key: fueling hardware sales.
</p>
<p>
So, Apple announced <a href="http://www.apple.com/icloud/what-is.html">iCloud</a>. Lion and iOS 5 are evolutionary steps, but iCloud is revolutionary. As Ben Brooks put it, iCloud is Apple&#8217;s <a href="http://brooksreview.net/2011/06/apple-mag-opus/">magnum opus</a>. Kudos to Apple for understanding their business and its problems so well and for attempting a comprehensive solution. I wish more companies were as self-aware and motivated.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bdunagan.com/2011/06/13/iterating-to-icloud/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Remind Me Later 1.3 is live!</title>
		<link>http://www.bdunagan.com/2011/02/03/remind-me-later-1-3-is-live/</link>
		<comments>http://www.bdunagan.com/2011/02/03/remind-me-later-1-3-is-live/#comments</comments>
		<pubDate>Thu, 03 Feb 2011 15:00:00 +0000</pubDate>
		<dc:creator>bdunagan</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[ideas]]></category>
		<category><![CDATA[remind me later]]></category>

		<guid isPermaLink="false">http://www.bdunagan.com/?p=1238</guid>
		<description><![CDATA[Remind Me Later 1.3 is now live on the Mac App Store and this blog! First and foremost in this update is the improved Launch, Help and Support. The first launch experience of previous releases has proven to be an unmitigated failure, but I&#8217;m pretty happy with this new workflow. And in case people have [...]]]></description>
			<content:encoded><![CDATA[<p><a href="/remind-me-later"><img src="http://bdunagan.com/files/rml.1.3.png"/></a></p>
<p>Remind Me Later 1.3 is now live on the <a href="http://bit.ly/rmlmacapp">Mac App Store</a> and <a href="/remind-me-later">this blog</a>! First and foremost in this update is the improved Launch, Help and Support. The first launch experience of <a href="http://www.bdunagan.com/2010/11/27/remind-me-later-1-2-ui-hints/">previous releases</a> has proven to be an unmitigated failure, but I&#8217;m pretty happy with this new workflow. And in case people have trouble, the Support links in Preferences should help users contact me more easily.</p>
<p>In addition, I added a number of features:</p>
<ul>
<li>Durations: &#8220;4pm to 5pm&#8221;</li>
<li>Delays: &#8220;in 1 hour&#8221;</li>
<li>All-day events: &#8220;Monday through Friday&#8221;</li>
<li>&#8220;Add and Launch iCal&#8221;: Cmd-Enter to add an event and open it in iCal</li>
<li>Configurable global hotkey</li>
<li>Fixed the clickable icon issue on Leopard (10.5)</li>
</ul>
<p>Download this new release from the <a href="http://bit.ly/rmlmacapp">Mac App Store</a> or <a href="/remind-me-later">this blog</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bdunagan.com/2011/02/03/remind-me-later-1-3-is-live/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Remind Me Later 1.2: UI Hints</title>
		<link>http://www.bdunagan.com/2010/11/27/remind-me-later-1-2-ui-hints/</link>
		<comments>http://www.bdunagan.com/2010/11/27/remind-me-later-1-2-ui-hints/#comments</comments>
		<pubDate>Sat, 27 Nov 2010 23:27:47 +0000</pubDate>
		<dc:creator>bdunagan</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[ideas]]></category>
		<category><![CDATA[remind me later]]></category>

		<guid isPermaLink="false">http://www.bdunagan.com/?p=1223</guid>
		<description><![CDATA[So, you stumble upon this Remind Me Later thingy. You download the app and run it. Nothing happens. You look around the computer screen. Nothing. You run the app again. Still nothing. A couple minutes later, you notice the bookmark icon in your menu bar. Not the best user experience. For version 1.2, I&#8217;ve added [...]]]></description>
			<content:encoded><![CDATA[<p>So, you stumble upon this Remind Me Later thingy. You download the app and run it. Nothing happens. You look around the computer screen. Nothing. You run the app again. Still nothing. A couple minutes later, you notice the bookmark icon in your menu bar. Not the best user experience.</p>
<p>For version 1.2, I&#8217;ve added UI hints. The menu bar pulses blue when launched to make its location clear. When you add an event, the icon pulses blue when all goes well and red when something goes awry. Hopefully, these small visual hints will help people understand the app a bit quicker.</p>
<p>Remind Me Later is a very simple app, but even the smallest apps need design work. Also, it&#8217;s free. <a href="/remind-me-later">Give it a try.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.bdunagan.com/2010/11/27/remind-me-later-1-2-ui-hints/feed/</wfw:commentRss>
		<slash:comments>36</slash:comments>
		</item>
		<item>
		<title>Don&#8217;t make users feel bad</title>
		<link>http://www.bdunagan.com/2010/06/15/dont-make-users-feel-bad/</link>
		<comments>http://www.bdunagan.com/2010/06/15/dont-make-users-feel-bad/#comments</comments>
		<pubDate>Wed, 16 Jun 2010 03:27:51 +0000</pubDate>
		<dc:creator>bdunagan</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[development]]></category>

		<guid isPermaLink="false">http://www.bdunagan.com/?p=983</guid>
		<description><![CDATA[Matt Drance posted an interesting thought the other day about the average consumer rejecting bad user experience. When helping out my parents or other non-technical folk, I&#8217;ve never found that. At least, not exactly. Average consumers do not think about user experience. They don&#8217;t think about workflows, calls to action, marketing copy, or corner cases. [...]]]></description>
			<content:encoded><![CDATA[<p>Matt Drance posted an interesting thought the other day about <a href="http://www.appleoutsider.com/2010/05/23/features-dont-matter-anymore/">the average consumer rejecting bad user experience</a>. When helping out my parents or other non-technical folk, I&#8217;ve never found that. At least, not exactly. Average consumers do not think about user experience. They don&#8217;t think about workflows, calls to action, marketing copy, or corner cases. Consumers just use stuff. When something goes wrong, it&#8217;s their fault. They internalize any problems. They blame themselves.</p>
<p>When consumers have a great user experience, they don&#8217;t notice. They don&#8217;t wonder how you designed the product so well. They just use it and move on, but that&#8217;s a good thing. They shouldn&#8217;t feel bad while using your product. Don&#8217;t make users feel bad because eventually they&#8217;ll choose a better user experience as a coping mechanism.</p>
<p>User experience: Because your users internalize your product&#8217;s failures.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bdunagan.com/2010/06/15/dont-make-users-feel-bad/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Measuring Design Changes</title>
		<link>http://www.bdunagan.com/2010/05/12/measuring-design-changes/</link>
		<comments>http://www.bdunagan.com/2010/05/12/measuring-design-changes/#comments</comments>
		<pubDate>Thu, 13 May 2010 02:38:44 +0000</pubDate>
		<dc:creator>bdunagan</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[marketing]]></category>

		<guid isPermaLink="false">http://www.bdunagan.com/?p=867</guid>
		<description><![CDATA[A week ago, I replaced the Flickr photos in my blog&#8217;s header with iPhone OS apps: Retrospect Touch and Dollar Clock. Since I hadn&#8217;t updated Flickr since Christmas, the iPhone/iPad apps seemed more appropriate, and I was curious to see if the switch affected the download numbers. Here&#8217;s the before and after: Today, I checked [...]]]></description>
			<content:encoded><![CDATA[<p>A week ago, I replaced the Flickr photos in my blog&#8217;s header with iPhone OS apps: Retrospect Touch and Dollar Clock. Since I hadn&#8217;t updated Flickr since Christmas, the iPhone/iPad apps seemed more appropriate, and I was curious to see if the switch affected the download numbers. Here&#8217;s the before and after:</p>
<p><img src="/files/blog_header_change.png"/></p>
<p>Today, I checked the numbers in iTunes Connect for Dollar Clock. At first, I only looked at the total downloads, in the left graph, where the hash mark notes the header change. Clearly, the header change increased the downloads. Then I looked at the purchases and updates separately, in the right graph, and the pattern was less clear. During the week after the header change (the bar after the hash mark), more of the downloads were updates, not purchases.</p>
<p><img src="/files/Dollar_Clock_Purchases.png"/></p>
<p>During the same week I changed the header, Dollar Clock 2.0 was posted to the App Store, and many people downloaded the update that week. The total downloads indicates my header change had a significant effect, but the breakdown reveals confounding variables. Perhaps if I had more variables, I would find that the header change had absolutely no effect.</p>
<p>Or maybe I just wanted an excuse to use Tufte&#8217;s <a href="http://en.wikipedia.org/wiki/Small_multiple">small multiples. <img src='http://www.bdunagan.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.bdunagan.com/2010/05/12/measuring-design-changes/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>WordPress Tip: Recent, Relevant, and Random Blog Posts</title>
		<link>http://www.bdunagan.com/2010/04/09/wordpress-tip-recent-relevant-and-random-blog-posts/</link>
		<comments>http://www.bdunagan.com/2010/04/09/wordpress-tip-recent-relevant-and-random-blog-posts/#comments</comments>
		<pubDate>Sat, 10 Apr 2010 04:36:08 +0000</pubDate>
		<dc:creator>bdunagan</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[marketing]]></category>

		<guid isPermaLink="false">http://www.bdunagan.com/?p=777</guid>
		<description><![CDATA[12 May 2010 Update: Interestingly, Google Analytics revealed that in the month since adding the sidebar, there&#8217;s been no significant change in the average time spent on the site (54s) or pages per visit (1.3). I still like it. Recently, I thought it would be interesting to add a sidebar to my WordPress blog. I [...]]]></description>
			<content:encoded><![CDATA[<p><b>12 May 2010 Update</b>: Interestingly, Google Analytics revealed that in the month since adding the sidebar, there&#8217;s been no significant change in the average time spent on the site (54s) or pages per visit (1.3). I still like it.</p>
<p>Recently, I thought it would be interesting to add a sidebar to my WordPress blog. I figured a short list of recent posts, relevant posts, and random posts would help surface information people might find useful. Here&#8217;s a quick rundown of how to add these with the PHP code below:</p>
<ul>
<li><i>Recent Posts</i>: one-liner with simple WP PHP call
<li><i>Random Posts</i>: a couple lines because I wanted random posts but sorted descending by date (not simply <tt>get_posts('numberposts=5&#038;orderby=rand&#038;order=desc');</tt>)
<li><i>Relevant Posts</i>: also called related posts, a template-based plugin worked best for me: <a href="http://mitcho.com/code/yarpp/">Yet Another Related Posts Plugin (YARPP)</a>
</ul>
<pre class="brush: php; title: ; notranslate">
&lt;div class=&quot;sidebar&quot;&gt;
&lt;b&gt;Recent&lt;/b&gt;
&lt;ul&gt;
&lt;?php wp_get_archives('title_li=&amp;type=postbypost&amp;limit=5'); ?&gt;
&lt;/ul&gt;
&lt;?php related_posts(); ?&gt;
&lt;b&gt;Random&lt;/b&gt;
&lt;ul&gt;
&lt;?php
   // Get five random posts.
   $rand_posts = get_posts('numberposts=5&amp;orderby=rand');
   // Sort them (by date).
   asort($rand_posts);
   // Reverse them.
   $rand_posts = array_reverse($rand_posts);
   foreach( $rand_posts as $post ) :
?&gt;
    &lt;li&gt;&lt;a href=&quot;&lt;?php the_permalink(); ?&gt;&quot;&gt;&lt;?php the_title(); ?&gt;&lt;/a&gt;&lt;/li&gt;
&lt;?php endforeach; ?&gt;
&lt;/ul&gt;
&lt;/div&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.bdunagan.com/2010/04/09/wordpress-tip-recent-relevant-and-random-blog-posts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tracking and Staging WordPress Changes</title>
		<link>http://www.bdunagan.com/2010/03/29/tracking-and-staging-wordpress-changes/</link>
		<comments>http://www.bdunagan.com/2010/03/29/tracking-and-staging-wordpress-changes/#comments</comments>
		<pubDate>Tue, 30 Mar 2010 04:38:39 +0000</pubDate>
		<dc:creator>bdunagan</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[development]]></category>

		<guid isPermaLink="false">http://www.bdunagan.com/?p=691</guid>
		<description><![CDATA[Making template/theme changes to a live blog is a bit frustrating. While mucking around with CSS or a theme header, I occasionally render this blog completely illegible or obviously broken, then I scramble to revert my changes, hoping I remember the original code correctly. Editing is a pain without source control or a staging process [...]]]></description>
			<content:encoded><![CDATA[<p>Making template/theme changes to a live blog is a bit frustrating. While mucking around with CSS or a theme header, I occasionally render this blog completely illegible or obviously broken, then I scramble to revert my changes, hoping I remember the original code correctly. Editing is a pain without source control or a staging process and very different from app development. Too different. So, I figured out how to track all my WordPress changes with git and stage them on a subdomain on DreamHost.</p>
<p><b>Tracking Changes</b></p>
<p>I&#8217;m using git and GitHub, but any scm would be fine. I&#8217;ll run through the steps here. (Keep in mind I use WordPress&#8217;s update system for version and plugin updates; I just want to track my own changes.)</p>
<ol>
<li>Removed unused themes and plugins to reduce installation size to 25MB (<tt>du -h</tt>)
<li>Created a private repo on GitHub
<li>Setup git in blog&#8217;s root directory on DreamHost:
<pre>
git init
# Didn't bother ignoring any files.
git add .
git commit -m "current state of blog"
git remote add origin git@github.com:username/myblog.git
git push origin master
</pre>
<li>Edited the CSS file using WordPress&#8217;s editor then listed the changes (<tt>git status</tt>) and diff&#8217;d the changed file using git (<tt>git diff style.css</tt>)
<li>Decided my edits didn&#8217;t look good on the live blog and reverted them (<tt>git checkout style.css</tt> or <tt>git reset HEAD --hard</tt>)
<li>Ran <tt>mysqldump</tt> then <tt>gzip</tt> on the blog db and added it to git also
<li>Updated <tt>.htaccess</tt> to hide the new <tt>.git</tt> directory (<a href="http://wiki.dreamhost.com/Htaccess#Deny_access_to_.22hidden.22_files">DreamHost</a>): <tt>RedirectMatch 403 /\..*$</tt>
</ol>
<p>Seeing the changed files in git is fantastic, and at this point, I wonder how I got by for so long without versioning my WordPress changes. But tracking changes isn&#8217;t enough.</p>
<p><b>Staging Changes</b></p>
<p>Now, I can easily revert horrible template changes, but anyone hitting the blog during that time will still see it. It reminds me of how the early Facebook team used to directly edit the HTML on the production site when they were adding features. Debugging changes on a live site is annoying and unnecessary. Instead, just use a subdomain. Here are my steps:</p>
<ol>
<li>Created a subdomain on DreamHost for the staging area <i>and</i> assigned it a private IP/enabled SSL (I require <a href="http://codex.wordpress.org/Administration_Over_SSL">SSL for administration</a>)
<li>Pulled the current repo in that new subdomain&#8217;s root directory on DreamHost:
<pre>
git init
git remote add origin git@github.com:username/myblog.git
git pull origin master
</pre>
<li>Pointed this instance of WordPress to the new subdomain by adding <tt>WP_HOME</tt> and <tt>WP_SITEURL</tt> in <tt>/wp-config.php</tt> according to <a href="http://codex.wordpress.org/Changing_The_Site_URL">WordPress&#8217;s &#8220;Changing The Site URL&#8221; page</a> (I want to use the same database so I didn&#8217;t change those entries)
<li>Waited a couple hours while the DNS changes propagated for the new subdomain
<li>Logged into WordPress on the subdomain and changed a couple lines of CSS
<li>Checked out the result on the subdomain and committed it to GitHub
<li>Pushed the commit to GitHub and pulled it down in the live blog
<li>Verified the change on the live blog
</ol>
<p>Staging changes is so much more comforting. Before, I wondered how many visitors hit my site mid-change (which sometimes took hours) and left annoyed. At least now I can think, &#8220;Actually, I designed it that way intentionally&#8230;&#8221;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bdunagan.com/2010/03/29/tracking-and-staging-wordpress-changes/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

