<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>Alex Young's weblog</title>
    <link>http://alexyoung.org</link>
    <description>Alex Young's notes on web development, music</description>
    <language>en-gb</language>
    <ttl>40</ttl>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/webdevelopernotes" type="application/rss+xml" /><feedburner:browserFriendly>This is an XML content feed. It is intended to be viewed in a newsreader or syndicated to another site, subject to copyright and fair use.</feedburner:browserFriendly><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
      <title>Rapid Rails: Boot Up Time</title>
      <description>&lt;p&gt;Rails boot up time really starts to drag when you&amp;#8217;re working in a &lt;span class="caps"&gt;TDD&lt;/span&gt; or &lt;span class="caps"&gt;BDD&lt;/span&gt; style.  There&amp;#8217;s projects out there that create long running distributed processes to ease this, but it&amp;#8217;s interesting to look at exactly why Rails might boot up slowly.&lt;/p&gt;


	&lt;p&gt;I have a project that isn&amp;#8217;t massively complicated, but it has suffered from &amp;#8220;just add&amp;#8221; culture.  I&amp;#8217;ve been told to &amp;#8220;just add&amp;#8221; Excel support, &lt;span class="caps"&gt;PDF&lt;/span&gt; generation, and a lot more features that require complex libraries.  This naturally increases the memory footprint of my application, and it also increases boot time.&lt;/p&gt;


	&lt;p&gt;Before I started my analysis, the boot time averaged at 11.6 seconds.  After my improvements the boot time is 7 seconds.  By comparison, the code for &lt;a href="http://deadlineapp.com"&gt;Deadline&lt;/a&gt; boots in 4 seconds, but it has few dependencies (it&amp;#8217;s a joy to work on by the way).&lt;/p&gt;


	&lt;p&gt;Before continuing this technical and possibly dull article, I&amp;#8217;ve mined my internet meme library to add a soundtrack.  Replace all instances of &lt;em&gt;on a boat&lt;/em&gt; with &lt;em&gt;on Rails&lt;/em&gt;:&lt;/p&gt;


&lt;object width="560" height="340"&gt;&lt;param name="movie" value="http://www.youtube.com/v/R7yfISlGLNU&amp;#38;hl=en&amp;#38;fs=1&amp;#38;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/R7yfISlGLNU&amp;#38;hl=en&amp;#38;fs=1&amp;#38;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="560" height="340"&gt;&lt;/embed&gt;&lt;/object&gt;

	&lt;p&gt;And I don&amp;#8217;t think we even get &lt;span class="caps"&gt;SNL&lt;/span&gt; in the UK!&lt;/p&gt;


	&lt;h3&gt;Analysing boot up time&lt;/h3&gt;


	&lt;p&gt;Boot up time shouldn&amp;#8217;t be related to the number of models and controllers you have.  Rails dependency loading should require these files when they&amp;#8217;re first referenced&amp;#8212;unless you use a plugin like ThinkingSphinx that intentionally loads models on start up.&lt;/p&gt;


	&lt;p&gt;To prove this, add this to the first line of a model file: &lt;code&gt;puts "I've been required"&lt;/code&gt;, then start &lt;code&gt;script/console&lt;/code&gt;.  Unless something is including the model, you shouldn&amp;#8217;t see the message until you type the model&amp;#8217;s class name and press return.&lt;/p&gt;


	&lt;p&gt;So what&amp;#8217;s increasing my app&amp;#8217;s carbon footprint if it&amp;#8217;s not my own code?  To find out, I wrapped up each major block of code in environment.rb in Benchmark.measure blocks.  I found that my library &lt;code&gt;requires&lt;/code&gt; were using most of the time.  Also, this code took over a second:&lt;/p&gt;


&lt;pre class="code"&gt;
ActiveSupport::Inflector.inflections do |inflect|
  inflect.irregular 'cookie', 'cookies'
end
&lt;/pre&gt;

	&lt;p&gt;I have that code because even though Rails correctly pluralises it gets the relationship wrong in a &lt;code&gt;has_many&lt;/code&gt; (it looks for &lt;code&gt;LoginCooky&lt;/code&gt;).  But why would that take a second?  I have no idea.  Seeing as I technically shouldn&amp;#8217;t need this definition I ignored it for now.&lt;/p&gt;


	&lt;h3&gt;Requires&lt;/h3&gt;


	&lt;p&gt;The gem &lt;code&gt;requires&lt;/code&gt; in &lt;code&gt;environment.rb&lt;/code&gt; were the real culprit.  If you think about what Ruby does here it&amp;#8217;s obvious: the amount of code evaluated for some libraries will be huge.&lt;/p&gt;


	&lt;p&gt;This project is old and wasn&amp;#8217;t using &lt;code&gt;config.gem&lt;/code&gt;, so I added calls to that in the &lt;code&gt;Rails::Initializer.run&lt;/code&gt; block instead of plain old &lt;code&gt;require&lt;/code&gt;.  This is cool because Rails will prompt missing library installation, but it&amp;#8217;s also cool because of this:&lt;/p&gt;


&lt;code&gt;config.gem 'scruffy', :lib =&amp;gt; false&lt;/code&gt;

	&lt;p&gt;Setting the lib to false will make Rails aware you want the library, but not require it.  This library is only used in one place, there&amp;#8217;s a GraphController that manages dynamic graph generation.  I added a &lt;code&gt;require 'scruffy'&lt;/code&gt; to that file instead.&lt;/p&gt;


	&lt;p&gt;This doesn&amp;#8217;t always make sense of course: there might be calls all over your code to a particular library.  That&amp;#8217;s fine, just require it at boot.  The amount of times that wasn&amp;#8217;t the case, however, reduced my boot time by 4 seconds.&lt;/p&gt;


	&lt;h3&gt;Forensics&lt;/h3&gt;


	&lt;p&gt;I&amp;#8217;m not exactly Grissom or Horatio, but I did write a little script to &lt;a href="http://gist.github.com/140012"&gt;watch the require time&lt;/a&gt; of every require in the project.  I &lt;code&gt;required&lt;/code&gt; it in &lt;code&gt;environment.rb&lt;/code&gt; and watched to see which libraries seemed slow.  I&amp;#8217;ve left my commented out bits where I was trying to figure out how to only measure &amp;#8220;top level&amp;#8221; requires in &lt;code&gt;environment.rb&lt;/code&gt;&amp;#8212;I never fully figured this out, does anyone know how to do it?&lt;/p&gt;


&lt;script src="http://gist.github.com/140012.js"&gt;&lt;/script&gt;

	&lt;h3&gt;Lessons&lt;/h3&gt;


	&lt;p&gt;It&amp;#8217;s interesting what you learn by looking at older Rails projects.  I always used to just require my libraries in the environment file so other developers would see the app break if they hadn&amp;#8217;t installed them.  The newer way, &lt;code&gt;config.gem&lt;/code&gt;, provides a better solution and lets us require files when we actually need them.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=3Y895Q7gltY:xjSRvqNrAYE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=3Y895Q7gltY:xjSRvqNrAYE:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=3Y895Q7gltY:xjSRvqNrAYE:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/webdevelopernotes/~4/3Y895Q7gltY" height="1" width="1"/&gt;</description>
      <pubDate>Fri,  3 Jul 2009 10:02:38 BST</pubDate>
      <link>http://feedproxy.google.com/~r/webdevelopernotes/~3/3Y895Q7gltY/rapid_rails_boot_up_time</link>
      <dc:creator>Alex Young</dc:creator>
    <feedburner:origLink>http://alexyoung.org/articles/show/89/rapid_rails_boot_up_time</feedburner:origLink></item>
    <item>
      <title>Rapid Rails: Mastering Indexes</title>
      <description>&lt;p&gt;I wrote a series last year called &amp;#8220;Rapid Rails&amp;#8221;.  It was all about making your Rails app and development process faster.  I&amp;#8217;ve been analysing the performance of some mature Rails projects recently, so rapid rails is back.&lt;/p&gt;


	&lt;p&gt;If I&amp;#8217;m tasked with improving an application&amp;#8217;s performance, the first thing I look at is indexes.  Indexes are something you&amp;#8217;re told are important when you learn about relational databases, but the effort of domain modeling usually makes most people forget all about them.  That means you&amp;#8217;ll often come across a slow project that can be improved just by adding indexes.&lt;/p&gt;


	&lt;p&gt;Rails lets you add these in a migration with &lt;code&gt;add_index :table, :row&lt;/code&gt; or even &lt;code&gt;add_index :table, [:row1, :row2]&lt;/code&gt;.  Most of you probably already know this.  What you might not know is your &lt;span class="caps"&gt;RDBMS&lt;/span&gt; might be ignoring your indexes anyway!&lt;/p&gt;


	&lt;p&gt;The following steps will help you detect and avoid this.&lt;/p&gt;


	&lt;h3&gt;#1: Identify a slow query to attack&lt;/h3&gt;


	&lt;p&gt;Look at your Rails development logs to find queries.  MySQL has a slow query log as well.&lt;/p&gt;


	&lt;p&gt;Look at what fields the query joins on, and look at what it sorts on too.  Add the index.&lt;/p&gt;


	&lt;h3&gt;#2: Determine if the index is being used&lt;/h3&gt;


	&lt;p&gt;Run &lt;code&gt;script/dbconsole&lt;/code&gt; and enter your database&amp;#8217;s password to get into a database shell.&lt;/p&gt;


	&lt;p&gt;If you&amp;#8217;re using MySQL or Postgres, &lt;code&gt;EXPLAIN&lt;/code&gt; will help identify what indexes are used.  Just call a query with it:&lt;/p&gt;


&lt;pre class="code"&gt;
EXPLAIN SELECT * FROM `articles`
WHERE
  (articles.published = 1 AND headline = 0 )
  AND ( (`articles`.`type` = 'EquitiesStory' ) )
ORDER BY created_on
DESC LIMIT 1000, 40&lt;/pre&gt;

	&lt;p&gt;This query took up to 5 seconds on some fast hardware with lots of memory.  It was really getting on my nerves.  Of course, &lt;span class="caps"&gt;STI&lt;/span&gt; wasn&amp;#8217;t helping with the application&amp;#8217;s large data sets, but it was a case of &lt;span class="caps"&gt;DRY&lt;/span&gt; vs. fully normalised data models.&lt;/p&gt;


	&lt;p&gt;In this case I added a fat index: &lt;code&gt;index_articles_on_type_and_published_and_headline_and_created_on&lt;/code&gt;.  However, MySQL said it wasn&amp;#8217;t even using my giant index.  &lt;code&gt;EXPLAIN&lt;/code&gt; said it used:&lt;/p&gt;


&lt;pre class="code"&gt;Using intersect(index_articles_on_published,index_articles_on_headline,index_articles_on_type)&lt;/pre&gt;

	&lt;h3&gt;#3: &lt;span class="caps"&gt;ANALYZE&lt;/span&gt;, OPTIMIZE&lt;/h3&gt;


	&lt;p&gt;MySQL store statistics on the way your tables are used.  It&amp;#8217;s not as fancy as it sounds.  If you&amp;#8217;d like to rebuild these, check out &lt;code&gt;ANALYZE&lt;/code&gt; and &lt;code&gt;OPTIMIZE&lt;/code&gt;.&lt;/p&gt;


	&lt;h3&gt;#4: &lt;span class="caps"&gt;USE INDEX&lt;/span&gt;&lt;/h3&gt;


	&lt;p&gt;If you suspect MySQL&amp;#8217;s optimiser is letting you down, try running the query with &lt;code&gt;USE INDEX&lt;/code&gt;:&lt;/p&gt;


&lt;pre class="code"&gt;
SELECT * FROM `articles`
USE INDEX
  (index_articles_on_type_and_published_and_headline_and_created_on)
WHERE
  (articles.published = 1 AND headline = 0 )
  AND ( (`articles`.`type` = 'EquitiesStory' ) )
ORDER BY created_on
DESC LIMIT 1040, 40;&lt;/pre&gt;

	&lt;p&gt;Even if this runs faster MySQL might have cached your previous tests.  That&amp;#8217;s why I have those LIMITs, I&amp;#8217;m trying to get results that haven&amp;#8217;t been cached.  And &lt;code&gt;EXPLAIN&lt;/code&gt; told me that this query uses the index I want.&lt;/p&gt;


	&lt;p&gt;It would be possible to construct a &lt;code&gt;find&lt;/code&gt; in Rails that uses &lt;code&gt;USE INDEX&lt;/code&gt;, but I don&amp;#8217;t want to.  I like keeping things database agnostic if possible.  If MySQL&amp;#8217;s optimiser is failing to use the right index, what else can we do?&lt;/p&gt;


	&lt;h3&gt;#5: Trick the optimiser&lt;/h3&gt;


	&lt;p&gt;This is bad advice.  MySQL&amp;#8217;s optimiser changes between versions, so I&amp;#8217;m telling you to do something naughty here.  After repeated experiments, I found changing my query slightly made the optimiser work harder to find the best index:&lt;/p&gt;


&lt;pre class="code"&gt;
SELECT * FROM `articles`
USE INDEX
  (index_articles_on_type_and_published_and_headline_and_created_on)
WHERE
  (articles.published = 1 AND headline != 1 )
  AND ( (`articles`.`type` = 'EquitiesStory' ) )
ORDER BY created_on DESC LIMIT 1080, 40;&lt;/pre&gt;

	&lt;p&gt;Notice the &lt;code&gt;headline != 1&lt;/code&gt;?  That somehow resulted in MySQL using the index I wanted.  This ridiculous modification has resulted in a massive performance gain and a happy client.&lt;/p&gt;


	&lt;h3&gt;#6: Filesort&lt;/h3&gt;


	&lt;p&gt;If you see filesort appear in your &lt;code&gt;EXPLAIN&lt;/code&gt;, it&amp;#8217;s likely that this will reduce performance.  It&amp;#8217;ll be caused by an &lt;code&gt;ORDER BY&lt;/code&gt;.  I found simply forcing MySQL to use my created_on index improved performance for the previous queries, because it went from &lt;code&gt;Using where, filesort&lt;/code&gt; to just &lt;code&gt;Using where&lt;/code&gt;.&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Filesort, as the name implies, is used to sort records when there is an &lt;span class="caps"&gt;ORDER BY&lt;/span&gt; clause in the query. The reason it has the prefix &amp;#8220;file&amp;#8221; is because temporary files may be used to store intermediate results.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;p&gt;From: &lt;a href="http://blogs.sun.com/realneel/entry/improving_filesort_performance_in_mysql"&gt;Improving Filesort performance in MySQL&lt;/a&gt;&lt;/p&gt;


	&lt;h3&gt;#7: Take a break&lt;/h3&gt;


	&lt;p&gt;Don&amp;#8217;t be rushing around adding indexes to live apps, and take some time out to surf YouTube.&lt;/p&gt;


&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/UWRyj5cHIQA&amp;#38;hl=en&amp;#38;fs=1&amp;#38;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/UWRyj5cHIQA&amp;#38;hl=en&amp;#38;fs=1&amp;#38;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=mCuhENjDD3s:UXzCNyfJANw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=mCuhENjDD3s:UXzCNyfJANw:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=mCuhENjDD3s:UXzCNyfJANw:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/webdevelopernotes/~4/mCuhENjDD3s" height="1" width="1"/&gt;</description>
      <pubDate>Thu,  2 Jul 2009 13:48:31 BST</pubDate>
      <link>http://feedproxy.google.com/~r/webdevelopernotes/~3/mCuhENjDD3s/rapid_rails_mastering_indexes</link>
      <dc:creator>Alex Young</dc:creator>
    <feedburner:origLink>http://alexyoung.org/articles/show/88/rapid_rails_mastering_indexes</feedburner:origLink></item>
    <item>
      <title>iPhone 3.0 Development Glitches</title>
      <description>&lt;p&gt;I had a few glitches in the &lt;a href="http://helipadapp.com/"&gt;Helipad&lt;/a&gt; iPhone app when 3.0 rolled around.  I&amp;#8217;ve put the solution here to help those of you searching for the error message.&lt;/p&gt;


	&lt;p&gt;Helipad syncs to our web app and displays a syncing progress screen.  I open this view in a new view controller like this:&lt;/p&gt;


&lt;pre class="code"&gt;
SyncController *sync = [[SyncController alloc] initWithNibName:@"SyncController" 
                                                        bundle:nil];
[self presentModalViewController:sync animated:YES];
&lt;/pre&gt;

	&lt;p&gt;The parent view displays a &lt;code&gt;UIWebView&lt;/code&gt;, and the controller runs the sync process on another thread so the display can be updated with feedback.  The problem was that updating &lt;code&gt;UIWebView&lt;/code&gt; crashed the app:&lt;/p&gt;


&lt;pre&gt;
bool _WebTryThreadLock(bool): Tried to obtain the web lock from a thread
other than the main thread or the web thread. This may be a result of calling
to UIKit from a secondary thread.
&lt;/pre&gt;

	&lt;p&gt;I can only assume that this was caused as part of the improvements to &lt;code&gt;UIWebView&lt;/code&gt;&amp;#8217;s performance.  The crash actually occurred when the sync process called &lt;code&gt;dismissModalViewControllerAnimated:&lt;/code&gt;.  To resolve this, I called it on the main thread like this:&lt;/p&gt;


&lt;pre class="code"&gt;
[self performSelectorOnMainThread:@selector(dismissSyncView) 
                       withObject:nil
                    waitUntilDone:YES];&lt;/pre&gt;

	&lt;p&gt;My method, dismissSyncView, looks like this:&lt;/p&gt;


&lt;pre class="code"&gt;
- (void)dismissSyncView {
    [self dismissModalViewControllerAnimated:YES];
    // Other custom code goes here  
}
&lt;/pre&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=XdhaQGRP0_0:OUnJ40xpBvQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=XdhaQGRP0_0:OUnJ40xpBvQ:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=XdhaQGRP0_0:OUnJ40xpBvQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/webdevelopernotes/~4/XdhaQGRP0_0" height="1" width="1"/&gt;</description>
      <pubDate>Tue, 23 Jun 2009 11:11:44 BST</pubDate>
      <link>http://feedproxy.google.com/~r/webdevelopernotes/~3/XdhaQGRP0_0/iphone_30_development_glitches</link>
      <dc:creator>Alex Young</dc:creator>
    <feedburner:origLink>http://alexyoung.org/articles/show/87/iphone_30_development_glitches</feedburner:origLink></item>
    <item>
      <title>Experiences Releasing an Open Source Project</title>
      <description>&lt;p&gt;&lt;img src="http://jschat.org/images/jschat.gif" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;&lt;em&gt;Note: If you want to read about &lt;a href="http://jschat.org"&gt;JsChat&lt;/a&gt; have a look at the &lt;a href="http://blog.jschat.org/"&gt;JsChat blog.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


	&lt;p&gt;I&amp;#8217;ve always dabbled with open source (Linux got me through university), but it&amp;#8217;s only since GitHub that I&amp;#8217;ve released a lot of stuff: &lt;a href="http://github.com/alexyoung/"&gt;GitHub.com/alexyoung&lt;/a&gt;&amp;#8212;I only had weird experiments on my site before, and I released some stuff through work too (&lt;a href="code.helicoid.net"&gt;code.helicoid.net&lt;/a&gt;).  Nothing much drew any major attention until I publicly announced JsChat.&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://jschat.org/"&gt;JsChat&lt;/a&gt; is a simple protocol for realtime chat.  It&amp;#8217;s like &lt;span class="caps"&gt;IRC&lt;/span&gt;, but relies on &lt;span class="caps"&gt;JSON&lt;/span&gt; for message encoding and syntax.  I made it so it would be easier to build nice web-based chat clients.  I built an Ncurses client, but it&amp;#8217;s&amp;#8230; kind of dodgy.  I use it daily but I recognise that it needs work.&lt;/p&gt;


	&lt;p&gt;The point is that JsChat is about communication.  When you visit the site, you can join a chat room straight away.  Therefore, when the project appeared on Ruby news sites, it was inevitable that people would join a chat room and talk to us.&lt;/p&gt;


	&lt;p&gt;This is what happened:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;People complained that we were using polling instead of Juggernaut or other Flash-sockets hacks&amp;#8212;they didn&amp;#8217;t seem to realise the project was more than the web client, or that I specifically decided not to rely on technologies like Flash&lt;/li&gt;
		&lt;li&gt;People complained about the language and libraries I used (I had good reasons for using these too)&lt;/li&gt;
		&lt;li&gt;People joined and made random racist comments&lt;/li&gt;
		&lt;li&gt;90% of people joined with a name like &amp;#8216;test&amp;#8217; and wrote random noise.  JsChat loads the lastlog automatically in the web client, so it&amp;#8217;s obvious that people are having real conversations&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;On the plus side:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;We made some friends through JsChat&lt;/li&gt;
		&lt;li&gt;Some people are now using it in their sites for professional projects&lt;/li&gt;
		&lt;li&gt;We got lots of bug reports and useful feedback&lt;/li&gt;
		&lt;li&gt;Some people said they liked the interface design&lt;/li&gt;
	&lt;/ul&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=p4P1LlsT4UQ:NrWZa2VPWEk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=p4P1LlsT4UQ:NrWZa2VPWEk:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=p4P1LlsT4UQ:NrWZa2VPWEk:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/webdevelopernotes/~4/p4P1LlsT4UQ" height="1" width="1"/&gt;</description>
      <pubDate>Tue,  2 Jun 2009 12:42:14 BST</pubDate>
      <link>http://feedproxy.google.com/~r/webdevelopernotes/~3/p4P1LlsT4UQ/experiences_releasing_an_open_source_project</link>
      <dc:creator>Alex Young</dc:creator>
    <feedburner:origLink>http://alexyoung.org/articles/show/86/experiences_releasing_an_open_source_project</feedburner:origLink></item>
    <item>
      <title>Intuitive Code</title>
      <description>&lt;p&gt;I&amp;#8217;ve read a lot of game reviews where the &lt;em&gt;intuitiveness&lt;/em&gt; of a game is described: the control scheme and menu system can be rated by how intuitive they feel.  Intuition is a useful concept, and means more than &amp;#8220;easy to use&amp;#8221;&amp;#8212;it imparts a sense of instinct; mental processes found in the subconscious.&lt;/p&gt;


	&lt;p&gt;Code can be intuitive too.  Not intuitive to write, but to read.  If this seems confusing just think about pseudo-code: beginners are immediately comfortable with pseudo-code but put off by the arcane constructs and symbols of a real programming language.  Some languages appear more like pseudo-code: Ruby can be written clearly with little hand-holding for the interpreter.  A few conventions must be learned: symbols and blocks usually confuse beginners, but once the basics are second nature code comprehension edges closer to instinct.&lt;/p&gt;


	&lt;p&gt;I&amp;#8217;ve always argued &lt;strong&gt;verbosity&lt;/strong&gt; over needless truncation: write &lt;code&gt;recurring_reminders&lt;/code&gt; not &lt;code&gt;rcrr_rmdrs&lt;/code&gt; or just &lt;code&gt;r&lt;/code&gt;.  Concise code is important but is not created by shortening variable or method names.  Verbose names are not enough, however.  There are more ways to create intuitive code.&lt;/p&gt;


	&lt;p&gt;Another more fundamental technique is to &lt;strong&gt;follow the conventions of your language&lt;/strong&gt;.  Ruby programmers commonly use two-letter spacing, lower-case names for variables, &lt;code&gt;do ... end&lt;/code&gt; blocks rather than curly brackets (unless the code fits on one line), symbols for options (rather than string constants), exclamation marks and question marks where appropriate.  Stick to your language&amp;#8217;s conventions so other people can follow your code (I learned this the hard way with JavaScript).&lt;/p&gt;


	&lt;p&gt;Short methods are another good technique: method names more accurately describe a short amount of code, and it&amp;#8217;s easier to consider a short amount of code as one chunk, and therefore compose more complex methods.&lt;/p&gt;


	&lt;p&gt;Tests should also be intuitive, they should follow the same stylistic guidelines.  There&amp;#8217;s an argument for single assertion tests, which logically follows short method names, but I find this is too restrictive.  Here&amp;#8217;s an example of one of my tests:&lt;/p&gt;


&lt;pre class="code"&gt;
  def test_contains_repeater?
    assert Deadline.contains_repeater?("Kev's birthday every April 9th")
    assert Deadline.contains_repeater?("Simon's birthday each May 9th")
    assert !Deadline.contains_repeater?("Buy every Star Trek DVD on June 9th")
  end
&lt;/pre&gt;

	&lt;p&gt;This code is simple and easy to follow, but it doesn&amp;#8217;t help the reader understand what a &amp;#8220;repeater&amp;#8221; is.  Rather than adding a comment, a clearer method name would help: &lt;code&gt;Deadline.contains_recurring_event?&lt;/code&gt;.  I find that &lt;span class="caps"&gt;TDD&lt;/span&gt; or &lt;span class="caps"&gt;BDD&lt;/span&gt; helps me write clear method names from the outset.&lt;/p&gt;


	&lt;p&gt;On the subject of method naming: I like the concept of &lt;a href="http://c2.com/cgi/wiki?IntentionNotAlgorithm"&gt;Intention Not Algorithm&lt;/a&gt;.  Methods should be named after what they accomplish, rather than how they work.  This could be applied to the test method name above:&lt;/p&gt;


&lt;pre class="code"&gt;
  def test_phrases_that_contain_recurring_events
    assert Deadline.contains_recurring_event?("Kev's birthday every April 9th")
    assert Deadline.contains_recurring_event?("Simon's birthday each May 9th")
  end

  def test_phrases_that_do_not_contain_recurring_events
    assert !Deadline.contains_recurring_event?("Buy every biscuit on June 9th")
  end
&lt;/pre&gt;

	&lt;p&gt;Without moving on to the obvious question of why &lt;code&gt;contains_recurring_event?&lt;/code&gt; is a class method, I hope you can see that considering how intuitive code is for the reader can yield some interesting insights into readability and structure.&lt;/p&gt;


	&lt;p&gt;It would be great to look at common design patterns to see how intuitive they are in implementation.  How many people are quickly confused by code that uses deep-OO jargon to describe simple patterns like Prototype, Decorator and Factories?&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=YzHmQknDSzU:d-x9xhptBEM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=YzHmQknDSzU:d-x9xhptBEM:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=YzHmQknDSzU:d-x9xhptBEM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/webdevelopernotes/~4/YzHmQknDSzU" height="1" width="1"/&gt;</description>
      <pubDate>Fri, 15 May 2009 16:10:34 BST</pubDate>
      <link>http://feedproxy.google.com/~r/webdevelopernotes/~3/YzHmQknDSzU/intuitive_code</link>
      <dc:creator>Alex Young</dc:creator>
    <feedburner:origLink>http://alexyoung.org/articles/show/85/intuitive_code</feedburner:origLink></item>
    <item>
      <title>Future of Web Design Notes</title>
      <description>&lt;p&gt;I &lt;em&gt;almost&lt;/em&gt; survived &lt;a href="http://events.carsonified.com/fowd"&gt;Future of Web Design&lt;/a&gt; unscathed.  I say almost because I still have a slightly dull head, thanks to the after party and free drinks.  I can&amp;#8217;t quite remember why, but at one point I thought ordering a load of sambuca shots would be a great idea.&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://www.carsonified.com/"&gt;Carsonified&amp;#8217;s&lt;/a&gt; events have so far been a rare chance for me to meet up with fellow web designers and developers.  This &lt;span class="caps"&gt;FOWD&lt;/span&gt; had a particularly friendly atmosphere, and I met lots of interesting people.  The Carsonified team were professional and friendly, keeping the event ticking along smoothly.&lt;/p&gt;


	&lt;p&gt;Web design is a diverse subject.  There&amp;#8217;s a continuum between design as ergonomics/usability and visual design.  Add standards to the mix and web design suddenly looks more like engineering.  The talks moved back and forth along this continuum throughout the day.&lt;/p&gt;


	&lt;p&gt;I don&amp;#8217;t think web design currently knows whether it&amp;#8217;s design, engineering or science, but combining all the required disciplines keeps enough people interested and inspired to make events like this both fascinating and productive.&lt;/p&gt;


	&lt;h3&gt;Danny Somekh&lt;/h3&gt;


	&lt;p&gt;The first talk was an off the bill presentation by &lt;a href="http://dannysomekh.wordpress.com/"&gt;Danny Somekh&lt;/a&gt; about a concept he calls Agile Branding.  I&amp;#8217;m sure he&amp;#8217;ll elaborate on the concept at his blog, but a few things stuck with me:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;During meetings, only involve people who can add to the creative process&lt;/li&gt;
		&lt;li&gt;Use visual exploration early on&lt;/li&gt;
		&lt;li&gt;Involve users/customers&lt;/li&gt;
		&lt;li&gt;Try to create an environment that fosters co-creation&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;As a Rails developer and big &lt;a href="http://pragprog.com/"&gt;PragProg&lt;/a&gt; fan, I find the idea of agile branding/design fascinating.  I found it hard to see how it would be implemented, but so many designers work with such rigid constraints that it could be a big thing in the future.&lt;/p&gt;


	&lt;h3&gt;Jim Coudal&lt;/h3&gt;


	&lt;p&gt;I&amp;#8217;ve got a &lt;a href="http://www.coudal.com/"&gt;Coudal&lt;/a&gt; sticker on my netbook, so I felt like a bit of a fanboy during Jim&amp;#8217;s keynote.  I&amp;#8217;m not really, but I do like their Field Notes books.&lt;/p&gt;


	&lt;p&gt;He agreed with some of Danny&amp;#8217;s points&amp;#8212;some early &lt;em&gt;agile design&lt;/em&gt; endorsement perhaps?  He went on to talk about &lt;a href="http://www.coudal.com/bookingbands.php"&gt;Booking Bands&lt;/a&gt; and the relationship between having a short attention span and the creative process.  I liked Jin&amp;#8217;s positive analysis of short attention spans, and how switching to new projects/technologies/tools can yield unexpected rewards.&lt;/p&gt;


	&lt;h3&gt;Meagan Fisher&lt;/h3&gt;


	&lt;p&gt;Meagan, from &lt;a href="http://simplebits.com/"&gt;SimpleBits&lt;/a&gt;, talked about building mobile web interfaces.  Her experiences and design decisions closely follow what I&amp;#8217;ve done at &lt;a href="http://helicoid.net/"&gt;Helicoid&lt;/a&gt;&amp;#8212;I launch all my apps with mobile interfaces like the ones she described, and blog occasionally about the process at &lt;a href="http://mmm.helicoid.net/"&gt;mmm&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;She really demystified mobile web design for people who were unfamiliar with it, and gave some great book recommendations, like &lt;a href="http://mobilewebbook.com/"&gt;Cameron Moll&amp;#8217;s Mobile Web Book&lt;/a&gt;.  I&amp;#8217;ve read it, it&amp;#8217;s just about all you need to get going in the mobile web.&lt;/p&gt;


	&lt;h3&gt;Brett Welch&lt;/h3&gt;


	&lt;p&gt;Brett from &lt;a href="http://goodbarry.com/"&gt;GoodBarry&lt;/a&gt; gave a talk about design and business, with advice on how designers can maintain confidence and relationships with their clients despite market trends.&lt;/p&gt;


	&lt;p&gt;His talk centred around establishing yourself as an expert, communicating value to clients in ways they can understand, understanding your clients and their strategies.  He even gave practical advice on how to conduct meetings with clients:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;When starting a meeting, always talk about the client&amp;#8217;s business first.  Try to establish the business context&lt;/li&gt;
		&lt;li&gt;Get a feel for their business and set a tone for helping them to become successful&lt;/li&gt;
		&lt;li&gt;Understand what they want to achieve and manage their expectations&lt;/li&gt;
		&lt;li&gt;Websites need marketing plans, and ongoing attention&lt;/li&gt;
		&lt;li&gt;Set business targets: avoid talking about traffic early on&lt;/li&gt;
		&lt;li&gt;Talk about tools, timeline, what happens after the site has been built&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;I learned a lot from Brett&amp;#8217;s talk, it was useful to hear business advice aimed at us.&lt;/p&gt;


	&lt;h3&gt;Mark Boulton&lt;/h3&gt;


	&lt;p&gt;&lt;a href="http://www.markboulton.co.uk/"&gt;Mark&amp;#8217;s&lt;/a&gt; talk was about typography.  He discussed the basics, type as interface, the controversial topic of font embedding, and helping Drupal.&lt;/p&gt;


	&lt;p&gt;I think his work on Drupal sounds like something that could be applied to many open source projects:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Wherever possible, help people make good design decisions&lt;/li&gt;
		&lt;li&gt;Provide smart defaults: don&amp;#8217;t offer every font, just let them choose from two good ones&lt;/li&gt;
		&lt;li&gt;Styles vs. lots of options: reduce choice&lt;/li&gt;
		&lt;li&gt;Authors want to be creative, which is why they&amp;#8217;ll always experiment with the design options.  Create a system that empowers them&lt;/li&gt;
		&lt;li&gt;Try to make choices higher up the &amp;#8220;cascade&amp;#8221;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;Robin Christpherson&lt;/h3&gt;


	&lt;p&gt;&lt;a href="http://www.abilitynet.org.uk/webteam#robin"&gt;Robin&amp;#8217;s&lt;/a&gt; talk was about designing for accessibility.  He used screen reading software to demonstrate how the web feels for the blind and visually impaired.&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Well-structured documents and headings make documents easier to navigate&lt;/li&gt;
		&lt;li&gt;Documents structured with a logical reading order helps a lot (I think most designers do this anyway since the &lt;span class="caps"&gt;CSS&lt;/span&gt;/standards revolution, but some of his example sites were still hard to navigate)&lt;/li&gt;
		&lt;li&gt;Consider the amount of info on each page: he brought up a list of the links on a page to navigate, but most of the pages had hundreds of links&lt;/li&gt;
		&lt;li&gt;Captcha accessibility is generally poor&lt;/li&gt;
		&lt;li&gt;Sifr/flash: despite attempts at accessibility, more than 4 of these objects on a page can make the reader very slow&lt;/li&gt;
		&lt;li&gt;Drop down boxes can be skipped entirely so he didn&amp;#8217;t have to read each option, unlike lists of links&lt;/li&gt;
		&lt;li&gt;&amp;#8220;Live regions&amp;#8221; and screen reader support&lt;/li&gt;
		&lt;li&gt;Mobile versions of sites are easier because they&amp;#8217;re so simple and quick to navigate&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;Mike Kus&lt;/h3&gt;


	&lt;p&gt;&lt;a href="http://www.thethingswemake.co.uk/"&gt;Mike&lt;/a&gt; discussed design from the perspective of someone with an extensive background in graphic design.  He suggested that we should break trends: designers usually research and draw on a wide range of influences for their work, discovering new combinations, and we should do the same.&lt;/p&gt;


	&lt;p&gt;His slides were beautiful, and he had a 3 minute video at the end showing how he made them: I expected a video will be posted of his talk at some point, it&amp;#8217;ll be worth finding to see this part.&lt;/p&gt;


	&lt;h3&gt;Sabrina Dent&lt;/h3&gt;


	&lt;p&gt;Sabrina talked about &amp;#8220;Stalinist web design&amp;#8221;.  Her presentation was full of humour, but it also had some useful tips:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Learn to say &amp;#8220;no&amp;#8221; &lt;/li&gt;
		&lt;li&gt;Eliminate choices: Why give clients 3 mockups?  Why not give them your best mockup&amp;#8212;you&amp;#8217;re the expert, design choices are yours to make&lt;/li&gt;
		&lt;li&gt;Just do it: Rather than asking a client about possible improvements, just do them&lt;/li&gt;
		&lt;li&gt;Caveat: You better be good&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;Folkert Gorter&lt;/h3&gt;


	&lt;p&gt;Folkert&amp;#8217;s slides are on a big &lt;span class="caps"&gt;HTML&lt;/span&gt; page here: &lt;a href="http://cargo.superfamous.com/972"&gt;cargo.superfamous.com/972&lt;/a&gt;.  He drew parallels between his early work on &lt;span class="caps"&gt;CDROM&lt;/span&gt; design and modern social web applications.&lt;/p&gt;


	&lt;h3&gt;Simon Sankarayya&lt;/h3&gt;


	&lt;p&gt;&lt;a href="http://www.allofus.com/"&gt;Simon Sankarayya&amp;#8217;s&lt;/a&gt; talk reminded me heavily of &lt;a href="http://www.amazon.co.uk/Smile-Mind-Thinking-Graphic-Design/dp/0714838128"&gt;A Smile in the Mind&lt;/a&gt;.  He also related his experience from the days of &lt;span class="caps"&gt;CDROM&lt;/span&gt; and Director to the modern web.  He mentioned &lt;a href="http://en.wikipedia.org/wiki/Naoto_Fukasawa"&gt;Naoto Fukasawa&lt;/a&gt; as an influence.&lt;/p&gt;


	&lt;h3&gt;Molly Holzschlag&lt;/h3&gt;


	&lt;p&gt;&lt;a href="http://molly.com/"&gt;Molly&amp;#8217;s&lt;/a&gt; talk concerned the future of web standards, and had some healthy Microsoft bashing.  I noticed she said the next IE will support &lt;span class="caps"&gt;SVG&lt;/span&gt; which is cool, but why couldn&amp;#8217;t that have gone into 8?&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=_xNRgNFbo3o:CK-GSke4cfo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=_xNRgNFbo3o:CK-GSke4cfo:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=_xNRgNFbo3o:CK-GSke4cfo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/webdevelopernotes/~4/_xNRgNFbo3o" height="1" width="1"/&gt;</description>
      <pubDate>Fri,  1 May 2009 19:25:59 BST</pubDate>
      <link>http://feedproxy.google.com/~r/webdevelopernotes/~3/_xNRgNFbo3o/future_of_web_design_notes</link>
      <dc:creator>Alex Young</dc:creator>
    <feedburner:origLink>http://alexyoung.org/articles/show/84/future_of_web_design_notes</feedburner:origLink></item>
    <item>
      <title>Ryan Singer Workshop</title>
      <description>&lt;p&gt;I went to the Ryan Singer Carsonified workshop yesterday.  The title of the workshop was &amp;#8220;How to design amazing web app user interfaces&amp;#8221;.  Ryan discussed his influences and processes behind &lt;a href="http://37signals.com/"&gt;37signal&amp;#8217;s&lt;/a&gt; interfaces.&lt;/p&gt;


	&lt;p&gt;Ryan&amp;#8217;s workshop covered:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Least effective difference&lt;/li&gt;
		&lt;li&gt;Copy&lt;/li&gt;
		&lt;li&gt;Workflow: Highrise example&lt;/li&gt;
		&lt;li&gt;Flow&lt;/li&gt;
		&lt;li&gt;Validation&lt;/li&gt;
		&lt;li&gt;Rails advice&lt;/li&gt;
		&lt;li&gt;How &lt;span class="caps"&gt;MVC&lt;/span&gt; helps organise designers and developers&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;As a web application developer and designer who uses Rails, I found his insights fascinating.  Here are my notes from the workshop.  I haven&amp;#8217;t managed to capture everything we talked about&amp;#8212;these are the things that made an impression on me.&lt;/p&gt;


	&lt;h2&gt;Least effective difference&lt;/h2&gt;


	&lt;p&gt;I think one thing most of the attendees will take away from that workshop will be the concept of &lt;em&gt;least effective difference&lt;/em&gt;.  Ryan cited Edward Tufte for this concept.&lt;/p&gt;


	&lt;p&gt;Contrast should be used purposefully.  For example: adding borders to a table may increase the contrast between the page and the table, making the table&amp;#8217;s data less prominent.  Certain things cause &amp;#8220;vibration&amp;#8221;, attracting the eye to things that aren&amp;#8217;t important.&lt;/p&gt;


	&lt;p&gt;Ryan suggested that &lt;span class="caps"&gt;HTML&lt;/span&gt; should have a &lt;code&gt;weak&lt;/code&gt; tag.  After all, it has &lt;code&gt;strong&lt;/code&gt;, so why not?  After all, music has piano, mezzo-piano, mezzo-forte, and forte.&lt;/p&gt;


	&lt;h2&gt;Copy&lt;/h2&gt;


	&lt;p&gt;One of Ryan&amp;#8217;s major points was the importance of copy in web applications.  Generating good quality text is part of his design process.  He discussed the following steps, using &lt;a href="http://highrisehq.com/"&gt;Highrise&amp;#8217;s&lt;/a&gt; sidebar as an example:&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;Write out a list of things the sidebar should do: Add New Person, Add New Company, etc.&lt;/li&gt;
		&lt;li&gt;Work on the copy without worrying about graphics, buttons, colours&amp;#8212;anyone should be able to understand the functionality from the text alone&lt;/li&gt;
		&lt;li&gt;Start with verbose text&lt;/li&gt;
		&lt;li&gt;Slowly tighten the language&lt;/li&gt;
		&lt;li&gt;Iterate this process to refine&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;I noticed that Ryan seemed to pull out active verbs, strip passive verbs and impersonal pronouns, and try to start the text with verbs.  For example:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Would you like to &lt;strong&gt;add&lt;/strong&gt; a person?&lt;/li&gt;
		&lt;li&gt;You can &lt;strong&gt;create&lt;/strong&gt; a person here&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;Add&lt;/strong&gt; a new person&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h2&gt;Workflow: Highrise example&lt;/h2&gt;


	&lt;p&gt;Ryan addressed the visual design decisions for a particular Highrise sidebar.   At this stage the design was a simple list of links.  These are the questions a designer should ask themselves:&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;Why change the list of links?  Does this design do the job?&lt;/li&gt;
		&lt;li&gt;Links are equally weighted: does this reflect use case?&lt;/li&gt;
		&lt;li&gt;As a designer, think about why someone is seeing the list, and think about where they want to go next&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;A daily operation in running a business is  &amp;#8220;got a new contact, need to add it to Highrise&amp;#8221;.  That means the &amp;#8220;Add new person&amp;#8221;  link would need to be the most prominent.  Ryan evolved the design, applying the least effective difference principle, making certain options grey, others bold and larger, with some spacing and suitable headers.&lt;/p&gt;


	&lt;p&gt;Ryan also suggested that links generally mean &amp;#8220;go somewhere&amp;#8221;, whereas buttons represent functionality.&lt;/p&gt;


	&lt;h3&gt;1: List things the feature requires&lt;/h3&gt;


&lt;div style="background-color: #ffc"&gt;&lt;pre&gt;
Add another person to Highrise
Add another company to Highrise
Import contact from vCard, Excel, Basecamp, Outlook
Export data to vCard, Excel
&lt;/pre&gt;&lt;/div&gt;

	&lt;h3&gt;2: Refine the copy&lt;/h3&gt;


&lt;div style="background-color: #ffc"&gt;&lt;pre&gt;
Add a new person
Add a new company
Import (vCard, Excel, Basecamp, Outlook...) 
Export (vCard, Excel) 
&lt;/pre&gt;&lt;/div&gt;

	&lt;h3&gt;3: Refine design&lt;/h3&gt;


	&lt;ol&gt;
	&lt;li&gt;Decide what matters&lt;/li&gt;
		&lt;li&gt;Make that pop out&lt;/li&gt;
		&lt;li&gt;Make everything else fade back&lt;/li&gt;
	&lt;/ol&gt;


	&lt;h3&gt;4: Consider other visual elements&lt;/h3&gt;


	&lt;p&gt;&lt;img src="http://dl.getdropbox.com/u/221414/blogs/highrise.png" alt="" /&gt;&lt;/p&gt;


	&lt;h2&gt;Flow&lt;/h2&gt;


	&lt;p&gt;&lt;strong&gt;Always be ready for the next user input or action.&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;Ryan explained the difference between database-like applications, and ones that consider flow.  He also gave examples of web applications that don&amp;#8217;t consider user flow.&lt;/p&gt;


	&lt;p&gt;He explained 37signal&amp;#8217;s thinking behind taking the user from the &lt;em&gt;add contact&lt;/em&gt; page to the &lt;em&gt;show contact&lt;/em&gt; page, rather than back to the list of contacts.&lt;/p&gt;


	&lt;p&gt;I found this interesting, because it&amp;#8217;s sometimes hard to see where the next action should be in a web application.  It&amp;#8217;s not always clear.  In Highrise, people commonly need to append related info to contacts after adding them, so it makes more sense to redirect to the &lt;em&gt;show contact&lt;/em&gt; page rather than the list of contacts.&lt;/p&gt;


	&lt;h2&gt;Validation&lt;/h2&gt;


	&lt;p&gt;Rather than being quick to rely on Rails validation errors, Ryan&amp;#8217;s designs attempt to accept any user input.&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Submitting an empty form could just show the form again, as submitting and showing an &amp;#8216;add page&amp;#8217; might be more confusing&lt;/li&gt;
		&lt;li&gt;In Backpack, adding a page with no title will create the page and just name it &amp;#8216;No title&amp;#8217;&lt;/li&gt;
		&lt;li&gt;Try and avoid states where the user can make a mistake&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h2&gt;Rails advice&lt;/h2&gt;


	&lt;ul&gt;
	&lt;li&gt;JavaScript and stylesheets follow Rails controller names&lt;/li&gt;
		&lt;li&gt;&amp;#8220;Body classes&amp;#8221; used to manage this&lt;/li&gt;
		&lt;li&gt;Rarely use helpers to render blocks of &lt;span class="caps"&gt;HTML&lt;/span&gt;, preferring lots of templates instead&lt;/li&gt;
		&lt;li&gt;Even rjs should use &lt;span class="caps"&gt;HTML&lt;/span&gt; partials&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h2&gt;Book recommendations&lt;/h2&gt;


	&lt;ul&gt;
	&lt;li&gt;Edward Tufte: The Visual Display of Quantitative Information&lt;/li&gt;
		&lt;li&gt;Kent Beck: Smalltalk Best Practice Patterns&lt;/li&gt;
		&lt;li&gt;Modeling: &lt;strong&gt;Christopher Alexander&lt;/strong&gt;&amp;#8217;s notes on synthesis form, &lt;strong&gt;Eric Evans&lt;/strong&gt; domain driven design&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h2&gt;Conclusions&lt;/h2&gt;


	&lt;p&gt;If read my blog, you&amp;#8217;ll know that my background is programming.  As a web developer for the last 10 years I&amp;#8217;ve had to learn design as a matter of course, and I&amp;#8217;ve taken it more seriously since starting my own consultancy and web application company.  The way Ryan works is very similar to me, so yesterday&amp;#8217;s workshop galvanised my confidence.&lt;/p&gt;


	&lt;p&gt;Also, I&amp;#8217;d love to work with designers who are familiar with Kent Beck and Edward Tufte&amp;#8217;s books, so get reading!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=gmhfkSHc2GU:oxXb5M4gXjQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=gmhfkSHc2GU:oxXb5M4gXjQ:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=gmhfkSHc2GU:oxXb5M4gXjQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/webdevelopernotes/~4/gmhfkSHc2GU" height="1" width="1"/&gt;</description>
      <pubDate>Tue, 28 Apr 2009 13:00:35 BST</pubDate>
      <link>http://feedproxy.google.com/~r/webdevelopernotes/~3/gmhfkSHc2GU/ryan_singer_workshop</link>
      <dc:creator>Alex Young</dc:creator>
    <feedburner:origLink>http://alexyoung.org/articles/show/83/ryan_singer_workshop</feedburner:origLink></item>
    <item>
      <title>Deadline for Mac (and GitHub hooks)</title>
      <description>&lt;p&gt;&lt;img src="http://dl.getdropbox.com/u/221414/deadline/deadline_mac_blog.png" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://deadlineapp.com"&gt;Deadline&lt;/a&gt; is a reminder web app I made.  It sends out alerts through &lt;span class="caps"&gt;SMS&lt;/span&gt;, email and IM, and now it works with Mac OS too.  I spent this weekend building a Mac cocoa app for it that integrates with Growl.  You can download it here:  &lt;a href="http://dl.getdropbox.com/u/221414/deadline/DeadlineGrowl.zip"&gt;DeadlineGrowl&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;Deadline also works with GitHub: &lt;a href="http://blog.helicoid.net/articles/2009/04/18/deadline_notification_api_and_github_support"&gt;Deadline: Notification &lt;span class="caps"&gt;API&lt;/span&gt; and GitHub support&lt;/a&gt;.  It uses post-receive hooks to grab commit messages and notify you through your preferred notification method.&lt;/p&gt;


	&lt;p&gt;I really like the idea of hook URLs.  Deadline has a generic notification &lt;span class="caps"&gt;API&lt;/span&gt; (it&amp;#8217;s just a &lt;span class="caps"&gt;GET&lt;/span&gt; to a &lt;span class="caps"&gt;URL&lt;/span&gt;) you could use to notify your users about events in your apps.  If you&amp;#8217;re interested in using this, or using Deadline&amp;#8217;s &lt;span class="caps"&gt;API&lt;/span&gt; for a project, let me know and I&amp;#8217;ll give you a hand.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=1xiU0h9foRI:honeZMwu8mo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=1xiU0h9foRI:honeZMwu8mo:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=1xiU0h9foRI:honeZMwu8mo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/webdevelopernotes/~4/1xiU0h9foRI" height="1" width="1"/&gt;</description>
      <pubDate>Tue, 21 Apr 2009 13:39:14 BST</pubDate>
      <link>http://feedproxy.google.com/~r/webdevelopernotes/~3/1xiU0h9foRI/deadline_for_mac_and_github_hooks</link>
      <dc:creator>Alex Young</dc:creator>
    <feedburner:origLink>http://alexyoung.org/articles/show/82/deadline_for_mac_and_github_hooks</feedburner:origLink></item>
    <item>
      <title>Secure Trading Rails Plugin</title>
      <description>&lt;p&gt;&lt;img src="http://dl.getdropbox.com/u/221414/blogs/securetrading.png" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;I use &lt;a href="http://www.securetrading.com/"&gt;Secure Trading&lt;/a&gt; for &lt;a href="http://helicoid.net"&gt;Helicoid&amp;#8217;s&lt;/a&gt; payment processing.  I wrote a payment processor plugin for our apps about two years ago, and it&amp;#8217;s been in production since then.  A few people have asked me to open source the code, so here it is: &lt;a href="http://github.com/alexyoung/securetrading-rails/tree/master"&gt;securetrading-rails&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;I&amp;#8217;d like to integrate it with &lt;a href="http://www.activemerchant.org/"&gt;ActiveMerchant&lt;/a&gt; because I like their &lt;span class="caps"&gt;API&lt;/span&gt;, but I haven&amp;#8217;t had time so far.&lt;/p&gt;


	&lt;p&gt;Out of all the payment processing companies I&amp;#8217;ve dealt with, which is a lot, Secure Trading have been the most reliable with the best customer service.  Their &lt;span class="caps"&gt;XML API&lt;/span&gt; is relatively straightforward too.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=LEYdeFEJVow:2Xqh-_2AG2E:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=LEYdeFEJVow:2Xqh-_2AG2E:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=LEYdeFEJVow:2Xqh-_2AG2E:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/webdevelopernotes/~4/LEYdeFEJVow" height="1" width="1"/&gt;</description>
      <pubDate>Wed, 15 Apr 2009 12:05:17 BST</pubDate>
      <link>http://feedproxy.google.com/~r/webdevelopernotes/~3/LEYdeFEJVow/secure_trading_rails_plugin</link>
      <dc:creator>Alex Young</dc:creator>
    <feedburner:origLink>http://alexyoung.org/articles/show/81/secure_trading_rails_plugin</feedburner:origLink></item>
    <item>
      <title>Beautiful Algorithms</title>
      <description>&lt;p&gt;I&amp;#8217;m starting a new series on Quite Useful called &lt;a href="http://quiteuseful.co.uk/post/94808348/beautiful-algorithms"&gt;beautiful algorithms&lt;/a&gt;.  I&amp;#8217;m going to talk about the algorithms behind graphical effects, especially those from the demo scene back in the 90s.&lt;/p&gt;


	&lt;p&gt;&lt;img src="http://dl.getdropbox.com/u/221414/quiteuseful/ba/burn_baby.png" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;I&amp;#8217;ve posted some examples to my GitHub account if you want to check out what I&amp;#8217;ve been researching so far.  They use &lt;a href="http://wiki.github.com/jashkenas/ruby-processing/"&gt;Ruby Processing&lt;/a&gt;, which is a pretty accessible way to try out ideas.&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://github.com/alexyoung/fire-p5r/tree/master"&gt;Fire effect&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://github.com/alexyoung/tunnel-p5r/tree/master"&gt;Tunnel effect&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Please contribute improvements to these and I&amp;#8217;ll include them.  Imagine what the demo scene would have been like if people shared code on GitHub!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=dV3gQVPo5a4:D_SoapyEEn0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=dV3gQVPo5a4:D_SoapyEEn0:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/webdevelopernotes?a=dV3gQVPo5a4:D_SoapyEEn0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/webdevelopernotes?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/webdevelopernotes/~4/dV3gQVPo5a4" height="1" width="1"/&gt;</description>
      <pubDate>Fri, 10 Apr 2009 11:07:22 BST</pubDate>
      <link>http://feedproxy.google.com/~r/webdevelopernotes/~3/dV3gQVPo5a4/beautiful_algorithms</link>
      <dc:creator>Alex Young</dc:creator>
    <feedburner:origLink>http://alexyoung.org/articles/show/80/beautiful_algorithms</feedburner:origLink></item>
  </channel>
</rss>
