Find file
Fetching contributors…
Cannot retrieve contributors at this time
2331 lines (1860 sloc) 222 KB
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Adventures in JavaScript Development]]></title>
<link href="http://rmurphey.com/atom.xml" rel="self"/>
<link href="http://rmurphey.com/"/>
<updated>2015-11-25T13:58:57-06:00</updated>
<id>http://rmurphey.com/</id>
<author>
<name><![CDATA[Rebecca Murphey]]></name>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[Building for HTTP/2]]></title>
<link href="http://rmurphey.com/blog/2015/11/25/building-for-http2/"/>
<updated>2015-11-25T14:00:00-06:00</updated>
<id>http://rmurphey.com/blog/2015/11/25/building-for-http2</id>
<content type="html"><![CDATA[<p>Earlier this year, I got the chance to speak with Google&#8217;s Ilya Grigorik about HTTP/2 for the <a href="http://ttlpodcast.com/episodes/ilya-grigorik.html">1.10 episode of the TTL Podcast</a>. It was a great primer for me on how HTTP/2 works and what it means for how we build the web, but it wasn&#8217;t until more recently that I started to think about what it means for how we <em>build</em> the web — that is, how we generate and deploy the HTML, CSS, and JS that power web applications.</p>
<p>If you&#8217;re not familiar with <a href="https://httpwg.github.io/specs/rfc7540.html">HTTP/2</a>, the basics are simultaneously simple and mind-boggling. Whereas its predecessors allowed each connection to a server to serve only one request at a time, HTTP/2 allows a connection to serve multiple requests simultaneously. A connection can also be used for a server to <em>push</em> a resource to a client — a protocol-level replacement for the technique we currently call “inlining.”</p>
<p>This is everything-you-thought-you-knew-is-wrong kind of stuff. In an HTTP/2 world, there are few benefits to concatenating a bunch of JS files together, and in many cases the practice will be actively harmful. <a href="http://www.stevesouders.com/blog/2013/09/05/domain-sharding-revisited/">Domain sharding</a> becomes an anti-pattern. Throwing a bunch of <code>&lt;script&gt;</code> tags in your HTML is suddenly not a laughably terrible idea. Inlining of resources is a thing of the past. Browser caching — and cache busting — can occur on a per-module basis.</p>
<p>What does this mean for how we build and deploy applications? Let&#8217;s start by looking at the state of the art in client-side application deployment prior to HTTP/2.</p>
<h2>Deploying JavaScript Applications (2013)</h2>
<p>In March of 2013, Alex Sexton wrote <a href="https://alexsexton.com/blog/2013/03/deploying-javascript-applications/">Deploying JavaScript Applications</a>, and it&#8217;s what I consider to be the canonical post on the topic for sites and apps that include more than about 50K of client-side code.</p>
<p>In his post, Alex describes a deployment that uses a &#8220;scout&#8221; approach: a small bit of code, included directly in the HTML or loaded via <code>&lt;script&gt;</code> tag.</p>
<p>The scout file exists to balance the desire for application resources to be highly cacheable vs. the need for changes to those resources to take effect quickly.</p>
<p>To meet that goal, the scout needs a short cache time when it&#8217;s a file; if the scout is in the HTML, then the HTML itself needs a short cache time. The scout contains information about the location of the file(s) that provide the current version of the application, and the code necessary to load those files.</p>
<p>Files loaded by the scout can have extremely long cache times because the scout loads resources from versioned URLs: when a resource is updated, it is hosted at a new URL, and the scout is updated to load the resource from that new URL.</p>
<p>Why a scout approach rather than just loading the versioned files using <code>&lt;script&gt;</code> tags directly from the HTML? The scout technique lets you deploy changes to your JavaScript application without requiring a re-deploy of the server-side application. (In an ideal world this might not seem valuable, but in the real world, it often is.) When the scout is served separately from the HTML, it also allows for a different caching strategy for the HTML.</p>
<p>In this system, it&#8217;s typical that the scout would load one or two JavaScript files that were generated by combining the modules needed for the initial state of the application. More code might be loaded later to support additional application behavior; again, that code would typically comprise a set of modules shipped in a single file.</p>
<p>There are a few shortcomings inherent to this approach, which are difficult to overcome without upsetting the balance between cacheability and changeability:</p>
<ul>
<li>Shipping the application as a large file with a long cache time works great for repeat visitors, but not so well for first-timers who have to wait for the large file to load.</li>
<li>All users have to download the whole large file again whenever something changes — even something small.</li>
<li>Even when <em>nothing</em> changes, a short cache time means repeat visitors may end up re-downloading the scout frequently.</li>
</ul>
<p>Adding HTTP/2 to the mix — that is, flipping the switch that gets your server to start speaking HTTP/2 to browsers that understand it — has a nominal positive impact the performance of an app crafted for maximum performance on HTTP/1. Indeed, the applications most likely to see big improvements without big changes are applications whose deployments were poorly designed in the first place.</p>
<p>To see performance gains in a well-engineered deployment, we&#8217;ll have to re-engineer the deployment itself.</p>
<h2>Splitting it up</h2>
<p>One of the most obvious opportunities is presented by HTTP/2&#8217;s ability to handle multiple requests over the same connection. Rather than shipping a single large application file over the wire, what if we tell the scout to load the individual modules that make up the application? We would no longer have to invalidate the cache for the whole application every time we make a change.</p>
<p>A few reasons come to mind why this might be a bad idea.</p>
<p>The first is the concern that compression might suffer if shipping modules individually. As it turns out, though, combining multiple modules into a single file results in only slightly better compression than if the modules are compressed individually. For example, compressing a file containing minified versions of jQuery, Underscore, and Backbone results in 42,186-byte file; compressing each minified file individually results in a combined size of 42,975 bytes. The difference is 789 bytes &#8211; barely meaningful.</p>
<p>Other second concern may be more legitimate: our server or CDN may be unhappy about serving one request per module; and it may be unduly complex to ship a single module per file, especially since any given request might fail for whatever reason. For the sake of discussion, we&#8217;ll assume that it&#8217;s reasonable to do <em>some</em> grouping of modules into individual files.</p>
<p>How to group those modules is up for debate. One strategy could be to group files according to their likelihood of changing, recognizing that library and framework modules don&#8217;t change often, while application modules do. Another strategy would be to group files associated with a unit of useful functionality, though this leaves us needing a way to deliver code that&#8217;s shared across units of functionality.</p>
<p>At Bazaarvoice, we solve this concern via a lightweight require/define system that ships in the scout file, allowing us to share vendor files such as jQuery and Backbone across applications. An application can express a dependency on a vendor file using <code>NAMESPACE.require()</code>, and vendor files declare themselves using <code>NAMESPACE.define()</code>. Once a vendor file has been defined, other modules on the page have access to it immediately via <code>NAMESPACE.require()</code>.</p>
<h2>Versioning</h2>
<p>For HTTP/1.1-friendly builds, we always increment the version of the built application file, and embed a URL pointing to that new version in the scout file. We do this because it is essentially guaranteed that the contents of the application file have changed whenever we do a new build &#8211; otherwise there would be no reason for the build.</p>
<p>For HTTP/2-friendly builds, we’re generating many smaller files; we only want to increment their version when something has changed.</p>
<p>For example, imagine a build that generates vendor-v1.js and application-v1.js; it also generates a scout that loads these two files. We then make a change to an application file, and we do another build, creating vendor-v2.js and application-v2.js. However, no vendor files have changed; our scout should now load to application-v2.js but still load vendor-v1.js. If our scout points to vendor-v2.js, we lose the benefit of being able to cache smaller pieces of our code.</p>
<p>This can be solved by using hashes of the file contents rather than version numbers: vendor-d41d8cd98f.js. If a file has not changed, its hash will remain the same. (Notably, inconsequential changes <em>will</em> change the hash &#8211; for example, a new copyright comment that is inserted post-minification.) Plenty of build strategies already use content hashes for versioning; however, many still use integers, dates, or commit hashes, which change even when the contents of a file have not.</p>
<p>Given files whose names include a hash, our scout can include a manifest that prescribes the file to load for a given resource. The manifest would be generated by the build after all of the resources were generated.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">baseUrl</span> <span class="o">:</span> <span class="s1">&#39;https://mysite.com/static/&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">resources</span> <span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">vendor</span> <span class="o">:</span> <span class="s1">&#39;vendor-d41d8cd98f.js&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">application</span> <span class="o">:</span> <span class="s1">&#39;application-a32e3ec23d.js&#39;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>
<h2>Push: Because you downloaded scout.js, you might also like &#8230;</h2>
<p>Another exciting opportunity in an HTTP/2 world is the ability to push a cascade of resources.</p>
<p>The first push opportunity is the scout itself: for sites and applications that currently ship the scout inlined in the initial HTML payload, server push affords an opportunity to send the scout as a separate resource when the initial HTML is requested.</p>
<p>There’s an interesting dilemma here: If the browser already has the resource cached, and the cache is still valid, it doesn’t need the server to push the resource. Currently, though, there’s no way for the browser to communicate its cache contents to the server. A browser can decline a push, but <a href="https://github.com/h2o/h2o/issues/355#issuecomment-109979111">the server may have already started to send it</a>. We’ve basically introduced a new tradeoff: server push can get the resource to the browser quickly, but we waste bandwidth if the browser doesn’t need it.</p>
<p>As discussed at the link above, a smart server could use session information to determine when to push &#8211; for example, if the page is reloaded within a resource’s cache time, there is no need to re-push that resource to the same session &#8211; but this makes push state-dependent, a frightening prospect if we hope to use CDNs to ensure efficient asset delivery.</p>
<p>Assuming we&#8217;ve generated a manifest as described above, we have the option of going a step further: we can separate the manifest and the scout, allowing the scout to have a far longer cache time than in a pre-HTTP/2 world. This is possible because the thing that typically <em>changes</em> about the scout is the version of the resources it loads, and it makes the most sense on a site where there are different payloads for different pages or users. For applications that previously included the scout in HTML, we can push the scout and the manifest, and have the scout request the manifest; for applications that loaded the scout as its own JS file, we can push the manifest when the scout file is loaded and, again, have the scout request the manifest.</p>
<p>This approach also makes a further case for a <a href="https://github.com/bazaarvoice/scoutfile">standardized scout</a>: application-specific configuration can be shipped in the manifest, and a standardized scout can be shared across applications. This scout could be a file loaded via a script tag, where the script tag itself provides information about the application manifest to use:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;script </span><span class="na">src=</span><span class="s">&quot;/static/shared/js/scout.js&quot;</span>
</span><span class='line'> <span class="na">data-manifest=</span><span class="s">&quot;/static/apps/myapp/manifest.js&quot;</span><span class="nt">&gt;&lt;/script&gt;</span>
</span></code></pre></td></tr></table></div></figure>
<p>The manifest contains information about the other resources that the scout will request, and can even be used by the server to determine what to push alongside the HTML.</p>
<p>A manifest could provide these instructions:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">baseUrl</span> <span class="o">:</span> <span class="s1">&#39;https://mysite.com/static/&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">resources</span> <span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">vendor</span> <span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">version</span> <span class="o">:</span> <span class="s1">&#39;vendor-d41d8cd98f.js&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">pushWith</span> <span class="o">:</span> <span class="p">[</span> <span class="s1">&#39;scout&#39;</span> <span class="p">]</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'> <span class="nx">application</span> <span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">version</span> <span class="o">:</span> <span class="s1">&#39;application-a32e3ec23d.js&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">pushWith</span> <span class="o">:</span> <span class="p">[</span> <span class="s1">&#39;scout&#39;</span> <span class="p">]</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'> <span class="nx">secondary</span> <span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">version</span> <span class="o">:</span> <span class="s1">&#39;secondary-e43b8ad12f.js&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">pushWith</span> <span class="o">:</span> <span class="p">[</span> <span class="p">]</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>
<p>Processing this manifest would require intelligence on the part of the CDN; it may be necessary to replace s3 storage with an actual server that is capable of making these decisions, fronted by a CDN that can intelligently relay responses that include server push.</p>
<h2>The elephants in the room</h2>
<p>There are two notable challenges to the rapid transition to an HTTP/2 world: the continued existence of legacy browsers, especially on mobile; and the requirement that HTTP/2 connections be conducted over TLS. Thankfully, the latter provides a reasonable opportunity to address the former. Let&#8217;s, then, talk about the TLS requirement first.</p>
<p>HTTP/2 is a new protocol, and as such, it is greatly confusing to a large segment of the existing internet: proxies, antivirus software, and the like. During the development of HTTP/2 and <a href="https://en.wikipedia.org/wiki/SPDY">SPDY</a> before it, engineers observed that traffic that was transported on an insecure connection would frequently fail. The reason? The proxies, the antivirus software, and all the rest had certain expectations of HTTP traffic; HTTP/2 violated those expectations, and so HTTP/2 traffic was considered unsafe. The software that thwarted insecure HTTP/2 traffic didn&#8217;t have the ability to inspect secure traffic, and so HTTP/2 traffic over a secure connection passed through just fine. Thus was born the requirement — which is a browser implementation detail, and not part of the HTTP/2 spec — that HTTP/2 web communication be conducted using TLS.</p>
<p>The <a href="https://letsencrypt.org/">Let&#8217;s Encrypt</a> project aims to eliminate the high cost of obtaining the certificate that enables secure HTTP communication; there will still be technical hurdles to using that certificate, but those should be surmountable for anyone who cares enough to engineer a performant HTTP/2 deployment.</p>
<p>In order for a browser and a server to communicate using HTTP/2, the browser and the server must first agree that they <em>can</em>. The TLS handshake that enables secure communication turns out to be the ideal time to negotiate the communication protocol, as well: no additional round trip is required for the negotiation.</p>
<p>When a server is handling a request, it knows whether the browser understands HTTP/2; we can use this information to shape our payload. We can send a legacy browser an HTML file that includes an inlined scout file, and that inlined scout file can include the manifest. The manifest can provide information about how to support legacy browsers:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">baseUrl</span> <span class="o">:</span> <span class="s1">&#39;https://mysite.com/static/&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">resources</span> <span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="c1">// ...</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'> <span class="nx">legacyResources</span> <span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">legacyMain</span> <span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">initialLoad</span> <span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span><span class='line'> <span class="nx">version</span> <span class="o">:</span> <span class="s1">&#39;legacy-main-c312efa43e.js&#39;</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'> <span class="nx">legacySecondary</span> <span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">version</span> <span class="o">:</span> <span class="s1">&#39;legacy-secondary-a22cf1e2af.js&#39;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>
<h2>For Consideration: HTTP/2-friendly deployments with HTTP/1.1 support</h2>
<p>Putting the pieces together, we arrive at a deployment process that does the following:</p>
<ul>
<li>Generates files that contain one or more modules, grouped by likelihood of changing, functionality, or another strategy. The file grouping strategy must persist across builds; new groupings would need a new, unique name that had not been used by earlier builds.</li>
<li>Generates <strong>legacy files</strong>, where those files contain modules that are grouped according to their likelihood to change, and according to whether they are required for initial load.</li>
<li>Names all files with a content hash.</li>
<li>Generates a manifest for the build, where the manifest includes:
<ul>
<li>a <code>baseUrl</code> property whose value is a string that should be used as the base for generating a full URL to a resource, using the pattern <code>&lt;baseUrl&gt;/&lt;resource.version&gt;</code></li>
<li>a <code>resources</code> property whose value is an object that, for each file, provides:
<ul>
<li>the most recent <em>changed</em> version</li>
<li>a list of individual files which, when any of the files is requested, should trigger a push of the bundle</li>
</ul>
</li>
<li>a <code>legacyResources</code> property whose value is an object that, for each legacy bundle, provices:
<ul>
<li>the most recent <em>changed</em> version</li>
<li>an optional <code>initialLoad</code> property whose value is <code>true</code> if the resource should be loaded immediately by the scout</li>
</ul>
</li>
</ul>
</li>
<li>Generates an HTTP/2 scout file* that provides the ability to load resources, and that loads a manifest.</li>
<li>Generates an HTTP/1 scout file* that provides the ability to load resources, and that <em>includes</em> the manifest.</li>
<li>Uploads the static resources.</li>
<li>Updates a delivery mechanism (such as a server or a CDN) based on the data in the new manifest.</li>
</ul>
<p>The versioning and caching of the resources would be as follows:</p>
<ul>
<li><strong>manifest</strong> Unversioned. Short cache time, e.g. 10 minutes, to allow for the rapid uptake of new resources for HTTP/2 browsers.</li>
<li><strong>scout</strong> Unversioned. Medium cache time, e.g. one day, assuming the contents of this file are considered relatively stable.</li>
<li><strong>legacy-scout</strong> Unversioned. Short cache time, e.g. 10 minutes, to allow for the rapid uptake of new resources for legacy browsers.</li>
<li><strong>application and vendor files</strong> Versioned. Long cache time, e.g. one year, given that new versions will be picked up when a new manifest is loaded.</li>
</ul>
<p><small>* In applications that a) control the initial HTML payload, and b) only use the scout to load other resources, it may not make sense to have a separate scout; it might be sufficient to just load those resources via <code>&lt;script&gt;</code> and <code>&lt;link&gt;</code> tags in the HTML itself. This approach isn&#8217;t viable for applications that do not control the initial HTML payload, such as third-party applications.</small></p>
<h2>Reality check</h2>
<p>In several places so far, I’ve talked about the need for a server to make decisions about which resources it delivers, and when and how it delivers them. As I alluded to earlier, this could be profoundly challenging for CDNs, which traditionally simply receive a request and return a single resource in response. It also suggests the need for close collaboration between client and server development teams, and an increased knowledge of server-side technology for client-side developers.</p>
<p>CDN support of HTTP/2 in general is rather disappointing, with some major vendors providing nothing more than vague timelines for non-specific support.</p>
<p>As of this writing, I&#8217;m unaware of CDNs that support any notion of server push, but I&#8217;d be happy to find I am ill-informed. Ideally, CDNs need to provide applications with the ability to express how static assets relate to each other &#8211; a task complicated by the fact that those relationships may be situational, such as in the case where an application doesn&#8217;t want to push an asset that was just pushed to the same client 10 seconds before. One-size-fits-all push could be accomplished by setting a header on a file, indicating that other files should be pushed alongside it, but that doesn&#8217;t allow for expressing more nuanced rules.</p>
<p>Even for applications that just want to split their payload into smaller files to take advantage of HTTP/2, and that don&#8217;t intend to use server push, there is still a gap when it comes to providing a positive experience for HTTP/1.1 clients. CDNs need to surface the ability to change a response not just based on the URL that is requested, but the protocol of the request. Without this ability, we&#8217;ll be stuck having to choose which protocol to support.</p>
<p>There is also work to be done on tooling, especially if we want to support HTTP/2 without significantly degrading the experience for legacy browsers. Ideally, our build tooling would figure out the optimal combination of files for us, with a knowledge of how the application was bundled previously so as not to squander past caching.</p>
<p>The developer story for HTTP/2 also leaves a lot to be desired as of this writing. Front-end developers are among the most likely in an organization to advocate for this new technology, but my experiences over a few weeks of learning about HTTP/2 suggest that the effort required to set up even a local environment will stretch the comfort zone for many. With a working local environment in hand, the tools to understand the differences between HTTP/2 and HTTP/1 behavior are limited and often confusing. Chrome presents information in its network tab that seems to conflict with the wall of text in its net-internals tool, especially when it comes to server push . Charles Proxy doesn&#8217;t yet speak HTTP/2. Firefox shows pushed resources as an entry in the network tab, but they appear as though they were never received. <a href="https://nghttp2.org/">nghttp2</a> provides great insight into how an HTTP/2 server is behaving, but it doesn&#8217;t speak HTTP/1.1, so you can&#8217;t use it to do comparisons. Measuring performance using a tool like WebPagetest requires a real certificate, which you may not have handy if you&#8217;re just trying to experiment.</p>
<p>Alex wrote his 2013 post to document the product of years of experience in creating performant HTTP/1.1 deployments. HTTP/2 means we need to rethink everything we know about shipping applications to the web, and while the building blocks are there, there&#8217;s still much to figure out about how we&#8217;ll use them; the &#8220;right&#8221; answers are, in many cases, still TBD while we wait for vendors to act.</p>
<h2>Further Reading</h2>
<p>I&#8217;ve been bookmarking useful <a href="https://pinboard.in/u:rmurphey/t:http2/">HTTP/2 resources</a> as I come across them.</p>
<h2>Thanks</h2>
<p>Thanks to the many folks who have talked to me about the ideas in this post, but especially to Lon Ingram, Jake Archibald, and Andy Davies.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Five Questions]]></title>
<link href="http://rmurphey.com/blog/2015/10/08/five-questions/"/>
<updated>2015-10-08T23:00:00-05:00</updated>
<id>http://rmurphey.com/blog/2015/10/08/five-questions</id>
<content type="html"><![CDATA[<p>I recently started in a new role: I&#8217;m the dev lead of a project that was
already in the hands of a group of skilled developers before I showed up, a
project whose scope and technologies extend far beyond the experiences I&#8217;ve had
up until now.</p>
<p>As you might imagine, there have been a lot of challenges, but one that&#8217;s been
particularly interesting has been figuring out how to meaningfully contribute
to decisions about systems I don&#8217;t intimately understand. It&#8217;s easy to be
inclined to sit those conversations out: I really don&#8217;t yet know enough to
participate, and the &#8220;who am I to have a say?&#8221; instinct is strong.</p>
<p>The problem: that attitude will ensure that I <em>never</em> know enough to
participate, and though I am definitely out of my comfort zone, my job &#8211; the
job I asked to do, and the job I have been asked to do &#8211; is to participate,
to learn, and to change the definition of my comfort zone.</p>
<p>While I may not have the project-specific experience to lean on, I&#8217;m finding
that there are a few questions that help me understand, discuss, and &#8211; ultimately &#8211; consent or object to a technical plan. They&#8217;re questions that
seem to work well across a spectrum of discussions; they work whether we&#8217;re
talking about a wholly new system, a migration from an old system, or a
solution to a particularly prickly problem.</p>
<p>These questions don&#8217;t just help me gain a better understanding of a topic, or
help me make better decisions; they&#8217;ve also helped me reframe my understanding
of my role as a lead.</p>
<h2>Question 1: What are we doing and why?</h2>
<p>When I hear the answer, I&#8217;m listening for whether the developer is clearly
articulating the problem and the solution. Do we clearly understand the
problem? Is the solution magical, or can we explain why it works? Are we
solving more than the problem, and thereby incurring unnecessary risk? Does the
developer agree that the work is necessary?</p>
<h2>Question 2: How could it go wrong?</h2>
<p>A developer who says nothing can go wrong probably hasn&#8217;t been a developer
for very long. I want to hear far-fetched scenarios, and an explanation for
why they&#8217;re far-fetched. I want to hear worst-case scenarios; good developers
have already thought about these plenty, they&#8217;ve worked to avoid them, and
yet they acknowledge their existence. The goal of this question isn&#8217;t to plan
for everything; rather, the answers provide context for poking at assumptions.</p>
<h2>Question 3: How will we know if it&#8217;s going wrong?</h2>
<p>This is probably my favorite question. If we&#8217;re talking about developing a new
system or project, it&#8217;s a question of how we&#8217;ll know we&#8217;re off track, which
leads to clear milestones and check-in points. If it&#8217;s a migration to a new
system, or a solution to a bad bug, it&#8217;s a question of how we&#8217;ll know that
the new state is less good than we thought it would be. If the answer is
&#8220;customers will tell us,&#8221; we&#8217;re in dangerous territory. For services, I hope to hear answers about automated monitoring, but manual checks will suffice. For
new projects, I hope to hear near-term goals that will help us gauge progress.</p>
<h2>Question 4: What will we do if it goes wrong?</h2>
<p>The answer to this may not always be knowable &#8211; obviously we won&#8217;t always know
the ways things will go wrong &#8211; but it&#8217;s a useful exercise nonetheless. The
answer may be &#8220;we&#8217;ll have to revert back to the old system and that will be
very hard,&#8221; but that at least helps me understand the stakes of the decision.
For new projects, this is a great way to identify the point of no return &#8211;
that is, the point in the project where starting over or changing course
becomes prohibitive.</p>
<h2>Question 5: Is there an &#8220;undo&#8221; button?</h2>
<p>Sometimes, the worst happens. Do we have an escape hatch? How hard will it be
to add one later vs. adding one now? Again, it may be OK if we don&#8217;t have a
rollback plan, but knowing that answer should help guide the decision
about whether to proceed.</p>
<hr />
<p>I&#8217;m learning that a lot of what makes me kind of OK (I hope!) at this dev lead
thing isn&#8217;t a deep knowledge of the specific technologies that are the
underpinning of the project (though it&#8217;s certainly important that I be able to
find my way around). Rather, it&#8217;s my ability to ask these questions, and to
hear and understand the answers, and interpret them into action. I&#8217;m thankful
to the team that is giving me the chance.</p>
<p><em>Addendum: A few people have pointed out that these questions seem to focus
on the negative: &#8220;what&#8217;s going to go wrong?&#8221; I think this has a lot to do with
the particular project I&#8217;m on right now: we&#8217;re in the midst of a lot of
changes to our underlying systems, so these sorts of questions are especially
relevant. On a project that is more focused on new development, the questions
might be focused more on the flip side: how do we know if things are going
<strong>right</strong>?</em></p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Pausing Office Hours]]></title>
<link href="http://rmurphey.com/blog/2015/08/04/pausing-office-hours/"/>
<updated>2015-08-04T21:00:00-05:00</updated>
<id>http://rmurphey.com/blog/2015/08/04/pausing-office-hours</id>
<content type="html"><![CDATA[<p>I started doing <a href="http://rmurphey.com/blog/2015/01/11/office-hours/">office hours</a> at the beginning of the year; it&#8217;s been tremendous fun, super eye-opening, and just generally quite rewarding. I won&#8217;t lie: it&#8217;s also been a lot of time, especially the first few weeks when I terribly underestimated how many people would sign up.</p>
<p>I was out for dinner with a friend tonight and she asked me how it was going, and I had to pause for a second when I realized that we might not be sitting there, right then, if she hadn&#8217;t signed up for a slot. Things like that &#8211; and getting to see, on stage, speakers who trusted me with their talk idea months ago &#8211; make me super-glad that I let (mostly) strangers put 30 minutes on my calendar a couple-few dozen times these last few months. Hopefully I helped a few people along the way too.</p>
<p>In the last couple of weeks I&#8217;ve started a new role at Bazaarvoice: after a few months of working on some fairly independent projects, I&#8217;m back to leading a team. I used to get a kick out of being the female lead of an otherwise-all-male team; now I&#8217;m honored and humbled to get to work with a team where I am one of <em>five</em> women. The ratio isn&#8217;t quite 50-50, but it&#8217;s closer than any team I&#8217;ve worked on before. It&#8217;s also the first lead role I&#8217;ve had where my responsibilities span beyond the front end, a prospect both exciting and daunting.</p>
<p>Which is to say: My hands seem a bit fuller than they did back when I started office hours, so for now, it&#8217;s time to hit the pause button while I focus on my new team. If you&#8217;re interested in picking up where I left off, hit me up and I&#8217;m happy to spread the word.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[So You're Going on a Podcast]]></title>
<link href="http://rmurphey.com/blog/2015/07/27/tech-podcast-recording-tips/"/>
<updated>2015-07-27T21:00:00-05:00</updated>
<id>http://rmurphey.com/blog/2015/07/27/tech-podcast-recording-tips</id>
<content type="html"><![CDATA[<p>I got a fair bit of experience recording a podcast back in the <a href="http://yayquery.com">yayQuery</a> days; when I decided to start another one, the technical side of it felt pretty familiar, minus the part where yayQuery was crazy enough to also record video. Back then, we mostly were talking to each other, so it was easy for us to all be on the same page about the technical requirements: headphones always, typing never (at least when you&#8217;re also talking), and buy a good microphone. We also had 20-some episodes to get good at working with each other.</p>
<p>I&#8217;ve been recording the <a href="http://ttlpodcast.com">TTL Podcast</a> for a few months now; it&#8217;s a show with a different guest every week, so the tech challenges are different, and each show is completely different from the last. It has been great fun, and I can&#8217;t believe how lucky I am to get to ask all of these people to talk to me and they keep saying yes.</p>
<p>I&#8217;ve learned a few things about how to be a good podcast guest along the way, but I haven&#8217;t always been good at sharing them ahead of time with guests. This, then, is really just an attempt to write them down in a single place, with the added benefit that maybe they will be useful to others. This is mostly focused on being a guest of a show; I have lots to say about being a host, but I feel like that&#8217;s a lot more complicated than this.</p>
<h2>Technical</h2>
<ul>
<li>Wear headphones, preferably the best ones you own. The iPhone headphones aren&#8217;t nice, and actually leak noise like crazy. I alternate between using <a href="http://www.klipsch.com/R6i">Klipsch</a> and Shure (sorry, not sure of the model, so no link) in-ear headphones, both of which have a nice silicone seal to keep the sound I&#8217;m hearing in my ears and out of my microphone.</li>
<li>Use the best microphone you can. A MacBook&#8217;s built-in microphone is decent enough in a pinch, but it&#8217;s probably worth springing for an external microphone. I used the <a href="http://www.audio-technica.com/cms/wired_mics/a0933a662b5ed0e2/">AT2020</a> for most of the yayQuery episodes, but I stepped up to a <a href="http://www.shure.com/americas/products/microphones/sm/sm7b-vocal-microphone">Shure SM7B</a> to record TTL at the suggest of Alex Sexton. The USB mic is just fine and very reasonably priced; the Shure sounds absolutely lovely but is a bit more of an investment. If you don&#8217;t want to spring for a mic, see if someone in your office has one you can borrow. If you have questions about audio gear, I am mostly clueless beyond what I&#8217;ve written above.</li>
<li>If you&#8217;re a guest, always plan to record your side of the conversation. (If you&#8217;re a host, always plan to record <em>all</em> sides of the conversation; I&#8217;ve lost an episode by failing to do this.) On a Mac, Quicktime has a simple audio recording feature. There&#8217;s also plenty of other software that will do the same.</li>
</ul>
<h2>Preparation</h2>
<ul>
<li>Listen to at least one episode of the show before you go on (and possibly before you even agree to go on).</li>
<li>Ask the host what they want to talk to you about, and try to have a decent sense of the outline of the conversation before you start. If the host doesn&#8217;t have great guidance &#8211; she&#8217;s almost certainly less familiar with your work than you are &#8211; it&#8217;s generally very welcome for you to propose an outline yourself.</li>
<li>If you have access to a soundproofed room, consider using it. Avoid large, echo-y rooms, or rooms that will be subject to a lot of hallway or construction noise.</li>
</ul>
<h2>The Show</h2>
<ul>
<li>Consider your biological needs before you start recording :) Except for a live show, you&#8217;re always welcome to pause if you need to step away, but you may find yourself distracted in the meantime. Make sure you have water nearby!</li>
<li>Silence phone notifications (no vibrating phones; silence means <em>silent</em>); on your computer, close Twitter, your mail client, etc.; option-click the Notification Center icon in your Mac toolbar to put it in do-not-disturb mode (thanks Ralph Holzmann for that tip).</li>
<li>Unless it&#8217;s a live show, feel free to pause and try again if you make a mistake or say something wrong. It&#8217;s important that you announce that you&#8217;re starting over, then pause, then start over &#8211; that way it&#8217;s easy to fix in post-production.</li>
<li>Remember that a podcast is a conversation, not a presentation. Unlike a presentation, you&#8217;re conversing with a host who knows the audience and can ask you the questions that will help that audience connect with you. Use a video chat so you can watch the host for visual cues that she might want to interject.</li>
</ul>
<p>That&#8217;s my list, though undoubtedly I&#8217;ve left things out. If you have stuff to add, please share in the comments —</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Browser Testing and Code Coverage with Karma, Tape, and Webpack]]></title>
<link href="http://rmurphey.com/blog/2015/07/20/karma-webpack-tape-code-coverage/"/>
<updated>2015-07-20T14:00:00-05:00</updated>
<id>http://rmurphey.com/blog/2015/07/20/karma-webpack-tape-code-coverage</id>
<content type="html"><![CDATA[<p>We recently set up a new project at Bazaarvoice for centralizing common UI modules. We started by using <a href="https://github.com/isaacs/node-tap">node-tap</a> for unit tests, but given that these are <em>UI</em> modules, we quickly switched to using <a href="https://github.com/substack/tape">tape</a>, because it has a fairly easy browser testing story with the help of <a href="http://karma-runner.github.io/0.13/index.html">Karma</a>.</p>
<p>One thing that node-tap provided that tape did not provide out of the box was the ability to measure the code coverage of unit tests. Karma <em>does</em> provide this, but getting it hooked up while using <a href="http://webpack.github.io/">Webpack</a> &#8211; which is our build tool of choice these days &#8211; wasn&#8217;t quite as clear as I would have liked. If you&#8217;re looking to use Karma, tape, and Webpack, then hopefully this post will help you spend a bit less time than I did.</p>
<h2>What You&#8217;ll Need</h2>
<p>By the time it was all said and done, I needed to <code>npm install</code> the following modules:</p>
<ul>
<li>karma</li>
<li>karma-phantomjs-launcher</li>
<li>karma-chrome-launcher</li>
<li>karma-tap</li>
<li>karma-webpack</li>
<li>karma-coverage</li>
<li>istanbul-instrumenter-loader</li>
<li>tape</li>
</ul>
<p>The directory structure was simple:</p>
<ul>
<li>a root directory, containing karma.conf.js and package.json</li>
<li>a lib subdirectory, containing module files</li>
<li>a test/unit subdirectory, containing the unit tests</li>
</ul>
<p>An example application file at lib/global/index.js looked like this:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="cm">/**</span>
</span><span class='line'><span class="cm"> * @fileOverview Provides a reference to the global object</span>
</span><span class='line'><span class="cm"> *</span>
</span><span class='line'><span class="cm"> * Functions created via the Function constructor in strict mode are sloppy</span>
</span><span class='line'><span class="cm"> * unless the function body contains a strict mode pragma. This is a reliable</span>
</span><span class='line'><span class="cm"> * way to obtain a reference to the global object in any ES3+ environment.</span>
</span><span class='line'><span class="cm"> * see http://stackoverflow.com/a/3277192/46867</span>
</span><span class='line'><span class="cm"> */</span>
</span><span class='line'><span class="s1">&#39;use strict&#39;</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">(</span><span class="k">new</span> <span class="nb">Function</span><span class="p">(</span><span class="s1">&#39;return this;&#39;</span><span class="p">))();</span>
</span></code></pre></td></tr></table></div></figure>
<p>An example test in test/unit/global/index.js looked like this:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">test</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;tape&#39;</span><span class="p">);</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">global</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;../../../lib/global&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">test</span><span class="p">(</span><span class="s1">&#39;Exports window&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">t</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">t</span><span class="p">.</span><span class="nx">equal</span><span class="p">(</span><span class="nx">global</span><span class="p">,</span> <span class="nb">window</span><span class="p">);</span>
</span><span class='line'> <span class="nx">t</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<h2>Testing CommonJS Modules in the Browser</h2>
<p>The applications that consume these UI modules use Webpack, so we author the modules (and their tests) as CommonJS modules. Of course, browsers can&#8217;t consume CommonJS directly, so we need to generate files that browsers <em>can</em> consume. There are several tools we can choose for this task, but since we&#8217;ve otherwise standardized on Webpack, we wanted to use Webpack here as well.</p>
<p>Since our goal is to load the tests in the browser, we use the test file as the &#8220;entry&#8221; file. Webpack processes the dependencies of an entry file to generate a new file that contains the entry file&#8217;s contents as well as the contents of its dependencies. This new file is the one that Karma will load into the browser to run the tests.</p>
<p>Getting this to happen is pretty straightforward with the <code>karma-webpack</code> plugin to Karma. The only catch was the need to tell Webpack how to deal with the <code>fs</code> dependency in tape. Here&#8217;s the initial Karma configuration that got the tests running:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">webpack</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;webpack&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">config</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">config</span><span class="p">.</span><span class="nx">set</span><span class="p">({</span>
</span><span class='line'> <span class="nx">plugins</span><span class="o">:</span> <span class="p">[</span>
</span><span class='line'> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;karma-webpack&#39;</span><span class="p">),</span>
</span><span class='line'> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;karma-tap&#39;</span><span class="p">),</span>
</span><span class='line'> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;karma-chrome-launcher&#39;</span><span class="p">),</span>
</span><span class='line'> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;karma-phantomjs-launcher&#39;</span><span class="p">)</span>
</span><span class='line'> <span class="p">],</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">basePath</span><span class="o">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">frameworks</span><span class="o">:</span> <span class="p">[</span> <span class="s1">&#39;tap&#39;</span> <span class="p">],</span>
</span><span class='line'> <span class="nx">files</span><span class="o">:</span> <span class="p">[</span> <span class="s1">&#39;test/**/*.js&#39;</span> <span class="p">],</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">preprocessors</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="s1">&#39;test/**/*.js&#39;</span><span class="o">:</span> <span class="p">[</span> <span class="s1">&#39;webpack&#39;</span> <span class="p">]</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">webpack</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">node</span> <span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">fs</span><span class="o">:</span> <span class="s1">&#39;empty&#39;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">webpackMiddleware</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">noInfo</span><span class="o">:</span> <span class="kc">true</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">reporters</span><span class="o">:</span> <span class="p">[</span> <span class="s1">&#39;dots&#39;</span> <span class="p">],</span>
</span><span class='line'> <span class="nx">port</span><span class="o">:</span> <span class="mi">9876</span><span class="p">,</span>
</span><span class='line'> <span class="nx">colors</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span><span class='line'> <span class="nx">logLevel</span><span class="o">:</span> <span class="nx">config</span><span class="p">.</span><span class="nx">LOG_INFO</span><span class="p">,</span>
</span><span class='line'> <span class="nx">autoWatch</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span><span class='line'> <span class="nx">browsers</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;Chrome&#39;</span><span class="p">],</span>
</span><span class='line'> <span class="nx">singleRun</span><span class="o">:</span> <span class="kc">false</span>
</span><span class='line'> <span class="p">})</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>
<p>However, as I mentioned above, I wanted to get code coverage information. Karma offers the <a href="https://github.com/karma-runner/karma-coverage">karma-coverage</a> plugin, but that alone was insufficient in Webpack land: it would end up instrumenting the whole Webpack output &#8211; including the test code itself! &#8211; and thus reporting highly inaccurate coverage numbers.</p>
<p>I ended up reading a <a href="https://github.com/webpack/karma-webpack/issues/21">karma-webpack issue</a> that told me someone else had already solved this exact problem by creating a <a href="https://github.com/deepsweet/istanbul-instrumenter-loader">Webpack loader</a> to instrument modules at build time. By adjusting our Webpack configuration to only apply this loader to application modules &#8211; not to test code or vendor code &#8211; the Webpack output ends up properly instrumented for the karma-coverage plugin to work with it. Our final Karma config ends up looking like this:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">webpack</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;webpack&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">config</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">config</span><span class="p">.</span><span class="nx">set</span><span class="p">({</span>
</span><span class='line'> <span class="nx">plugins</span><span class="o">:</span> <span class="p">[</span>
</span><span class='line'> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;karma-webpack&#39;</span><span class="p">),</span>
</span><span class='line'> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;karma-tap&#39;</span><span class="p">),</span>
</span><span class='line'> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;karma-chrome-launcher&#39;</span><span class="p">),</span>
</span><span class='line'> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;karma-phantomjs-launcher&#39;</span><span class="p">),</span>
</span><span class='line'> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;karma-coverage&#39;</span><span class="p">)</span>
</span><span class='line'> <span class="p">],</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">basePath</span><span class="o">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">frameworks</span><span class="o">:</span> <span class="p">[</span> <span class="s1">&#39;tap&#39;</span> <span class="p">],</span>
</span><span class='line'> <span class="nx">files</span><span class="o">:</span> <span class="p">[</span> <span class="s1">&#39;test/**/*.js&#39;</span> <span class="p">],</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">preprocessors</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="s1">&#39;test/**/*.js&#39;</span><span class="o">:</span> <span class="p">[</span> <span class="s1">&#39;webpack&#39;</span> <span class="p">]</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">webpack</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">node</span> <span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">fs</span><span class="o">:</span> <span class="s1">&#39;empty&#39;</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// Instrument code that isn&#39;t test or vendor code.</span>
</span><span class='line'> <span class="nx">module</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">postLoaders</span><span class="o">:</span> <span class="p">[{</span>
</span><span class='line'> <span class="nx">test</span><span class="o">:</span> <span class="sr">/\.js$/</span><span class="p">,</span>
</span><span class='line'> <span class="nx">exclude</span><span class="o">:</span> <span class="sr">/(test|node_modules)\//</span><span class="p">,</span>
</span><span class='line'> <span class="nx">loader</span><span class="o">:</span> <span class="s1">&#39;istanbul-instrumenter&#39;</span>
</span><span class='line'> <span class="p">}]</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">webpackMiddleware</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">noInfo</span><span class="o">:</span> <span class="kc">true</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">reporters</span><span class="o">:</span> <span class="p">[</span>
</span><span class='line'> <span class="s1">&#39;dots&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="s1">&#39;coverage&#39;</span>
</span><span class='line'> <span class="p">],</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">coverageReporter</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">type</span><span class="o">:</span> <span class="s1">&#39;text&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">dir</span><span class="o">:</span> <span class="s1">&#39;coverage/&#39;</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">port</span><span class="o">:</span> <span class="mi">9876</span><span class="p">,</span>
</span><span class='line'> <span class="nx">colors</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span><span class='line'> <span class="nx">logLevel</span><span class="o">:</span> <span class="nx">config</span><span class="p">.</span><span class="nx">LOG_INFO</span><span class="p">,</span>
</span><span class='line'> <span class="nx">autoWatch</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span><span class='line'> <span class="nx">browsers</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;Chrome&#39;</span><span class="p">],</span>
</span><span class='line'> <span class="nx">singleRun</span><span class="o">:</span> <span class="kc">false</span>
</span><span class='line'> <span class="p">})</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>
<p>Even with the coverage hiccup, the speed with which I was able to get Karma set up the way I wanted &#8211; and working with <a href="http://travis-ci.org/">TravisCI</a> &#8211; was nothing short of breathtaking. I&#8217;m late to the Karma party, but I had no idea it could be this easy. If you haven&#8217;t checked it out yet, you should.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[The TTL Podcast]]></title>
<link href="http://rmurphey.com/blog/2015/05/11/ttl-podcast/"/>
<updated>2015-05-11T21:12:00-05:00</updated>
<id>http://rmurphey.com/blog/2015/05/11/ttl-podcast</id>
<content type="html"><![CDATA[<p>Over the past several months, I&#8217;ve been on a <a href="https://www.youtube.com/watch?v=1BYeDhvxm4Q">few</a> <a href="https://developertea.com/episodes/9413">different</a> <a href="http://www.motherboardpodcast.com/episode-11-rebecca-murphey/">podcasts</a>, plus I&#8217;ve been having a lot of fun doing <a href="http://rmurphey.com/blog/2015/01/11/office-hours/">office hours</a>, and generally talking a lot with other people who do the kind of work that I do. I&#8217;ve particulary enjoyed talking about a subject that Alex Sexton dubbed <a href="http://www.smashingmagazine.com/2013/06/11/front-end-ops/">Front-End Ops</a>.</p>
<p>It has occurred to me that a) I&#8217;m really super fortunate to get to have conversations about this stuff with super-smart people; b) there aren&#8217;t yet a lot of great sources of information about front-end ops in the real world; and c) I used to be on a <a href="http://yayquery.com">podcast</a> and that sure was fun.</p>
<p>To that end, I threw a tweet out into the world to see who might be willing to talk to me and let me record the conversation. I got enough great responses that I decided to don my podcasting hat again for a little bit, and the result is the <a href="http://ttlpodcast.com">TTL Podcast</a>.</p>
<p><img src="http://rmurphey.com/images/ttl-podcast.png" alt="ttlpodcast.com" /></p>
<p>If you&#8217;re a mid-level front-end dev looking to level up, I&#8217;d humbly suggest that this is very much a show for you &#8211; you&#8217;ll get to listen in on the thought process of some of the best front-end devs I know. That said, it&#8217;s not just a show for those aspiring to take the front-end world by storm; it&#8217;s also a chance for those who are already in the trenches, doing daily battle with WebDriver and trying to shave 10 more milliseconds off page load, to commiserate asynchronously. I know I personally have learned a ton &#8211; in some cases I&#8217;ve seen a new angle on a problem, and in other cases I&#8217;ve had some serious Developer Guilt assuaged.</p>
<p>I&#8217;ve released three episodes so far &#8211; conversations with Alex, Burak Yiğit Kaya (Disqus), and Daniel Espeset and Seth Walker (Etsy). More episodes are in the pipeline, including developers from Walmart Labs, Yammer, FT Labs, and The Guardian.</p>
<p>While the initial focus has been on front-end ops, I can see the scope widening over time to cover, generally, the tools and challenges of doing front-end dev at significant scale. If you or someone you know would be a good person to talk to about that sort of thing, I hope you&#8217;ll <a href="mailto:rmurphey+ttlpodcast@gmail.com">let me know</a>.</p>
<p>While I&#8217;m here, I want to give huge and sincere thanks to <a href="https://saucelabs.com/">SauceLabs</a> and <a href="https://travis-ci.com/">Travis CI</a> for their support of the show; to <a href="http://una.github.io/">Una Kravets</a> for finding time in her busy life to make me a website; to my sister, who&#8217;s been kind enough to pitch in with the editing; and to <a href="http://bazaarvoice.com">Bazaarvoice</a> for giving me the freedom to take on a project like this.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[A Baseline for Front-End [JS] Developers: 2015]]></title>
<link href="http://rmurphey.com/blog/2015/03/23/a-baseline-for-front-end-developers-2015/"/>
<updated>2015-03-23T21:12:00-05:00</updated>
<id>http://rmurphey.com/blog/2015/03/23/a-baseline-for-front-end-developers-2015</id>
<content type="html"><![CDATA[<p>It&#8217;s been almost three years since I wrote <a href="http://rmurphey.com/blog/2012/04/12/a-baseline-for-front-end-developers/">A Baseline for Front-End Developers</a>, probably my most popular post ever. Three years later, I still get Twitter mentions from people who are discovering it for the first time.</p>
<p>In some ways, my words have aged well: there is, shockingly, nothing from that 2012 post that has me hanging my head in shame. Still, though: three years is a long time, and a whole lot has changed. In 2012 I encouraged people to learn browser dev tools and get on the module bandwagon; CSS pre-processors and client-side templating were still worthy of mention as new-ish things that people might not be sold on; and JSHint was a welcome relief from the #getoffmylawn admonitions &#8211; accurate though they may have been &#8211; of JSLint.</p>
<p>It&#8217;s 2015. I want to write an update, but as I sit down to do just that, I realize a couple of things. One, it&#8217;s arguably not fair to call this stuff a &#8220;baseline&#8221; &#8211; if you thought that about the original post, you&#8217;ll find it doubly true for this one. One could argue we should consider the good-enough-to-get-a-job skills to be the &#8220;baseline.&#8221; But there are a whole lot of front-end jobs to choose from, and getting one doesn&#8217;t establish much of a baseline. For me, I don&#8217;t want to get a job; I want to get invited to great jobs. I don&#8217;t want to go to work; I want to go to work with talented people. And I don&#8217;t want to be satisfied with knowing enough to do the work that needed to be done yesterday; I want to know how to do the work that will need to get done tomorrow.</p>
<p>Two, my world has become entirely JavaScript-centric: knowledge of the ins and outs of CSS has become less and less relevant to my day-to-day work, except where performance is concerned. I know there are plenty of very smart front-end developers for whom this isn&#8217;t true, but I have also noticed a growing gulf between those who focus on CSS and those who focus on JavaScript. That&#8217;s probably a subject for another blog post, but I bring it up just to say: I am woefully unequipped to make recommendations about what you should know about CSS these days, so I&#8217;m not going to try.</p>
<p>In short: if this list of things doesn&#8217;t fit your vision of the front-end world, that&#8217;s OK! We&#8217;re both still good people. Promise.</p>
<h2>JavaScript</h2>
<p>Remember back in 2009 when you read that HTML5 would be ready to use in 2014, and that seemed like a day that would never come? If so, you&#8217;re well prepared for the slow-but-steady emergence of ES6 (which is now called <a href="https://esdiscuss.org/topic/javascript-2015">ES2015</a>, a name that is sure to catch on any day now), the next version of JavaScript. Getting my bearings with ES6 &#8211; er, ES2015 &#8211; is hands-down my biggest JavaScript to-do item at the moment; it is going to be somewhere between game-changing and life-altering, what with classes, real privacy, better functions and arguments, <code>import</code>-able modules, and so much more. Those who are competent and productive with the new syntax will have no trouble standing out in the JS community. Required reading:</p>
<ul>
<li><a href="https://leanpub.com/understandinges6/read/">Understanding ES6</a>, a work-in-progress book being developed in the open by Nicholas Zakas.</li>
<li><a href="http://babeljs.io/">BabelJS</a>, a tool that lets you write ES6 today and &#8220;compile&#8221; it to ES5 that will run in current browsers. They also have a good <a href="http://babeljs.io/docs/learn-es6/">learning</a> section.</li>
<li><a href="http://es6rocks.com/">ES6 Rocks</a>, with various posts that explore ES6 features, semantics, and gotchas.</li>
</ul>
<p>Do you need to be an ES6/ES2015 expert? Probably not today, but you should know at least as much about it as your peers, and possibly more. It&#8217;s also worth at least entertaining the possibility of writing your next greenfield project using ES6; the future will be here before you know it.</p>
<p>New language features aside, you should be able to speak fluently about the asynchronicity of JavaScript, and using callbacks and promises to manage it. You should have well-formed opinions about strategies for loading applications in the browser and communicating between pieces of an application. You should maybe have a favorite application development framework, but not at the expense of having a general understanding of how other frameworks operate, and the tradeoffs you accept when you choose one.</p>
<h2>Modules &amp; Build Tools</h2>
<p>There&#8217;s no debate that modules should be the building blocks of client-side web applications. Back in 2012, there was lots of debate about what <em>kind</em> of modules we should use for building apps destined for the browser &#8211; <a href="https://github.com/amdjs/amdjs-api/blob/master/AMD.md">AMD</a> or <a href="http://webpack.github.io/docs/commonjs.html">CommonJS</a>. The somewhat-gross <a href="https://github.com/umdjs/umd">UMD</a> wrapper arose to try to avoid answering the question while still allowing code reuse &#8211; because hey, what&#8217;s a few more bytes between friends?</p>
<p>I don&#8217;t feel like this debate is anywhere near resolved, but this is the area where I feel like we&#8217;ve seen the largest transformation since my 2012 article, though perhaps that&#8217;s a reflection of my personal change of heart. I&#8217;m not ready to say that I&#8217;m done with AMD, but let&#8217;s just say I&#8217;m floored by how practical it has become to develop and deploy web applications using CommonJS, including modules imported with <code>npm</code>.</p>
<p>With much love for all that <a href="http://requirejs.org/">RequireJS</a> has contributed to the module conversation, I&#8217;m a bit enamored of <a href="http://webpack.github.io/">webpack</a> right now. Its features &#8211; such as easy-to-understand build flags &#8211; feel more accessible than RequireJS. Its hot-swap builds via its built-in dev server make for a fast and delightful development story. It doesn&#8217;t force an AMD vs. CommonJS decision, because it supports both. It also comes with a ton of loaders, making it fairly trivial to do lots of common tasks. <a href="http://browserify.org/">Browserify</a> is worth knowing about, but lags far behind Webpack in my opinion. Smart people I trust tell me that <a href="https://github.com/systemjs/systemjs">systemjs</a> is also a serious contender in this space, but I haven&#8217;t used it yet, and its docs leave me wanting. Its companion package manager <a href="http://jspm.io/">jspm</a> is intriguing, allowing you to pull in modules from multiple sources including npm, but I&#8217;m a bit wary of combining those two concerns. Then again, I never thought I&#8217;d break up with AMD, yet here I seem to be, so we&#8217;ll see.</p>
<p>I still long for a day when we stop having module and build tool debates, and there is a single module system and sharing code between arbitrary projects becomes realistic and trivial without the overhead of UMD. Ideally, the arrival of <a href="http://www.2ality.com/2014/09/es6-modules-final.html">ES6 modules</a> will bring that day &#8211; and transpilers will fill in the gaps as the day draws closer &#8211; but I find it just as likely that we&#8217;ll keep finding ways to make it complicated.</p>
<p>In the meantime, front-end developers need to have an opinion about at least a couple of build tools and the associated module system, and that opinion should be backed up by experience. For better or worse, JavaScript is still in a state where the module decision you make will inform the rest of your project.</p>
<h2>Testing</h2>
<p>Testing of client-side code has become more commonplace, and a few new testing frameworks have arrived on the scene, including <a href="http://karma-runner.github.io/0.12/index.html">Karma</a> and <a href="https://theintern.github.io/">Intern</a>. I find Intern&#8217;s promise-based approach to async testing to be particulary pleasing, though I confess that I still write most of my tests using <a href="http://mochajs.org/">Mocha</a> &#8211; sometimes I&#8217;m just a creature of habit.</p>
<p>The main blocker to testing is the code that front-end devs tend to write. I gave a talk toward the end of 2012 about <a href="https://www.youtube.com/watch?v=OzjogCFO4Zo">writing testable JavaScript</a>, and followed up with an <a href="http://alistapart.com/article/writing-testable-javascript">article</a> on the topic a few months later.</p>
<p>The second biggest blocker to testing remains the tooling. Webdriver is still a huge pain to work with. Continuous automated testing of a complex UI across all supported browsers continues to be either impossible, or so practically expensive that it might as well be impossible &#8211; and never mind mobile. We&#8217;re still largely stuck doing lightweight automated functional tests on a small subset of supported browser/device/OS combinations, and leaning as hard as we can on lower-level tests that can run quickly and inexpensively. This is a bummer.</p>
<p>If you&#8217;re interested in improving the problem of untested &#8211; or untestable &#8211; code, the single most valuable book you can read is <a href="http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052">Working Effectively with Legacy Code</a>. The author, Michael Feathers, defines &#8220;legacy code&#8221; as any code that does not have tests. On the topic of testing, the baseline is to accept the truth of that statement, even if other constraints are preventing you from addressing it.</p>
<h2>Process Automation</h2>
<p>You, hopefully, take for granted the existence of <a href="http://gruntjs.com/">Grunt</a> for task automation. <a href="http://gulpjs.com/">Gulp</a> and <a href="http://broccolijs.com/">Broccoli</a> provide a different approach to automating builds in particular. I haven&#8217;t used Broccoli, and I&#8217;ve only dabbled in Gulp, but I&#8217;ve definitely come to appreciate some of the limitations of Grunt when it comes to automating complex tasks that depend on other services &#8211; especially when that task needs to run thousands of times a day.</p>
<p>The arrival of <a href="http://yeoman.io/">Yeoman</a> was a mere 45 days away when I wrote my 2012 post. I confess I didn&#8217;t use it when it first came out, but recently I&#8217;ve been a) starting projects from scratch using unfamiliar tech; and b) trying to figure out how to standardize our approach to developing third-party JS apps at Bazaarvoice. Yeoman really shines in both of these cases. A simple <code>yo react-webpack</code> from the command line creates a whole new project for you, with all the bells and whistles you could possibly want &#8211; tests, a dev server, a hello world app, and more. If React and Webpack aren&#8217;t your thing, there&#8217;s probably a generator to meet your needs, and it&#8217;s also easy to create your own.</p>
<p>Given that Yeoman is a tool that you generally use only at the start of a project, and given that new projects don&#8217;t get started all the time, it&#8217;s mostly just something worth knowing about. Unless, of course, you&#8217;re also trying to standardize practices across projects &#8211; then it might be a bit more valuable.</p>
<p>Broccoli has gotten its biggest adoption as the basis for ember-cli, and folks I trust suggest that pairing may get a makeover &#8211; and a new name &#8211; to form the basis of a Grunt/Yeoman replacement in the future. Development on both Grunt and Yeoman has certainly slowed down, so it will be interesting to see what the future brings there.</p>
<h2>Code Quality</h2>
<p>If you, like me, start to twitch when you see code that violates a project&#8217;s well-documented style guide, then tools like <a href="http://jscs.info/">JSCS</a> and <a href="http://eslint.org/">ESLint</a> are godsends, and neither of them existed for you to know about them back in 2012. They both provide a means to document your style guide rules, and then verify your code against those rules automatically, before it ever makes it into a pull request. Which brings me to &hellip;</p>
<h2>Git</h2>
<p>I don&#8217;t think a whole lot has changed in the world of Git workflows since 2012, and I&#8217;d like to point out Github <em>still</em> hasn&#8217;t made branch names linkable on the pull request page, for f@#$s sake.</p>
<p>You should obviously be comfortable working with feature branches, rebasing your work on the work of others, squashing commits using interactive rebase, and doing work in small units that are unlikely to cause conflicts whenever possible. Another Git tool to add to your toolbox if you haven&#8217;t already is the ability to run hooks &#8211; specifically, pre-push and pre-commit hooks to run your tests and execute any code quality checks. You can write them yourself, but tools like <a href="https://www.npmjs.com/package/ghooks">ghooks</a> make it so trivial that there&#8217;s little excuse not to integrate them into your workflow.</p>
<h2>Client-Side Templating</h2>
<p>This may be the thing I got the most wrong in my original post, for some definition of &#8220;wrong.&#8221; Client-side templating is still highly valuable, of course &#8211; so valuable that it will be built-in to ES2015 &#8211; but there can be too much of a good thing. It&#8217;s been a hard-earned lesson for lots of teams that moving all rendering to the browser has high costs when it comes to performance, and thus has the &#8220;generate all the HTML client-side&#8221; approach rightfully fallen out of favor. Smart projects are now generating HTML server-side &#8211; maybe even pre-generating it, and storing it as static files that can be served quickly &#8211; and then &#8220;hydrating&#8221; that HTML client-side, updating it with client-side templates as events warrant.</p>
<p>The new expectation here &#8211; and I say this to myself as much as to anyone else &#8211; is that you are considering the performance implications of your decisions, and maybe not restricting yourself quite so thoroughly to the realm of the browser. Which, conveniently, leads to &hellip;</p>
<h2>Node</h2>
<p>You say you know JavaScript, so these days I expect that you can hop on over to the Node side of things and at least pitch in, if not get at least knee-deep. Yes, there are file systems and streams and servers &#8211; and some paradigms that are fundamentally different from front-end dev &#8211; but front-end developers who keep the back end at arm&#8217;s length are definitely limiting their potential.</p>
<p>Even if your actual production back-end doesn&#8217;t use Node, it&#8217;s an invaluable tool when it comes to keeping you from getting blocked by back-end development. At the very least, you should be familiar with how to <a href="https://docs.npmjs.com/cli/init">initialize a Node project</a>; how to set up an <a href="http://expressjs.com/">Express</a> server and routes; and how use the <a href="https://www.npmjs.com/package/request">request</a> module to proxy requests.</p>
<h2>The End</h2>
<p>Thanks to Paul, Alex, Adam, and Ralph for their thorough review of this post, and for generously pointing out places where I could do better. Thank them for the good parts, and blame any errors on me.</p>
<p>With that, good luck. See you again in another three years, perhaps.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Writing Conference Proposals]]></title>
<link href="http://rmurphey.com/blog/2015/01/26/writing-conference-proposals/"/>
<updated>2015-01-26T21:00:00-06:00</updated>
<id>http://rmurphey.com/blog/2015/01/26/writing-conference-proposals</id>
<content type="html"><![CDATA[<p>I&#8217;ve had several <a href="http://rmurphey.com/blog/2015/01/11/office-hours/">office hours</a> sessions in the last couple of weeks, and one topic that comes up again and again is how to write a talk description.</p>
<p>If you think about it, conference organizers don&#8217;t have a whole lot to go on when they&#8217;re choosing talks, unless they already know who you are. Even if your name is well-known, though, organizers may still not know who you are &#8211; lots of conferences are taking a <a href="http://weareallaweso.me/for_curators/">blind approach</a> to selecting speakers. That means that no matter who you are, your talk description might be the only thing organizers have on which to base their decision. When you give your talk, you&#8217;ll need to engage your audience; the abstract is your chance to engage the organizer.</p>
<p>After answering the question several times, I&#8217;ve realized that I have a pretty explainable &#8211; some might call it formulaic &#8211; approach to writing abstracts for a certain common type of talk. It works well for talks about how you solved a problem, talks about how you came to learn a thing you didn&#8217;t know, and even &#8220;10 things you didn&#8217;t know about X&#8221; talks. I thought I&#8217;d try to explain it here.</p>
<h2>Paragraph 1: The context</h2>
<p>The first paragraph is where you set the scene, and make it clear to your reader that they have been in the situation you&#8217;re going to talk about. This is where you establish a connection, baiting a hook that you&#8217;ll set later.</p>
<blockquote><p>You&#8217;ve got the hang of this whole JavaScript thing. Your code works on ancient browsers, and positively sings on new ones. AMD, SPA, MVC &#8211; you can do that stuff in your sleep.</p></blockquote>
<h2>Paragraph 2: Well, actually &#8230;</h2>
<p>The second paragraph is where you break the bad news, which savvy readers may already know: the thing you laid out in the first paragraph is more complicated than it seems, or has downsides that people don&#8217;t realize, or generally is a bad approach &#8230; but only with the benefit of hindsight, which you just happen to have.</p>
<blockquote><p>But now your users are trying to type in your Very Important Form, and nothing is showing up; that widget that&#8217;s supposed to end up in a certain div is showing up somewhere completely different; and, rarely but not never, your app just doesn&#8217;t load at all. You <em>thought</em> you had the hang of this whole JavaScript thing, but now you&#8217;re in the world of third-party JavaScript, where all you control is a single script tag and where it&#8217;s all but impossible to dream up every hostile environment in which your code will be expected to work. &#8220;It works on my machine&#8221; has never rung quite so hollow.</p></blockquote>
<h2>Paragraph 3: The promise</h2>
<p>You&#8217;ve successfully induced a bit of anxiety in your reader &#8211; and a strong desire to know what they don&#8217;t know. The hook is set, so the last paragraph is the time to promise to relieve that anxiety &#8211; but only if your talk is chosen!</p>
<blockquote><p>In this talk, we&#8217;ll take a look at some of the delightful bugs we&#8217;ve had to solve at Bazaarvoice while working on the third-party JavaScript app that collects and displays ratings and reviews for some of the world&#8217;s largest retailers. We&#8217;ll also look at some strategies for early detection &#8211; and at some scenarios where you are just plain SOL.</p></blockquote>
<h2>Next</h2>
<p>It turns out that in the process of writing your abstract, you&#8217;ve also written the most basic outline for your talk: on stage, you&#8217;ll want to set the context, explain the complexity, then deliver on your promise. Pretty handy, if you ask me.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Office Hours for Aspiring Speakers]]></title>
<link href="http://rmurphey.com/blog/2015/01/11/office-hours/"/>
<updated>2015-01-11T21:00:00-06:00</updated>
<id>http://rmurphey.com/blog/2015/01/11/office-hours</id>
<content type="html"><![CDATA[<p><em>Update: Office hours are <a href="http://rmurphey.com/blog/2015/08/04/pausing-office-hours/">on hold</a> for now while I settle into a new role at Bazaarvoice.</em></p>
<p>I&#8217;m expecting that my 2015 is going to include a bit less speaking than in years past, so I&#8217;m hoping I can use some of that newly available time to help new speakers find their way to the stage. To that end, I&#8217;m kicking off &#8220;office hours&#8221; this week: a few slots a week where aspiring and up-and-coming speakers can borrow my ear for a bit to talk about their ideas, their fears, their questions, and their ambitions.</p>
<p>This idea isn&#8217;t mine; I was inspired by a similar effort by <a href="http://jenmyers.net/mentoring/">Jen Myers</a>, who has been offering mentoring sessions to aspiring speakers since 2013. I&#8217;m forever indebted to the folks who helped me get through my first talk, and I&#8217;ve been honored to give a gentle nudge to several other speakers in the years since.</p>
<p>If you&#8217;re interested, you can <a href="http://calendly.com/rmurphey/office-hours">sign up here</a>. There&#8217;s no script or agenda, and &#8211; at least to start with &#8211; I&#8217;m not going to try to suggest who should or shouldn&#8217;t sign up. If you think it would be useful to you, go for it! My only ask is that you be seriously interested in giving coherent, informative, engaging talks on technical topics.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Writing Unit Tests for Existing JavaScript]]></title>
<link href="http://rmurphey.com/blog/2014/07/13/unit-tests/"/>
<updated>2014-07-13T21:21:00-05:00</updated>
<id>http://rmurphey.com/blog/2014/07/13/unit-tests</id>
<content type="html"><![CDATA[<p>My team at <a href="http://www.bazaarvoice.com/careers/">Bazaarvoice</a> has been spending a lot of time lately thinking about quality and how we can have greater confidence that our software is working as it should.</p>
<p>We&#8217;ve long had functional tests in place that attempt to ask questions like &#8220;When a user clicks a button, will The Widget do The Thing?&#8221; These tests tell us a fair amount about the state of our product, but we&#8217;ve found that they&#8217;re brittle &#8211; even after we abstracted away the CSS selectors that they rely on &#8211; and that they take approximately forever to run, especially if we want to run them in all of the browsers we support. The quality of the tests themselves is all over the map, too &#8211; some of them are in fact unit tests, not really testing anything <em>functional</em> at all.</p>
<p>A few months ago we welcomed a new QA lead to our team as part of our renewed focus on quality. Having a team member who is taking a thoughtful, systematic approach to quality is a game-changer &#8211; he&#8217;s not just making sure that new features work, but rather has scrutinized our entire approach to delivering quality software, to great effect.</p>
<p>One of the things he has repeatedly emphasized is the need to push our tests down the stack. Our functional tests should be black-box &#8211; writing them shouldn&#8217;t require detailed knowledge of how the software works under the hood. Our unit tests, on the other hand, should provide broad and detailed coverage of the actual code base. In an ideal world, functional tests can be few and slow-ish, because they serve as an infrequent smoke test of the application; unit tests should be thorough, but execute quickly enough that we run them all the time.</p>
<p>Until now, our unit tests have been entirely focused on utility and framework code &#8211; do we properly parse a URL, for example? &#8211; not on code that&#8217;s up close and personal with getting The Widget to do The Thing. I&#8217;d told myself that this was fine and right and good, but in reality I was pretty terrified of trying to bolt unit tests onto feature code of incredibly varying quality, months or even years after it was first written.</p>
<p>A week or so ago, thanks to some coaxing/chiding from fellow team members, I decided to bite the bullet and see just how bad it would be. A week later, I feel like I&#8217;ve taken the first ten steps in a marathon. Of course, taking those first steps involves making the decision to run, and doing enough training ahead of time that you don&#8217;t die, so in that regard I&#8217;ve come a long way already. Here&#8217;s what I&#8217;ve done and learned so far.</p>
<h3>Step 0</h3>
<p>I was lucky in that I wasn&#8217;t starting entirely from scratch, but if you don&#8217;t already have a unit testing framework in place, don&#8217;t fret &#8211; it&#8217;s pretty easy to set up. We use <a href="http://gruntjs.com/">Grunt</a> with <a href="http://visionmedia.github.io/mocha/">Mocha</a> as our test framework and <a href="https://github.com/LearnBoost/expect.js/">expect.js</a> as our assertion library, but if I were starting over today I&#8217;d take a pretty serious look at <a href="http://theintern.io/">Intern</a>.</p>
<p>Our unit tests are organized into suites. Each suite consists of a number of files, each of which tests a single AMD module. Most of the modules under test when I started down this path were pretty isolated &#8211; they didn&#8217;t have a ton of dependencies generally, and had very few runtime dependencies. They didn&#8217;t interact with other modules that much. Almost all of the existing unit test files loaded a module, executed its methods, and inspected the return value. No big deal.</p>
<p>Feature-related code &#8211; especially already-written feature-related code &#8211; is a different story. Views have templates. Models expect data. Models pass information to views, and views pass information to models. Some models need parents; others expect children. And pretty much everything depended on a global-ish message broker to pass information around.</p>
<p>Since the code was originally written without tests, we are guaranteed that it would be in various states of testability, but a broad rewrite for testability is of course off the table. We&#8217;ll rewrite targeted pieces, but doing so comes with great risk. For the most part, our goal will be to write tests for what we have, then refactor cautiously once tests are in place.</p>
<p>We decided that the first place to start was with models, so I found the simplest model I could:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">define</span><span class="p">([</span>
</span><span class='line'> <span class="s1">&#39;framework/bmodel&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="s1">&#39;underscore&#39;</span>
</span><span class='line'><span class="p">],</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">BModel</span><span class="p">,</span> <span class="nx">_</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">BModel</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
</span><span class='line'> <span class="nx">options</span> <span class="o">:</span> <span class="p">{},</span>
</span><span class='line'> <span class="nx">name</span> <span class="o">:</span> <span class="s1">&#39;mediaViewer&#39;</span><span class="p">,</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">init</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">config</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">_</span><span class="p">.</span><span class="nx">extend</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">options</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<p>Why do we have a model that does approximately nothing? I&#8217;m not going to attempt to answer that, though there are Reasons &#8211; but for the sake of this discussion, it certainly provides an easy place to start.</p>
<p>I created a new suite for model tests, and added a file to the suite to test the model. I could tell you that I naively plowed ahead thinking that I could just load the module and write some assertions, but that would be a lie.</p>
<h3>Mocking: Squire.js</h3>
<p>I knew from writing other tests, on this project and projects in the past, that I was going to need to &#8220;mock&#8221; some of my dependencies. For example, we have a module called <code>ENV</code> that is used for &#8230; well, way too much, though it&#8217;s better than it used to be. A large portion of <code>ENV</code> isn&#8217;t used by any given module, but <code>ENV</code> itself is required by essentially every model and view.</p>
<p><a href="https://github.com/iammerrick/Squire.js/">Squire.js</a> is a really fantastic library for doing mocking in RequireJS-land. It lets you override how a certain dependency will be fulfilled; so, when a module under test asks for <code>'ENV'</code>, you can use Squire to say &#8220;use this object that I&#8217;ve hand-crafted for this specific test instead.&#8221;</p>
<p>I created an Injector module that does the work of loading Squire, plus mocking a couple of things that will be missing when the tests are executed in Node-land.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">define</span><span class="p">([</span>
</span><span class='line'> <span class="s1">&#39;squire&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="s1">&#39;jquery&#39;</span>
</span><span class='line'><span class="p">],</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">Squire</span><span class="p">,</span> <span class="nx">$</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">injector</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nb">window</span> <span class="o">===</span> <span class="s1">&#39;undefined&#39;</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">injector</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Squire</span><span class="p">(</span><span class="s1">&#39;_BV&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">injector</span><span class="p">.</span><span class="nx">mock</span><span class="p">(</span><span class="s1">&#39;jquery&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">$</span><span class="p">;</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">injector</span><span class="p">.</span><span class="nx">mock</span><span class="p">(</span><span class="s1">&#39;window&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="p">{};</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">injector</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Squire</span><span class="p">();</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">return</span> <span class="nx">injector</span><span class="p">;</span>
</span><span class='line'> <span class="p">};</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<p>Next, I wired up the test to see how far I could get without mocking anything. Note that the main module doesn&#8217;t actually load the thing we&#8217;re going to test &#8211; first, it sets up the mocks by calling the <code>injector</code> function, and then it uses the created injector to require the module we want to test. Just like a normal <code>require</code>, the <code>injector.require</code> is async, so we have to let our test framework know to wait until it&#8217;s loaded before proceeding with our assertions.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">define</span><span class="p">([</span>
</span><span class='line'> <span class="s1">&#39;test/unit/injector&#39;</span>
</span><span class='line'><span class="p">],</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">injector</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">injector</span> <span class="o">=</span> <span class="nx">injector</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'> <span class="kd">var</span> <span class="nx">MediaViewer</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">describe</span><span class="p">(</span><span class="s1">&#39;MediaViewer Model&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">before</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">done</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">injector</span><span class="p">.</span><span class="nx">require</span><span class="p">([</span>
</span><span class='line'> <span class="s1">&#39;bv/c2013/model/mediaViewer&#39;</span>
</span><span class='line'> <span class="p">],</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">M</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">MediaViewer</span> <span class="o">=</span> <span class="nx">M</span><span class="p">;</span>
</span><span class='line'> <span class="nx">done</span><span class="p">();</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">it</span><span class="p">(</span><span class="s1">&#39;should be named&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">m</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">MediaViewer</span><span class="p">({});</span>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">m</span><span class="p">.</span><span class="nx">name</span><span class="p">).</span><span class="nx">to</span><span class="p">.</span><span class="nx">equal</span><span class="p">(</span><span class="s1">&#39;mediaViewer&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">it</span><span class="p">(</span><span class="s1">&#39;should mix in provided options&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">m</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">MediaViewer</span><span class="p">({},</span> <span class="p">{</span> <span class="nx">foo</span> <span class="o">:</span> <span class="s1">&#39;bar&#39;</span> <span class="p">});</span>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">m</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nx">foo</span><span class="p">).</span><span class="nx">to</span><span class="p">.</span><span class="nx">equal</span><span class="p">(</span><span class="s1">&#39;bar&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<p>This, of course, still failed pretty spectacularly. In real life, a model gets instantiated with a component, and a model also expects to have access to an <code>ENV</code> that has knowledge of the component. Creating a &#8220;real&#8221; component and letting the &#8220;real&#8221; <code>ENV</code> know about it would be an exercise in <a href="https://www.youtube.com/watch?v=7s664NsLeFM">inventing the universe</a>, and this is exactly what mocks are for.</p>
<p>While the &#8220;real&#8221; <code>ENV</code> is a Backbone model that is instantiated using customer-specific configuration data, a much simpler <code>ENV</code> suffices for the sake of testing a model&#8217;s functionality:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">define</span><span class="p">([</span>
</span><span class='line'> <span class="s1">&#39;backbone&#39;</span>
</span><span class='line'><span class="p">],</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">Backbone</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">injector</span><span class="p">,</span> <span class="nx">opts</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">injector</span><span class="p">.</span><span class="nx">mock</span><span class="p">(</span><span class="s1">&#39;ENV&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">ENV</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Backbone</span><span class="p">.</span><span class="nx">Model</span><span class="p">({</span>
</span><span class='line'> <span class="nx">componentManager</span> <span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">find</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">component</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'>
</span><span class='line'> <span class="k">return</span> <span class="nx">ENV</span><span class="p">;</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'>
</span><span class='line'> <span class="k">return</span> <span class="nx">injector</span><span class="p">;</span>
</span><span class='line'> <span class="p">};</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<p>Likewise, a &#8220;real&#8221; component is complicated and difficult to create, but the pieces of a component that this model needs to function are limited. Here&#8217;s what the component mock ended up looking like:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">define</span><span class="p">([</span>
</span><span class='line'> <span class="s1">&#39;underscore&#39;</span>
</span><span class='line'><span class="p">],</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">_</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">settings</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">settings</span> <span class="o">=</span> <span class="nx">settings</span> <span class="o">||</span> <span class="p">{};</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">settings</span><span class="p">.</span><span class="nx">features</span> <span class="o">=</span> <span class="nx">settings</span><span class="p">.</span><span class="nx">features</span> <span class="o">||</span> <span class="p">[];</span>
</span><span class='line'>
</span><span class='line'> <span class="k">return</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">trigger</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{},</span>
</span><span class='line'> <span class="nx">hasFeature</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">refName</span><span class="p">,</span> <span class="nx">featureName</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">_</span><span class="p">.</span><span class="nx">contains</span><span class="p">(</span><span class="nx">settings</span><span class="p">.</span><span class="nx">features</span><span class="p">,</span> <span class="nx">featureName</span><span class="p">);</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'> <span class="nx">getScope</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="s1">&#39;scope&#39;</span><span class="p">;</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'> <span class="nx">contentType</span> <span class="o">:</span> <span class="nx">settings</span><span class="p">.</span><span class="nx">contentType</span><span class="p">,</span>
</span><span class='line'> <span class="nx">componentId</span> <span class="o">:</span> <span class="nx">settings</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span>
</span><span class='line'> <span class="nx">views</span> <span class="o">:</span> <span class="p">{}</span>
</span><span class='line'> <span class="p">};</span>
</span><span class='line'> <span class="p">};</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<p>In the case of both mocks, we&#8217;ve taken some dramatic shortcuts: the real <code>hasFeature</code> method of a component is a lot more complicated, but in the component mock we create a <code>hasFeature</code> method whose return value can be easily known by the test that uses the mock. Likewise, the behavior of the <code>componentManager</code>&#8217;s <code>find</code> method is complex in real life, but in our mock, the method just returns the same thing all the time. Our mocks are designed to be configurable by &#8211; and predictable for &#8211; the test that uses it.</p>
<p>Knowing what to mock and when and how is a learned skill. It&#8217;s entirely possible to mock something in such a way that a unit test passes but the actual functionality is broken. We actually have pretty decent tests around our real component code, but not so much around our real <code>ENV</code> code. We should probably fix that, and then I can feel better about mocking <code>ENV</code> as needed.</p>
<p>So far, my approach has been: try to make a test pass without mocking anything, and then mock as little as possible after that. I&#8217;ve also made a point of trying to centralize our mocks in a single place, so we aren&#8217;t reinventing the wheel for every test.</p>
<p>Finally: when I first set up the injector module, I accidentally made it so that the same injector would be shared by any test that included the module. This is bad, because you end up sharing mocks across tests &#8211; violating the &#8220;only mock what you must&#8221; rule. The injector module shown above is correct in that it returns a function that can be used to create a new injector, rather than the injector itself.</p>
<p>Here&#8217;s what the final MediaViewer test ended up looking like:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">define</span><span class="p">([</span>
</span><span class='line'> <span class="c1">// This properly sets up Squire and mocks window and jQuery</span>
</span><span class='line'> <span class="c1">// if necessary (for running tests from the command line).</span>
</span><span class='line'> <span class="s1">&#39;test/unit/injector&#39;</span><span class="p">,</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// This is a function that mocks the ENV module.</span>
</span><span class='line'> <span class="s1">&#39;test/unit/mocks/ENV&#39;</span><span class="p">,</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// This is a function that mocks a component.</span>
</span><span class='line'> <span class="s1">&#39;test/unit/mocks/component&#39;</span>
</span><span class='line'><span class="p">],</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">injector</span><span class="p">,</span> <span class="nx">ENVMock</span><span class="p">,</span> <span class="nx">component</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">injector</span> <span class="o">=</span> <span class="nx">injector</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// This will become the constructor for the model under test.</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">MediaViewer</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// Create an object that can serve as a model&#39;s component.</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">c</span> <span class="o">=</span> <span class="nx">component</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// We also need to mock the ENV module and make it aware of</span>
</span><span class='line'> <span class="c1">// the fake component we just created.</span>
</span><span class='line'> <span class="nx">ENVMock</span><span class="p">(</span><span class="nx">injector</span><span class="p">,</span> <span class="p">{</span> <span class="nx">component</span> <span class="o">:</span> <span class="nx">c</span> <span class="p">});</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">describe</span><span class="p">(</span><span class="s1">&#39;MediaViewer Model&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">before</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">done</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">injector</span><span class="p">.</span><span class="nx">require</span><span class="p">([</span>
</span><span class='line'> <span class="s1">&#39;bv/c2013/model/mediaViewer&#39;</span>
</span><span class='line'> <span class="p">],</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">M</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">MediaViewer</span> <span class="o">=</span> <span class="nx">M</span><span class="p">;</span>
</span><span class='line'> <span class="nx">done</span><span class="p">();</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">it</span><span class="p">(</span><span class="s1">&#39;should be named&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">m</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">MediaViewer</span><span class="p">({</span>
</span><span class='line'> <span class="nx">component</span> <span class="o">:</span> <span class="nx">c</span>
</span><span class='line'> <span class="p">},</span> <span class="p">{});</span>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">m</span><span class="p">.</span><span class="nx">name</span><span class="p">).</span><span class="nx">to</span><span class="p">.</span><span class="nx">equal</span><span class="p">(</span><span class="s1">&#39;mediaViewer&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">it</span><span class="p">(</span><span class="s1">&#39;should mix in provided options&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">m</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">MediaViewer</span><span class="p">({</span>
</span><span class='line'> <span class="nx">component</span> <span class="o">:</span> <span class="nx">c</span>
</span><span class='line'> <span class="p">},</span> <span class="p">{</span> <span class="nx">foo</span> <span class="o">:</span> <span class="s1">&#39;bar&#39;</span> <span class="p">});</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">m</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nx">foo</span><span class="p">).</span><span class="nx">to</span><span class="p">.</span><span class="nx">equal</span><span class="p">(</span><span class="s1">&#39;bar&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<h3>Spying: Sinon</h3>
<p>After my stunning success with writing 49 lines of test code to test a 13-line model, I was feeling optimistic about testing views, too. I decided to tackle this fairly simple view first:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">define</span><span class="p">([</span>
</span><span class='line'> <span class="s1">&#39;framework/bview&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="s1">&#39;underscore&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="s1">&#39;hbs!contentAuthorProfileInline&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="s1">&#39;mf!bv/c2013/messages/avatar&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="s1">&#39;bv/util/productInfo&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="s1">&#39;framework/util/bvtracker&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="s1">&#39;util/specialKeys&#39;</span>
</span><span class='line'><span class="p">],</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">BView</span><span class="p">,</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">template</span><span class="p">,</span> <span class="nx">msgPack</span><span class="p">,</span> <span class="nx">ProductInfo</span><span class="p">,</span> <span class="nx">BVTracker</span><span class="p">,</span> <span class="nx">specialKeys</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">BView</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
</span><span class='line'> <span class="nx">name</span> <span class="o">:</span> <span class="s1">&#39;inlineProfile&#39;</span><span class="p">,</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">templateName</span> <span class="o">:</span> <span class="s1">&#39;contentAuthorProfileInline&#39;</span><span class="p">,</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">events</span> <span class="o">:</span> <span class="p">{</span>
</span><span class='line'> <span class="s1">&#39;click .bv-content-author-name .bv-fullprofile-popup-target&#39;</span> <span class="o">:</span> <span class="s1">&#39;launchProfile&#39;</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">template</span> <span class="o">:</span> <span class="nx">template</span><span class="p">,</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">msgpacks</span> <span class="o">:</span> <span class="p">[</span><span class="nx">msgPack</span><span class="p">],</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">launchProfile</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="c1">// use r&amp;r component outlet to trigger full profile popup component event</span>
</span><span class='line'> <span class="k">this</span><span class="p">.</span><span class="nx">getTopModel</span><span class="p">().</span><span class="nx">trigger</span><span class="p">(</span> <span class="s1">&#39;showfullprofile&#39;</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">model</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;Author&#39;</span><span class="p">)</span> <span class="p">);</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">BVTracker</span><span class="p">.</span><span class="nx">feature</span><span class="p">({</span>
</span><span class='line'> <span class="nx">type</span> <span class="o">:</span> <span class="s1">&#39;Used&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">name</span> <span class="o">:</span> <span class="s1">&#39;Click&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">detail1</span> <span class="o">:</span> <span class="s1">&#39;ViewProfileButton&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">detail2</span> <span class="o">:</span> <span class="s1">&#39;AuthorAvatar&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">bvProduct</span> <span class="o">:</span> <span class="nx">ProductInfo</span><span class="p">.</span><span class="nx">getType</span><span class="p">(</span><span class="k">this</span><span class="p">),</span>
</span><span class='line'> <span class="nx">productId</span> <span class="o">:</span> <span class="nx">ProductInfo</span><span class="p">.</span><span class="nx">getId</span><span class="p">(</span><span class="k">this</span><span class="p">)</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<p>It turned out that I needed to do the same basic mocking for this as I did for the model, but this code presented a couple of interesting things to consider.</p>
<p>First, I wanted to test that <code>this.getTopModel().trigger(...)</code> triggered the proper event, but the <code>getTopModel</code> method was implemented in <code>BView</code>, not the code under test, and without a whole lot of gymnastics, it wasn&#8217;t going to return an object with a <code>trigger</code> method.</p>
<p>Second, I wanted to know that <code>BVTracker.feature</code> was getting called with the right values, so I needed a way to inspect the object that got passed to it, but without doing something terrible like exposing it globally.</p>
<p>Enter <a href="http://sinonjs.org">Sinon</a> and its <a href="http://sinonjs.org/docs/#spies">spies</a>. Spies let you observe methods as they are called. You can either let the method still do its thing while watching how it is called, or simply replace the method with a spy.</p>
<p>I solved the first problem by defining my own <code>getTopModel</code> method on the model instance, and having it return an object. I gave that object a <code>trigger</code> method that was actually just a spy &#8211; for the sake of my test, I didn&#8217;t care what trigger <em>did</em>, only how it was called. Other tests [will eventually] ensure that triggering this event has the desired effect on the targeted model, but for the sake of this test, we don&#8217;t care.</p>
<p>Here&#8217;s what the test looks like:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">describe</span><span class="p">(</span><span class="s1">&#39;#launchProfile&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">spy</span><span class="p">;</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">v</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">before</span><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">spy</span> <span class="o">=</span> <span class="nx">sinon</span><span class="p">.</span><span class="nx">spy</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">v</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">InlineProfile</span><span class="p">({</span>
</span><span class='line'> <span class="c1">// model and component are defined elsewhere</span>
</span><span class='line'> <span class="nx">component</span> <span class="o">:</span> <span class="nx">component</span><span class="p">,</span>
</span><span class='line'> <span class="nx">model</span> <span class="o">:</span> <span class="nx">model</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">model</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;Author&#39;</span><span class="p">,</span> <span class="s1">&#39;author&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">v</span><span class="p">.</span><span class="nx">getTopModel</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">trigger</span> <span class="o">:</span> <span class="nx">spy</span>
</span><span class='line'> <span class="p">};</span>
</span><span class='line'> <span class="p">};</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">it</span><span class="p">(</span><span class="s1">&#39;should trigger showfullprofile event on top model&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">v</span><span class="p">.</span><span class="nx">launchProfile</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">spy</span><span class="p">.</span><span class="nx">lastCall</span><span class="p">.</span><span class="nx">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]).</span><span class="nx">to</span><span class="p">.</span><span class="nx">equal</span><span class="p">(</span><span class="s1">&#39;showfullprofile&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">spy</span><span class="p">.</span><span class="nx">lastCall</span><span class="p">.</span><span class="nx">args</span><span class="p">[</span><span class="mi">1</span><span class="p">]).</span><span class="nx">to</span><span class="p">.</span><span class="nx">equal</span><span class="p">(</span><span class="s1">&#39;author&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<p>I solved the second problem &#8211; the need to see what&#8217;s getting passed to <code>BVTracker.feature</code> &#8211; by creating a <code>BVTracker</code> mock where every method is just a spy:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="c1">// This is a mock for BVTracker that can be used by unit tests.</span>
</span><span class='line'><span class="nx">define</span><span class="p">([</span>
</span><span class='line'> <span class="s1">&#39;underscore&#39;</span>
</span><span class='line'><span class="p">],</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">_</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">injector</span><span class="p">,</span> <span class="nx">opts</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">BVTracker</span> <span class="o">=</span> <span class="p">{};</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">injector</span><span class="p">.</span><span class="nx">mock</span><span class="p">(</span><span class="s1">&#39;framework/util/bvtracker&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">_</span><span class="p">([</span>
</span><span class='line'> <span class="s1">&#39;error&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="s1">&#39;pageview&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="s1">&#39;feature&#39;</span>
</span><span class='line'> <span class="p">]).</span><span class="nx">each</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">BVTracker</span><span class="p">[</span><span class="nx">event</span><span class="p">]</span> <span class="o">=</span> <span class="nx">sinon</span><span class="p">.</span><span class="nx">spy</span><span class="p">();</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'>
</span><span class='line'> <span class="k">return</span> <span class="nx">BVTracker</span><span class="p">;</span>
</span><span class='line'> <span class="p">};</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<p>My test looked at the <code>BVTracker.feature</code> spy to see what it got when the view&#8217;s <code>launchProfile</code> method was called:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">it</span><span class="p">(</span><span class="s1">&#39;should send a feature analytics event&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">v</span><span class="p">.</span><span class="nx">launchProfile</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'> <span class="kd">var</span> <span class="nx">evt</span> <span class="o">=</span> <span class="nx">BVTracker</span><span class="p">.</span><span class="nx">feature</span><span class="p">.</span><span class="nx">lastCall</span><span class="p">.</span><span class="nx">args</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">evt</span><span class="p">.</span><span class="nx">type</span><span class="p">).</span><span class="nx">to</span><span class="p">.</span><span class="nx">equal</span><span class="p">(</span><span class="s1">&#39;Used&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">evt</span><span class="p">.</span><span class="nx">name</span><span class="p">).</span><span class="nx">to</span><span class="p">.</span><span class="nx">equal</span><span class="p">(</span><span class="s1">&#39;Click&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">evt</span><span class="p">.</span><span class="nx">detail1</span><span class="p">).</span><span class="nx">to</span><span class="p">.</span><span class="nx">equal</span><span class="p">(</span><span class="s1">&#39;ViewProfileButton&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">evt</span><span class="p">.</span><span class="nx">detail2</span><span class="p">).</span><span class="nx">to</span><span class="p">.</span><span class="nx">equal</span><span class="p">(</span><span class="s1">&#39;AuthorAvatar&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">evt</span><span class="p">.</span><span class="nx">bvProduct</span><span class="p">).</span><span class="nx">to</span><span class="p">.</span><span class="nx">equal</span><span class="p">(</span><span class="s1">&#39;RatingsAndReviews&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">evt</span><span class="p">.</span><span class="nx">productId</span><span class="p">).</span><span class="nx">to</span><span class="p">.</span><span class="nx">equal</span><span class="p">(</span><span class="s1">&#39;product1&#39;</span><span class="p">);</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<p>I&#8217;ve barely touched on what you can do with spies, or with Sinon in general. Besides providing simple spy functionality, Sinon delivers a host of functionality that makes tests easier to write &#8211; swaths of which I haven&#8217;t even begun to explore. One part I have explored is its ability to create fake XHRs and to fake whole servers, allowing you to test how your code behaves when things go wrong on the server. Do yourself a favor and spend some time reading through the excellent <a href="http://sinonjs.org/docs/">docs</a>.</p>
<h3>What to test &#8230; and not</h3>
<p>I&#8217;ve written tests now for a tiny handful of models and views. Setting up the mocks was a bit of a hurdle &#8211; and there were plenty of other hurdles that are too specific to our project for me to talk about them in detail &#8211; but overall, the hardest part has been figuring out what, exactly, to test. I crafted the examples above to be pretty straightforward, but reality is a lot more complicated.</p>
<p>Writing tests for existing code requires first understanding the code that&#8217;s being tested and identifying interesting moments in that code. If there&#8217;s an operation that affects the &#8220;public&#8221; experience of the module &#8211; for example, if the value of a model attribute changes &#8211; then we need to write a test that covers that operation&#8217;s side effect(s). If there&#8217;s code that runs conditionally, we need to test the behavior of that code when that condition is true &#8211; and when it&#8217;s not. If there are six possible conditions, we need to test them all. If a model behaves completely differently when it has a parent &#8211; and this happens far too often in our code &#8211; then we need to simulate the parent case, and simulate the standalone case.</p>
<p>It can be tempting to try to test the implementation details of existing code &#8211; and difficult to realize that you&#8217;re doing it even when you don&#8217;t mean to. I try to stay focused on testing how other code might consume and interact with the module I&#8217;m testing. For example, if the module I&#8217;m testing triggers an event in a certain situation, I&#8217;m going to write a test that proves it, because some other code is probably expecting that event to get triggered. However, I&#8217;m not going to test that a method of a certain name gets called in a certain case &#8211; that&#8217;s an implementation detail that might change.</p>
<p>The exercise of writing unit tests against existing code proves to be a phenomenal incentive to write better code in the future. One comes to develop a great appreciation of methods that have return values, not side effects. One comes to loathe the person &#8211; often one&#8217;s past self &#8211; who authored complex, nested conditional logic. One comes to worship small methods that do exactly one thing.</p>
<p>So far, I haven&#8217;t rewritten any of the code I&#8217;ve been testing, even when I&#8217;ve spotted obvious flaws, and even when rewriting would make the tests themselves easier to write. I don&#8217;t know how long I&#8217;ll be able to stick to this; there are some specific views and models that I know will be nearly impossible to test without revisiting their innards. When that becomes necessary, I&#8217;m hoping I can do it incrementally, testing as I go &#8211; and that our functional tests will give me the cover I need to know I haven&#8217;t gone horribly wrong.</p>
<h3>Spreading the love</h3>
<p>Our team&#8217;s next step is to widen the effort to get better unit test coverage of our code. We have something like 100 modules that need testing, and their size and complexity are all over the map. Over the coming weeks, we&#8217;ll start to divide and conquer.</p>
<p>One thing I&#8217;ve done to try to make the effort easier is to create a scaffolding task using Grunt. Running <code>grunt scaffold-test:model:modelName</code> will generate a basic file that includes mocking that&#8217;s guaranteed to be needed, as well as the basic instantiation that will be required and a couple of simple tests.</p>
<p>There&#8217;s another senior team member who has led an effort in the past to apply unit tests to an existing code base, and he&#8217;s already warned me to expect a bit of a bumpy road as the team struggles through the inevitable early challenges of trying to write unit tests for existing feature code. I expect there to be a pretty steep hill to climb at first, but at the very least, the work I&#8217;ve done so far has &#8211; hopefully &#8211; gotten us to the top of the vertical wall that had been standing in our way.</p>
<h3>Further Reading</h3>
<p>I&#8217;m not exactly the first person to write about this. You may find these items interesting:</p>
<ul>
<li><a href="http://stackoverflow.com/questions/3476054/can-unit-testing-be-successfully-added-into-an-existing-production-project-if-s">On adding unit tests to existing code</a></li>
<li><a href="http://programmers.stackexchange.com/questions/207401/writing-tests-for-existing-code">On whether it&#8217;s worth the effort</a></li>
<li><a href="http://www.amazon.com/gp/product/0131177052">Working Effectively with Legacy Code</a></li>
</ul>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Austin]]></title>
<link href="http://rmurphey.com/blog/2014/01/01/austin/"/>
<updated>2014-01-01T19:03:00-06:00</updated>
<id>http://rmurphey.com/blog/2014/01/01/austin</id>
<content type="html"><![CDATA[<p>In August 2002, it was a little more than a year since I&#8217;d left my job at my hometown newspaper. I had just sold my car and left my two jobs as a bartender. Between the tips in my pocket and the money I&#8217;d made from selling my car &#8211; a 1996 Neon with a probably cracked head gasket &#8211; I had about $2,000 to my name. I had a bicycle, camping gear, cooking gear, maps, a handheld GPS, a flip phone, two changes of bicycle clothing, and two changes of street clothes. I was in Camden, Maine, and my parents were taking my picture in front of a bicycle shop.</p>
<iframe src="https://www.flickr.com/photos/rdmey/3147066467/player/ed302f4534" height="213" width="320" frameborder="0" allowfullscreen webkitallowfullscreen mozallowfullscreen oallowfullscreen msallowfullscreen></iframe>
<p>My destination was Austin. My plan was to ride to Savannah, GA &#8211; via Boston, New York, and the eastern shore of Maryland &#8211; and then turn right. I didn&#8217;t really have much of a plan beyond that, except that I hoped to crash with a friend of a friend when I got to Austin. I heard they had a good bus system. I figured I could sort out a job before my money ran out.</p>
<p>Three weeks and 1,000 miles later, I found myself outside of New Bern, NC, more tan and more fit than I&#8217;d ever been or would ever be again. I stopped at a grocery store and picked up food for the evening, tying a bag of apples off the side of my bike. I was planning to camp just south of town, but as I neared a park in the center of town, I found myself surrounded by cyclists setting up camp. They were there for a fund-raising ride, and no, no one would mind if I camped in the park with them instead of riding another 10 miles.</p>
<p>I pitched my tent. I followed them to the free dinner being served for them across the street.</p>
<p>I rode 150 miles &#8211; unencumbered by camping gear and all the rest &#8211; in the fund-raising ride for the next two days.</p>
<p>I made new friends. They invited me to come stay with them for a few days in Chapel Hill.</p>
<p>I lived with them for a month. I borrowed their 1990 Ford Festiva for a year.</p>
<p>I got a job painting a house. I got a job waitressing. I got a job doing desktop publishing. I got a job making web sites.</p>
<p>I got good at JavaScript. I traveled the world talking about it.</p>
<p>I met a girl. We bought a house. We adopted a baby.</p>
<p>I never made it to Austin, though life has taken me there a few days at a time more times than I can count. Finally, in 2013, I even got a job there. Since February, I&#8217;ve made the trek enough times that it&#8217;s truly become a home away from home. I&#8217;ve stopped using my phone to find my way around. Waitresses recognize me. People tell me about the secret back way to work, but I already know it. I have opinions about breakfast tacos.</p>
<p>It&#8217;s time to finish the story I started more than a decade ago, which brings me to the point: With much love for Durham, and for the irreplaceable people who have made our lives so full here, we&#8217;re moving to Austin this spring. At last.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Refactoring setInterval-based polling]]></title>
<link href="http://rmurphey.com/blog/2013/02/04/refactoring-setInterval-polling/"/>
<updated>2013-02-04T15:30:00-06:00</updated>
<id>http://rmurphey.com/blog/2013/02/04/refactoring-setInterval-polling</id>
<content type="html"><![CDATA[<p>I came across some code that looked something like this the other day, give or take a few details.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">App</span><span class="p">.</span><span class="nx">Helpers</span><span class="p">.</span><span class="nx">checkSyncStatus</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="nx">App</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;syncCheck&#39;</span><span class="p">))</span> <span class="p">{</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="kd">var</span> <span class="nx">check</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">$</span><span class="p">.</span><span class="nx">ajax</span><span class="p">(</span><span class="s1">&#39;/sync_status&#39;</span><span class="p">,</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">dataType</span><span class="o">:</span> <span class="s1">&#39;json&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">success</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">resp</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="nx">resp</span><span class="p">.</span><span class="nx">status</span> <span class="o">===</span> <span class="s1">&#39;done&#39;</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">App</span><span class="p">.</span><span class="nx">Helpers</span><span class="p">.</span><span class="nx">reloadUser</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">clearInterval</span><span class="p">(</span><span class="nx">App</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;syncCheck&#39;</span><span class="p">));</span>
</span><span class='line'> <span class="nx">App</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;syncCheck&#39;</span><span class="p">,</span> <span class="kc">null</span><span class="p">);</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'> <span class="p">};</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">App</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;syncCheck&#39;</span><span class="p">,</span> <span class="nx">setInterval</span><span class="p">(</span><span class="nx">check</span><span class="p">,</span> <span class="mi">1000</span><span class="p">));</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>
<p>The code comes from an app whose server-side code queries a third-party service for new data every now and then. When the server is fetching that new data, certain actions on the front-end are forbidden. The code above was responsible for determining when the server-side sync is complete, and putting the app back in a state where those front-end interactions could be allowed again.</p>
<p>You might have heard that <code>setInterval</code> can be a dangerous thing when it comes to polling a server*, and, looking at the code above, it&#8217;s easy to see why. The polling happens every 1000 seconds, <em>whether the request was successful or not</em>. If the request results in an error, or fails, or takes more than 1000 milliseconds, <code>setInterval</code> doesn&#8217;t care &#8211; it will blindly kick off another request. The interval only gets cleared when the request succeeds and the sync is done.</p>
<p>The first refactoring for this is easy: switch to using <code>setTimeout</code>, and only enqueue another request once we know what happened with the previous one.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">App</span><span class="p">.</span><span class="nx">Helpers</span><span class="p">.</span><span class="nx">checkSyncStatus</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="nx">App</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;syncCheck&#39;</span><span class="p">))</span> <span class="p">{</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="kd">var</span> <span class="nx">check</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">$</span><span class="p">.</span><span class="nx">ajax</span><span class="p">(</span><span class="s1">&#39;/sync_status&#39;</span><span class="p">,</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">dataType</span><span class="o">:</span> <span class="s1">&#39;json&#39;</span><span class="p">,</span>
</span><span class='line'> <span class="nx">success</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">resp</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="nx">resp</span><span class="p">.</span><span class="nx">status</span> <span class="o">===</span> <span class="s1">&#39;done&#39;</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">App</span><span class="p">.</span><span class="nx">Helpers</span><span class="p">.</span><span class="nx">reloadUser</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">App</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;syncCheck&#39;</span><span class="p">,</span> <span class="kc">null</span><span class="p">);</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">setTimeout</span><span class="p">(</span><span class="nx">check</span><span class="p">,</span> <span class="mi">1000</span><span class="p">);</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'> <span class="p">};</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">App</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;syncCheck&#39;</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>
<p>Now, if the request fails, or takes more than 1000 milliseconds, at least we won&#8217;t be perpetrating a mini-DOS attack on our own server.</p>
<p>Our code still has some shortcomings, though. For one thing, we aren&#8217;t handling the failure case. Additionally, the rest of our application is stuck looking at the <code>syncCheck</code> property of our <code>App</code> object to figure out when the sync has completed.</p>
<p>We can use a promise to make our function a whole lot more powerful. We&#8217;ll return the promise from the function, and also store it as the value of our <code>App</code> object&#8217;s <code>syncCheck</code> property. This will let other pieces of code respond to the outcome of the request, whether it succeeds or fails. With a simple guard statement at the beginning of our function, we can also make it so that the <code>checkSyncStatus</code> function will return the promise immediately if a status check is already in progress.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">App</span><span class="p">.</span><span class="nx">Helpers</span><span class="p">.</span><span class="nx">checkSyncStatus</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">syncCheck</span> <span class="o">=</span> <span class="nx">App</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;syncCheck&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="nx">syncCheck</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">syncCheck</span><span class="p">;</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="kd">var</span> <span class="nx">dfd</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="nx">Deferred</span><span class="p">();</span>
</span><span class='line'> <span class="nx">App</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;syncCheck&#39;</span><span class="p">,</span> <span class="nx">dfd</span><span class="p">.</span><span class="nx">promise</span><span class="p">());</span>
</span><span class='line'>
</span><span class='line'> <span class="kd">var</span> <span class="nx">success</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">resp</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="nx">resp</span><span class="p">.</span><span class="nx">status</span> <span class="o">===</span> <span class="s1">&#39;done&#39;</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">App</span><span class="p">.</span><span class="nx">Helpers</span><span class="p">.</span><span class="nx">reloadUser</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">dfd</span><span class="p">.</span><span class="nx">resolve</span><span class="p">();</span>
</span><span class='line'> <span class="nx">App</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;syncCheck&#39;</span><span class="p">,</span> <span class="kc">null</span><span class="p">);</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">setTimeout</span><span class="p">(</span><span class="nx">check</span><span class="p">,</span> <span class="mi">1000</span><span class="p">);</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">};</span>
</span><span class='line'>
</span><span class='line'> <span class="kd">var</span> <span class="nx">fail</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">dfd</span><span class="p">.</span><span class="nx">reject</span><span class="p">();</span>
</span><span class='line'> <span class="nx">App</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;syncCheck&#39;</span><span class="p">,</span> <span class="kc">null</span><span class="p">);</span>
</span><span class='line'> <span class="p">};</span>
</span><span class='line'>
</span><span class='line'> <span class="kd">var</span> <span class="nx">check</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">req</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="nx">ajax</span><span class="p">(</span><span class="s1">&#39;/sync_status&#39;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">dataType</span><span class="o">:</span> <span class="s1">&#39;json&#39;</span> <span class="p">});</span>
</span><span class='line'> <span class="nx">req</span><span class="p">.</span><span class="nx">then</span><span class="p">(</span> <span class="nx">success</span><span class="p">,</span> <span class="nx">fail</span> <span class="p">);</span>
</span><span class='line'> <span class="p">};</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">setTimeout</span><span class="p">(</span><span class="nx">check</span><span class="p">,</span> <span class="mi">1000</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'> <span class="k">return</span> <span class="nx">dfd</span><span class="p">.</span><span class="nx">promise</span><span class="p">();</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>
<p>Now, we can call our new function, and use the returned promise to react to the <em>eventual outcome</em> of the sync:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">App</span><span class="p">.</span><span class="nx">Helpers</span><span class="p">.</span><span class="nx">checkSyncStatus</span><span class="p">().</span><span class="nx">then</span><span class="p">(</span>
</span><span class='line'> <span class="c1">// this will run if the sync was successful,</span>
</span><span class='line'> <span class="c1">// once the user has been reloaded</span>
</span><span class='line'> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;it worked&#39;</span><span class="p">);</span> <span class="p">},</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// this will run if the sync failed</span>
</span><span class='line'> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;it failed&#39;</span><span class="p">);</span> <span class="p">}</span>
</span><span class='line'><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>
<p>With a few more lines of code, we&#8217;ve made our function safer &#8211; eliminating the possibility of an out-of-control <code>setInterval</code> &#8211; and also made it vastly more useful to other pieces of the application that care about the outcome of the sync.</p>
<p>While the example above used <a href="http://api.jquery.com/deferred.promise/">jQuery&#8217;s promises implementation</a>, there are plenty of other implementations as well, including Sam Breed&#8217;s <a href="https://github.com/wookiehangover/underscore.Deferred">underscore.Deferred</a>, which mimics the behavior of jQuery&#8217;s promises without the dependency on jQuery.</p>
<p><small>* <a href="http://www.html5rocks.com/en/tutorials/websockets/basics/">Websockets</a> are a great way to eliminate polling all together, but in the case of this application, they weren&#8217;t an option.</small></p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Onward]]></title>
<link href="http://rmurphey.com/blog/2013/01/18/onward/"/>
<updated>2013-01-18T10:30:00-06:00</updated>
<id>http://rmurphey.com/blog/2013/01/18/onward</id>
<content type="html"><![CDATA[<p>My friend IM&#8217;d me a link the other day to a document he and a colleague wrote
at the end of 2011, listing all the things they wanted to make happen in the
world of web development in 2012.</p>
<p>&#8220;We did almost all of it,&#8221; he said.</p>
<p>&#8220;Well shit,&#8221; I said. &#8220;I should write up something like this for 2013.&#8221;</p>
<p>&#8220;Why do you think I showed it to you?&#8221;</p>
<hr />
<p>A year ago I was working at Toura, a startup based in New York that was
developing software to make it easy to create content-centric mobile
applications. I started there as a consultant back in 2010, helping them write
a saner version of the prototype they&#8217;d developed in the months before.</p>
<p>I got the gig because apparently I spoke with their director of development,
Matt, at a meetup in Brooklyn, though I actually have no recollection of this.
By this time last year, I&#8217;d been there for more than a year, and Matt and I had
convinced the company a few months before that the technology we&#8217;d developed &#8211;
a JavaScript framework called Mulberry that ran inside of a Phonegap wrapper
&#8211; was worth open-sourcing.</p>
<p>I spent much of January and February speaking at meetups and events &#8211;
Vancouver, Boston, Austin, Charlotte &#8211; telling people why Mulberry was
something they might consider using to develop their own content-centric mobile
apps. By March, though, it was clear that Toura was headed in a direction that
was different from where I wanted to go. As it turned out, Matt and I gave our
notice on the same day.</p>
<hr />
<p>April was the first time in almost 10 years that I purposefully didn&#8217;t work for
a solid month. I spent almost two weeks in Europe, first in Berlin and then in
Warsaw for <a href="http://2013.front-trends.com/">Front Trends</a>. I sold my car &#8211; it
mostly just sat in the driveway anyway &#8211; to make Melissa feel a bit better
about the part where I wasn&#8217;t making any money.
<a href="http://twitter.com/theophani">Tiffany</a> was a marvelous host; we took the train
together from Berlin to Warsaw for the conference, barely talking the whole way
as we worked on our respective presentations. Warsaw was a two-day whirlwind of
wonderful people &#8211; Melanie, Milos, Chris, Alex, Frances &#8211; memorable for my
terrible laryngitis and capped by endless hours of post-conference celebration
in the hotel lobby, which was magically spotless when we made our way,
bleary-eyed, to the train station early the next morning.</p>
<p>I flew home two days later; two days after that, I started at
<a href="http://bocoup.com/">Bocoup</a>.</p>
<hr />
<p>Taking a job at Bocoup was a strategic change of pace for me. For 18 months, I
had been immersed in a single product and a single codebase, and I was the
architect of it and the expert on it. As fun as that was, I was ready to
broaden my horizons and face a steady stream of new challenges in the company
of some extremely bright people.</p>
<p>As it turned out, I ended up focusing a lot more on the training and education
side of things at Bocoup &#8211; I spent the summer developing an updated and more
interactive version of <a href="http://jqfundamentals.com">jQuery Fundamentals</a>, and
worked through the summer and fall on developing and teaching various
JavaScript trainings, including a really fun two-day course on writing testable
JavaScript. I also worked on creating a
<a href="http://training.bocoup.com/coaching/">coaching</a> offering, kicked off a
<a href="http://training.bocoup.com/screencasts/">screencasts</a> project, and had some
great conversations as part of <a href="https://plus.google.com/101066175187812737186/posts">Bocoup on Air</a>.
Throughout it all, I kept up a steady schedule of speaking &#8211; TXJS, the jQuery Conference,
Fronteers, Full Frontal, and more.</p>
<p>Though I was keeping busy and creating lots of new content, there was one thing
I wasn&#8217;t doing nearly enough of: writing code.</p>
<hr />
<p>I went to New York in November to speak at the New York Times <a href="http://opensourcesciencefair.com/">Open Source Science Fair</a>,
and the next day I dropped in on Matt, my old boss from Toura, before heading
to the airport. He&#8217;s working at another startup these days, and they&#8217;re using
<a href="http://emberjs.com/">Ember</a> for their front-end. Though I was lucky enough to
get a guided tour of Ember from Tom Dale over the summer, I&#8217;d always felt like
I wouldn&#8217;t really appreciate it until I saw it in use on a sufficiently complex
project.</p>
<p>As it turned out, Matt was looking for some JavaScript help; I wasn&#8217;t really
looking for extra work, but I figured it would be a good chance to dig in to a
real Ember project. I told him I&#8217;d work for cheap if he&#8217;d tolerate me working
on nights and weekends. He gave me a feature to work on and access to the repo.</p>
<p>The first few hours with Ember were brutal. The next few hours were manageable.
The hours after that were magical. The most exciting part of all, despite all
the brain hurting along the way, was that I was solving problems with code
again. It felt good.</p>
<hr />
<p>With much love to my friends and colleagues at Bocoup, I&#8217;ve realized it is time
to move on. I&#8217;ll be taking a few weeks off before starting as a senior
software engineer at <a href="http://www.bazaarvoice.com/">Bazaarvoice</a>, the company
behind the ratings and reviews on the websites of companies such as WalMart,
Lowe&#8217;s, Costco, Best Buy, and lots more.</p>
<p>If you&#8217;re in the JS world, Bazaarvoice might sound familiar because <a href="http://alexsexton.com/">Alex Sexton</a>,
of yayQuery, TXJS, and redhead fame, works there. I&#8217;ll be joining the team he
works on, helping to flesh out, document, test, and implement a JavaScript
framework he&#8217;s been prototyping for the last several months.</p>
<p>I&#8217;ve gotten tiny peeks at the framework as Alex and the rest of the team have
been working on it, starting way back in February of last year, when I flew out
to Austin, signed an NDA, and spoke at BVJS, an internal conference the company
organized to encourage appreciation for JS as a first-class citizen. Talking to
Alex and his colleagues over the last few weeks about the work that&#8217;s ahead of
them, and how I might be able to help, has quite literally given me goosebumps
more than once. I can&#8217;t wait.</p>
<hr />
<p>I look back on 2012 with a lot of mixed emotions. I traveled to the UK,
to Amsterdam, to Warsaw, to Berlin two times. I broke a bone in a foreign
country, achievement unlocked. I learned about hardware and made my first
significant code contribution to an open-source project in the process. I met
amazing people who inspired me and humbled me, and even made a few new friends.</p>
<p>What I lost sight of, though, was making sure that I was seeking out new
challenges and facing them head on, making sure that I was seeking
opportunities to learn new things, even when they were hard, even when I didn&#8217;t
have to. I didn&#8217;t realize til my work with Ember just how thoroughly I&#8217;d let
that slip, and how very much I need it in order to stay sane.</p>
<p>And so while my friend probably has his list of things he will change in the
world of web development in 2013, and while maybe I&#8217;ll get around to making
that list for myself too, the list I want to be sure to look back on, 12 months
or so from now, is more personal, and contains one item:</p>
<p><em>Do work that requires learning new things all the time. Even if that&#8217;s a
little scary sometimes. Especially if that&#8217;s a little scary sometimes. In the
end you will be glad.</em></p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Two Things about Conditionals in JavaScript]]></title>
<link href="http://rmurphey.com/blog/2012/12/10/js-conditionals/"/>
<updated>2012-12-10T21:40:00-06:00</updated>
<id>http://rmurphey.com/blog/2012/12/10/js-conditionals</id>
<content type="html"><![CDATA[<p>Just a quick post, inspired by <a href="http://laurakalbag.com/display-none/">Laura Kalbag&#8217;s post</a>, which included this gem:</p>
<blockquote><p>We shouldn’t be fearful of writing about what we know. Even if you write from the most basic point of view, about something which has been ‘around for ages’, you’ll likely be saying something new to someone.</p></blockquote>
<h2>One: There is no <code>else if</code></h2>
<p>When you write something like this &#8230;</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="kd">function</span> <span class="nx">saySomething</span><span class="p">(</span> <span class="nx">msg</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span> <span class="nx">msg</span> <span class="o">===</span> <span class="s1">&#39;Hello&#39;</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Hello there&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span> <span class="nx">msg</span> <span class="o">===</span> <span class="s1">&#39;Yo&#39;</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Yo dawg&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>&#8230; then what you&#8217;re actually writing is this &#8230;</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="kd">function</span> <span class="nx">saySomething</span><span class="p">(</span> <span class="nx">msg</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span> <span class="nx">msg</span> <span class="o">===</span> <span class="s1">&#39;Hello&#39;</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Hello there&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span> <span class="nx">msg</span> <span class="o">===</span> <span class="s1">&#39;Yo&#39;</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Yo dawg&#39;</span><span class="p">);</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>That&#8217;s because there is no <code>else if</code> in JavaScript. You know how you can write an <code>if</code> statement without any curly braces?</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="k">if</span> <span class="p">(</span> <span class="nx">foo</span> <span class="p">)</span> <span class="nx">bar</span><span class="p">()</span> <span class="c1">// please don&#39;t do this if you want your code to be legible</span>
</span></code></pre></td></tr></table></div></figure>
<p>You&#8217;re doing the same thing with the <code>else</code> part of the initial <code>if</code> statement when you write <code>else if</code>: you&#8217;re skipping the curly braces for the second <code>if</code> block, the one you&#8217;re providing to <code>else</code>. There&#8217;s nothing <em>wrong</em> with <code>else if</code> per se, but it&#8217;s worth knowing about what&#8217;s actually happening.</p>
<h2>Two: <code>return</code> Means Never Having to Say <code>else</code></h2>
<p>Consider some code like this:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="kd">function</span> <span class="nx">howBig</span><span class="p">(</span> <span class="nx">num</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span> <span class="nx">num</span> <span class="o">&lt;</span> <span class="mi">10</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="s1">&#39;small&#39;</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span> <span class="nx">num</span> <span class="o">&gt;=</span> <span class="mi">10</span> <span class="o">&amp;&amp;</span> <span class="nx">num</span> <span class="o">&lt;</span> <span class="mi">100</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="s1">&#39;medium&#39;</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span> <span class="nx">num</span> <span class="o">&gt;=</span> <span class="mi">100</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="s1">&#39;big&#39;</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>If the number we pass to <code>howBig</code> is less than 10, then our function will return <code>'small'</code>. As soon as it returns, none of the rest of the function will run &#8211; this means we can skip the <code>else</code> part entirely, which means our code could look like this:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="kd">function</span> <span class="nx">howBig</span><span class="p">(</span> <span class="nx">num</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span> <span class="nx">num</span> <span class="o">&lt;</span> <span class="mi">10</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="s1">&#39;small&#39;</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span> <span class="nx">num</span> <span class="o">&lt;</span> <span class="mi">100</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="s1">&#39;medium&#39;</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span> <span class="nx">num</span> <span class="o">&gt;=</span> <span class="mi">100</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="s1">&#39;big&#39;</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>But wait &#8211; if the first <code>if</code> statement isn&#8217;t true, and the second <code>if</code> statement isn&#8217;t true, then we will <em>always</em> return <code>'big'</code>. That means the third <code>if</code> statement isn&#8217;t even required:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="kd">function</span> <span class="nx">howBig</span><span class="p">(</span> <span class="nx">num</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span> <span class="nx">num</span> <span class="o">&lt;</span> <span class="mi">10</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="s1">&#39;small&#39;</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span> <span class="nx">num</span> <span class="o">&lt;</span> <span class="mi">100</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="s1">&#39;medium&#39;</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="k">return</span> <span class="s1">&#39;big&#39;</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p><small><em>Note: this post was edited to improve a couple of the examples and to fix some typos.</em></small></p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[This is the Cigarette]]></title>
<link href="http://rmurphey.com/blog/2012/12/09/this-is-the-cigarette/"/>
<updated>2012-12-09T19:40:00-06:00</updated>
<id>http://rmurphey.com/blog/2012/12/09/this-is-the-cigarette</id>
<content type="html"><![CDATA[<p><a href="http://www.flickr.com/photos/rdmey/8259827572/" title="Untitled by rdmey, on Flickr"><img src="http://farm9.staticflickr.com/8212/8259827572_73b5a4e269.jpg" width="200"></a></p>
<p>This is the cigarette I smoked* on Wednesday after I got out of a meeting in Boston and went to my desk and read my messages and learned that our birthmother &#8220;match&#8221; had fallen through.</p>
<p>The last three weeks have been among the happiest, most exciting, most terrifying times I can remember. Saying that we are sad and disappointed and et cetera doesn&#8217;t really cover it, but, well, there it is. Our search will continue.</p>
<p><small>* Don&#8217;t worry, Mom, I don&#8217;t usually smoke. Desperate times, desperate measures.</small></p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[On Choosing a Syntax Highlighting Scheme for Your Next Presentation]]></title>
<link href="http://rmurphey.com/blog/2012/11/29/choosing-presentation-color-scheme/"/>
<updated>2012-11-29T20:20:00-06:00</updated>
<id>http://rmurphey.com/blog/2012/11/29/choosing-presentation-color-scheme</id>
<content type="html"><![CDATA[<p>This is a projector screen:</p>
<p><img src="https://dl.dropboxusercontent.com/u/2916642/projection-screen.jpg" width="300px"></p>
<p>You will notice that it is white, or some reasonable approximation thereof. It is probably made of a reflective material that sparkles a bit when light shines on it. Still: white.</p>
<p>Do you know what color this screen is when you use a projector to display this image onto it?</p>
<p><img src="https://dl.dropboxusercontent.com/u/2916642/dark-code.png" width="300px"></p>
<p>It is still white. Crazy, I know! The thing is, projectors cannot project black; they can only <em>not</em> project any light on a region that you intend to be black.</p>
<p>Chances are you are reading this on an LCD screen of some sort, where the rules are completely different: they usually start out essentially black, not white, and pixels are brightened as required. The pixels that start out dark can generally stay pretty dark.</p>
<p>On a projection screen, on the other hand, the appearance of black is nothing more than an optical illusion, made possible by the projector projecting brightness everywhere else.</p>
<p>What does this mean? Lots of things, but in particular, it means that you should never, ever, ever use a color scheme with a dark background &#8211; no matter how high-contrast and good it looks on your monitor &#8211; if you will be presenting using a projector that is projecting onto a white screen. At least, assuming that you intend for your audience to be able to actually read the code.</p>
<h3>Presentation Color Schemes That I Have Loved</h3>
<ul>
<li><a href="https://gist.github.com/4171437">Ben Alman&#8217;s TextMate Theme</a>: Ben has tailored this to be incredible for presenting about JS code.</li>
<li><a href="https://github.com/chriskempson/tomorrow-theme">Tomorrow Theme</a>: The light-background flavor is decent, but could probably stand to be higher-contrast, at least for some languages.</li>
</ul>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Show & Tell]]></title>
<link href="http://rmurphey.com/blog/2012/11/25/times-open-science-fair/"/>
<updated>2012-11-25T20:20:00-06:00</updated>
<id>http://rmurphey.com/blog/2012/11/25/times-open-science-fair</id>
<content type="html"><![CDATA[<p>I spoke at the <a href="http://opensourcesciencefair.com/">Times Open Source Science Fair</a> a couple of weeks ago. I&#8217;ll admit that I was pretty skeptical of the concept when I was first asked, but as someone who used to work as an editor at a tiny newspaper in upstate New York, I wasn&#8217;t about to say no when the Times asked me to come say hi.</p>
<p>A few days before the event, I got an email asking me for information about what I&#8217;d be showing off at my booth. Booth? Wat? They weren&#8217;t kidding about the science fair thing, but what the heck was I going to show at a booth?</p>
<p>It turns out this is basically the best idea ever. I recruited my Bocoup colleague <a href="http://twitter.com/rwaldron">Rick Waldron</a> to join me, and together we spent a whirlwind hour showing off <a href="https://github.com/rwldrn/johnny-five">robots powered by JavaScript</a> to an endless stream of people walking up to our booth. Rick did a great job of setting up a demo that people could play with, and they took turns moving <a href="https://www.sparkfun.com/products/9119">sliding potentiometers</a> that controlled <a href="https://www.sparkfun.com/products/9064">servos</a> that moved an arm with a gripper at the end, trying to pick up Bocoup stickers. Ours was one of about a <a href="http://open.blogs.nytimes.com/2012/11/21/open-source-science-fair-exhibitor-experiences/">dozen booths</a> showing off open-source projects, and the room was a wonderful madhouse.</p>
<p>After a break for dinner, I, <a href="http://twitter.com/jashkenas">Jeremy Ashkenas</a>, and <a href="http://twitter.com/holman">Zach Holman</a> each gave 20-minute talks, but the talks were really just icing on the evening. The &#8220;science fair&#8221; format promoted such <em>intentional interaction</em>, in a way that traditional conferences just can&#8217;t, no matter how great the hall track or the parties may be. The format invited and encouraged attendees to talk to the presenters &#8211; indeed, if they didn&#8217;t talk to the presenters, there wasn&#8217;t much else for them to do. By the time the official talks came around, a super-casual, super-conversational atmosphere had already been established, and the energy that created was tangibly different from any event I&#8217;ve been to before.</p>
<p>I love conferences, and the sharing of knowledge that happens there, and there&#8217;s a whole lot to be said for their speaker-audience format &#8211; don&#8217;t get me wrong. But I&#8217;d also love to see more events figure out how to integrate this show and tell format. &#8220;Booths&#8221; don&#8217;t need to mean &#8220;vendors trying to sell things&#8221; &#8211; they can actually be a great opportunity to facilitate conversation, and to let open source contributors show off their hard work.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Recent Talks]]></title>
<link href="http://rmurphey.com/blog/2012/11/21/recent-talks/"/>
<updated>2012-11-21T10:40:00-06:00</updated>
<id>http://rmurphey.com/blog/2012/11/21/recent-talks</id>
<content type="html"><![CDATA[<p><a href="http://infrequently.org/2012/11/bits-and-remainders/">A post from Alex Russell</a> reminded me that I&#8217;ve given a number of talks in the last few months, and some of them even have video on the internet.</p>
<p>I&#8217;ve been ridiculously spoiled to get to travel all over the place these last few months &#8211; San Francisco, New York, Amsterdam, Berlin, Brighton &#8211; and speak at some truly first-class conferences, sharing the stage, sharing meals, and sharing beers with some seriously amazing folks. My <a href="http://rmurphey.com/blog/2012/11/14/this-is-the-cup-of-coffee/">recent news</a> means I&#8217;ll be doing a lot less travel for the next little bit, but I&#8217;m ever-so-grateful for the opportunities I&#8217;ve had and the people I&#8217;ve gotten to see and meet these last few months.</p>
<h3>Writing Testable JavaScript</h3>
<p>This is the first talk I&#8217;ve developed that I&#8217;ve managed to give several times in rapid succession: three times in six days, including at <a href="http://2012.full-frontal.org/">Full Frontal</a>, the online <a href="http://environmentsforhumans.com/2012/javascript-summit/">JS Summit</a>, and to a group of developers at the New York Times. There&#8217;s no video yet, but the <a href="https://speakerdeck.com/rmurphey/writing-testable-javascript-mocha-version">slides are here</a>, and there should be video soon, I think.</p>
<p><script async class="speakerdeck-embed" data-id="eb8bb4800ff201308f97123138155402" data-ratio="1.33333333333333" src="http://rmurphey.com//speakerdeck.com/assets/embed.js"></script></p>
<h3>JS Minty Fresh</h3>
<p>A fun talk at <a href="http://fronteers.nl/congres/2012">Fronteers</a> about eliminating code smells from your JavaScript. The best feedback I got afterwards was from an attendee who said they felt at the beginning of the talk like the material was going to be too basic for them, and by the end of the talk, the material was nearly over their head. &#8220;I guess that makes you a good teacher,&#8221; he said. Aw!</p>
<iframe src="http://player.vimeo.com/video/53416986?badge=0" width="500" height="281" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
<p><a href="http://vimeo.com/53416986">Rebecca Murphey | JS Minty Fresh: Identifying and Eliminating Smells in Your Code Base | Fronteers 2012</a> from <a href="http://vimeo.com/fronteers">Fronteers</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
<p><a href="http://rmurphey.com/js-minty-fresh/presentation/">Slides</a></p>
<p>If you like this, you should also check out the <a href="http://training.bocoup.com/screencasts/">screencasts</a> we released at Bocoup earlier this week.</p>
<h3>Beyond the DOM: Sane Structure for JS Apps</h3>
<p>An update of my code organization talk, delivered at the <a href="http://events.jquery.org/2012/sf/">jQuery Conference in San Francisco</a>. It&#8217;s fun for me to see how my thinking around code organization has evolved and improved since my first, now-almost-embarassing talk at the 2009 jQuery Conference in Boston.</p>
<iframe width="500" height="281" src="http://www.youtube.com/embed/cd7HHN6IkrU" frameborder="0" allowfullscreen></iframe>
<p><a href="https://speakerdeck.com/rmurphey/jquery-conference-sf-2012-beyond-the-dom-sane-structure-for-js-apps">Slides</a></p>
<h3>Johnny Five: Bringing the JavaScript Culture to Hardware</h3>
<p>This one was from the New York Times <a href="http://opensourcesciencefair.com/">Open Source Science Fair</a>, a fun night of about a dozen folks presenting open-source projects at &#8220;booths,&#8221; followed by short talks about open source by Jeremy Ashkenas, me, and Zach Holman. The slides don&#8217;t necessarily stand on their own very well, but the short version is: use JavaScript to make things in the real world, because it&#8217;s ridiculously easy and ridiculously fun.</p>
<p><script async class="speakerdeck-embed" data-id="6ab92f30161e0130f5111231381d612b" data-ratio="1.2994923857868" src="http://rmurphey.com//speakerdeck.com/assets/embed.js"></script></p>
<h3>Getting Better at JavaScript</h3>
<p>I put this together as a quickie for the Berlin <a href="http://up.front.ug/">UpFront</a> user group &#8211; it was the first talk I gave with my broken foot, and the last talk I&#8217;d give for weeks because I lost my voice a couple of hours later. There&#8217;s not a whole lot here, but it was a fun talk and a fun group, and a topic that I get plenty of questions about. Again, no video, but here are the slides:</p>
<p><script async class="speakerdeck-embed" data-id="50746953453e4d0002081c02" data-ratio="1.2994923857868" src="http://rmurphey.com//speakerdeck.com/assets/embed.js"></script></p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[This is the Cup of Coffee]]></title>
<link href="http://rmurphey.com/blog/2012/11/14/this-is-the-cup-of-coffee/"/>
<updated>2012-11-14T10:40:00-06:00</updated>
<id>http://rmurphey.com/blog/2012/11/14/this-is-the-cup-of-coffee</id>
<content type="html"><![CDATA[<p><img src="http://farm9.staticflickr.com/8482/8187360514_db246b4ac9.jpg" width="400"></p>
<p>This is the cup of coffee I was making earlier this week when Melissa gave me a thumbs-up while she talked on the phone to a woman in Pennsylvania who had just finished telling Melissa that yes, indeed, after 10 weeks or three years of waiting depending on how you count, a 29-year-old woman who&#8217;s due to give birth in Iowa at the beginning of February has decided that Melissa and I should be so lucky as to get to be her baby girl&#8217;s forever family.</p>
<p>Most people get to post ultrasound pictures on Twitter at moments like these, but for now this will suffice to remind me of the moment I found out I would get to be a mom. My head is spinning, and while on the one hand it&#8217;s a little difficult to fathom that this is all just 10 weeks away, on the other hand I&#8217;m counting down the days.</p>
<p>Our adoption will be an open one; the meaning of &#8220;open&#8221; varies widely, but in our case it means we talked to the birth mother before she chose us, we&#8217;ll be meeting her in a few weeks, we&#8217;ll do our very best to be in Iowa for the delivery, and we&#8217;ll stay in touch with letters and pictures afterwards. Melissa and I are grateful that we&#8217;ll be able to adopt as a couple, though we are saddened that we have to adopt outside of our home state of North Carolina in order to do so. It&#8217;s important to us that our child have both of us as her <em>legal</em> parents, and I don&#8217;t hesitate to say that it&#8217;s downright shitty that we have to jump through significant legal and financial hoops &#8211; and stay in a hotel in Iowa with a newborn for an unknown number of days &#8211; to make it so. It is what it is, and good people are working and voting to make it better, and it can&#8217;t happen fast enough.</p>
<p>I&#8217;ve learned a lot about adoption these past few months, and I know a lot of people have a lot of questions, some of which they&#8217;re reluctant to ask. If you&#8217;re interested in learning more, I <em>highly</em> recommend <a href="http://www.amazon.com/In-On-It-Adoption-Relatives/dp/0982876505/ref=sr_1_1?ie=UTF8&amp;qid=1352948795&amp;sr=8-1&amp;keywords=in+on+it">In On It: What Adoptive Parents Would Like You to Know About Adoption</a>. You&#8217;re also welcome to ask me questions if you see me in real life or on the internets &#8211; I can&#8217;t promise I&#8217;ll know the answers, but I promise to do my best.</p>
<p>In the meantime, wish us luck :)</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[A Baseline for Front-End Developers]]></title>
<link href="http://rmurphey.com/blog/2012/04/12/a-baseline-for-front-end-developers/"/>
<updated>2012-04-12T11:30:00-05:00</updated>
<id>http://rmurphey.com/blog/2012/04/12/a-baseline-for-front-end-developers</id>
<content type="html"><![CDATA[<p>I wrote a README the other day for a project that I&#8217;m hoping other developers will look at and learn from, and as I was writing it, I realized that it was the sort of thing that might have intimidated the hell out of me a couple of years ago, what with its casual mentions of Node, npm, Homebrew, git, tests, and development and production builds.</p>
<p>Once upon a time, editing files, testing them locally (as best as we could, anyway), and then FTPing them to the server was the essential workflow of a front-end dev. We measured our mettle based on our ability to wrangle IE6 into submission or achieve pixel perfection across browsers. Many members of the community &#8211; myself included &#8211; lacked traditional programming experience. HTML, CSS, and JavaScript &#8211; usually in the form of jQuery &#8211; were self-taught skills.</p>
<p>Something has changed in the last couple of years. Maybe it&#8217;s the result of people starting to take front-end dev seriously, maybe it&#8217;s browser vendors mostly getting their shit together, or maybe it&#8217;s front-end devs &#8211; again, myself included &#8211; coming to see some well-established light about the process of software development.</p>
<p>Whatever it is, I think we&#8217;re seeing the emphasis shift from valuing trivia to valuing tools. There&#8217;s a new set of baseline skills required in order to be successful as a front-end developer, and developers who don&#8217;t meet this baseline are going to start feeling more and more left behind as those who are sharing their knowledge start to assume that certain things go without saying.</p>
<p>Here are a few things that <em>I</em> want to start expecting people to be familiar with, along with some resources you can use if you feel like you need to get up to speed. (Thanks to Paul Irish, Mike Taylor, Angus Croll, and Vlad Filippov for their contributions.)</p>
<h2>JavaScript</h2>
<p>This might go without saying, but simply knowing a JavaScript library isn&#8217;t sufficient any more. I&#8217;m not saying you need to know how to implement all the features of a library in plain JavaScript, but you should know when a library is actually required, and be capable of working with plain old JavaScript when it&#8217;s not.</p>
<p>That means that you&#8217;ve read <a href="http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742">JavaScript: The Good Parts</a> &#8211; hopefully more than once. You understand data structures like objects and arrays; functions, including how and why you would <code>call</code> and <code>apply</code> them; working with prototypal inheritance; and managing the asynchronicity of it all.</p>
<p>If your plain JS fu is weak, here are some resources to help you out:</p>
<ul>
<li><a href="http://eloquentjavascript.net">Eloquent Javascript</a>: A wonderful book (also available in print) that takes you back to JavaScript basics</li>
<li><a href="https://github.com/rmurphey/js-assessment">A Test-Driven JS Assessment</a>: A set of failing tests that cover various JavaScript topics; can you write code to make the tests pass?</li>
<li><a href="http://paulirish.com/2010/10-things-i-learned-from-the-jquery-source/">10 things I learned from the jQuery Source</a> is an oldie but goodie from Paul Irish that shows what you can learn by reading other people&#8217;s code.</li>
</ul>
<h2>Git (and a Github account)</h2>
<p>If you&#8217;re not on Github, you&#8217;re essentially unable to participate in the rich open-source community that has arisen around front-end development technologies. Cloning a repo to try it out should be second-nature to you, and you should understand how to <a href="http://nvie.com/posts/a-successful-git-branching-model/">use branches on collaborative projects</a>.</p>
<p>Need to boost your git skills?</p>
<ul>
<li><a href="http://help.github.com/">help.github.com</a></li>
<li><a href="http://help.github.com/git-cheat-sheets/">Github git cheat sheet</a></li>
<li><a href="http://cheat.errtheblog.com/s/git">More cheat sheet</a></li>
<li><a href="http://pinboard.in/u:rmurphey/t:git/">More git links</a></li>
</ul>
<h2>Modularity, dependency management, and production builds</h2>
<p>The days of managing dependencies by throwing one more script or style tag on the page are long gone. Even if you haven&#8217;t been able to incorporate great tools like <a href="http://requirejs.org">RequireJS</a> into your workflow at work, you should find time to investigate them in a personal project or in a project like <a href="https://github.com/tbranyen/backbone-boilerplate">Backbone Boilerplate</a>, because the benefits they convey are huge. RequireJS in particular lets you develop with small, modular JS and CSS files, and then concatenates and minifies them via its optimization tool for production use.</p>
<p>Skeptical of AMD? That&#8217;s no excuse to be doing nothing. At the very least, you should be aware of tools like <a href="https://github.com/mishoo/UglifyJS">UglifyJS</a> or <a href="https://developers.google.com/closure/compiler/">Closure Compiler</a> that will intelligently minify your code, and then concatenate those minified files prior to production.</p>
<p>If you&#8217;re writing plain CSS &#8211; that is, if you&#8217;re not using a preprocessor like Sass or Stylus &#8211; RequireJS can help you keep your CSS files modular, too. Use <code>@import</code> statements in a base file to load dependencies for development, and then run the RequireJS <a href="http://requirejs.org/docs/optimization.html#onecss">optimizer</a> on the base file to create a file built for production.</p>
<h2>In-Browser Developer Tools</h2>
<p>Browser-based development tools have improved tremendously over the last couple of years, and they can dramatically improve your development experience if you know how to use them. (Hint: if you&#8217;re still using <code>alert</code> to debug your code, you&#8217;re wasting a lot of time.)</p>
<p>You should probably find one browser whose developer tools you primarily use &#8211; I&#8217;m partial to <a href="https://developers.google.com/chrome-developer-tools/">Google Chrome&#8217;s Developer Tools</a> these days &#8211; but don&#8217;t dismiss the tools in other browsers out of hand, because they are constantly adding useful features based on developer feedback. Opera&#8217;s <a href="http://my.opera.com/dragonfly/blog/">Dragonfly</a> in particular has some features that make its developer tools stand out, such as an (experimental) CSS profiler, customizable keyboard shortcuts, remote debugging without requiring a USB connection, and the ability to save and use custom color palettes.</p>
<p>If your understanding of browser dev tools is limited, <a href="http://fixingthesejquery.com/#slide1">Fixing these jQuery</a> is a great (and not particularly jQuery-centric) overview of debugging, including how to do <a href="https://developers.google.com/chrome-developer-tools/docs/scripts-breakpoints">step debugging</a> &#8211; a life-altering thing to learn if you don&#8217;t already know it.</p>
<h2>The command line</h2>
<p>Speaking of the command line, being comfortable with it is no longer optional &#8211; you&#8217;re missing out on way too much if you&#8217;re not ready to head over to a terminal window and get your hands dirty. I&#8217;m not saying you have to do <em>everything</em> in the terminal &#8211; I won&#8217;t take your git GUI away from you even though I think you&#8217;ll be better off without it eventually &#8211; but you should absolutely have a terminal window open for whatever project you&#8217;re working on. There are a few command line tasks you should be able to do without thinking:</p>
<ul>
<li><code>ssh</code> to log in to another machine or server</li>
<li><code>scp</code> to copy files to another machine or server</li>
<li><code>ack</code> or <code>grep</code> to find files in a project that contain a string or pattern</li>
<li><code>find</code> to locate files whose names match a given pattern</li>
<li><code>git</code> to do at least basic things like <code>add</code>, <code>commit</code>, <code>status</code>, and <code>pull</code></li>
<li><code>brew</code> to use Homebrew to install packages</li>
<li><code>npm</code> to install Node packages</li>
<li><code>gem</code> to install Ruby packages</li>
</ul>
<p>If there are commands you use frequently, edit your <code>.bashrc</code> or <code>.profile</code> or <code>.zshrc</code> or whatever, and create an <a href="http://tldp.org/LDP/abs/html/aliases.html">alias</a> so you don&#8217;t have to type as much. You can also add aliases to your <code>~/.gitconfig</code> file. Gianni Chiappetta&#8217;s <a href="https://github.com/gf3/dotfiles">dotfiles</a> are an excellent inspiration for what&#8217;s possible.</p>
<p><em>Note: If you&#8217;re on Windows, I don&#8217;t begin to know how to help you, aside from suggesting <a href="http://www.cygwin.com/">Cygwin</a>. Right or wrong, participating in the open-source front-end developer community is materially more difficult on a Windows machine. On the bright side, MacBook Airs are cheap, powerful, and ridiculously portable, and there&#8217;s always Ubuntu or another *nix.</em></p>
<h2>Client-side templating</h2>
<p>It wasn&#8217;t so long ago that it was entirely typical for servers to respond to XHRs with a snippet of HTML, but sometime in the last 12 to 18 months, the front-end dev community saw the light and started demanding pure data from the server instead. Turning that data into HTML ready to be inserted in the DOM can be a messy and unmaintainable process if it&#8217;s done directly in your code. That&#8217;s where <a href="http://www.slideshare.net/garann/using-templates-to-achieve-awesomer-architecture">client-side templating libraries</a> come in: they let you maintain templates that, when mixed with some data, turn into a string of HTML. Need help picking a templating tool? Garann Means&#8217; <a href="http://garann.github.com/template-chooser/">template chooser</a> can point you in the right direction.</p>
<h2>CSS preprocessors</h2>
<p>Paul Irish <a href="https://twitter.com/#!/paul_irish/status/188329390822801409">noted</a> the other day that we&#8217;re starting to see front-end devs write code that&#8217;s very different from what ends up in production, and code written with CSS preprocessors is a shining example of this. There&#8217;s still a vocal crowd that feels that pure CSS is the only way to go, but they&#8217;re <a href="http://www.stuffandnonsense.co.uk/blog/about/less">starting to come around</a>. These tools give you features that arguably should be in CSS proper by now &#8211; variables, math, logic, mixins &#8211; and they can also help smooth over the CSS property prefix mess.</p>
<h2>Testing</h2>
<p>One of the joys of writing modular, loosely coupled code is that your code becomes vastly easier to test, and with tools like <a href="https://github.com/cowboy/grunt">Grunt</a>, setting up a project to include tests has never been easier. Grunt comes with QUnit integration, but there are a host of testing frameworks that you can choose from &#8211; <a href="https://github.com/pivotal/jasmine/wiki">Jasmine</a> and <a href="http://visionmedia.github.com/mocha/">Mocha</a> are a couple of my current favorites &#8211; depending on your preferred style and the makeup of the rest of your stack.</p>
<p>While testing is a joy when your code is modular and loosely coupled, testing code that&#8217;s not well organized can be somewhere between difficult and impossible. On the other hand, forcing yourself to write tests &#8211; perhaps before you even write the code &#8211; will help you organize your thinking <em>and</em> your code. It will also let you refactor your code with greater confidence down the line.</p>
<ul>
<li>A short <a href="http://vimeo.com/20457625">screencast</a> I recorded about testing your jQuery with Jasmine.</li>
<li>An example of <a href="https://github.com/cowboy/jquery-bbq/blob/master/unit/unit.js">unit tests</a> on the jquery-bbq plugin.</li>
</ul>
<h2>Process automation (rake/make/grunt/etc.)</h2>
<p>Grunt&#8217;s ability to set up a project with built-in support for unit tests is one example of process automation. The reality of front-end development is that there&#8217;s a whole lot of repetitive stuff we have to do, but as a friend once told me, a good developer is a lazy developer: as a rule of thumb, if you find yourself doing the same thing three times, it&#8217;s time to automate it.</p>
<p>Tools like <code>make</code> have been around for a long time to help us with this, but there&#8217;s also <code>rake</code>, <code>grunt</code>, and others. Learning a language other than JavaScript can be extremely helpful if you want to automate tasks that deal with the filesystem, as Node&#8217;s async nature can become a real burden when you&#8217;re just manipulating files. There are lots of task-specific automation tools, too &#8211; tools for deployment, build generation, code quality assurance, and more.</p>
<h2>Code quality</h2>
<p>If you&#8217;ve ever been bitten by a missing semicolon or an extra comma, you know how much time can be lost to subtle flaws in your code. That&#8217;s why you&#8217;re running your code through a tool like <a href="http://www.jshint.com/">JSHint</a>, right? It&#8217;s <a href="http://www.jshint.com/options/">configurable</a> and has lots of ways to integrate it into your <a href="http://www.jshint.com/platforms/">editor or build process</a>.</p>
<h2>The fine manual</h2>
<p>Alas, there is no manual for front-end development, but <a href="https://developer.mozilla.org/en-US/">MDN</a> comes pretty close. Good front-end devs know to prefix any search engine query with <code>mdn</code> &#8211; for example, <code>mdn javascript arrays</code> &#8211; in order to avoid the for-profit plague that is w3schools.</p>
<h2>The End</h2>
<p>As with anything, reading about these things won&#8217;t make you an expert, or even moderately skilled &#8211; the only surefire way to get better at a thing is to <a href="http://rmurphey.com/blog/2011/05/20/getting-better-at-javascript/">do that thing</a>. Good luck.</p>
]]></content>
</entry>
</feed>