<?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>Theodicius &#187; Web Design</title>
	<atom:link href="http://www.theodicius.net/archives/category/web-design/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.theodicius.net</link>
	<description>Good. Evil. Bratwurst.</description>
	<lastBuildDate>Sat, 29 Dec 2012 22:21:29 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Patterns of Understanding</title>
		<link>http://www.theodicius.net/archives/2012/11/10/patterns-of-understanding/</link>
		<comments>http://www.theodicius.net/archives/2012/11/10/patterns-of-understanding/#comments</comments>
		<pubDate>Sat, 10 Nov 2012 20:41:56 +0000</pubDate>
		<dc:creator>arlen</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://www.theodicius.net/?p=535</guid>
		<description><![CDATA[I wrote a little while ago about the advisability of teaching software patterns to beginning developers as well as experienced ones. But it occurs to me there&#8217;s reason for doing it that I may not have covered completely. I’m going to take as my starting point Donald Knuth’s idea that the main task in software [...]]]></description>
				<content:encoded><![CDATA[<p>I wrote a <a href="http://www.theodicius.net/archives/2012/10/13/on-chess-and-s…re-development/ ‎">little while ago</a> about the advisability of teaching software patterns to beginning developers as well as experienced ones. But it occurs to me there&#8217;s  reason for doing it that I may not have covered completely.</p>
<p>I’m going to take as my starting point Donald Knuth’s idea that the main task in software development is to explain to other developers what we want the computer to do, that the primary audience of source code is a human, not a machine. That seems obvious enough to not need much supporting evidence. Nobody lives forever, no one stays in the same job forever; everybody gets replaced, either voluntarily or involuntarily.</p>
<p>While the syntax of the language makes this communication possible, we still need a common conceptual base to make it efficient. Even in English it’s easy to come away from a single sentence with multiple meanings; development languages, with their near-total focus on what over why, can be even more adept at hiding meaning.<br />
<span id="more-535"></span><br />
Noted psychologist Adrian deGroot performed a number of experiments with the minds of chess players (you just knew I was going to work chess into this, somehow, didn&#8217;t you?) but the one that is most relevant to this involves testing memory and understanding of chess positions.</p>
<p>He gave players of varying playing strength a few seconds to look at a &#8220;normal&#8221; chess position, meaning one that quite easily could arise during actual play, even if it hadn’t. He then asked the players to reconstruct the position from memory on an empty chessboard. The better the player, he found, the more accurately they could reconstruct the position.</p>
<p>Then deGroot repeated the experiment using random diagrams, with pieces in improbable (even impossible) positions. Interestingly, he found good players were no better than anyone else at recalling those “nonsensical” positions.</p>
<p>There&#8217;s a reason for this that extends beyond chess. The brain simply isn&#8217;t good at remembering lots of little details. It&#8217;s as if the brain only has so many short-term “slots” to hold things, no matter their size. So it takes what it sees and &#8220;chunks&#8221; it into larger groupings that make sense to it. In this way, a grouping of chess pieces that commonly occurs in a game can be remembered as a single unit.</p>
<p>But we&#8217;re talking about software, not chess. Or are we? Think about a batch of unfamiliar code in front of you, that you&#8217;ve been brought in to revise and extend. If both you and the developer(s) who originally created the code have learned the same patterns, you can take many lines of this code and group them mentally under that pattern, keeping them in your mind efficiently while continuing to read more code.</p>
<p>If you and the original developer(s) of the codebase you&#8217;re working on did not have this common “pattern language” to call upon, you would still end up grouping lines of code into “chunks” in order to comprehend it, but you would additionally have to create your own “chunking algorithm” to do it. “Reinventing the wheel” like this is not only inefficient, it runs counter to today’s more pragmatic development principles.</p>
<p>And because you&#8217;ve been using a common pattern language, you not only group many lines of the code into a single “slot” in your memory under the name of a pattern you already understand, the odds are you and the original developer(s) had the same chunks in mind. You can build your mental model of the code more quickly and reliably, and your model will more closely resemble the original ideas behind the existing code.</p>
<p>This means even if you’re a new developer, you’d be more productive with a new codebase faster knowing the patterns than if you hadn’t learned the patterns in the first place.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.theodicius.net/archives/2012/11/10/patterns-of-understanding/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>What I Did To The Jasmine Phantom</title>
		<link>http://www.theodicius.net/archives/2012/09/25/what-i-did-to-the-jasmine-phantom/</link>
		<comments>http://www.theodicius.net/archives/2012/09/25/what-i-did-to-the-jasmine-phantom/#comments</comments>
		<pubDate>Tue, 25 Sep 2012 17:14:49 +0000</pubDate>
		<dc:creator>arlen</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://www.theodicius.net/?p=507</guid>
		<description><![CDATA[Being a continuation of the saga began in Jasmine And The Headless Webkit. OK, after the last installment I had a working in-browser test runner (standalone Jasmine) and a working command-line test runner (phantom-jasmine). But they were different files, meaning if anything significant changed, I was going to have to duplicate the changes in two [...]]]></description>
				<content:encoded><![CDATA[<p>Being a continuation of the saga began in <a href="http://www.theodicius.net/archives/2012/09/10/the-story-of-jasmine-and-the-headless-webkit/" title="Jasmine And The Headless Webkit">Jasmine And The Headless Webkit</a>.</p>
<p>OK, after the last installment I had a working in-browser test runner (standalone Jasmine) and a working command-line test runner (phantom-jasmine). But they were different files, meaning if anything significant changed, I was going to have to duplicate the changes in two different testing files. This, while workable short-term, is not an acceptable solution.</p>
<p>So I dug in to the files.<br />
<span id="more-507"></span><br />
Upon examination, the browser runner that came with standalone Jasmine included the exact same jasmine files that the command-line runner that came with phantom-jasmine included, so I could dispense with those. But the reporters were different.</p>
<p>The standalone Jasmine used the HTMLReporter from jasmine-html.js, but that reporter wouldn&#8217;t cut it from the command line. And phantom-jasmine used a custom-written ConsoleReporter that wasn&#8217;t included at all in standalone Jasmine.</p>
<p>So I had some reconciliation to do. I revised the testing script in my testrunner file (I used the standalone Jasmine specrunner.html as my base file, because it already included most of what I wanted it to be) and revised the test script in it to be:</p>
<pre>
  var console_reporter = new jasmine.ConsoleReporter()
  var htmlReporter = new jasmine.HtmlReporter();
  var jasmineEnv = jasmine.getEnv();
  jasmineEnv.specFilter = function(spec) {
	return htmlReporter.specFilter(spec);
  };
  jasmineEnv.addReporter(htmlReporter);
  jasmineEnv.addReporter(console_reporter);
      var currentWindowOnload = window.onload;

      window.onload = function() {
        if (currentWindowOnload) {
          currentWindowOnload();
        }
        execJasmine();
      };

      function execJasmine() {
        jasmineEnv.execute();
      }
</pre>
<p>Originally, phantom-jasmine used the TrivialReporter, but that&#8217;s marked as deprecated currently, with the HTMLReporter suggested as the replacement for it, making this easy, because the specrunner file already used it.</p>
<p>Then I moved the ConsoleReporter javascript file into a &#8220;vendor&#8221; directory in my jasmine directory and added a &lt;script> tag to point at its new location. Voila! The tests now ran from either source. A single file ran the same tests either from the command-line or the browser.</p>
<p>I mentioned I&#8217;d been using the command-line to run the tests for a while, and while I had been developing with it I noticed the reporting from it wasn&#8217;t what I&#8217;d like it to be. So I dug into more of the code.</p>
<p>Everything I needed to change was in the method &#8220;reportSuiteResults.&#8221; Originally it read:</p>
<pre>
  proto.reportSuiteResults = function(suite) {
    if (!suite.parentSuite) { return; }
    var results = suite.results();
    var failed = results.totalCount - results.passedCount;
    var color = (failed > 0)? "red" : "green";
    this.log(suite.description + ": " + results.passedCount + " of " + results.totalCount + " passed.", color);
  };
</pre>
<p>Note this completely skips reporting on the top level of describe blocks, so while you may know a little of what you&#8217;re testing, you don&#8217;t know the full context. Plus, if you had a series of tests that were at the top describe level, the results weren&#8217;t reported by this code. Not Good.</p>
<p>So I revised the code to be this:</p>
<pre>
  proto.reportSuiteResults = function(suite) {
    var results = suite.results();
    var failed = results.totalCount - results.passedCount;
    var color = (failed > 0)? "red" : "green";
    var mySuite = suite;
    var description = suite.description;
    while (mySuite.parentSuite) {
        mySuite = mySuite.parentSuite;
        description = mySuite.description + " " + description;
    }
    if (!suite.parentSuite) {
        this.log("-- " + description + " spec subtotals: " +
            results.passedCount + " of " + results.totalCount + " passed.",
            color);
    } else {
        this.log(description + ": " + results.passedCount + " of " +
            results.totalCount + " passed.", color);
    }
  };
</pre>
<p>This starts out pretty much the same as the original code. But it captures the describe blocks at every level, including the top, and concatenates them into one long sentence. It then creates either a subtotal line for an outer describe block or a results line for the inner describe block. This change helps me more easily find which tests ran fine and which ones didn&#8217;t.</p>
<p>I&#8217;m not sure this is the exact thing I&#8217;m looking for in this reporter, yet, but it&#8217;ll do for now. And hopefully I&#8217;ve given you some ideas for customizing the Jasmine reporters yourself. Let me know if you find some interesting things to do in them.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.theodicius.net/archives/2012/09/25/what-i-did-to-the-jasmine-phantom/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The story of Jasmine and the Headless Webkit</title>
		<link>http://www.theodicius.net/archives/2012/09/10/the-story-of-jasmine-and-the-headless-webkit/</link>
		<comments>http://www.theodicius.net/archives/2012/09/10/the-story-of-jasmine-and-the-headless-webkit/#comments</comments>
		<pubDate>Mon, 10 Sep 2012 20:10:05 +0000</pubDate>
		<dc:creator>arlen</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://www.theodicius.net/?p=495</guid>
		<description><![CDATA[No, I&#8217;m not hitting Halloween early. There&#8217;s nothing about pumpkins involved here. I&#8217;m talking about testing your javascript. I&#8217;m talking sane development practice, not ghost stories. I&#8217;d been using jsTestDriver for a while, but got tired of the way it would take off and go navel-gazing without warning, so I looked for something else and [...]]]></description>
				<content:encoded><![CDATA[<p>No, I&#8217;m not hitting Halloween early. There&#8217;s nothing about pumpkins involved here. I&#8217;m talking about testing your javascript.</p>
<p>I&#8217;m talking sane development practice, not ghost stories.</p>
<p>I&#8217;d been using jsTestDriver for a while, but got tired of the way it would take off and go navel-gazing without warning, so I looked for something else and found <a href="http://pivotal.github.com/jasmine/">Jasmine</a>. This was working well for me (I was using the standalone version of Jasmine, which required me to refresh the browser whenever I wanted to test in it) but I missed the convenience of kicking off the tests automagically, from a command line.</p>
<p>Then I found the Phantom.<br />
<span id="more-495"></span><br />
<a href="http://phantomjs.org/index.html">PhantomJS</a> is a project that creates a webkit-based browser in headless form, quite useful for running things that don&#8217;t require a UI, such as tests. And, best of all, it installs easily under OS/X, providing you use <a href="http://mxcl.github.com/homebrew/">homebrew</a> on your mac. (Installation instructions for OS/X and other systems <a href="http://phantomjs.org/download.html">can be found here</a>.)</p>
<p>For me, it was as simple as:<br />
<code><br />
brew update<br />
brew install phantomjs<br />
</code></p>
<p>And phantom was installed.</p>
<p>Then I turned to <a href="https://github.com/jcarver989/phantom-jasmine">phantom-jasmine</a> to hook the Phantom up with jasmine 1.2 and I was ready to roll. It was a simple matter of cloning the phantom-jasmine repo down unto my system, then popping the TestRunner.html file in place and pointing its internals at the locations I&#8217;d placed the code.</p>
<p>Invoking the tests from within my development directory turned out to be a trifle tricky, but nothing extremely complex:<br />
<code><br />
phantomjs ../phantom-jasmine/lib/run_jasmine_test.coffee TestRunner.html<br />
</code></p>
<p>To break this down, &#8220;phantomjs&#8221; is what I installed with homebrew, the &#8220;../phantom-jasmine/lib/run_jasmine_test.coffee&#8221; parameter is from the phantom-jasmine readme (strictly cargo-culted, er, copy/pasted from the readme, it is the coffeescript that actually loads and runs the specified page) while the TestRunner.html file is the page to be used to run the tests. It was placed in my project root so this command line was run as if from there.</p>
<p>For a more concrete example, have a look at my <a href="https://github.com/Paladin/Marshall">Marshall project</a>. I didn&#8217;t include TestRunner in the repo (perhaps I should have) because it relied on the configuration of my dev system, specifically the location of the phantom-jasmine project, but I&#8217;ll reproduce it here for your benefit:<br />
<code><br />
&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"<br />
  "http://www.w3.org/TR/html4/loose.dtd"><br />
&lt;html><br />
&lt;head><br />
  &lt;title>Jasmine Test Runner&lt;/title><br />
  &lt;link rel="stylesheet" type="text/css" href="../phantom-jasmine/vendor/jasmine-1.2.0/jasmine.css"><br />
  &lt;script type="text/javascript" src="../phantom-jasmine/vendor/jasmine-1.2.0/jasmine.js">&lt;/script><br />
  &lt;script type="text/javascript" src="../phantom-jasmine/vendor/jasmine-1.2.0/jasmine-html.js">&lt;/script></p>
<p>  &lt;script type="text/javascript" src="../phantom-jasmine/lib/console-runner.js">&lt;/script></p>
<p>  &lt;!-- SOURCE FILES --><br />
	&lt;script src="js/src/Board.js">&lt;/script><br />
	&lt;script src="js/src/Game.js">&lt;/script><br />
	&lt;script src="js/src/MoveTree.js">&lt;/script><br />
	&lt;script src="js/src/NAG.js">&lt;/script><br />
	&lt;script src="js/src/Pgn.js">&lt;/script><br />
	&lt;script src="js/src/Piece.js">&lt;/script><br />
	&lt;script src="js/src/VBoard.js">&lt;/script></p>
<p>  &lt;!-- TEST FILES --><br />
  &lt;script src="test/board.spec.js">&lt;/script><br />
  &lt;script src="test/game.spec.js">&lt;/script><br />
  &lt;script src="test/MoveTree.spec.js">&lt;/script><br />
  &lt;script src="test/Pgn.spec.js">&lt;/script><br />
  &lt;script src="test/Piece.spec.js">&lt;/script><br />
  &lt;script src="test/VBoard.spec.js">&lt;/script><br />
&lt;/head><br />
&lt;body><br />
&lt;div>&lt;div id="game1">&lt;/div>&lt;div id="game1_board">&lt;/div>&lt;/div></p>
<p>&lt;script type="text/javascript"><br />
  var console_reporter = new jasmine.ConsoleReporter()<br />
  jasmine.getEnv().addReporter(new jasmine.TrivialReporter());<br />
  jasmine.getEnv().addReporter(console_reporter);<br />
  jasmine.getEnv().execute();<br />
&lt;/script></p>
<p>&lt;/body><br />
&lt;/html><br />
</code></p>
<p>You&#8217;ll note the phantom-jasmine directory is located alongside the marshall project files in my dev directory on my dev machine. This isn&#8217;t necessary, just my custom.</p>
<p>Every other reference is based around the TestRunner being in the project root.</p>
<p>I&#8217;ll leave as an exercise for the reader the right way to integrate the command-line test execution into your chosen IDE.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.theodicius.net/archives/2012/09/10/the-story-of-jasmine-and-the-headless-webkit/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting Rails 3.0.3/Nginx/Passenger Up On Dreamhost VPS</title>
		<link>http://www.theodicius.net/archives/2011/10/21/getting-rails-3-0-3nginxpassenger-up-on-dreamhost-vps/</link>
		<comments>http://www.theodicius.net/archives/2011/10/21/getting-rails-3-0-3nginxpassenger-up-on-dreamhost-vps/#comments</comments>
		<pubDate>Fri, 21 Oct 2011 20:12:46 +0000</pubDate>
		<dc:creator>arlen</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://www.theodicius.net/?p=450</guid>
		<description><![CDATA[(Edited 2001/10/24 to add apache notes at end.) Rails isn&#8217;t always an easy proposition on Dreamhost, and this was no exception. BTW, this is *not* the rvm version. I wanted to get the Dreamhost default setup working before I started playing with rvm. I&#8217;ll probably post an rvm-related set of instructions later. In this case, [...]]]></description>
				<content:encoded><![CDATA[<p>(Edited 2001/10/24 to add apache notes at end.)</p>
<p>Rails isn&#8217;t always an easy proposition on Dreamhost, and this was no exception. BTW, this is *not* the rvm version. I wanted to get the Dreamhost default setup working before I started playing with rvm. I&#8217;ll probably post an rvm-related set of instructions later.</p>
<p>In this case, I wanted to move some sites over to NginX as a trial, because the apache/passenger combination had been seeming rather slow and memory-intensive of late. I wanted to see how much time and RAM NginX would save me.<span id="more-450"></span></p>
<p><a href="http://www.theodicius.net/wp-content/uploads/2011/10/dhcp.png"><img src="http://www.theodicius.net/wp-content/uploads/2011/10/dhcp.png" alt="Dreamhost Control Panel Settings -- NginX on and mod_php off" title="dhcp" height="200" style="float:left;padding:10px;" /></a>The first bits were simple. Setting up the VPS using the Dreamhost CP went easily, then came time to configure it. The settings are pretty much self-explanatory, as you can see. The idea is to select the NginX web server, then turn mod_php off. (I did the latter just because I&#8217;m anal-retentive: mod_php is an apache module, so it wouldn&#8217;t work with NginX anyway. But even if it did, I wouldn&#8217;t want it; I want to run PHP as a fastCGI/FPM process, anyway.)</p>
<p>Setting those gives you the basic setup for the domain. Unfortunately, that in itself isn&#8217;t enough to get the default Rails setup on Dreamhost (Rails 3.0.3 at the time of this writing) working properly. The fun starts now.</p>
<p>After<br />
<code><br />
rails new appname --database=mysql<br />
bundle install<br />
</code><br />
builds the rails app, but there are more issues to come. The first is that Passenger doesn&#8217;t find the bundler to load. This is because it&#8217;s not looking for it (and, by extension, <em>all</em> your site&#8217;s gems) in the right place.</p>
<p>I recommend covering this in a couple of places, because this is something that will end up biting you again and again if you don&#8217;t. So, first, in the .bashrc file of your home directory you&#8217;ll want:</p>
<p><code>export GEM_HOME="$HOME/.gems/"<br />
export GEM_PATH="$GEM_HOME:/usr/lib/ruby/gems/1.8"<br />
export PATH="$HOME/bin:$HOME/.gems/bin:$PATH"<br />
</code></p>
<p>This will make sure your deployment tools, like capistrano, will see the gems. The &#8216;/user/lib/ruby/gems/1.8&#8242; path is the default path Dreamhost is storing its own set of gems. You should check to ensure that&#8217;s where it is on your system, and if it&#8217;s different change it to whatever it is on your site.</p>
<p>Then you need to do something similar in /config/setup_load_paths.rb (you&#8217;ll need to create the file yourself, it&#8217;s not in the standard Rails 3.0.3 setup):</p>
<p><code>ENV['GEM_HOME']='/home/username/.gems'<br />
# You can also set GEM_PATH if needed<br />
ENV['GEM_PATH']="#{ENV['GEM_HOME']}:/usr/lib/ruby/gems/1.8"</code></p>
<p>You need it here, so that Rack can find the gems; it loads before Rails, after all, so putting them in the Rails config area wouldn&#8217;t help.</p>
<p>You&#8217;re probably not done yet. There&#8217;s another bug waiting to bite you in your Gemfile. I built this Rails app for mySQL, remember? This line:</p>
<p><code>gem 'mysql2'</code></p>
<p>was put in the Gemfile by Rails as a default. It resulted (in my case) in bundler using the Dreamhost-supplied mysql2-0.3.7 gem. And you&#8217;ll probably trigger an ActiveRecord error with that, along the lines of &#8220;this version of mySQL2 doesn&#8217;t ship with the ActiveRecord adapter.&#8221; Oops.</p>
<p>The solution is to drop back to a previous version of the mysql2 adapter for this, by changing the mysql2 line in your Gemfile to be</p>
<p><code>gem 'mysql2', '< 0.3'</code></p>
<p>That tells bundler you want one earlier than 0.3. I've seen it work with 0.2.7 and 0.2.13, so it doesn't seem to be too picky. It may even work with later ones than that; all I can say is I know 0.3.7 doesn't work with it.</p>
<p>That was the extra work it took me up front to get just a vanilla Rails install functioning on Dreamhost VPS. Hope it saves someone else the hours of searching and trial and error I spent getting it to work.</p>
<h4>And Of Course Apache Is Different</h4>
<p>It can't be so simple as to be the same changes with both. With apache, you need to place the gem path code at the top of config.ru:<br />
</code><code><br />
ENV['GEM_HOME']='/home/demorails/.gems'<br />
# You can also set GEM_PATH if needed<br />
ENV['GEM_PATH']="#{ENV['GEM_HOME']}:/usr/lib/ruby/gems/1.8"<br />
</code><br />
and it doesn&#8217;t need the setup_load_paths.rb file to be present.</p>
<p>Of course, you can always put the path code in both places. Having the setup_load_paths.rb file doesn&#8217;t seem to disturb apache and the extra code in config.ru doesn&#8217;t bother NginX. It&#8217;s not DRY, no, but it&#8217;s also not something that will be changing very often, if at all, so I can live with it.</p>
<h4>Credits</h4>
<ul>
<li><a href="http://iceboundflame.com/2010/12/setting-gem_home-on-phusion-passenger-3" title="David Liu">David Liu</a></li>
<li><a href="http://stackoverflow.com/questions/3467054/problem-with-mysql2-and-rails3-bundler" title="mysql2 issue">Trinitronix</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.theodicius.net/archives/2011/10/21/getting-rails-3-0-3nginxpassenger-up-on-dreamhost-vps/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Generational Change</title>
		<link>http://www.theodicius.net/archives/2010/07/14/generational-change/</link>
		<comments>http://www.theodicius.net/archives/2010/07/14/generational-change/#comments</comments>
		<pubDate>Wed, 14 Jul 2010 16:31:40 +0000</pubDate>
		<dc:creator>arlen</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://www.theodicius.net/?p=396</guid>
		<description><![CDATA[Come gather &#8217;round people wherever you roam And admit that the waters around you have grown And accept it that soon you&#8217;ll be drenched to the bone. If your time to you is worth savin&#8217; Then you better start swimmin&#8217; or you&#8217;ll sink like a stone For the times they are a-changin&#8217;. It always happens. [...]]]></description>
				<content:encoded><![CDATA[<blockquote><p>Come gather &#8217;round people wherever you roam<br />
And admit that the waters around you have grown<br />
And accept it that soon you&#8217;ll be drenched to the bone.<br />
If your time to you is worth savin&#8217;<br />
Then you better start swimmin&#8217; or you&#8217;ll sink like a stone<br />
For the times they are a-changin&#8217;.
</p></blockquote>
<p>It always happens. Something comes along and catches on with the new kids, while the old fogeys pooh-pooh it as nothing special. Change comes, and only the agile survive. The gesture-based interface made popular on the iPhones and iPads is the change this time around.<br />
<span id="more-396"></span><br />
I&#8217;m not going to insist the specific iOS gesture interface will be the final winner, but I am going to insist that <strong>a</strong> gesture-based interface will be. If you don&#8217;t believe me, hand a gesture-based device to a child and see how quickly they figure it out. <em>Any</em> interface that can be picked up that quickly by a bright toddler is <em>going</em> to succeed, no matter what you or I think about it, and no matter how hard you fight against it.</p>
<p>And if we (web designers and developers) want our work to stay relevant as time marches on, we have to  listen to Dylan. We had better start swimming or we&#8217;ll sink like a stone. Or like a WordStar. We need to stop thinking in terms of specific interface actions, and shift into more portable semantic abstractions.</p>
<h3>Stop Hovering Around and Get Semantic On It</h3>
<p>Stop thinking in terms of &#8220;hover.&#8221; There is <em>no cursor</em> in a gesture-based interface, so hover-based actions no longer make sense. Apples&#8217; iOS turns that event into &#8220;touch and hold&#8221;, but future interfaces may even dispense with touch, so don&#8217;t count on that being the replacement as the gesture-based interfaces mature.</p>
<p>That&#8217;s right. The gestures aren&#8217;t completely worked out, yet. Apple has a leg up on defining them, but first doesn&#8217;t equal winner in this game. If things are going to keep changing, how can we cope today?</p>
<p>We can come out of our denial, first of all. Remember when the mouse was sneered at? Remember when the WordStar folks claimed &#8220;the mouse is the ideal computer interface &mdash; for those with three hands&#8221;? I&#8217;ll bet you don&#8217;t even remember WordStar, do you?</p>
<p>And that&#8217;s my point. We need to change our thinking, now, or we&#8217;ll be tomorrow&#8217;s WordStar.</p>
<p>Instead of thinking about cursors and pointers, about specific interface actions like &#8220;hover&#8221; and &#8220;mouseout&#8221;, think instead of semantics. For example, what we think of as a hover action today (touch and hold in iOS) is really a &#8220;more info&#8221; action. When you design, define it that way: &#8220;triggering MoreInfo on this link will show a further set of menu selections&#8221; or &#8220;triggering MoreInfo on this term will bring up a definition of it.&#8221;</p>
<p>Don&#8217;t stop with hover. Continue this process for every action. When you write your scripts, don&#8217;t name the objects after specifics like &#8220;hover&#8221; or &#8220;tap&#8221; or even &#8220;rollover&#8221;. Name the objects after the response, such as &#8220;MoreInfo&#8221; and then apply that object to every UI element that triggers it.</p>
<p>Not only that, use those terms in your presentations. Speaking to clients in terms of &#8220;action/response&#8221; can help keep you from getting bogged down in implementation minutia during the presentation (&#8220;Should that be left-click always? Shouldn&#8217;t it be right-click for left-handed people? What if there are 1/3/9 buttons on the mouse?&#8221;). You&#8217;ll keep your meetings on track, and have more time to build.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.theodicius.net/archives/2010/07/14/generational-change/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Customizing Safari Reader</title>
		<link>http://www.theodicius.net/archives/2010/06/10/customizing-safari-reader/</link>
		<comments>http://www.theodicius.net/archives/2010/06/10/customizing-safari-reader/#comments</comments>
		<pubDate>Thu, 10 Jun 2010 16:14:33 +0000</pubDate>
		<dc:creator>arlen</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://www.theodicius.net/?p=389</guid>
		<description><![CDATA[OK, so the new Safari (version 5) is out, and it includes a &#8220;reader&#8221; feature that&#8217;s been taking some heat. The complaints are justified &#8212; what it does to links is insufficient for some vision-impaired users, and justified text looks horrible without good hypenation, which Safari doesn&#8217;t do, just to name the two most obvious. [...]]]></description>
				<content:encoded><![CDATA[<p>OK, so the new Safari (version 5) is out, and <a href="http://www.apple.com/safari/whats-new.html#reader">it includes a &#8220;reader&#8221; feature</a> that&#8217;s been <a href="http://www.flickr.com/photos/fraying/4681109486/">taking some heat</a>.</p>
<p>The complaints are justified &#8212; what it does to links is insufficient for some vision-impaired users, and justified text looks horrible without good hypenation, which Safari doesn&#8217;t do, just to name the two most obvious.</p>
<p>But that can be fixed.<br />
<span id="more-389"></span><br />
The proper way to adjust Safari&#8217;s defaults is through a custom user style sheet. But that doesn&#8217;t work here, because Safari doesn&#8217;t load the user style sheet when the Reader is engaged. Hopefully Apple will fix this bug (and yes, it should be considered a bug) in the near future.</p>
<p>But that doesn&#8217;t mean you have to wait until they do in order to change the reader style defaults. It just means you have to go a little deeper to do it.</p>
<ol>
<li>Open your <strong>Applications</strong> folder</li>
<li>Right- (or control-) click on Safari</li>
<li>Select &#8220;Show Package Contents&#8221; from the contextual menu</li>
<li>Open the &#8220;Contents&#8221; folder</li>
<li>Open the &#8220;Resources&#8221; folder</li>
</ol>
<p>There you will find the file &#8220;Reader.html,&#8221; which is the template for displaying pages in Safari Reader. In order to change it, you will need to open it in your usual text editor. (Neither Pages nor TextEdit are up to doing this. I used BBEdit to change mine, but Text Wrangler, Textmate, or Coda should be up to the challenge as well. You may be warned about the ownership of the file when you make changes to it.) All of the styles you want to change will be inside the style block with the ID &#8220;article-content.&#8221; For example:<br />
<code><br />
        .page a {<br />
            text-decoration: none;<br />
            color: rgb(32, 0, 127);<br />
        }<br />
</code></p>
<p>is the code block that sets the colors and removes the underline from the links, and<br />
<code><br />
        .page {<br />
            font: 20px Palatino, Georgia, Times, "Times New Roman", serif;<br />
            line-height: 160%;<br />
            text-align: justify;<br />
        }<br />
</code></p>
<p>is where it sets the text to be justified, instead of ragged-right.</p>
<p>If you want the links underlined, change &#8220;text-decoration: none&#8221; to &#8220;text-decoration: underline&#8221; and if you want ragged-right paragraphs, change &#8220;text-align: justify&#8221; to &#8220;text-align: left&#8221; and save the file (the system will prompt you for the password when you save the file). Your Reader will now pick up your new settings.</p>
<p>The usual warnings apply to making this sort of change. It&#8217;s best to save an unchanged copy of Reader.html to fall back to, and any changes you make may be erased by a future update to Safari, so you might want to store a copy of the changed file in your documents folder, as well. But, hopefully, the next time Apple updates Safari it will fix the bug that prevents user style sheets from being applied to Reader. If/When that happens, I&#8217;ll follow up with instructions for creating a sheet to do that, as well.</p>
<p>(Edited 6/14 to correct &#8220;left/right&#8221; typo. Mea Culpa. Meus bardus.)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.theodicius.net/archives/2010/06/10/customizing-safari-reader/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Missing the Point</title>
		<link>http://www.theodicius.net/archives/2010/05/09/missing-the-point/</link>
		<comments>http://www.theodicius.net/archives/2010/05/09/missing-the-point/#comments</comments>
		<pubDate>Sun, 09 May 2010 05:10:29 +0000</pubDate>
		<dc:creator>arlen</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://www.theodicius.net/?p=383</guid>
		<description><![CDATA[Giorgio Sironi writes about (among other things)his first experience with Rails over at Web Builder Zone: class Post &#60; ActiveRecord::Baseend Oh thanks, now I&#8217;m enlightened. No fields, no scope, no getters or setters. What is going on here? Where is the business logic? It&#8217;s a common enough reaction from Rails newcomers, but it completely misses [...]]]></description>
				<content:encoded><![CDATA[<p>Giorgio Sironi writes about (among other things)<a href="http://css.dzone.com/articles/php-and-ruby-rails">his first experience with Rails</a> over at Web Builder Zone:</p>
<blockquote><p><code>class Post &lt; ActiveRecord::Base<br />end</code></p>
<p>Oh thanks, now I&#8217;m enlightened. No fields, no scope, no getters or setters. What is going on here? Where is the business logic?</p>
</blockquote>
<p>It&#8217;s a common enough reaction from Rails newcomers, but it completely misses the point.</p>
<p><span id="more-383"></span></p>
<p>There are no fields, etc., shown because they are all supplied by Rails by default. <em>You don&#8217;t need to write them, and their operation is so obvious you don&#8217;t need to see the code for them.</em> There&#8217;s no business logic because as yet he hasn&#8217;t supplied any; any attempt by the system to automatically create some at this point is doomed to fail because of insufficient information.</p>
<p>You want to see the database fields you&#8217;ve created, check the schema.rb file&mdash;that&#8217;s where you&#8217;ll find them. You want your code to access them? Post.fieldname does that; set the value by assigning to it, get the value by reading from it.</p>
<p>To be sure, the context of the article is not supposed to be explaining either Ruby or Rails, but rather what the next generation of PHP frameworks have learned, either from Rails or from their own past. But when he extols the development in Doctrine 2 that allows you to override the default getters and setters with entries in a class file located in a special location in the hierarchy, he doesn&#8217;t appear to realize that the Ruby file he was just complaining about being empty performs that same exact function. (Instead, he implies that you can&#8217;t do it at all in ActiveRecord, which is patently untrue.)</p>
<p>To override the default getter for the field &#8220;date&#8221;, for example, you would create a method for date in the existing file (why you&#8217;d want to override the default getter for a database field, is another question). Or to create a new field based on it, let&#8217;s use &#8220;creation_year&#8221; for an extremely simple example, you would create a method entitled &#8220;creation_year&#8221; which would take the date created and pull out just the year. In like manner, to create a custom setter for a field such as, say, &#8220;permalink&#8221; (to keep with his blog example) you would create a method entitled &#8220;=permallink&#8221;&mdash;Ruby-ese for creating a setter&mdash; and inside that method place the business logic for creating a permalink.</p>
<p>I suspect the source of this error is he expected Ruby to work like PHP. It doesn&#8217;t, but often it takes a while for newcomers to the language to understand that. Ruby may bear a superficial resemblance to it on the surface, but trust me; it&#8217;s horse of a completely different color. It might even be a zebra.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.theodicius.net/archives/2010/05/09/missing-the-point/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Frameworks over CMS&#8217;s</title>
		<link>http://www.theodicius.net/archives/2010/02/25/frameworks-over-cmss/</link>
		<comments>http://www.theodicius.net/archives/2010/02/25/frameworks-over-cmss/#comments</comments>
		<pubDate>Thu, 25 Feb 2010 17:34:04 +0000</pubDate>
		<dc:creator>arlen</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://www.theodicius.net/?p=378</guid>
		<description><![CDATA[I gave a presentation recently at Web414 that promoted the idea that frameworks were the future of web development. The presentation didn&#8217;t go well (It started its slide downhill when I realized too late there would be no way to show my slides. I switched to a more interactive, discussion-oriented presentation, which of course I [...]]]></description>
				<content:encoded><![CDATA[<p>I gave a presentation recently at Web414 that promoted the idea that frameworks were the future of web development. The presentation didn&#8217;t go well (It started its slide downhill when I realized too late there would be no way to show my slides. I switched to a more interactive, discussion-oriented presentation, which of course I hadn&#8217;t properly prepared for, which in turn only contributed to a further slide.) Still, it served to clarify a little more my thinking on the subject. (Half the reason to make presentations at your local user&#8217;s group is to help you view a subject from a different perspective; think of them as &#8220;code reviews for your mind.&#8221;)</p>
<p>The fundamental point I was making, that the future of web development lies with web application frameworks and not in traditional CMS&#8217;s, relies on two rather finely drawn (I cheerfully admit) lines.</p>
<p><span id="more-378"></span>The first is on the difference between implementing a CMS and developing for the web. To implement a CMS you typically need specialized knowledge and skill concerning which modules to employ to achieve the aim. The user group got hung up on this distinction, I suspect because many of the CMS implementors thought I was denigrating what they do. I wasn&#8217;t. I was simply saying that particular skill set is different from a developer&#8217;s skill set. It&#8217;s the difference between a production designer and a graphic artist &#8212; the graphic artist creates the images the production designer uses. The one who implements the CMS (I&#8217;ll call that particular skill set &#8220;systems integrator,&#8221; for lack of a better term) has a specialized knowledge that comes into play as the modules are assembled to make a web site. The developer&#8217;s skill set creates the modules the systems integrator selects from. In the world of the CMS, both skill sets are required, and they are generally found in different people.</p>
<p>The second line is between a traditional CMS and a framework. This line is becoming even finer, as more CMS&#8217;s (such as <a href="http://radiantcms.org/">Radiant</a> or <a href="http://expressionengine.com/">Expression Engine</a>) are developed that rest upon published frameworks (such as <a href="http://codeigniter.com/">CodeIgniter</a> or <a href="http://rubyonrails.org/">Rails</a>). For my purposes, I&#8217;ll define the CMS as a collection of software modules that require no (or minimal) coding in anything other than the standard languages of the web (HTML and CSS) to implement. WordPress, for example, requires little or no knowledge of PHP (the language it&#8217;s written in) in order to be installed and used.</p>
<p>I received a lot of push-back when drawing the first line; it seemed to me a lot of the noise was being generated by the implicit assumption that I was saying the systems integrator skill set was somehow inferior to the developer skill set. This isn&#8217;t the case at all.</p>
<p>What I <em>was</em> saying was that the systems integrator skill set wasn&#8217;t interesting to the developer. This isn&#8217;t saying it&#8217;s inferior; I could say the same thing about the developer skill set not being interesting to the integrator. It&#8217;s not interesting, because at root it&#8217;s not relevant to what they do best. Just as excellent graphic artists can make bad production designers, excellent developers can make bad integrators, and vice versa.</p>
<p>These days it&#8217;s possible to put together a CMS that adequately meets 80% of most customer&#8217;s business needs from a free or low-cost CMS, using off-the-shelf modules. If a developer plans on making more than a subsistence living in that market, it can only be by giving up or seriously limiting the amount of time spent doing what a developer does best (if satisfactory extensions are free, there&#8217;s not a good economic case for getting paid to write them from scratch) and instead turning into a systems integrator. Some developers can do this, some can&#8217;t, but even those who <em>can</em> do this only succeed by, in effect, ceasing to be a developer.</p>
<p>Therefore the developer has to step out in a different direction. One possibility is to build completely custom coded websites, while another is to develop and sell modules for the systems integrators to use.</p>
<p>If a developer chooses to go the custom-code route, a framework will provide a solid foundation to build off of. Frameworks provide stub code and basic functionality which can easily be extended to cover the precise needs of the site at hand, without incurring the burden of unnecessary code.  Built-in or otherwise available framework modules to handle user authentication, for example, form the basis for a more complete user profile system, only requiring the custom features of the user profile required by the community site under development to be written by the developer. The framework does the heavy lifting, while the developer supplies the chrome and the custom business logic, tailored to 100%  of the site owner&#8217;s needs. Instead of off-the-rack, the result is a custom-tailored fit.</p>
<p>This road isn&#8217;t easy. Off-the-rack suits fit most bodies reasonably well, so the potential market is smaller. But at the same time it&#8217;s more lucrative, so the two balance. And with a good framework, a creative and knowledgeable developer can provide enough of a value add to make the time and cost more than worth it to the customer. If the &#8220;standard&#8221; CMS yields 80% of the goal, a good framework under it can often make the other 20% easier to reach.</p>
<p>If the developer chooses to build and sell CMS modules or extensions, the market is tighter. There will be a lot of competition from low- (or no-) cost alternatives exerting downward pressure on the market, still it&#8217;s possible for a developer to make a living there. But in taking that route, the developer <em>still</em> is using a framework. In this case, the internals of the CMS itself form the framework that is used to build the extension. Sometimes that&#8217;s explicitly designated as a framework, as with Expression Engine or Joomla, and sometimes it&#8217;s just a published API, as with WordPress or Drupal. But whether it&#8217;s officially named that or not, it&#8217;s still a framework.</p>
<p>So what&#8217;s the &#8220;action list&#8221; for you as a developer? </p>
<ul>
<li><strong>Look at the framework first.</strong> Don&#8217;t (please, just &#8230; don&#8217;t) write your own framework from scratch. There are plenty of Open Source ones out there to contribute to; find one you can live with and while you&#8217;re learning it, fix some bugs and add some features to make it better. It&#8217;ll be easier to add the features you want to an existing framework than write an entire framework from scratch around those features.</li>
<li><strong>What CMS choices are built on it?</strong> This will feed into the next decision you make. If there are some good CMS choices on the framework, it will make it easier for you to write extensions for others to use, expanding your reach and your market. And, hopefully, your bank account. (Yes, money isn&#8217;t everything but the lack of it makes it hard to buy new hardware.)</li>
<li><strong>Decide &#8212; Custom Code or CMS extensions.</strong> Make this decision on top of the best framework you can find. The framework itself will provide some of the tools you&#8217;ll be using to build the modules, after all, and no one likes working with inferior tools.</li>
</ul>
<p>There&#8217;s you road map. Start your journey.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.theodicius.net/archives/2010/02/25/frameworks-over-cmss/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Lies and Marketing</title>
		<link>http://www.theodicius.net/archives/2010/01/30/lies-and-marketing/</link>
		<comments>http://www.theodicius.net/archives/2010/01/30/lies-and-marketing/#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:57:39 +0000</pubDate>
		<dc:creator>arlen</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://www.theodicius.net/?p=364</guid>
		<description><![CDATA[Lee Brimelow made this wonderful post ridiculing the iPad&#8217;s lack of flash. Only one problem with it. It&#8217;s a lie. And that&#8217;s a problem. Apparently, he made those wonderful claims of his without ever once checking the reality of them. Most of those sites that supposedly don&#8217;t show anything, actually do. As this set of [...]]]></description>
				<content:encoded><![CDATA[<p>Lee Brimelow made <a href="http://theflashblog.com/?p=1703">this wonderful post</a> ridiculing the iPad&#8217;s lack of flash. Only one problem with it.</p>
<p>It&#8217;s a lie.</p>
<p>And that&#8217;s a problem. Apparently, he made those wonderful claims of his without ever once checking the reality of them. Most of those sites that supposedly don&#8217;t show anything, actually do. As <a href="http://www.flickr.com/photos/kigiphoto/4314276957/">this set of screen captures</a> shows.<br />
<span id="more-364"></span><br />
Which means he wasn&#8217;t interested in truth at all, nor even in the experience of web users, as he claims. All he wanted to do was complain because that Big Meanie over at One Infinite Loop in Cupertino didn&#8217;t want to let him bring his own toys to the iPad and iPhone party. Boo hoo.</p>
<p>Let&#8217;s get something straight right up front. I ain&#8217;t no fanboy. I don&#8217;t own an iPhone, nor will I be queueing up on day one to get an iPad. I&#8217;ve been an Adobe customer for as long as I&#8217;ve been an Apple customer, since Photoshop version 2.x. I even stayed an Adobe customer after they deliberately killed the best illustration program I&#8217;ve ever used (Freehand &#8212; after two earlier failed attempts they finally managed, not to beat it in the marketplace, but rather they kept buying companies in a repeated attempt to get it off the market). I&#8217;ll admit to a point of view, here. I&#8217;m amused by the flash fanboys who can&#8217;t seem to realize their own playground is just as proprietary, just as limited and controlled, as Apple&#8217;s.</p>
<p>Yes, it&#8217;s amusing to watch Adobe, from their closed proprietary yard, cry foul at Apple&#8217;s closed proprietary yard (pot, meet kettle) but that&#8217;s about it. The world, and the web, will do fine, with or without Flash. Right now, there are far more examples of bad Flash use than bad HTML5 Video use, but I&#8217;m sure that will level out eventually &#8212; flash developers have certainly not cornered the market on ineptitude. It only seems that way, sometimes.</p>
<p>Professionals know the iPad is just another device we have to deal with, just like we know Flash is just another tool in the box, and no tool is the right choice for every device, and probably never will be. So we plow around the rocks in the field that we can&#8217;t lift. For simple video, the solution is fairly obvious: do your video in H.264, because that will give you the widest access to your customers. As John Nack pointed out in <a href="http://blogs.adobe.com/jnack/2010/01/sympathy_for_the_devil.html">a post on a more official site</a> Flash will deliver H.264 as well as native flash format. So you do the video in H.264, and use Flash as the ancillary system to deliver the H.264 to the clients that can&#8217;t see it natively. Problem solved, the same way we&#8217;ve been working around IE&#8217;s limitations for years (thanks for the practice, MS).</p>
<p>John raises other issues about why Flash is such a hog on OSX, and while they may or may not be true (I admit I don&#8217;t know) I really can&#8217;t see why I, as a professional web builder, should care. It is what it is, and I have to deal with it the way it is, not the way John Nock or Steve Jobs, or anyone else, for that matter, wants it to be. And the way it is, the performance of Flash on OSX is sub-par. That&#8217;s reality, and it&#8217;d be far more productive to fix that than stand around pointing fingers.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.theodicius.net/archives/2010/01/30/lies-and-marketing/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Some Capistrano Recipes for Radiant</title>
		<link>http://www.theodicius.net/archives/2009/09/30/some-capistrano-recipes-for-radiant/</link>
		<comments>http://www.theodicius.net/archives/2009/09/30/some-capistrano-recipes-for-radiant/#comments</comments>
		<pubDate>Wed, 30 Sep 2009 13:45:02 +0000</pubDate>
		<dc:creator>arlen</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://www.theodicius.net/?p=351</guid>
		<description><![CDATA[I&#8217;ve been dipping my toes into the Radiant CMS lately (a side-effect of my love affair with Ruby on Rails) and have run into several interesting moments. On the assumption I&#8217;m not alone in that, I thought I&#8217;d share some of my favorite recipes for deploying a Radiant app to an Apache-Phusion Passenger combination. As [...]]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve been dipping my toes into the <a href="http://radiantcms.org/">Radiant CMS</a> lately (a side-effect of my love affair with <a href="http://rubyonrails.org/">Ruby on Rails</a>) and have run into several interesting moments. On the assumption I&#8217;m not alone in that, I thought I&#8217;d share some of my favorite recipes for deploying a Radiant app to an Apache-<a href="http://www.modrails.com/">Phusion Passenger</a> combination.</p>
<p>As I look at my deploy.rb file I&#8217;m reminded of the old Tom Lehrer ditty, &#8220;Lobachevsky&#8221;:</p>
<blockquote><p>I am never forget the day I first meet the great Lobachevsky.<br />
In  one word he told me secret of success in mathematics:<br />
Plagiarize!</p>
<p>Plagiarize,<br />
Let no one else&#8217;s work evade your eyes,<br />
Remember why the good Lord made your eyes,<br />
So don&#8217;t shade your eyes,<br />
But plagiarize, plagiarize, plagiarize -<br />
Only be sure always to call it please &#8216;research&#8217;.</p></blockquote>
<p>So here is the result of my &#8216;research&#8217; (where I remember where I got the code from, I will also quote the source; where I don&#8217;t remember, I apologize in advance):<br />
<span id="more-351"></span></p>
<p>First, there are the Passenger-specific recipes:</p>
<p><code>  desc "Restarting mod_rails with restart.txt"<br />
  task :restart, :roles => :app, :except => { :no_release => true } do<br />
    run "touch #{current_path}/tmp/restart.txt"<br />
  end<br />
  desc "Starting mod_rails with restart.txt"<br />
  task :start, :roles => :app, :except => { :no_release => true } do<br />
    run "touch #{current_path}/tmp/restart.txt"<br />
  end</p>
<p>  desc "stop task is a no-op with mod_rails"<br />
  task :stop, :roles => :app do<br />
  end<br />
</code></p>
<p>This code block is one of those I found so long ago I&#8217;ve forgotten where I picked it up from. Passenger is usually run in &#8216;production&#8217; mode, which means the server needs to be restarted whenever a code change is mode. Rather than taking apache down, this a accomplished by &#8220;touch&#8221;-ing a file called &#8220;restart.txt&#8221; and when the server notes the change it reloads the code. This code block will do that, except when the no_release option is active (no_release after all means no changes have been made, so there&#8217;s no need to force a restart).</p>
<p>I put the same code in for &#8220;start&#8221; as for &#8220;restart&#8221;, not that it&#8217;s needed. I was just being anal about having a recipe for that; if I ever find I need that function (as opposed to restart) I&#8217;ll have to work out first of all if it&#8217;s possible even to do it in capistrano. Likewise with &#8220;stop;&#8221; the recipe is a placeholder for functionality I&#8217;ve never needed.</p>
<p>This next recipe came to me from <a href="http://blog.matt-darby.com/posts/759-capistrano-make-sure-there-is-something-to-deploy">Matt Darby</a> who in turn got it from <a href="http://blog.ninjahideout.com/">Darcy Laycock</a>:</p>
<p><code>  desc "Make sure there is something to deploy"<br />
  task :check_revision, :roles => [:web] do<br />
    unless `git rev-parse HEAD` == `git rev-parse origin/master`<br />
      puts ""<br />
      puts "  \033[1;33m**************************************************\033[0m"<br />
      puts "  \033[1;33m* WARNING: HEAD is not the same as origin/master *\033[0m"<br />
      puts "  \033[1;33m**************************************************\033[0m"<br />
      puts ""</p>
<p>      exit<br />
    end<br />
  end<br />
</code></p>
<p>(when using, preface the deploy namespace with:<br />
<code>before "deploy", "deploy:check_revision"</code><br />
so it runs before the deploy.)</p>
<p>The one qualm I have with this recipe concerns the "rev-parse" -- when I get the time and inclination I'm going to look at using "ls-remote" instead. Not sure at the moment which way is "the right way" but this works so changing it isn't high on my priority list.</p>
<p>The principle here is to stop me from wasting time. I've been working for days on some changes, and they're committed to my local repo, but somehow I forgot to push the changes up to origin, but instead I just deploy. And I sit there waiting for the deploy to finish, only to find the new version has the same bugs as the old. This recipe checks the local repo against origin and if they're not the same, drops you out of the deploy with a message that you forgot to push before deploying.</p>
<p>(I toyed with the idea of just automatically doing the push instead of the message, but decided that wouldn't be a good idea, as I might need to do something else before/after the push, and even if not, typing one extra command line didn't seem a huge penalty to pay for absent-mindedness. Feel free to disagree with me.)</p>
<p>I pulled this post-deploy recipe from the <a href="http://github.com/ehaselwanter/radiant-capistrano-extension">ehaselwanter-radiant-capistrano-extension</a>:</p>
<p><code>  after "deploy:cold", "deploy:radiant:bootstrap"<br />
  after "deploy:migrate", "deploy:radiant:migrate:extensions"<br />
  after "deploy:update" do<br />
    run "mkdir #{latest_release}/cache"<br />
    #run "cp #{latest_release}/config/database_eyecatch.yml #{latest_release}/config/database.yml"<br />
    run "chmod -R g+w #{deploy_to}"<br />
    run "[ ! -d #{shared_path}/assets ] &#038;&#038; mkdir #{shared_path}/assets; true"<br />
    run "[ ! -d #{shared_path}/galleries ] &#038;&#038; mkdir #{shared_path}/galleries; true"<br />
    run "[ ! -d #{shared_path}/uploads ] &#038;&#038; mkdir #{shared_path}/uploads; true"<br />
    run "ln -s #{shared_path}/assets #{latest_release}/public/assets"<br />
    run "ln -s #{shared_path}/galleries #{latest_release}/public/galleries"<br />
    run "ln -s #{shared_path}/uploads #{latest_release}/public/uploads"<br />
  end<br />
</code></p>
<p>I&#8217;m using a few other recipes from that file as well, but I&#8217;m not convinced about them, and am still looking to revise/replace them, so I&#8217;ll not post them here.</p>
<p>Also, I&#8217;m rather interested in taking a peek at <a href="http://tempe.st/?s=medlar">Giovanni Intini&#8217;s</a> set of recipes but the link there doesn&#8217;t seem to work.</p>
<p>I&#8217;m still looking for useful recipes, so please point me to others, especially for bootstrap and migrations, as the ones I&#8217;m using aren&#8217;t yet reliable enough to publish.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.theodicius.net/archives/2009/09/30/some-capistrano-recipes-for-radiant/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
