<?xml version="1.0" encoding="utf-8" ?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Pete's Points</title>
  <link href="http://peterlyons.com/problog/feed" rel="self"></link>
  <link href="http://peterlyons.com/problog/feed"></link><updated>2013-04-28T04:36:41.827Z</updated><id>http://peterlyons.com/problog/feed</id>
  <author>
    <name>Peter Lyons</name>
  </author>
  <entry>
    <title>Flickr Date Fixer</title>
    <link href="http://peterlyons.com/problog/2013/04/flickr-date-fixer"></link><updated>2013-04-28T04:36:41.827Z</updated><id>http://peterlyons.com/problog/2013/04/flickr-date-fixer</id>
    <content type="html">&lt;p&gt;&lt;a href=&quot;http://flickrdatefixer.jit.su&quot;&gt;Try my flickr date fixer app&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;So the startup/solopreneur community really likes little mantras and axioms. I wrote a little web application that follows mantras such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;solve a problem&lt;/li&gt;
&lt;li&gt;focus on a small problem in a niche market&lt;/li&gt;
&lt;li&gt;scratch your own itch&lt;/li&gt;
&lt;li&gt;build the minimum viable product and ship quickly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have built and released a web app that focuses on an itch I have and may serve a small niche market consisting of only myself, but with that understood, my app is able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Locate your flickr photos with an incorrect &quot;taken&quot; date&lt;/li&gt;
&lt;li&gt;Show you a list of photos with this problem and let you choose to fix them individually or en masse&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to find this app useful, you probably have to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Take photos on an Android smartphone&lt;/li&gt;
&lt;li&gt;Be running Android 2.2 &quot;Froyo&quot; (I suspect other version have resolved this bug)&lt;/li&gt;
&lt;li&gt;Upload them to flickr&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not sure if anyone other than me fits all these criteria, but this is fundamentally a bug in the camera app on these phones and for reasons I cannot fathom, Google seems unwilling or uninterested in releasing an update with a fix. The problem is incorrect EXIF metadata within the photo image files themselves. The bug causes every photo to be marked as December 8, 2002 at noon.&lt;/p&gt;

&lt;p&gt;The app is pretty small and gave me a nice opportunity to try some new technologies (as well as use many that have been in my preferred stack for months or years).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;node.js&lt;/li&gt;
&lt;li&gt;coffee-script&lt;/li&gt;
&lt;li&gt;express.js&lt;/li&gt;
&lt;li&gt;passport.js for OAuth integration with flickr&lt;/li&gt;
&lt;li&gt;backbone.js and jQuery in the browser&lt;/li&gt;
&lt;li&gt;require.js&lt;/li&gt;
&lt;li&gt;grunt.js&lt;/li&gt;
&lt;li&gt;nodejitsu&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The nice thing about this app is given that it is all OAuth based and is basically a custom UI using the flickr API for all the business logic, it doesn't need any database at all. This means it is easy to deploy. So for the novelty of it, I have chosen to deploy it onto nodejitsu, and in theory they will host it for free since it is open source.&lt;/p&gt;

&lt;h3&gt;Resources&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://flickrdatefixer.jit.su&quot;&gt;Flickr Date Fixer&lt;/a&gt; running live on nodejitsu's &lt;a href=&quot;&quot;&gt;http://flickrdatefixer.jit.su&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/focusaurus/flickr-date-fixer&quot;&gt;flickr-date-fixer source code on github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nodejitsu.com&quot;&gt;Nodejitsu&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>AirPair on TechCrunch</title>
    <link href="http://peterlyons.com/problog/2013/03/airpair-on-techcrunch"></link><updated>2013-03-04T16:30:24.614Z</updated><id>http://peterlyons.com/problog/2013/03/airpair-on-techcrunch</id>
    <content type="html">&lt;p&gt;TechCrunch has &lt;a href=&quot;http://techcrunch.com/2013/03/04/airpair-connects-startups-with-expert-developers-to-get-help-with-code-via-online-sessions/&quot;&gt;this article on AirPair&lt;/a&gt; today with a nice quote about me. This is my first ever mention on TechCrunch (but hopefully not my first and only!).&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>My Airpair Session was written up</title>
    <link href="http://peterlyons.com/problog/2013/02/my-airpair-session-was-written-up"></link><updated>2013-02-26T04:28:29.842Z</updated><id>http://peterlyons.com/problog/2013/02/my-airpair-session-was-written-up</id>
    <content type="html">&lt;p&gt;&lt;a href=&quot;http://hackerpreneurialism.com/post/44040862234/product-fit-and-success-in-online-marketplaces&quot;&gt;Here's a post&lt;/a&gt; about my recent experience with the new &lt;a href=&quot;http://airpair.co&quot;&gt;AirPair&lt;/a&gt; service connecting entrepreneurs with technology experts.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Airpair</title>
    <link href="http://peterlyons.com/problog/2013/02/airpair"></link><updated>2013-02-23T22:26:52.624Z</updated><id>http://peterlyons.com/problog/2013/02/airpair</id>
    <content type="html">&lt;p&gt;So I've just been one of the earliest progragrammers to get involved with &lt;a href=&quot;http://codereview.airpair.co/&quot;&gt;AirPair&lt;/a&gt;. It's a service that pairs entrepreneurs with technology experts for code review and pair programming sessions to help them with their coding projects.&lt;/p&gt;

&lt;p&gt;I did some google hangouts with an entrepreneur who built his own Ruby on Rails app that analyzes geology data files for oil &amp; gas companies and is just starting to port it over to node.js. There's a &lt;a href=&quot;http://www.youtube.com/channel/UCOwZvL29sSlUAj6c2i_f53A?v=gdi9xDKZ5qg&quot;&gt;youtube recording video of the 2-hour google hangout session this morning&lt;/a&gt; up. You can skip around in that if you want to get a feel for the service and experience. &lt;/p&gt;

&lt;p&gt;I'm perpetually interested in the startup community in general and connecting people across geographies via the Internet, so I was excited to try it out. I've done 3 hour-long sessions so far and so far so good.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>npm modules: development and release versions</title>
    <link href="http://peterlyons.com/problog/2013/02/npm-modules:-development-and-release-versions"></link><updated>2013-02-01T20:17:35.407Z</updated><id>http://peterlyons.com/problog/2013/02/npm-modules:-development-and-release-versions</id>
    <content type="html">&lt;p&gt;You are working on two npm modules that are both actively being developed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;my_app&lt;/code&gt;: some application, which depends on &lt;code&gt;my_lib&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;my_lib&lt;/code&gt;: a shared library&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are 2 modes you'll need inside &lt;code&gt;my_app&lt;/code&gt;: 1) using a published release of &lt;code&gt;my_lib&lt;/code&gt; and 2) using a local development version of &lt;code&gt;my_lib&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Using a published release of &lt;code&gt;my_lib&lt;/code&gt; is standard faire:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;list &lt;code&gt;my_lib&lt;/code&gt; as a dependency in &lt;code&gt;my_app/package.json&lt;/code&gt;
&lt;ol&gt;&lt;li&gt;&lt;code&gt;dependencies: {&quot;my_lib&quot;: &quot;1.2.x&quot;}&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd my_app &amp;&amp; npm install&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;npm will populate &lt;code&gt;my_app/node_modules/my_lib&lt;/code&gt; for you as you would expect&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To use your development version so you can easily make changes to both codebases and have them available with minimal fuss, set up this structure&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;~/projects/my_app (working directory for the app)
~/projects/my_lib   (working directory for the lib)
~/projects/node_modules/my_lib (symlink to ../../my_lib)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can set this up with&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mkdir -p ~/projects/my_app ~/projects/my_lib ~/projects/node_modules
cd ~/projects/node_modules
ln -nsf ../../my_lib
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So now when developing &lt;code&gt;my_app&lt;/code&gt; and you want to use the local development version of &lt;code&gt;my_lib&lt;/code&gt;, just do :&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cd ~/projects/my_app
npm uninstall my_lib
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now node's &lt;code&gt;require&lt;/code&gt; function will load &lt;code&gt;my_lib&lt;/code&gt; from &lt;code&gt;~/projects/node_modules/my_lib&lt;/code&gt; and you are good to go. To switch back to a public of &lt;code&gt;my_lib&lt;/code&gt; just do:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cd ~/projects/my_app
npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Of course, there is &lt;a href=&quot;https://npmjs.org/doc/link.html&quot;&gt;the npm link command&lt;/a&gt; which does something nearly identical to this, so far I prefer this approach as I find it a little simpler.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Hilarious Recruiter Email</title>
    <link href="http://peterlyons.com/problog/2012/12/hilarious-recruiter-email"></link><updated>2012-12-12T21:49:52.792Z</updated><id>http://peterlyons.com/problog/2012/12/hilarious-recruiter-email</id>
    <content type="html">&lt;p&gt;Here is the full text of a recruiter email I received today.&lt;/p&gt;

&lt;hr/&gt;

&lt;p&gt;Dear Pete,&lt;/p&gt;

&lt;p&gt;Wouldn't it feel great to wake up each day knowing that you're part of a dynamic organization that's on the cutting edge of innovation web products? That’s what the team experiences and you could too!&lt;/p&gt;

&lt;p&gt;What you will find challenging about this job is to develop revolutionary and challenging web applications using object oriented javascript frameworks like backbone.js, angular.js,  HTML, and CSS.&lt;/p&gt;

&lt;p&gt;As a result, there are many exciting decisions to be made to keep it in line with demands. You won't find formulaic thinking here. As a company that specializes in innovation, they want the best and brightest creative visionaries who think so far out of the box that the box isn't even in the picture anymore. Where others say &quot;can't&quot;, you say &quot;how&quot;.&lt;/p&gt;

&lt;p&gt;Keeping in mind that most successful people find opportunity not when they're looking but when it knocks,  how's my timing?&lt;/p&gt;

&lt;p&gt;I'd be happy to talk to you further about it. I'm reaching out to key individuals before I go on a full scale search for this. You have an ideal background and I think it's a good match for you geographically.&lt;/p&gt;

&lt;p&gt;Fortune Favors the bravo!&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Find closer OKCupid matches with this bookmarklet</title>
    <link href="http://peterlyons.com/problog/2012/10/okcupid-closer"></link><updated>2012-10-23T03:15:05.735Z</updated><id>http://peterlyons.com/problog/2012/10/okcupid-closer</id>
    <content type="html">&lt;p&gt;I have written a little bookmarklet that will allow you to filter your &lt;a href=&quot;http://okcupid.com&quot;&gt;OKCupid&lt;/a&gt; matches by a smaller geographic region. By default, their search filters allow no smaller than a 25-mile radius. Drag the bookmarklet link below onto your bookmarks toolbar, then click it when you are on the OKC search page, and voilà, you will have the options for 5 and 10-mile searches. 10-mile radius will be selected, so just click &quot;search&quot; and you will have your results.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;javascript:(function(){var%20opt5=document.createElement('option');opt5.value=5;opt5.text='5%20miles';var%20opt10=document.createElement('option');opt10.value=10;opt10.text='10%20miles';var%20radius=document.getElementById('radius');radius.insertBefore(opt10,radius.firstChild);radius.insertBefore(opt5,radius.firstChild);opt10.selected=true;var%20label=document.getElementById('location_interface_button_text');label.textContent=label.textContent.replace(/\d+/,'10');})();&quot;&gt;OKCupid Closer Matches&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;If you have no idea WTF a bookmarklet is or how to use one, read &lt;a href=&quot;http://support.mozilla.org/en-US/kb/bookmarklets-perform-common-web-page-tasks&quot;&gt;this&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;I live close to both Boulder and Denver Colorado. These are two quite different worlds, but they are both within 25 miles of my town. Since Denver's population is 10x the size of Boulder's, most of my search results are Denver residents, when I'm really only insterested in folks within biking distance.&lt;/li&gt;
&lt;li&gt;After you click search, the default search form will re-appear and it will look like your search has a 25 mile radius. Never fear, the query string has &lt;code&gt;filter3=10&lt;/code&gt;, which is what is required, and based on my results, yes, the OKC servers do seem to actually respect this query string parameter even if the value is not offered in the search form.&lt;/li&gt;
&lt;li&gt;You need to re-click the bookmarklet for each new search. Sorry. Send feature requests to OKCupid until they add this permanently. Technically I could make this into a Chrome extension and have it always work, so I may do that at some point.&lt;/li&gt;
&lt;li&gt;Thanks to &lt;a href=&quot;http://chris.zarate.org/bookmarkleter&quot;&gt;Chris Zarate's handy Bookmarkleter utility&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;And for you web dev nerds out there, I even wrote this with (gasp!) &lt;a href=&quot;http://vanilla-js.com/&quot;&gt;Vanilla JS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Great Support from Herman Miller</title>
    <link href="http://peterlyons.com/problog/2012/09/great-support-from-herman-miller"></link><updated>2012-09-27T16:48:31.202Z</updated><id>http://peterlyons.com/problog/2012/09/great-support-from-herman-miller</id>
    <content type="html">&lt;p&gt;So I use one of the famous &lt;a href=&quot;http://www.hermanmiller.com/&quot;&gt;Herman Miller&lt;/a&gt; &lt;a href=&quot;http://en.wikipedia.org/wiki/Aeron_chair&quot;&gt;Aeron chairs&lt;/a&gt; in my home office. I love it primarily because the mesh seat prevents &lt;a href=&quot;http://www.urbandictionary.com/define.php?term=swampass&quot;&gt;swampass&lt;/a&gt;, but of course overall it is a highly ergonomic chair, nicely adjustable, rugged, and holds its value well. My specific chair was made in 2000 and I bought it used on craigslist for $250 in 2009. Today exactly the 12-year warranty finally expires. About two weeks ago it suddenly broke. A thin rod broke free of its clamp and started protruding from the bottom such that the casters wouldn't hit the ground anymore. I was worried that I would need to replace the chair, but given my trend toward more DIY and frugality, I called up Herman Miller support to see what they would say. Staff was out at training that day so I left a voice mail and called again Monday. I spoke with a woman who had heard my voice mail and had me on her list to call back. I told her what my chair was doing and she shipped me out a repair kit for the main problem as well as a set of repair kits to fix the arms, which wouldn't hold their adjusted height. These arrived a bit later with hand-drawn instructions on how to do the repair. The diagrams weren't entirely clear (earth to furniture industry: we have these things called photographs. Stop sending out line drawing pencil art instructions.), but after some futzing I was able to properly repair the main hydraulic rod as well as the arms. I managed to bust the tilt adjuster in the process of putting my chair on its side many times, though. The back was now stuck dead vertical. I called support again. The rep's business card and direct phone number were including in the package of repair kits. She instructed me to stand on the back legs of the chair and lift the chair back up to unlock it. Now my Aeron is back to working condition, and it didn't cost me a time. Herman Miller shipped the repair kits free and the support consultation was free. That's great service!&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Managing Per-Project Interpreters and the PATH</title>
    <link href="http://peterlyons.com/problog/2012/09/managing-per-project-interpreters-and-the-path"></link><updated>2012-09-02T21:35:19.427Z</updated><id>http://peterlyons.com/problog/2012/09/managing-per-project-interpreters-and-the-path</id>
    <content type="html">&lt;p&gt;So let's talk about managing runtimes and interpreters for projects and applications. This post comes about after I have seen a vast jungle of non-solutions and dead ends out there for managing installations of interpreters such as Python, Ruby, node.js, etc. First, let's clear the air of a bunch of nonesense you may find out there that makes this problem confusing.&lt;/p&gt;

&lt;h2&gt;Never use the interpreter provided by your operating system&lt;/h2&gt;

&lt;p&gt;If you are building a web application or any other project that should by all rights be cross-platform and doesn't ship with OS, then you should have absolutely nothing to do with the interpreter that may be included with the OS. The OS interpreters are there for components of the OS itself written in those languages. They have no business being used by third party projects and applications that run on top of the OS as opposed to being part of the OS. Forget about the Ruby that comes with OS X. Forget about the Python that comes with Ubuntu. Forget about the Debian packages for node.js (slightly different/better, but still, ignore them).&lt;/p&gt;

&lt;p&gt;The reasoning behind this guideline is as follows.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Exact version&lt;/strong&gt;: Applications need exact and strict control of the version of their interpreter. You should be using the exact same version of your interpreter across all of your development, test, staging, and production environments. This will avoid problems which are easily-avoidable, so do it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modern version&lt;/strong&gt;: OSes tend to ship versions of these interpreters that are significantly behind the latest stable version. New applications should be written to work with the latest stable version and should keep up with ongoing releases, never getting more than 3 months behind.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Independence&lt;/strong&gt; Applications need independence from one another. If you have 3 Django projects on the same machine, each one needs to have the ability to use whatever interpreter &lt;strong&gt;version&lt;/strong&gt; it needs on its own independent &lt;strong&gt;schedule&lt;/strong&gt;. Due to this fact, that means the correct location for these interpretters is within your application's directory alongside your application code, which is why I advise you to ignore the node.js debian packages you may find out there because it installs into a shared location, which does not meet our goals here.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Keep the app-specific interpreter within the application install directory&lt;/h2&gt;

&lt;p&gt;Again, don't let the OS's notion of shared interpreters in a shared location distract you from the right layout here. The app-specific interpreter installation belongs inside you project's installation directory.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;project_root/python&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;project_root/node&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;project_root/ruby&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, the old school unix principles have gone stale on us. Years ago, sysadmins had rules for filesystem layout with different goals. For example, sysadmins wanted to be able to NFS mount a shared directory where binaries could live, be maintained in a single place, and be mounted and run by many additional servers. They wanted to do this to be efficient with disk space and to be able to make manual changes in one place and have them to affect immediately on an arbitrary number of servers that use the same NFS volume.&lt;/p&gt;

&lt;p&gt;Now we use automated tools to manage deployments to clusters of independent servers, and disk space is cheap, so we want each server to have its own copy of what it needs to run with as few external dependencies as possible. We want to be able to do rolling deploys across a cluster or run 1/2 the cluster on the new code and half on the old code.  Disk space is cheap and plentiful, so if we have 5 or 10 apps running on the same staging server, we could not care less about a few megabytes of duplication to handle a bunch of python installations.&lt;/p&gt;

&lt;h2&gt;Installing local versions of node.js&lt;/h2&gt;

&lt;p&gt;Now that Joyent is shipping pre-compiled binaries, installing node interpreters in the manner described here is a snap. Here's an &lt;code&gt;install_node.sh&lt;/code&gt; script. Pass it the version you want and where you want it installed (works with node &gt;= 0.8).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/bin/sh
VERSION=${1-0.8.8}
PREFIX=${2-node}
PLATFORM=$(uname | tr A-Z a-z)
ARCH=x64
case $(uname -p) in
    i686)
        ARCH=x86
    ;;
esac
if [ -e &quot;${PREFIX}&quot; ]; then
    TS=$(date +%Y%m%d-%H%M%S)
    echo &quot;WARNING: Moving existing file at ${PREFIX} to ${PREFIX}-previous-${TS}&quot; 1&gt;&amp;2
    mv &quot;${PREFIX}&quot; &quot;${PREFIX}-previous-${TS}&quot;
fi
mkdir -p &quot;${PREFIX}&quot;
curl --silent \
  &quot;http://nodejs.org/dist/v${VERSION}/node-v${VERSION}-${PLATFORM}-${ARCH}.tar.gz&quot; \
  | tar xzf - --strip-components=1 -C &quot;${PREFIX}&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Never use npm -g&lt;/h2&gt;

&lt;p&gt;This is a follow up to my &lt;a href=&quot;/problog/2011/12/no-need-for-npm-g&quot;&gt;earlier blog post about avoiding npm -g&lt;/a&gt;, now improved and revised. For the most part, I believe &lt;a href=&quot;https://npmjs.org/&quot;&gt;npm&lt;/a&gt; to be the state-of-the-art package management system and to be superior to the messes available for python and ruby. However, the &lt;code&gt;-g&lt;/code&gt; switch, which installs commands &lt;code&gt;globally&lt;/code&gt;, should be avoided in favor of the system described here. You don't want to have to upgrade all your express.js apps at once, so give them each their own copy of the &lt;code&gt;express&lt;/code&gt; script.&lt;/p&gt;

&lt;h2&gt;Provide a single script to launch your application commands&lt;/h2&gt;

&lt;p&gt;Encapsulate each version with a wrapper shell script that understands the project directory layout and manages your PATH appropriately. I tend to call this file &lt;code&gt;project_root/do&lt;/code&gt; but &lt;code&gt;project_root/bin/tasks.sh&lt;/code&gt; or similar are good locations for this. This script should handle your service operations like start, stop, reload, etc, as well as any one-off commands you make have like clearing a cache, regenering static files, and so forth.&lt;/p&gt;

&lt;p&gt;Here's a snippet of my &lt;code&gt;project_root/do&lt;/code&gt; script which locates the correct installation of python and fabric and passes control to them.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/bin/sh -e
cd $(dirname &quot;${0}&quot;)
exec ./python/bin/fab &quot;${@}&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Thus I can run this script from any directory, or from an init/upstart script, with any PATH, and the application correctly handles its own required settings. The above is the bare bones and the crux of the separation of concerns in the design. I normally have some other code in there to bootstrap the project's dependencies, but I'll save that topic for another blog post.&lt;/p&gt;

&lt;h2&gt;For local development, manage your PATH intelligently and automatically&lt;/h2&gt;

&lt;p&gt;As you work on many projects which contain their own interpreter installations, you don't want to always have to A) work from the project root directory and B) run commands like &lt;code&gt;./python/bin/python myapp.py&lt;/code&gt;. So here are some utilities that can intelligently manage your PATH similar to what is done by &lt;a href=&quot;https://github.com/sstephenson/rbenv&quot;&gt;rbenv&lt;/a&gt;, but not tied to ruby and based on you changing project directories.&lt;/p&gt;

&lt;p&gt;First, here's how I set up my &lt;code&gt;PATH&lt;/code&gt; in my &lt;code&gt;~/.zshrc&lt;/code&gt; file (works equally well for bash or bourne shell). I've added extra explanatory comments inline.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#This helper function will add a directory to the PATH if it exists
#This is a simple way to handle different machines, OSes, and configurations
addPath() {
    if [ -d &quot;${1}&quot; ]; then
        if [ -z &quot;${PATH}&quot; ]; then
            export PATH=&quot;${1}&quot;
        else
          export PATH=$PATH:&quot;${1}&quot;
        fi
    fi
}

setupPath() {
    #Start with an empty PATH
    PATH=
    #Local pwd stuff
    addPath &quot;${PWD}/script&quot;
    addPath &quot;${PWD}/bin&quot;
    #For node
    addPath &quot;${PWD}/node_modules/.bin&quot;
    addPath &quot;${PWD}/node/bin&quot;
    #For python virtualenvs
    addPath &quot;${PWD}/python/bin&quot;

    #Personal home dir stuff
    addPath ~/bin
    #For rbenv
    addPath ~/.rbenv/bin
    addPath ~/.cabal/bin
    #Homebrew
    addPath ~/Library/Python/2.7/bin
    addPath /usr/local/share/python
    addPath /usr/local/bin
    #XCode/Developer
    addPath /Developer/usr/bin
    #Normal system stuff
    addPath /bin
    addPath /usr/bin
    addPath /sbin
    addPath /usr/sbin
    addPath /usr/X11/bin
}
#Run this during shell startup. Can be re-run as needed manually as well
setupPath
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;OK, so that's how the &lt;code&gt;PATH&lt;/code&gt; gets built up, but we want to change the PATH as we move our current working directory between projects. For that we use a shell hook function. What this does is try to detect if we've changed into a project directory, and if so, rebuild the &lt;code&gt;PATH&lt;/code&gt;, which will put our project-specific directories early in the &lt;code&gt;PATH&lt;/code&gt; list, so when we type &lt;code&gt;node&lt;/code&gt; or &lt;code&gt;python&lt;/code&gt; or &lt;code&gt;coffee&lt;/code&gt;, etc, we get the project specific one under the project root. Because this adds absolute paths and only changes the &lt;code&gt;PATH&lt;/code&gt; when we &lt;code&gt;cd&lt;/code&gt; to a project root, we can cd to subdirectories within the project and still be running the correct project-specific interpreter. This does breakdown, however, if you cd directly into a project subdirectory without stopping in the project root. I don't hit that problem because I'm not in the habit of doing that, but YMMV. Here's the zsh version, which uses the &lt;a href=&quot;http://www.refining-linux.org/archives/42/ZSH-Gem-8-Hook-function-chpwd/&quot;&gt;chpwd&lt;/a&gt; hook function.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;if [ -n &quot;${ZSH_VERSION}&quot; ]; then
    chpwd() {
        [ -d .git -o \
          -d  node_modules/.bin -o \
          -d python/bin -o \
          -d node/bin ] &amp;&amp; setupPath
    }
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Bash users, &lt;a href=&quot;http://stackoverflow.com/questions/3276247/is-there-a-hook-in-bash-to-find-out-when-the-cwd-changes&quot;&gt;you're on your own&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's an example of this at work.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;~-&gt; cd projects/peterlyons.com
~/projects/peterlyons.com-&gt; which node
/Users/plyons/projects/peterlyons.com/node/bin/node
~/projects/peterlyons.com-&gt; cd ../craft
~/projects/craft-&gt; which node
/Users/plyons/projects/craft/node/bin/node
~/projects/craft-&gt; cd ../othenticate.com
~/projects/othenticate.com-&gt; which node
/Users/plyons/projects/othenticate.com/node/bin/node
~/projects/othenticate.com-&gt; cd ../m-cm/indivo_provision
~/projects/m-cm/indivo_provision-&gt; which python
/Users/plyons/projects/m-cm/indivo_provision/python/bin/python
~/projects/m-cm/indivo_provision-&gt; cd ./conf
~/projects/m-cm/indivo_provision/conf-&gt; which python
/Users/plyons/projects/m-cm/indivo_provision/python/bin/python
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;(Bonus item) Keep variable files for data and logging under your project directory&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;project_root/var/log&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;project_root/var/data&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a mindset shift from traditional unix administration best practices. It's in my opinion a less complex and more application-centric design that makes better sense given our focus on applications that tend to be providing network services and generally are less tightly coupled to the underlying OS these days. Traditional unix administration (as documented in the &lt;a href=&quot;http://www.pathname.com/fhs/&quot;&gt;Filesystem Heirarchy Standard&lt;/a&gt;) has a strong and system-wide distinction that runtime variable data like data files and log files go under &lt;code&gt;/var&lt;/code&gt; and everything else except for &lt;code&gt;/home&lt;/code&gt; and &lt;code&gt;/tmp&lt;/code&gt; is static data. Again, this no longer applies to modern applications. These rules had to do with preventing key filesystems from filling up, primarily. They wanted application data to be static and allocate a certain amount of space that had separate filesystem limits from the variable data, which they wanted organized centrally under &lt;code&gt;/var&lt;/code&gt; so they could manage log file growth and space disk space centrally. There were reasons for these designs at the time that made sense given the constraints and goals, but times have changed.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>CoffeeScript and Progress</title>
    <link href="http://peterlyons.com/problog/2012/03/coffeescript-and-progress"></link><updated>2012-03-05T04:36:35.083Z</updated><id>http://peterlyons.com/problog/2012/03/coffeescript-and-progress</id>
    <content type="html">&lt;p&gt;If you like &lt;a href=&quot;http://jashkenas.github.com/coffee-script&quot;&gt;CoffeeScript&lt;/a&gt;, you should write applications in CoffeeScript. If you prefer JavaScript, you should write applications in JavaScript. In this post I want to address the common attitude I have found among JavaScript programmers that CoffeeScript is a priori somehow wrong or inferior or a bad choice. I'll briefly recount some of the technical reasons why I like and use CoffeeScript at the end of this post, but the focus is a rejection of the attitude above on philosophical grounds. To be clear, the position I'm taking issue with is the position that JavaScript is the one and only language we should be writing in for the browser and node.js.&lt;/p&gt;

&lt;h1&gt;Philosophical Rejection of Monoglotism&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Availability of a multitude of highly varied programming languages is good
&lt;ul&gt;&lt;li&gt;Check out &lt;a href=&quot;http://dartr.com/&quot;&gt;Dart&lt;/a&gt;, &lt;a href=&quot;http://haxe.org/&quot;&gt;Haxe&lt;/a&gt;, &lt;a href=&quot;http://jashkenas.github.com/coffee-script&quot;&gt;CoffeeScript&lt;/a&gt;, &lt;a href=&quot;http://code.google.com/webtoolkit/&quot;&gt;GWT&lt;/a&gt;, or &lt;a href=&quot;http://caterwauljs.org/&quot;&gt;Caterwaul&lt;/a&gt; for examples&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;The goal of a single programming language for the browser is a detrimental non-goal&lt;/li&gt;
&lt;li&gt;Openness and freedom are important, as are standards and interoperability, but standards that don't evolve on an appropriate schedule are detrimental.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I brought up the topic of Google's Dart language at a local tech meetup when Dart was first announced. I asked people what their reaction was. The few who responded seemed to dislike it, not for any particular technical objection to the language or its features, but simply to its existence at all, which surprised me. This struck me as completely unexpected and strange. Why, I asked. &quot;JavaScript is a standard&quot; came back from one person. &quot;Why do you like it?&quot;, he asked. I said I didn't yet know much of anything about it, but I liked the creation of new programming languages for the browser as a basic idea. I said that choice of programming tools is a good thing, and JavaScript is clearly flawed in extremely well-understood ways. Why is there this relentless stranglehold on universal and eternal backward compatibility? What is the cost/benefit analysis that goes into that?&lt;/p&gt;

&lt;p&gt;Software in general, including programming languages and tools, must continually advance, and the faster, the better. Addressing backward compatibility by slowing forward progress is a losing solution. Ye olde for loop, while venerable, has been surpassed. Let it go. I agree with &lt;a href=&quot;http://www.artima.com/weblogs/viewpost.jsp?thread=221903&quot;&gt;Bruce Eckel&lt;/a&gt; here in that once you have a stable version of a language, authors who &quot;don't want to deal with those changes&quot; should be able to just continue using that version while the current version of the language advances. If you wrote a JDK 1.2 application in 2000 or so and you still want to run it, just keep running it on JDK 1.2. Don't hold the entire java language back for the lifetime of this application which you are unwilling to maintain and advance along with the platform. Browsers should do the same thing with their javascript engines every 2 years or so. If you want to write a codebase once and not update it, ship it on custom hardware that does not include networking capability and call it a day. If you want to write software that works on the Internet, commit to a certain amount of ongoing maintenance. Even if we had perfect technical backward compatible support, the state of everything else: UX, UI, performance, data formats, protocols, continues to advance. Craigslist.org can get away with keeping the same UI for a decade because they make their own rules. Every other site needs to modernize.&lt;/p&gt;

&lt;p&gt;I overheard a well-regarded server-side JavaScript programmer complain about CoffeeScript saying something along the lines of &quot;Why would you write a module in some language I don't know?&quot;. WTF? How would it sound if I said that about any other server side programming language? It would sound ridiculous, because it is.&lt;/p&gt;

&lt;p&gt;This notion that the web is ever going to be some all-purpose panacea built upon a single markup language plus a single stylesheet language plus a single programming language is a false goal. Let it go. Embrace a variety of tools. The vast majority of web sites are not built from direct HTML files. HTML is generated by dozens of highly divergent programming languages across many paradigms with all combinations of trade-offs. So it should be for the application in the browser. It's not a problem on the server, and it's not going to be a problem in the browser.&lt;/p&gt;

&lt;h1&gt;Rejection of FUD&lt;/h1&gt;

&lt;p&gt;CoffeeScript is clearly a well-thought-through and beautiful language. It brilliantly removes the terrible parts of javascript and replaces verbose javascript boilerplate with elegant expressiveness. For example, the function keyword being replaced with the gorgeous arrow symbol &lt;code&gt;-&gt;&lt;/code&gt; and the introduction of list comprehensions. It is so small and concise that there are no glaring warts to be ironed out. If you like python or ruby, you will probably like CoffeeScript better than JavaScript. If you try it for 6 months and change your mind, compile it to javascript and use that as your no codebase. No harm, no foul.&lt;/p&gt;

&lt;h1&gt;But but but...&lt;/h1&gt;

&lt;p&gt;Debugging. I hear arguments that because the line numbers in the browser stack traces don't align with the line numbers in your .coffee files, debugging is harder in CoffeeScript than JavaScript. I don't find this a problem. I just don't. My variable and function names are preserved. I anchor to a function name and my functions don't get exceedingly long. I see that in the browser the error is a few lines down in the &quot;loadUserList&quot; function and I go look at the &quot;loadUserList&quot; function in CoffeeScript and find the problem without a lot of fuss. In my experience there's just no impact here. I don't really know why people bring this up so often. It's just a non-problem for me. We use multiple preprocessing techniques including concatenating JS files together. Line numbers just ain't never gonna map back to actual files in your editor. Get over it.&lt;/p&gt;

&lt;h1&gt;In case you didn't know&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Multiline strings. OMFG yes, duh.&lt;/li&gt;
&lt;li&gt;String interpolation. So nice. So nice.&lt;/li&gt;
&lt;li&gt;Destructuring assignment. Coming to JavaScript circa 2019...&lt;/li&gt;
&lt;li&gt;No 8-letter function keyword. These days we're building anonymous functions every 4 lines or so. Skinny arrow FTW!&lt;/li&gt;
&lt;li&gt;Array literals with newlines and no commas. I'm not sure what the obsession with commas is, but people, we don't need them. I don't even think we need them in one-line lists. We have the mighty space character, which is how you eye parses code already! If we can do &lt;code&gt;[1, 2, 3, 4]&lt;/code&gt;, then why can't we just do &lt;code&gt;[1 2 3 4]&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Automatic IIFE wrapper. No var keyword. Default values for function parameters. Die boilerplate, die!&lt;/li&gt;
&lt;li&gt;It's like skinny dipping, but for punctuation! Look at some Jasmine or Mocha BDD tests in JavaScript and then CoffeeScript. One looks like a garbled mess of crap with line after dedented line of &lt;code&gt;}); }); });&lt;/code&gt;, and one looks like poetry.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a sample BDD spec in CoffeeScript from &lt;a href=&quot;https://raw.github.com/gist/1379251/274de0e881eb736ebf04657c3c1955a00475836a/4_math_spec.coffee&quot;&gt;a gist on github&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;describe 'Math:', -&gt;
  describe 'fib()', -&gt;
    it 'should calculate the numbers correctly up to fib(16)', -&gt;
      fib = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]
      expect(Math.fib(i)).toEqual fib[i] for i in [0..16]

  describe 'uuid()', -&gt;
    it 'should have the proper UUID format', -&gt;
      expect(Math.uuid()).toMatch /[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{13}/

    it 'should have always the numer 4 at position 14', -&gt;
      expect(Math.uuid()).toMatch /[A-Z0-9]{8}-[A-Z0-9]{4}-4[A-Z0-9]{3}-[A-Z0-9]{4}-[A-Z0-9]{13}/
      expect(Math.uuid()).toMatch /[A-Z0-9]{8}-[A-Z0-9]{4}-4[A-Z0-9]{3}-[A-Z0-9]{4}-[A-Z0-9]{13}/
      expect(Math.uuid()).toMatch /[A-Z0-9]{8}-[A-Z0-9]{4}-4[A-Z0-9]{3}-[A-Z0-9]{4}-[A-Z0-9]{13}/

    it 'should generate a unique uuid for 1000 generated uuids at least', -&gt;
      uuids = []
      counter = 0

      while counter &lt; 1000
        uuids.push Math.uuid()
        counter++

      expect(uuids.length).toEqual _.uniq(uuids).length
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And here's a &lt;a href=&quot;https://raw.github.com/gist/1680082/7180717961b2938f00acedbff14b7192561ac2cc/gistfile1.js&quot;&gt;similar jasmine spec in JavaScript&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;describe(&quot;NotesView&quot;, function() {
  beforeEach(function() {
    var notes = new NotesCollection();
    spyOn(notes, &quot;fetch&quot;);

    var view = new NotesView({collection: notes});
  });

  describe(&quot;#initialize&quot;, function() {
    it(&quot;should fetch the notes&quot;, function() {
      expect(notes.fetch).toHaveBeenCalled();
    });

    describe(&quot;on notes fetch success&quot;, function() {
      beforeEach(function() {
        var request = mostRecentAjaxRequest();
        request.response({
          status: 200,
          responseText: JSON.stringify([
            {body: &quot;Blog post #1&quot;, id: &quot;1&quot;}
          ])
        });
      });

      it(&quot;should render the view&quot;, function() {
        expect($(view.el).find(&quot;.post&quot;)).toHaveText(&quot;Blog post #1&quot;);
      });
    });
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ouch, my eyes! All those closing punctuation groups!&lt;/p&gt;

&lt;p&gt;Reduction of boilerplate and increasing expressiveness are what I want from a language. CoffeeScript delivers strongly in these areas. It compiles to JavaScript and works right now in all browsers and in node.js.&lt;/p&gt;

&lt;h1&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;It's a polyglot world. Every app is going to use more than one programming language. Work toward making the programming languages we use better instead of trying to shame us into continuing to use languages as better alternatives are created. Shame on you. Move forward.&lt;/p&gt;</content>
  </entry>
</feed>