<?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>Push cx &#187; design</title>
	<atom:link href="http://push.cx/tag/design/feed" rel="self" type="application/rss+xml" />
	<link>http://push.cx</link>
	<description>A traveling geek&#039;s blog on development, games, and the web</description>
	<lastBuildDate>Thu, 19 Apr 2012 20:39:20 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Rules of Database App Aging</title>
		<link>http://push.cx/2009/rules-of-database-app-aging</link>
		<comments>http://push.cx/2009/rules-of-database-app-aging#comments</comments>
		<pubDate>Fri, 16 Jan 2009 03:25:53 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[databases]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[lifecycle]]></category>
		<category><![CDATA[schemas]]></category>

		<guid isPermaLink="false">http://push.cx/?p=407</guid>
		<description><![CDATA[I mentioned I&#8217;ve learned some rules of how database apps change over time, now that I&#8217;ve done a few dozen. They are: All Fields Become Optional As your dataset grows, exceptions creep in. There&#8217;s not enough research time to fill in all your company profiles, there&#8217;s one guy in Guam when you expected everyone to [...]]]></description>
			<content:encoded><![CDATA[<p>
I <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvMjAwOS93YXNoaW5ndG9uLXBvc3QtdXBkYXRl">mentioned</a> I&#8217;ve learned some rules of how database apps change over time, now that I&#8217;ve done a few dozen. They are:
</p>

<ol>

<li>
<h3>All Fields Become Optional</h3>

<p>
As your dataset grows, exceptions creep in. There&#8217;s not enough research time to fill in all your company profiles, there&#8217;s one guy in Guam when you expected everyone to be in a U.S. state, there&#8217;s data missing from the page you&#8217;re scraping, you have to pull updates from a new source.
</p>

<p>
Every field eventually loses that beautiful <kbd>NOT NULL</kbd> sheen, your code gets filled up with guard clauses of one kind <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3dlYmxvZy5yYWdhbndhbGQuY29tLzIwMDgvMDEvb2JqZWN0YW5kYW5kLW9iamVjdG1lLWluLXJ1YnkuaHRtbA==">or another</a> and every &lt;div&gt; in your template is wrapped by an <kbd>if</kbd> statement. And this happens to foreign keys, too, so <kbd>OR IS (NOT) NULL</kbd> sneaks in and left joins mutate into outer joins.
</p>

<p>
This is by far the biggest effect on apps over time. It&#8217;s getting to the point that I can gauge age by eyeballing the number of fields that retain their <kbd>NOT NULL</bd> constraint.
</p>
</li>

<li>
<h3>All Relationships Become Many-to-Many</h3>

<p>
Some guy works in DC but lives in Virginia, so he needs two Locations. A new type of incoming email needs to be shoveled out to different feeds. A state has both a primary and a caucus. Someone eventually realizes categories never really were mutually exclusive.
</p>

<p>
The modern database paradigm is defined by relations, so of course that's what falls apart as soon as you get an app into production. The urge to hack is overwhelming, fudge in a little denormalization or duplicate a row and the pressure's off for now, but it's like freezing a bottle of water, it always grows and breaks worse in the end.
</p>
</li>

<li>
<h3>Chatter Always Expands</h3>

<p>
All the little oddities that change database schemas affect the user presentation as well. Chatter is the intro and outro text around the content of a page that almost no one ever reads. But it has to be there to explain what's going on, the source of information, why things may seem peculiar, the limitations of the dataset, etc. Add in the difficulty of writing succintly and chatter grows until you burn it all down by rebuilding the app.
</p>
</li>

</ol>

<p>
And when you do rebuild the app from the ground up, you have your chance to slip some NULLs back on, renormalize your data to have easy one-to-many relationships, and present the data in a self-evident and consistent fashion. Then, about a week later, there's a politician who's a Democrat but running for re-election as an Independent...
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=407" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2009/rules-of-database-app-aging/feed</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>RailsRumble Postmortem</title>
		<link>http://push.cx/2008/railsrumble-postmortem</link>
		<comments>http://push.cx/2008/railsrumble-postmortem#comments</comments>
		<pubDate>Sun, 19 Oct 2008 23:28:38 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[AASM]]></category>
		<category><![CDATA[Bort]]></category>
		<category><![CDATA[ConfReader]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[haml]]></category>
		<category><![CDATA[open_id_authentication]]></category>
		<category><![CDATA[Paperclip]]></category>
		<category><![CDATA[planning]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[RailsRumble]]></category>
		<category><![CDATA[resource_this]]></category>
		<category><![CDATA[restful_authentication]]></category>
		<category><![CDATA[RSpec]]></category>
		<category><![CDATA[scheduling]]></category>
		<category><![CDATA[teamwork]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://push.cx/?p=364</guid>
		<description><![CDATA[I failed to launch my Rails Rumble project ConfReader. Why? Poor scheduling Couldn&#8217;t stay up because work is demanding in the election season, so working late would mean I&#8217;d limp through the next week of important coverage. More than that, though, was a bad mistake in scheduling a social outing. I didn&#8217;t figure in some [...]]]></description>
			<content:encoded><![CDATA[<p>
I failed to launch my Rails Rumble project <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=LzIwMDgvcmFpbHNydW1ibGluZw==">ConfReader</a>. Why?
</p>


<h3>Poor scheduling</h3>
<p>
Couldn&#8217;t stay up because work is demanding in the election season, so working late would mean I&#8217;d limp through the next week of important coverage. More than that, though, was a bad mistake in scheduling a social outing. I didn&#8217;t figure in some of travel time and the friend driving wanted to spend a lot more time out, so instead of having a nice morning out I got home at 7 PM tired and in a foul mood. I was able to relax a bit and get some code done, but it cut my available time by more than half.
</p>


<h3>Too many new toys</h3>
<p>
I knew I hadn&#8217;t played with encoding video before, so I asked an expert for some tips and tinkered around breaking test videos down into short, easily-transcribed segments. Not coincidentally, this is basically the only feature that works. I started with <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2dpdGh1Yi5jb20vZnVkZ2VzdHVkaW9zL2JvcnQvdHJlZS9tYXN0ZXI=">bort</a> to get a lot of basic functionality quickly, but I had no experience with most of the plugins it provided (and those I otherwise planned to use).
</p>

<dl>
  <dt>aasm</dt> <dd>Differences between acts_as_state_machine (which I started with) and aasm (the successor that bort ships).</dd>
  <dt>haml</dt> <dd>Translating scaffolding from erb to haml and a (still-unsolved) bug that causes it to render content twice on one page. (And I&#8217;ve even used haml before.)</dd>
  <dt>open_id_authentication/restful_authentication</dt> <dd>I wanted users to be able to contribute anonymously or use OpenID to receive credit for their contributions without having to set up an account, and the plugins came configured for conventional user accounts.</dd>
  <dt>resource_this</dt> <dd>I had to fix a templating bug, and there&#8217;s a fair amount of magic to learn to work with.</dd>
  <dt>rspec</dt> <dd>Scaffolded tests needed slow, tedious tweaks to work with resource_this. I think I like the idea of rspec more than the implementation.</dd>
  <dt>paperclip</dt> <dd>Sorting out finicky path/url issues, and I couldn&#8217;t find a way to mock validates_attachment_presence so several models went unspeced..</dd>
</dl>

<p>
Each of these issues ate 30-60m, and there went the time to build. Some plugins (acts_as_versioned, footnotes, random_finders) just worked great, but none was really related to core functionality. Speaking of which:
</p>


<h3>Core featureset too big</h3>
<p>
The line between nothing and application includes site graphic design, listing conferences, uploading presentation videos, splitting videos into segments, adding transcripts, viewing all of the these, editing transcripts&#8230; I had a lot of features listed as optional, but there was still a long set of base features and each uncovered another one of those frustrations.
</p>


<h3>No teammates</h3>
<p>
It would&#8217;ve helped a lot to have someone to work with. Not just because it would have taken less time to finish the core features, but for the enjoyment of teamwork and to complement my weaknesses.
</p>

<h3>All told</h3>
<p>
I&#8217;m glad I spent time I spent hanging out in #railsrumble or on the RailsRumble present.ly. Even if it didn&#8217;t directly result in items checked off the todo list, it&#8217;s been a fun community to be in, and I was glad to help folks out. I&#8217;m eager to see what other people came up with.
</p>

<p>
I didn&#8217;t enter RailsRumble to win, I entered for the excuse to create what I thought was an interesting small project. I&#8217;ll pick ConfReader back up in a little while, probably after the election. I still think it&#8217;s too good an idea not to build, but I&#8217;m a bit tired right now.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=364" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2008/railsrumble-postmortem/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How To De-Asshole-ify Links</title>
		<link>http://push.cx/2007/how-to-de-asshole-ify-links</link>
		<comments>http://push.cx/2007/how-to-de-asshole-ify-links#comments</comments>
		<pubDate>Thu, 01 Nov 2007 16:26:30 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[assholes]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[links]]></category>
		<category><![CDATA[user experience]]></category>

		<guid isPermaLink="false">http://push.cx/2007/how-to-de-asshole-ify-links</guid>
		<description><![CDATA[I loathe sites that set unvisited and visited links to be the same color. There are exactly two reasons that sites do this: A graphic designer thought it would be more harmonious to have them the same color. A business guy thought it would increase pageviews. The worst part is, they&#8217;re both right. But they&#8217;re [...]]]></description>
			<content:encoded><![CDATA[<p>
I loathe sites that set unvisited and visited links to be the same color. There are exactly two reasons that sites do this:
</p>

<ol>
    <li>A graphic designer thought it would be more harmonious to have them the same color.</li>
    <li>A business guy thought it would increase pageviews.</li>
</ol>

<p>
The worst part is, they&#8217;re both right. But they&#8217;re assholes because they&#8217;re selling out user experience to avoid picking a color or to inflate a not-very-useful statistic. Users are deliberately confused and led to click in circles for their trivial convenience or wrongheaded book-cooking.
</p>

<p>
This boiled over for me when I was trying to read <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5jb3B5YmxvZ2dlci5jb20=">CopyBlogger</a>. They have some really nice writing, but I found myself opening the articles over and over because I couldn&#8217;t see that I&#8217;d visited it. I just gave up on reading the site, who needs assholes?
</p>

<p>
A few days later I remembered that Firefox has a setting in the preferences to override page and link colors. Unfortunately, it doesn&#8217;t let me override link colors and leave page colors alone.
</p>

<p>
The way to do undo the damage these assholes have done to their own site is to add a user stylesheet to Firefox. It&#8217;s a styling file that Firefox loads for every single page you visit. In Linux it&#8217;s <kbd>~/.mozilla/firefox/<i>random junk</i>/chrome/userContent.css</kbd>. On other systems, search for the file <kbd>userContent.css</kbd>, though you may just need to search for the <kbd>chrome</kbd> directory and create the file. Here&#8217;s what to put in there:
</p>

<pre>&nbsp;
p &gt; a <span style="color: #66cc66;">&#123;</span> <span style="color: #000000; font-weight: bold;">color</span>: <span style="color: #000000; font-weight: bold;">blue</span> !important; <span style="color: #000000; font-weight: bold;">text-decoration</span>: <span style="color: #993333;">underline</span> !important; <span style="color: #66cc66;">&#125;</span>
p &gt; a<span style="color: #3333ff;">:visited </span><span style="color: #66cc66;">&#123;</span> <span style="color: #000000; font-weight: bold;">color</span>: <span style="color: #993333;">purple</span> !important; <span style="color: #000000; font-weight: bold;">text-decoration</span>: <span style="color: #993333;">underline</span> !important; <span style="color: #66cc66;">&#125;</span></pre>

<p>
This forces all unvisited links in the text of a page to be blue and underlined, and all visited links to be purple and underlined. This isn&#8217;t perfect, sometimes the text of a page will be <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL21ldGFmaWx0ZXIuY29t">on a blue background</a>, but it works well for nearly all pages I visit. The best part about is is the <kbd>p &gt;</kbd> keeps it from changing link colors in headers and other parts of the page that are almost never on white backgrounds.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=269" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2007/how-to-de-asshole-ify-links/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Good Timing</title>
		<link>http://push.cx/2007/good-timing</link>
		<comments>http://push.cx/2007/good-timing#comments</comments>
		<pubDate>Mon, 02 Jul 2007 12:58:53 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[Hostway]]></category>
		<category><![CDATA[RegistryPro]]></category>
		<category><![CDATA[sleep]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://push.cx/2007/good-timing</guid>
		<description><![CDATA[This morning, at about 4:30 AM, I awoke and just knew the Right Way to rebuild RegistryPro to be completely reliable, even more compact, and provide meaningful reporting. It would take less than two weeks of coding time and the pitfalls are well-demarcated and avoidable. It would be really great if I&#8217;d thought of it [...]]]></description>
			<content:encoded><![CDATA[<p>
This morning, at about 4:30 AM, I awoke and just <i>knew</i> the Right Way to rebuild <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3JlZ2lzdHJ5cHJvLnBybw==">RegistryPro</a> to be completely reliable, even more compact, and provide meaningful reporting. It would take less than two weeks of coding time and the pitfalls are well-demarcated and avoidable. It would be really great if I&#8217;d thought of it two years ago when I still worked there. Thanks, brain.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=248" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2007/good-timing/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Human-Readable ActiveResource URLs</title>
		<link>http://push.cx/2007/human-readable-activeresource-urls</link>
		<comments>http://push.cx/2007/human-readable-activeresource-urls#comments</comments>
		<pubDate>Tue, 03 Apr 2007 21:15:07 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[ActiveResource]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[human-readable]]></category>
		<category><![CDATA[named routes]]></category>
		<category><![CDATA[nested routes]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Rails 1.1]]></category>
		<category><![CDATA[Rails 1.2]]></category>
		<category><![CDATA[RESTful]]></category>
		<category><![CDATA[routes]]></category>
		<category><![CDATA[URLs]]></category>

		<guid isPermaLink="false">http://push.cx/2007/human-readable-activeresource-urls</guid>
		<description><![CDATA[I&#8217;ve got URLs on the brain this week. I started NearbyGamers using Rails 1.1 with just gamers and tags. I upgraded to Rails 1.2 (and liked it) , and added discussions after I updated to Rails 1.2. I was able to use ActiveResource for Discussions with Posts as a nested resource. I&#8217;m really happy with [...]]]></description>
			<content:encoded><![CDATA[<p>
I&#8217;ve got URLs on the brain this week. I started <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJieWdhbWVycy5jb20=">NearbyGamers</a> using Rails 1.1 with just gamers and <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJieWdhbWVycy5jb20vdGFncw==">tags</a>. I upgraded to Rails 1.2 (and <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvMjAwNy9yYWlscy0xMjEtaW1wcmVzc2lvbg==">liked it</a>)
, and added <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJieWdhbWVycy5jb20vZGlzY3Vzc2lvbnM=">discussions</a> after I updated to Rails 1.2. I was able to use ActiveResource for Discussions with Posts as a nested resource. I&#8217;m really happy with this code, as it&#8217;s very tidy.
</p>

<p>
On Sunday I updated gamers and tags to use ActiveResource. It wasn&#8217;t hard, mostly just renames (the &#8216;view&#8217; action became &#8216;show&#8217;, for example) and removing url_for hashes (<kbd>:controller => 'gamers', :action => 'view', :handle => @gamer.handle</kbd>) with much nicer named routes (<kbd>gamer_path(@gamer)</kbd>). A gripe I have about ActiveResource is that it has poor URLs, with internal record IDs leaking out. I&#8217;ve had nice URLs (<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJieWdhbWVycy5jb20vZ2FtZXJzL0hhcmtpbnM=">/gamers/Harkins</a> and <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL25lYXJieWdhbWVycy5jb20vdGFncy9SUEdz">/tags/RPGs</a>) for gamers and tags and I wanted to keep them.
</p>

<p>
Joshua Schacter gave a presentation on building and growing <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2RlbC5pY2lvLnVz">del.icio.us</a> that included the gems (among <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3NpbW9uLmluY3V0aW8uY29tL25vdGVzLzIwMDYvc3VtbWl0L3NjaGFjaHRlci50eHQ=">many other gems</a>):
</p>

<blockquote>
<ul>
  <li>Dont expose your unique id&#8217;s to the outside world (php?id=1 etc.) people can
scrape through everything very easily. This is why del.icio.us uses MD5 hashes
of links instead.
</li>
  <li>URLs are prime real estate &#8211; respect them</li>
</ul>
</blockquote>

<p>
It turns out this is not just possible but easy, though I blew an hour or so finding it (Rails docs still need love). In my Gamer and Tag objects, I just define a <kbd>to_param</kbd> method and the URL builder picks it up:
</p>

<pre>&nbsp;
class Gamer &lt; ActiveRecord::<span style="color: #006600;">Base</span>
  def to_param
    self.<span style="">handle</span>
  <span style="color: #b1b100;">end</span>
end
class Tag &lt; ActiveRecord::<span style="color: #006600;">Base</span>
  def to_param
    self.<span style="">name</span>
  <span style="color: #b1b100;">end</span>
end
&nbsp;
<span style="color: #808080; font-style: italic;"># and over in config/routes.rb I do the usual:</span>
<span style="color: #000066;">map</span>.<span style="">resources</span> :gamers
<span style="color: #000066;">map</span>.<span style="">resources</span> :tags, :memger =&gt; <span style="color: #66cc66;">&#123;</span> :history =&gt; :get, :variantes =&gt; :get <span style="color: #66cc66;">&#125;</span>
<span style="color: #808080; font-style: italic;"># and now gamer_path(@gamer) and tag_path(@tag) work in my views</span></pre>

<p>
My controller looks like:
</p>

<pre>&nbsp;
class GamersController &lt; ApplicationController
  before_filter :load_gamer, :except =&gt; <span style="color: #66cc66;">&#91;</span> :<span style="color: #000066;">index</span> <span style="color: #66cc66;">&#93;</span>
&nbsp;
  <span style="color: #808080; font-style: italic;"># The regular index, show, edit, and update actions here</span>
&nbsp;
  private
  def load_gamer
    <span style="color: #0000ff;">@gamer</span> = Gamer.<span style="">find_by_handle</span><span style="color: #66cc66;">&#40;</span>params<span style="color: #66cc66;">&#91;</span>:id<span style="color: #66cc66;">&#93;</span>, :include =&gt; <span style="color: #66cc66;">&#91;</span>:location, :tags<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span>
    raise ::<span style="color: #006600;">ActionController</span>::<span style="color: #006600;">RoutingError</span>, <span style="color: #ff0000;">"Recognition failed for #{request.path}"</span> <span style="color: #b1b100;">if</span> <span style="color: #0000ff;">@gamer</span>.<span style="">nil</span>?
    <span style="color: #808080; font-style: italic;"># canonicalize case</span>
    redirect_to gamer_path<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">@gamer</span><span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">and</span> <span style="color: #000066;">return</span> <span style="color: #b1b100;">if</span> <span style="color: #0000ff;">@gamer</span>.<span style="">handle</span> != params<span style="color: #66cc66;">&#91;</span>:id<span style="color: #66cc66;">&#93;</span>
  <span style="color: #b1b100;">end</span></pre>

<p>
And every action that needs it has the @gamer object loaded from the URL param, with 404 errors handled and mistaken case fixed. There&#8217;s <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2Rldi5ydWJ5b25yYWlscy5vcmcvdGlja2V0LzY4MTQ=">a patch</a> that will let you rename the :id parameter. I can&#8217;t say I mind if it&#8217;s not accepted; I don&#8217;t mind calling it :id instead of :handle or :name because I think of it as the public id of the object.
</p>

<p>
Come back Thursday, I&#8217;ll tell you how I made my discussion URLs even more useful.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=232" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2007/human-readable-activeresource-urls/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Microsoft AdCenter&#8217;s 316-page Terms of Service</title>
		<link>http://push.cx/2006/microsoft-adcenters-316-page-terms-of-service</link>
		<comments>http://push.cx/2006/microsoft-adcenters-316-page-terms-of-service#comments</comments>
		<pubDate>Fri, 29 Dec 2006 20:50:32 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Biz]]></category>
		<category><![CDATA[AdCenter]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://push.cx/2006/microsoft-adcenters-316-page-terms-of-service</guid>
		<description><![CDATA[I signed up for Microsoft AdCenter, and got an interesting presentation of terms and condititions: The terms and conditions are exactly 2,840 words long. At 9 words each, that&#8217;s 316 pages. There&#8217;s no way to resize the TOS div and, yes, the whole form is abnormally wide. Between the above problems and the problems in [...]]]></description>
			<content:encoded><![CDATA[<p>
I signed up for Microsoft AdCenter, and got an interesting presentation of terms and condititions:
</p>

<img class="content" src="http://push.cx/wp-content/uploads/2006/12/adcenter.png" alt="Microsofter AdCenter's TOS" />

<p>
The terms and conditions are exactly 2,840 words long. At 9 words each, that&#8217;s 316 pages. There&#8217;s no way to resize the TOS div and, yes, the whole form is abnormally wide.
</p>

<p>
Between the above problems and the problems in the rest of the signup, I have to guess they failed to test in Firefox. I can see why Microsoft might not want to, but 30% of surfers use Firefox, and it&#8217;s a far higher percentage higher for the web professionals who are going to be using this service.
</p>

<p>
It does get worse: when I go to sign in I type my username and password, click &#8220;Sign In&#8221;, and am presented with the sign in form with my username and no password or errors. It just silently fails to log me in. I&#8217;m not too optimistic about their support, they can&#8217;t even keep the url to it from breaking across two lines in the &#8220;Welcome to AdCenter&#8221; mail.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=192" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2006/microsoft-adcenters-316-page-terms-of-service/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Tidy Stylesheets in Rails</title>
		<link>http://push.cx/2006/tidy-stylesheets-in-rails</link>
		<comments>http://push.cx/2006/tidy-stylesheets-in-rails#comments</comments>
		<pubDate>Sat, 28 Oct 2006 03:06:06 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[maintainability]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://push.cx/2006/tidy-stylesheets-in-rails</guid>
		<description><![CDATA[It&#8217;s very easy for a site&#8217;s CSS to grow a single giant, brittle stylesheet. It becomes impossible to change anything because of bizarre interactions between elements, unexpected interactions, and simply because it&#8217;s just too big for anyone to understand. Much of programming is managing complexity, and I&#8217;ll share a nice technique in that vein. I [...]]]></description>
			<content:encoded><![CDATA[<p>
It&#8217;s very easy for a site&#8217;s CSS to grow a single giant, brittle stylesheet. It becomes impossible to change anything because of bizarre interactions between elements, unexpected interactions, and simply because it&#8217;s just too big for anyone to understand. Much of programming is managing complexity, and I&#8217;ll share a nice technique in that vein.
</p>

<p>
I like to break down stylesheets so there&#8217;s a site-wide stylesheet with global stylings like fonts, the site&#8217;s template, and common elements. This is the file that metastasizes on you.
</p>

<p>
My solution is to break down stylesheets by controller and action, and Rails makes this quite easy:
</p>

<pre>&nbsp;
<span style="color: #808080; font-style: italic;"># app/views/layout/application.rb</span>
&lt;%= stylesheet_link_tag *<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'global'</span><span style="color: #66cc66;">&#93;</span> + <span style="color: #0000ff;">@stylesheets</span><span style="color: #66cc66;">&#41;</span> %&gt;</pre>

<pre>&nbsp;
<span style="color: #808080; font-style: italic;"># app/controllers/application.rb</span>
class ApplicationController &lt; ActionController::<span style="color: #006600;">Base</span>
  before_filter :add_stylesheets
&nbsp;
  def initialize
    <span style="color: #0000ff;">@stylesheets</span> = <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#93;</span>
  <span style="color: #b1b100;">end</span>
&nbsp;
  def add_stylesheets
    <span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">"#{controller_name}/_controller"</span>, <span style="color: #ff0000;">"#{controller_name}/#{action_name}"</span><span style="color: #66cc66;">&#93;</span>.<span style="">each</span> <span style="color: #b1b100;">do</span> |stylesheet|
      <span style="color: #0000ff;">@stylesheets</span> &lt;&lt; stylesheet <span style="color: #b1b100;">if</span> File.<span style="">exists</span>? <span style="color: #ff0000;">"#{Dir.pwd}/stylesheets/#{stylesheet}.css"</span>
    <span style="color: #b1b100;">end</span>
  <span style="color: #b1b100;">end</span>
end</pre>

<p>
This code automatically loads stylesheets for the controller and the action if they exist. The subdivision allows you to make them as compact and specific as possible. If a partial needs its own code, write at the top:
</p>

<pre>&nbsp;
&lt;% <span style="color: #0000ff;">@styleshets</span> &lt;&lt; <span style="color: #ff0000;">"controller/_partial_name"</span> %&gt;</pre>

<p>
Nice and tidy.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=186" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2006/tidy-stylesheets-in-rails/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Vox Non-Launch Party</title>
		<link>http://push.cx/2006/vox-non-launch-party</link>
		<comments>http://push.cx/2006/vox-non-launch-party#comments</comments>
		<pubDate>Sun, 30 Jul 2006 00:02:20 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Biz]]></category>
		<category><![CDATA[Chicago]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[user interface]]></category>
		<category><![CDATA[Vox]]></category>

		<guid isPermaLink="false">http://push.cx/2006/vox-non-launch-party</guid>
		<description><![CDATA[I got invited Thursday night to a party for Vox. Invitation-only parties are weird. I&#8217;m not used to feeling like the in-crowd, so my out-crowd mentality always makes me feel vaguely guilty. But after I got over that, it was a good evening. I&#8217;d say Vox is basic LiveJournal aimed at an older audience. It&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>
<img class="decoration" width="179" height="101" src="http://push.cx/wp-content/uploads/2006/07/vox-logo.jpg" alt="Vox logo" />
I got invited Thursday night to a party for <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3ZveC5jb20=">Vox</a>. Invitation-only parties are weird. I&#8217;m not used to feeling like the in-crowd, so my out-crowd mentality always makes me feel vaguely guilty. But after I got over that, it was a good evening.
</p>

<p>
I&#8217;d say Vox is basic <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2xpdmVqb3VybmFsLmNvbQ==">LiveJournal</a> aimed at an older audience. It&#8217;s a blog for people who hear blog and think &#8220;Oh, those things that the newspaper keeps mentioning as bad for business and the cable news is so scared of.&#8221; People who don&#8217;t want to share pictures of their kids with random internet strangers but find their cc list getting unmanageably long. Vox is a blogging site with a surprisingly nice user interface, the first I feel I can recommend to my mom without signing up to do a few hours of tutoring and answering questions.
</p>

<p>
It really is nice. Six Apart clearly learned a lot from LiveJournal and thought hard about how to make a blogging service to let you bring your relationships with family and friends online with minimal weirdness. Vox is not trying to be an engineering triumph, it just is a user interface triumph.
</p>

<p>
All is not roses, of course. They&#8217;re not fully launching until roughly October. You have to join an announcement list to get an account, I got the impression they&#8217;re adding a batch of a couple thousand people every few weeks. The site simply doesn&#8217;t work in Safari yet, and IE is iffy. There&#8217;s no public bug tracker, so I can&#8217;t even guess at how many features are missing or broken, so I can&#8217;t recommend anyone sign up until the launch in a few months. Also, if you happen to know any hardcore LiveJournal fans you&#8217;re in for a rant about how Six Apart wants to destroy LJ and Vox is some kind of weapon in this covert campaign.
</p>

<p>
The party was one of a series Vox is doing before launch ostensibly so that Vox doesn&#8217;t just grow out of California like most social websites. There was a blurry demo, open bar, and around fifty people at the <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=bWNhY2hpY2Fnby5vcmcv">MCA</a>. I enjoyed chatting with four of the Six Apart employees present (out of seven or so) and around a third of the other guests.
</p>

<p>
I look forward to seeing launch, and web developers should learn from their very nice blog posting interface.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=168" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2006/vox-non-launch-party/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Sock Strategies</title>
		<link>http://push.cx/2006/sock-strategies</link>
		<comments>http://push.cx/2006/sock-strategies#comments</comments>
		<pubDate>Sat, 15 Jul 2006 16:17:32 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[design]]></category>

		<guid isPermaLink="false">http://push.cx/2006/sock-strategies</guid>
		<description><![CDATA[It&#8217;s easy for socks to go missing, and it&#8217;s annoying to have to match up socks. My girlfriend and I have developed two entirely different strategies for dealing with these eventualities. She owns a good variety of socks which are safety-pinned together anytime they&#8217;re not actually on her feet. Her socks do everything paired up. [...]]]></description>
			<content:encoded><![CDATA[<p>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2ZsaWNrci5jb20vcGhvdG9zL25vcmljdW0vMTA4NDg4OTQ3Lw=="><img class="decoration" src="http://push.cx/wp-content/uploads/2006/07/fox_in_socks.jpg" alt="Fox in Socks" width="300" height="196" /></a>
It&#8217;s easy for socks to go missing, and it&#8217;s annoying to have to match up socks. My girlfriend and I have developed two entirely different strategies for dealing with these eventualities.
</p>

<p>
She owns a good variety of socks which are safety-pinned together anytime they&#8217;re not actually on her feet. Her socks do everything paired up. This solves the matching problem and greatly reduces the likelihood any go missing (and at least they do it in pairs). If one should wear out before the other, though, they&#8217;re both lost.
</p>

<p>
My strategy is to own a large number of exactly two styles of socks:  black unlabeled athletic ankle socks and black unlabeled athletic crew socks. Sorting is trivial, loss and damage are inconsequential. Wearing mismatched socks is only sometimes necessary on laundry day and is at least unobtrusive. When I notice one type of sock is low, I just go buy another dozen.
</p>

<p>
What&#8217;s your sock strategy?
</p>

<p class="update">
<b>2007-02-22</b>: My girlfriend would like it to be known that she does not dispose of the surviving complements to worn out socks, they go into a drawer to be potentially matched up with other socks whose mates are lost. This distinction is vital, and I admit my sole culpability in its oversight.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=153" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2006/sock-strategies/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Ripping Unicode</title>
		<link>http://push.cx/2006/ripping-unicode</link>
		<comments>http://push.cx/2006/ripping-unicode#comments</comments>
		<pubDate>Fri, 16 Jun 2006 03:57:05 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[graphics]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://push.cx/2006/ripping-unicode</guid>
		<description><![CDATA[I love shoving around large amounts of data. Unicode is an industry standard for encoding data in most every written script there&#8217;s ever been. It has over 97,000 characters. A while ago I read about a guy who made his own Unicode poster and I realized I had an opportunity for a fun project. I [...]]]></description>
			<content:encoded><![CDATA[<p>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvd3AtY29udGVudC91cGxvYWRzLzIwMDYvMDYvMUQ1MEYucG5n"><img class="decoration" src="http://push.cx/wp-content/uploads/2006/06/1D50F.thumbnail.png" width="67" height="96" alt="some unicode glyphs" /></a>
I love shoving around large amounts of data. Unicode is an industry standard for encoding data in most every written script there&#8217;s ever been. It has over 97,000 characters. A while ago I read about a guy who <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2lhbi1hbGJlcnQuY29tL21pc2MvdW5pY2hhcnQucGhw">made his own Unicode poster</a> and I realized I had an opportunity for a fun project. I think Unicode is an invaluable and beautiful project, and this is my tribute to it.
</p>

<p>
Unicode puts out PDF code charts of each and every glyph so people can have some idea of what they should look like (though the actual display to the user is left up to fonts). If you&#8217;d like to see one, the chart for <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy51bmljb2RlLm9yZy9jaGFydHMvUERGL1UxMDAwMC5wZGY=">Linear B</a> is a nice little example. Because I didn&#8217;t want to mess around with putting dozens of PDFs together, I just grabbed the <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3VuaWNvZGUub3JnL1B1YmxpYy80LjEuMC9jaGFydHMvQ29kZUNoYXJ0cy5wZGY=">single 30MB 777-page PDF</a> for the latest version, 4.1.0. (New versions are released as they add more scripts &#8212; cuneiform is scheduled for 5.0, yay!)
</p>

<p>
Looking at the PDF (whether you grabbed the small example or decided to be macho and pulled up the whole thing), it&#8217;s obvious that the &#8220;one big table per page&#8221; approach makes it pretty easy to extract the glyphs. I wrote a program to do this, because it would be <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5sb2djYWJpbi5vcmc=">stupid and ultimately self-defeating</a> to open the PDF with <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2dpbXAub3Jn">GIMP</a> to manually select and save each glyph.
</p>

<p>
First, I used <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5jcy53aXNjLmVkdS9+Z2hvc3Qv">ghostscript</a> to convert the PDF to a series of 600 DPI pngs, one image per page. This took about 39 minutes and 471MB of disk space. (I&#8217;ll explain why I converted at such a high resolution in about two paragraphs.)
</p>

<p>
Next, I wrote a <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2RpdmVpbnRvcHl0aG9uLm9yZw==">Python</a> script using the <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5weXRob253YXJlLmNvbS9wcm9kdWN0cy9waWwv">Python Imaging Library</a> to analyze every page, locate the glyph table if the page has one, and walk through the table exporting each glyph to its own individual PNG. The 769MB of individual glyph images took about 5.6 hours to rip. And that&#8217;s OK! I kept the code simple to read because <i>performance doesn&#8217;t matter</i>. That&#8217;s an odd thing to say for a program that takes hours to finish, but you only ever run this program <i>once</i>. Note, that&#8217;s never an excuse for shoddy quality, because you never run a program just once. Yes, those two statements are at odds. If you don&#8217;t see that they&#8217;re both true, you have not yet learned the Tao of Code.
</p>

<p>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvd3AtY29udGVudC91cGxvYWRzLzIwMDYvMDYvQTI5Qy5wbmc="><img class="decoration" src="http://push.cx/wp-content/uploads/2006/06/A29C.thumbnail.png" alt="Unicode glyph A29C" width="71" height="96" /></a>
Well, there&#8217;s one important step elided from the previous paragraph: figuring out which glyph is which so I know what the filename should be. Every glyph is labeled with a four or five-digit hexadecimal number, but of course the label is part of the image rather than text. Converting images to text is known as OCR (optical character recognition) and it&#8217;s difficult to avoid errors. In my favor I had images that were big (600 DPI, see, I told you I&#8217;d get back to it), error-free, and black-and-white; but a strike against me was that it can&#8217;t spell-check a word like &#8220;A29C&#8221;. After trying a few different OCR programs, I got <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5nbnUub3JnL3NvZnR3YXJlL29jcmFkL29jcmFkLmh0bWw=">ocrad</a> working well (with a little tinkering, it often mistook the number 0 for the letter O).
</p>

<p>
Well, mission accomplished. I&#8217;ve ripped 97,715 glyphs from the Unicode code charts to individual PNGs. So what should I do with them all?
</p>

<p>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvd3AtY29udGVudC91cGxvYWRzLzIwMDYvMDYvaG9zdHdheV9sb2dvLnBuZw=="><img class="decoration" src="http://push.cx/wp-content/uploads/2006/06/hostway_logo.thumbnail.png" alt="Hostway logo" width="128" height="11" /></a>
I work at <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2hvc3R3YXkuY29t">Hostway</a>, a web hosting company with about a dozen offices worldwide. I picked up a copy of our logo in vector format from one of our graphic designers and resized it until it had about the same number of black pixels as I have glyphs.
</p>

<img class="content" src="http://push.cx/wp-content/uploads/2006/06/zoom1.png" width="392" height="401" alt="some unicode glyphs" />

<p>
Then, of course, I wrote another script to render a final image. It created a huge new image in which every pixel from the source was a downsampled (because I&#8217;m printing at 300 DPI) glyph, and it tries to make sure it puts the darkest glyphs in place of the darkest pixel so I have a (very) rough antialiasing effect to soften the edges of letters. (If it&#8217;s not already painfully obvious, yes, I did <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9BU0NJSV9hcnQ=">ascii art</a> as a teenager.) This script immediately <i>crashed and burned</i>.
</p>

<img class="content" src="http://push.cx/wp-content/uploads/2006/06/zoom2.png"  width="392" height="399" alt="some unicode glyphs" />

<p>
The problem is scale. The source image is 1618 x 151 pixels, and I&#8217;m outputting at 300 DPI: 1618 x 151 x 300 x 300 = 20.9GB. As cool as it would be, I just don&#8217;t have that much RAM. I had to break up the image into pieces three feet wide, which is good because that&#8217;s also how wide the biggest printer in the office is. And I got to write a great error message:  &#8220;Can&#8217;t create images this big. Reduce max_piece_width or buy more RAM.&#8221;
</p>

<img class="content" src="http://push.cx/wp-content/uploads/2006/06/zoom3.png"  width="392" height="400" alt="some unicode glyphs" />

<p>
Made of 16 images totaling 310MB (it took 45m), the Hostway logo worked out to be 6 feet tall and 46 feet long. My boss told me it was &#8220;too big&#8221; to hang up. I told him that was &#8220;exactly the point of the whole thing&#8221;. I&#8217;ll change his mind yet &#8212; everyone in the office I show it to loves it, so it&#8217;s just a matter of time.
</p>

<img class="content" src="http://push.cx/wp-content/uploads/2006/06/zoom4.png"  width="170" height="343" alt="some unicode glyphs" />

<p>
I presented the code at the June 2006 meeting of <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2NoaXB5Lm9yZw==">ChiPy</a> and it was well-received. One attendee told me afterwards it was the funniest, nerdiest presentation he&#8217;s ever seen, which I consider high praise. As promised, I&#8217;m sharing the source code.
</p>

<p>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvd3AtY29udGVudC91cGxvYWRzLzIwMDYvMDYvdW5pY29kZS1hcnQuMjAwNi0wNi0xNS50YXIuZ3o=">unicode-art.2006-06-15.tar.gz</a>
</p>

<p>
You&#8217;ll have to be a little familiar with graphics and Python to make use
of this. It is not a copy of all the glyph graphics, and I will not
provide you with them or make posters for you, so please don&#8217;t ask. I&#8217;d love to hear what about what you do with it, please do something cool and post a comment or trackback.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=10" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2006/ripping-unicode/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Developing With Evil</title>
		<link>http://push.cx/2006/developing-with-evil</link>
		<comments>http://push.cx/2006/developing-with-evil#comments</comments>
		<pubDate>Thu, 15 Jun 2006 19:50:06 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[humor]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://push.cx/2006/developing-with-evil</guid>
		<description><![CDATA[allaryin: whee&#8230; allaryin: i&#8217;ve been given a job to put a simple email address subscription form on a site Harkins: sounds pretty easy allaryin: and&#8230; as far as i can tell, the server has neither php nor perl :P allaryin: i&#8217;m running out of options :P Harkins: cgi, baby allaryin: for db access? Harkins: Or [...]]]></description>
			<content:encoded><![CDATA[<p>
<span style="color: red">allaryin</span>: whee&#8230;<br />
<span style="color: red">allaryin</span>: i&#8217;ve been given a job to put a simple email address subscription form on a site<br />
<span style="color: blue">Harkins</span>: sounds pretty easy<br />
<span style="color: red">allaryin</span>: and&#8230; as far as i can tell, the server has neither php nor perl :P<br />
<span style="color: red">allaryin</span>: i&#8217;m running out of options :P<br />
<span style="color: blue">Harkins</span>: cgi, baby<br />
<span style="color: red">allaryin</span>: for db access?<br />                  <span style="color: blue">Harkins</span>: Or change the target of the form to a server you control running PHP/perl that saves the data and redirects back to the other server.<br />
<span style="color: red">allaryin</span>: yeah&#8230;<br />                         <span style="color: red">allaryin</span>: but i really don&#8217;t want to commit any of our server resources to their site :P<br />
<span style="color: green">BSDCat</span>: I think a &#8216;simplicity&#8217; fairy just lost its wings<br />
<span style="color: blue">Harkins</span>: Or make the form GET and write a cron job to scrape access.log.<br />
<span style="color: red">allaryin</span>: &#8230;<br />
<span style="color: red">allaryin</span>: wow.<br />
<span style="color: blue">Harkins</span>: Yes, I&#8217;m evil.<br />
<span style="color: red">allaryin</span>: it&#8217;s beautiful really<br />
<span style="color: blue">Harkins</span>: bwa<br />
<span style="color: red">allaryin</span>: but yes, evil<br />
</p>
 <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=129" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2006/developing-with-evil/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ripping Unicode at ChiPy</title>
		<link>http://push.cx/2006/ripping-unicode-at-chipy</link>
		<comments>http://push.cx/2006/ripping-unicode-at-chipy#comments</comments>
		<pubDate>Fri, 09 Jun 2006 16:00:53 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[graphics]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://push.cx/2006/ripping-unicode-at-chipy</guid>
		<description><![CDATA[Last night at the June 2006 ChiPy meeting I gave a presentation on how I wrote a few small Python scripts to take apart the Unicode PDF of all its glyphs and recombine them into giant ascii-art-like posters. I know a few folks are dropping by looking for the source I promised to post. It&#8217;ll [...]]]></description>
			<content:encoded><![CDATA[<p>
Last night at the June 2006 <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2NoaXB5Lm9yZw==">ChiPy</a> meeting I gave a presentation on how I wrote a few small Python scripts to take apart the <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3VuaWNvZGUub3Jn">Unicode</a> PDF of all its glyphs and recombine them into giant ascii-art-like posters.
</p>

<p>
I know a few folks are dropping by looking for the source I promised to post. It&#8217;ll be up later tonight or tomorrow morning &#8212; I had to recreate one of my scripts from scratch and I&#8217;d like to make sure I did it right so I don&#8217;t post broken code. And as all of you at the presentation understand, running any of these scripts takes a few hours. So it&#8217;ll be up Real Soon Now.
</p>

<p>
Thanks again to Fawad Halim for loaning me the use of his laptop for my presentation.
</p>

<p class="update">
Of course it took a little longer than I expected, but <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvMjAwNi9yaXBwaW5nLXVuaWNvZGU=">it&#8217;s up now</a>.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=127" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2006/ripping-unicode-at-chipy/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Building a Site With Clean URLs</title>
		<link>http://push.cx/2006/building-a-site-with-clean-urls</link>
		<comments>http://push.cx/2006/building-a-site-with-clean-urls#comments</comments>
		<pubDate>Wed, 07 Jun 2006 18:37:26 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://push.cx/2006/building-a-site-with-clean-urls</guid>
		<description><![CDATA[As an aside in my post about Cambrian House I posted some code for making pretty URLs. A few people (no, not CH) have asked for a little more info, so I&#8217;ve written up an explanation of that code. PHP makes it very easy to create bad URLs like /member.php?id=8. Those are bad because web [...]]]></description>
			<content:encoded><![CDATA[<p>
As an aside in <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvMjAwNi9wcmUtY2FtYnJpYW4taG91c2U=">my post about Cambrian House</a> I posted some code for making pretty URLs. A few people (no, not CH) have asked for a little more info, so I&#8217;ve written up an explanation of that code.
</p>

<p>
PHP makes it very easy to create bad URLs like <kbd>/member.php?id=8</kbd>. Those are bad because web spiders don&#8217;t like to crawl URLs with GET variables, some browsers don&#8217;t cache any GET URLs, they expose that you use PHP (when the visitor should never even know), and they&#8217;re just downright ugly and hard to remember. I&#8217;m going to present a way to build a PHP/Apache site with clean URLs.
</p>

<p>
Let&#8217;s look, line-by-line, at the contents of <kbd>.htaccess</kbd>. While writing this article I found a more elegant equivalent in the WordPress code, so I&#8217;ll present that here:
</p>

<pre>
# Tell Apache to load mod_rewrite.
RewriteEngine On
# Rewrite URLs for the location starting at /
# Note this is URL location, not a path to your web root.
RewriteBase /
# If the request asks for a file or directory that doesn't exist
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# send the request to index.php.
RewriteRule . /index.php [L]
</pre>

<p>
The hard part about this change is the shift in thinking. A URL isn&#8217;t just a path to a file you FTP&#8217;d to a web server, it&#8217;s a Universal Resource Locator, an address for information. It doesn&#8217;t matter whether your site presents data taken from files, a database, or a random number generator &#8212; a web browser requests a URL and knows nothing about where the website gets it from.
</p>

<p>
With that in mind, let&#8217;s look at how your PHP site can take apart the URL to route the request to the right PHP script. Create an index.php that looks like:
</p>

<pre>&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> url_parse<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$url</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #808080; font-style: italic;">// strip off get vars and anchor tags</span>
        <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5waHAubmV0L3N0cnBvcw=="><span style="color: #000066;">strpos</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$url</span>, <span style="color: #ff0000;">'?'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
                <span style="color: #0000ff;">$url</span> = <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5waHAubmV0L3N1YnN0cg=="><span style="color: #000066;">substr</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$url</span>, <span style="color: #cc66cc;">0</span>, <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5waHAubmV0L3N0cnBvcw=="><span style="color: #000066;">strpos</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$url</span>, <span style="color: #ff0000;">'?'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5waHAubmV0L3N0cnBvcw=="><span style="color: #000066;">strpos</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$url</span>, <span style="color: #ff0000;">'#'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
                <span style="color: #0000ff;">$url</span> = <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5waHAubmV0L3N1YnN0cg=="><span style="color: #000066;">substr</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$url</span>, <span style="color: #cc66cc;">0</span>, <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5waHAubmV0L3N0cnBvcw=="><span style="color: #000066;">strpos</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$url</span>, <span style="color: #ff0000;">'#'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
        <span style="color: #808080; font-style: italic;">//remove leading slash and possible trailing slash, store in $url</span>
        <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5waHAubmV0L3N1YnN0cg=="><span style="color: #000066;">substr</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$url</span>, <span style="color: #cc66cc;">0</span>, <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span> == <span style="color: #ff0000;">'/'</span><span style="color: #66cc66;">&#41;</span>
                <span style="color: #0000ff;">$url</span> = <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5waHAubmV0L3N1YnN0cg=="><span style="color: #000066;">substr</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$url</span>, <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5waHAubmV0L3N1YnN0cg=="><span style="color: #000066;">substr</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$url</span>, -<span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span> == <span style="color: #ff0000;">'/'</span><span style="color: #66cc66;">&#41;</span>
                <span style="color: #0000ff;">$url</span> = <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5waHAubmV0L3N1YnN0cg=="><span style="color: #000066;">substr</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$url</span>, <span style="color: #cc66cc;">0</span>, -<span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$url</span> == <span style="color: #ff0000;">'/'</span><span style="color: #66cc66;">&#41;</span>
                <span style="color: #0000ff;">$url</span> = <span style="color: #ff0000;">''</span>;
        <span style="color: #0000ff;">$url</span> = <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5waHAubmV0L2V4cGxvZGU="><span style="color: #000066;">explode</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'/'</span>, <span style="color: #0000ff;">$url</span><span style="color: #66cc66;">&#41;</span>;
        
        <span style="color: #b1b100;">return</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$url</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">$actions</span> = <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5waHAubmV0L2FycmF5"><span style="color: #000066;">Array</span></a><span style="color: #66cc66;">&#40;</span>
    <span style="color: #ff0000;">""</span> =&gt; <span style="color: #ff0000;">"front_page.php"</span>,
    <span style="color: #ff0000;">"mail"</span> =&gt; <span style="color: #ff0000;">"mail.php"</span>,
    <span style="color: #ff0000;">"member"</span> =&gt; <span style="color: #ff0000;">"profile.php"</span>,
    <span style="color: #ff0000;">"messageboard"</span> =&gt; <span style="color: #ff0000;">"boards.php"</span>,
<span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #0000ff;">$url</span> = url_parse<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$_SERVER</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'REQUEST_URI'</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #0000ff;">$action</span> = <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5waHAubmV0L2FycmF5X3NoaWZ0"><span style="color: #000066;">array_shift</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$url</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5waHAubmV0L2FycmF5X2tleV9leGlzdHM="><span style="color: #000066;">array_key_exists</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$action</span>, <span style="color: #0000ff;">$actions</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">require</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$actions</span><span style="color: #66cc66;">&#91;</span><span style="color: #0000ff;">$action</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">require</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"404.php"</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #66cc66;">&#125;</span></pre>

<p>
So <kbd>index.php</kbd> takes the first element off the array, and probably uses it to <kbd>require()</kbd> specific templates or scripts that do the work with the rest of the <kbd>$url</kbd> array. Think of it like a switchboard operator &#8212; it sends requests where they need to go.
</p>

<p>
Your individual pages can <kbd>array_shift()</kbd> their arguments from the <kbd>$url</kbd> array. In the example above, <kbd>profile.php</kbd> would expect a username or ID number, and it can <kbd>require("404.php");</kbd> if there&#8217;s nothing there or no user by that id.
</p>

<p>
More complex nested URLs (say, <kbd>/messageboard/chat/new_thread</kbd>) work much the same way <kbd>index.php</kbd> works: the base script examines <kbd>$url</kbd> and passes it on to the scripts it knows about. In the example above, <kbd>boards.php</kbd> can load the requested board or the pages used to create a new post or a new board.
</p>

<p>
In my next post, I&#8217;ll provide <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3B1c2guY3gvMjAwNi9idWlsZGluZy1jbGVhbi11cmxzLWludG8tYS1zaXRl">a clean URL solution for existing sites</a> that can&#8217;t afford to redesign their PHP scripts.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=123" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2006/building-a-site-with-clean-urls/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Writing and Formatting</title>
		<link>http://push.cx/2006/writing-and-formatting</link>
		<comments>http://push.cx/2006/writing-and-formatting#comments</comments>
		<pubDate>Mon, 01 May 2006 16:28:43 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://push.cx/2006/writing-and-formatting</guid>
		<description><![CDATA[<p>
I just read a good post on Gadetopia about <a href="http://www.gadgetopia.com/post/5258">writing skills</a> and had a small correction to offer. Go read it and come back (and read the two linked posts about Word and Frontpage use). I'll wait.
</p>]]></description>
			<content:encoded><![CDATA[<p>
I just read a good post on Gadetopia about <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5nYWRnZXRvcGlhLmNvbS9wb3N0LzUyNTg=">writing skills</a> and had a small correction to offer. Go read it and come back (and read the two linked posts about Word and Frontpage use). I&#8217;ll wait.
</p>

<p>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5mbGlja3IuY29tL3Bob3Rvcy9tLWxvdWlzLzExMDM4NzU5Ny8="><img class="decoration" src="http://push.cx/wp-content/uploads/2006/05/typewriter_keys.jpg" width="225" height="150" alt="Typewriter Keys" /></a>
My correction is to Deane&#8217;s list of &#8220;really poorly-formatted text&#8221; he sees over and over &#8212; he actually has two lists:
</p>

<h2>Really poorly-formatted text</h2>
<ul>
<li>No concept of whitespace</li>
<li>No awareness of how images should be positioned</li>
<li>A desire to center every heading, title, and subtitle</li>
<li>Attempts to “hack” horizontal whitespace with tabs and consecutive spaces</li>
<li>Overly large tables without headings, captions, or consistent spacing</li>
</ul>

<h2>Really poorly-written text</h2>
<ul>
<li>No use of headings</li>
<li>No use of bulleted or numbered lists</li>
<li>Overuse of underlining and boldface</li>
<li>Paragraphs that are way too long for the Web</li>
<li>No awareness of the difference between a line break and a paragraph break</li>
<li>No awareness of what terms should be hyperlinked, and where they should link</li>
</ul>

<p>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5kYW5zaW1tb25zLmNvbS93cml0aW5nX3dlbGxsL2FyY2hpdmUvMjAwNl8wMS5odG0=">Writing well is hard</a>, especially for a young medium like the web where we&#8217;re still figuring out what works on top of the fact that most people never actually learn to write well. I saw a letter a few days ago that read &#8220;You have been selected for a process called VERIFICATION. Verification is a process by which we are required to verify certain information you submitted on your FAFSA application.&#8221; Formatting is not that writer&#8217;s first problem.
</p>

<p>
<a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5mbGlja3IuY29tL3Bob3Rvcy9ld2VkaXN0cmljdC83NDE4NTg1Mi8="><img class="decoration" src="http://push.cx/wp-content/uploads/2006/05/laptop_and_typewriter.jpg" width="225" height="150" alt="Typewriter Keys" /></a>
Additionally, writing on a computer requires thinking about structure and form in a way that&#8217;s wholly alien to writing longhand or on a typewriter. On those, what you see is all you get. What you see on a computer is a representation of some content controlled by generally invisible metadata. Today&#8217;s kids are still being taught by the typewriter generation, so it&#8217;s going to be at least another twenty years before the kids who grew up with an understanding of this duality start teaching to the kids who won&#8217;t believe it could be any other way.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=101" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2006/writing-and-formatting/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sociable Is The New Black</title>
		<link>http://push.cx/2006/sociable-is-the-new-black</link>
		<comments>http://push.cx/2006/sociable-is-the-new-black#comments</comments>
		<pubDate>Wed, 05 Apr 2006 16:38:07 +0000</pubDate>
		<dc:creator>Peter Harkins</dc:creator>
				<category><![CDATA[Biz]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[Sociable]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://push.cx/2006/sociable-is-the-new-black</guid>
		<description><![CDATA[<p>
One of the problems Sociable has is that it can be incredibly tacky. Yes, speaking as officially as possible, I'm saying lots of links to social bookmarking sites at the end of your posts are ugly. So let me address why I wrote a plugin that's easily used to make blogs ugly.
</p>]]></description>
			<content:encoded><![CDATA[<p>
One of the problems Sociable has is that it can be incredibly tacky. Yes, speaking as officially as possible, I&#8217;m saying lots of links to social bookmarking sites at the end of your posts are ugly. So let me address why I wrote a plugin that&#8217;s easily used to make blogs ugly.
</p>

<p>
A lot of web surfers have never heard of social bookmarking sites (SBS). Gasp, shock, horror, not everyone is up-to-date on the web 2.0 meme. I put a little introduction to SBS in the hover text for newbies, and deliberately didn&#8217;t make it editable through the admin interface so that it wouldn&#8217;t get changed into a thousand variations on &#8220;OMG CLIK &#038; MAK MY BLOGG POPULER!&#8221;.  Users can (and do) edit it in the PHP, but as Sociable users are not especially technically savvy it&#8217;s uncommon.
</p>

<p>
More experienced users say linking to SBS is hammy because not every reader uses them, because the sites provide their own bookmarklets and plugins, etc. I don&#8217;t disagree. Sociable exists because blog authors want more traffic and SBS are a great way to get it. Sociable exists for the same reason grocery stores put candy in the checkout lanes and Amazon lets you buy books with one click: as soon as readers finish a post they&#8217;re reminded they can share it with others, it&#8217;s the web 2.0 equivalent of the impulse buy.
</p>

<p>
I wrote Sociable because I wanted to add those links to the bottom of my blog posts. I thought writing a WordPress plugin would be fun, and other people might like to use it. With all that in mind, let me talk about the graphic design decisions I made.
</p>

<p>
By default, Sociable only adds icons to posts when they&#8217;re displayed on individual pages and not on the front page, archives, search results, or feeds. A whole lot of users set Sociable to display everywhere with predictably bad results. I added this option because I&#8217;ve seen blogs that don&#8217;t have (or don&#8217;t prefer to use) pages for individual posts, just archive pages. I weighed this decision heavily but decided in this case that it&#8217;s better to support more users than stop all users from shooting themselves in the foot. (This option is a pretty good analogy for the different design philosophies behind Unix and OS X.)
</p>

<p>
The other big default is to show all SBS icons, and it&#8217;s getting worse and worse. New SBS contact me about once each week to get added, so pretty soon the default is going to pass from humorous overkill into a sprawling mess. (And let me parenthetically tip my hat to the folks who&#8217;ve realized it&#8217;s intentionally silly.) I&#8217;m not sure what to do about this one yet. If I have them all off by default, I&#8217;m going to get inundated with mails from people who&#8217;ve installed it and rightly say it doesn&#8217;t work out of the box. Bad first experience. If I turn on only the most popular few by default, there&#8217;s an ugly &#8220;rich get richer&#8221; effect. I haven&#8217;t thought of a good solution and would appreciate advice.
</p>

<p>
Lastly, I tried to keep the visual clutter down as much as possible in the default CSS. There&#8217;s a caption, and then the icons without adornment, period. The CSS even has to deliberately strip away a lot of visual styling that different blog themes would otherwise add. Most of the noise comes from the fact that the sites&#8217; icons are all visually dissimilar with different color palletes. Any random blog is guaranteed that most of them won&#8217;t match the blog theme, let alone each other.
</p>

<p>
At the moment I&#8217;m looking at it as a good incentive for blog owners to prune down the number of sites they display, but it probably needs more help. One user had a <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL2R5ZXJzLm9yZy9ibG9nL2FyY2hpdmVzLzIwMDYvMDMvMTAvaGFja2luZy10aGUtc29jaWFibGUtd29yZHByZXNzLXBsdWdpbi1mb3ItaW1hZ2Utcm9sbG92ZXJzLw==">creative solution</a> to display icons in grayscale until they&#8217;re hovered over, and I&#8217;ll include that feature (probably in the next version).
</p>

<p>
I hope I&#8217;ve addressed the <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3dlYi1ncmFwaGljcy5jb20vbXRhcmNoaXZlLzAwMTczNi5waHA=">valid</a> <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5jcmU4ZC1kZXNpZ24uY29tL2Jsb2cvMjAwNi8wNC8wNS90aGUtbmV3LWJsb2ctY2x1dHRlci8=">concerns</a> of <a href="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?url=aHR0cDovL3d3dy5pZ25hY2lvbWFyY29zLmNvbS5hci9pbmRleC5waHAvMjAwNi8wNC8wNC9ib3RvbmVzLW8tZGUtY29tby1zZS1lbnN1Y2lhbi1hbGd1bm9zLWJsb2dzLyA=">critics</a>, and I appreciate any advice for further improvements.
</p> <img src="http://push.cx/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=97" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://push.cx/2006/sociable-is-the-new-black/feed</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
	</channel>
</rss>

