roderick.dk2023-06-08T12:52:28+00:00http://roderick.dk/Morgan Roderickmorgan@roderick.dk2023 Birthday Party2023-03-20T19:01:00+00:00http://roderick.dk//2023/03/20/2023-birthday-partyMorgan Roderickmorgan@roderick.dk<h1 id="2023-birthday-party">2023 Birthday Party</h1>
<p>Save the date!</p>
<p>Uyanga and I will be celebrating our combined 90 years on this planet by having a birthday party on 2023-06-24 in the afternoon. It will be in Berlin, Germany and will be fairly casual.</p>
<p>There will be some food … think mingling with a plate of delicious bits, not sitting down for a three course meal. There will be some drinks of what people like drinking on a Saturday afternoon in summer.</p>
<p>Please don’t get us any presents, we have more than enough earthly belongings. Instead, a small donation towards paying for the party would be very welcome. Please send donations to <a href="https://paypal.me/MorganRoderick">my PayPal</a>.</p>
<p>There will be more details about exact venue and time to those that RSVP at a later state.</p>
<p>RSVP: please send me an email at <a href="mailto:morgan@roderick.dk?subject=RSVP: Birthday Party">morgan@roderick.dk</a> before 2023-06-01.</p>
Get Started With TypeScript the Easy Way2022-02-07T10:38:00+00:00http://roderick.dk//2022/02/07/typeScript-the-easy-wayMorgan Roderickmorgan@roderick.dk<h1 id="get-started-with-typescript-the-easy-way">Get Started With TypeScript the Easy Way</h1>
<blockquote>
<p>Unlike many tutorials today, this one will focus on minimizing the technical requirements to follow along. We will get up and running with TypeScript without opening a terminal, installing dependencies, or even initializing an NPM project. In the advanced portion we will need to do a bit of that, but for most users, all you will need is Visual Studio Code as your editor.</p>
</blockquote>
<p>Link <a href="https://austingil.com/typescript-the-easy-way/">Get Started With TypeScript the Easy Way</a></p>
You might not need TypeScript... (syntax)2022-02-07T10:38:00+00:00http://roderick.dk//2022/02/07/you-might-not-need-typescript-syntaxMorgan Roderickmorgan@roderick.dk<h1 id="you-might-not-need-typescript-syntax">You might not need TypeScript… (syntax)</h1>
<blockquote>
<p>Everyone loves types, Everyone loves autocompletion, Everyone loves getting warnings before they arise.</p>
<p>But nobody likes wasting time compiling stuff. Hopefully this will help convince you or your company that you don’t actually need the TypeScript flavor syntax. So i have embedded the same editor used in VS-code to show you that <em>you can have type safety with vanilla JavaScript</em> and have the best of both worlds and play around with it.</p>
</blockquote>
<p>Link <a href="https://jimmywarting.github.io/you-might-not-need-typescript/">You might not need TypeScript… (syntax)</a></p>
How to manage volume for Multi-output Audio devices on macOS2022-02-07T10:05:00+00:00http://roderick.dk//2022/02/07/how-to-manage-volume-for-multi-output-audio-devices-on-macosMorgan Roderickmorgan@roderick.dk<h1 id="how-to-manage-volume-for-multi-output-audio-devices-on-macos">How to manage volume for Multi-output Audio devices on macOS</h1>
<p>Last year I learned how to use <a href="/2021/05/24/two-headphones-with-a-mac/">two headphones with a Mac</a>, which is a great feature to use when travelling. Basically, we can watch movies in Apple TV on one computer.</p>
<p>Since our travel last year, my partner has switched to from their Sony over the ear headphones (with built-in amplifier) to Airpods Pro (no built-in amplifier).</p>
<p>That gave us some challenges, as they could not really hear what was going on, and couldn’t turn the volume up due to those headphones not having volume controls or amplifier. My Sony headphones do not have those challenges, so I was fine with the Multi-output audio.</p>
<p>The solution to this challenge is described in great detail by Fatima Wahab in <a href="https://www.addictivetips.com/mac-os/manage-volume-for-multi-output-audio-devices-on-macos/">How to manage volume for Multi-output Audio devices on macOS</a>.</p>
<p>The solution worked perfectly for us, and we could pass time together on our travels again.</p>
#NoEstimates, talk by Allen Holub2022-01-25T13:20:00+00:00http://roderick.dk//2022/01/25/noestimates-talk-by-allen-holubMorgan Roderickmorgan@roderick.dk<h1 id="noestimates-talk-by-allen-holub">#NoEstimates, talk by Allen Holub</h1>
<blockquote>
<p>This keynote presents my (and many other’s) thinking about #NoEstimates. It argues that estimation is a bad thing, particularly in the Agile world, and presents ways to plan that don’t involve estimation.</p>
</blockquote>
<p>Link: <a href="https://www.youtube.com/watch?v=QVBlnCTu9Ms">#NoEstimates</a></p>
Everyone sweeps the floor2021-12-21T17:35:00+00:00http://roderick.dk//2021/12/21/everyone-sweeps-the-floorMorgan Roderickmorgan@roderick.dk<h2 id="everyone-sweeps-the-floor">Everyone sweeps the floor</h2>
<p>The rule “Everyone sweeps the floor” always resonated with me.</p>
<p>This was very much the behaviour and expectations of the person that ran the unit that I worked in some years ago at Apple.</p>
<p>At the time, I was unaware that the badge sticker existed. My boss did mention that they appreciated me always “sweeping the floor” … both in the codebases I worked in, but also emptying the dishwasher.</p>
<p>Link <a href="https://fossbytes.com/11-rules-for-success-apple/">JB’s Rules for Success</a></p>
The reduce ({...spread}) anti-pattern2021-12-21T08:50:00+00:00http://roderick.dk//2021/12/21/the-reduce-spread-anti-patternMorgan Roderickmorgan@roderick.dk<h2 id="the-reduce-spread-anti-pattern">The reduce <code class="language-plaintext highlighter-rouge">({...spread})</code> anti-pattern</h2>
<p>I thought this was a really interesting examination of the performance penalties of using <code class="language-plaintext highlighter-rouge">({...spread})</code> in JavaScript.</p>
<p>Link: <a href="https://www.richsnapp.com/article/2019/06-09-reduce-spread-anti-pattern">The reduce ({…spread}) anti-pattern</a></p>
Writing good git history2021-09-24T08:29:00+00:00http://roderick.dk//2021/09/24/writing-good-git-historyMorgan Roderickmorgan@roderick.dk<h2 id="writing-good-git-history">Writing good git history</h2>
<p>I firmly believe that writing a good git history, or <em>narrative</em> is important and worthwhile.</p>
<p>Future Developer will thanks us when they’re using <code class="language-plaintext highlighter-rouge">git log -S</code> to find a particular line or fragment, or when they’re using <code class="language-plaintext highlighter-rouge">git bisect</code> to figure out when and how a particular defect was introduced.</p>
<p>In the past I’ve given a talk about crafting a lovely git narrative. Thankfully, there’s no recording of that talk.</p>
<p>However, both of these two talks are recorded, and are much better than mine.</p>
<ul>
<li><a href="https://skillsmatter.com/skillscasts/13463-how-to-craft-your-commit-history">How to Craft Your Commit History</a> by Tatiana Stantonian</li>
<li><a href="https://www.youtube.com/watch?v=FQ4IdcrOUz0">Getting more from Git</a> by Alice Bartlett</li>
</ul>
<p>At the time of recording, both these people worked at Financial Times. It’s almost as if that organisation cares about good use of git… maybe I should apply to work there 🤔</p>
<p>Enjoy!</p>
Don't git pull, use git pull --rebase instead2021-09-17T09:21:00+00:00http://roderick.dk//2021/09/17/don-t-git-pull-use-git-pull-rebase-insteadMorgan Roderickmorgan@roderick.dk<h2 id="dont-git-pull-use-git-pull-rebase-instead">Don’t git pull, use git pull –rebase instead</h2>
<p>I can’t remember where I saw this first, as I configured it awhile ago.</p>
<p>Emmanouil Liakos shares a quick tip about how to use <code class="language-plaintext highlighter-rouge">git pull --rebase</code> and to configure your <code class="language-plaintext highlighter-rouge">git</code> to do this automagically.</p>
<p>Link: <a href="https://blog.manos-liakos.dev/rebase-vs-pull/">Don’t git pull, use git pull –rebase instead</a></p>
6 Reasons Why Asynchronous Communication Benefits Remote Teams2021-09-06T08:06:00+00:00http://roderick.dk//2021/09/06/6-reasons-why-asynchronous-communication-benefits-remote-teamsMorgan Roderickmorgan@roderick.dk<h2 id="6-reasons-why-asynchronous-communication-benefits-remote-teams">6 Reasons Why Asynchronous Communication Benefits Remote Teams</h2>
<blockquote>
<p>2020 has taken the concept of “new normal” and given it a whole new lease of life. It’s a word that’s been thrown around so often but it’s true – it’s permeated every aspect of our lives. Our once loud and proud office culture has been replaced with remote work; the ultimate “new normal” for businesses around the world. We’ve had to juggle family life and childcare with our usual working routines, shifting from video calls to email on a near-constant basis to stay “updated”.</p>
<p>But the growing popularity of remote work has led many to question this traditional way of communicating. This trend of replying instantly, also known as synchronous communication, can have a negative impact on productivity if used for too long. That’s why its counterpart – asynchronous communication – has started to gain traction amongst remote teams.</p>
<p>So, what’s the difference?</p>
</blockquote>
<p>Link: <a href="https://krisp.ai/blog/asynchronous-communication-benefits/">6 Reasons Why Asynchronous Communication Benefits Remote Teams</a></p>
An Incomplete Guide to Inclusive Language for Startups and Tech2021-08-24T08:57:00+00:00http://roderick.dk//2021/08/24/an-incomplete-guide-to-inclusive-language-for-startups-and-techMorgan Roderickmorgan@roderick.dk<h2 id="an-incomplete-guide-to-inclusive-language-for-startups-and-tech">An Incomplete Guide to Inclusive Language for Startups and Tech</h2>
<blockquote>
<p>Language is one of the most powerful tools we have as humans. It binds us. Instructs us. When used well, it creates a common understanding.</p>
<p>And it’s essential for creating an environment where everyone feels welcome and included.</p>
<p>Historically, language has left many out. Individuals and groups have been marginalized and discriminated against because of their culture, race and ethnicity, gender, sexual orientation, age, disability, socioeconomic status, appearance and more.</p>
<p>We can do better. Inclusive language seeks to treat all people with respect, dignity, and impartiality. It is constructed to bring everyone into the group and exclude no one.</p>
</blockquote>
<p>Link <a href="https://buffer.com/resources/inclusive-language-tech/">An Incomplete Guide to Inclusive Language for Startups and Tech</a></p>
Why you shouldn’t use @here on Slack2021-08-12T07:27:00+00:00http://roderick.dk//2021/08/12/why-you-shouldn-t-use-here-on-slackMorgan Roderickmorgan@roderick.dk<h2 id="why-you-shouldnt-use-here-on-slack">Why you shouldn’t use @here on Slack</h2>
<blockquote>
<h4 id="the-rules-according-to-graham">The Rules (according to Graham)</h4>
<ul>
<li>Don’t use <code class="language-plaintext highlighter-rouge">@here</code> unless it is truly relevant to everyone in a channel</li>
<li>Don’t use <code class="language-plaintext highlighter-rouge">@channel</code> unless there is a fire or a nuclear explosion that everyone needs to be aware of now</li>
<li>Use targeted Slack group mentions for getting a hold of stakeholders in a channel (i.e. <code class="language-plaintext highlighter-rouge">@support_</code> in the <code class="language-plaintext highlighter-rouge">#support</code> channel)</li>
<li>Use Slack as an asynchronous medium, not a synchronous one (assume people will not respond immediately, rather than the opposite)</li>
</ul>
</blockquote>
<p>Link: <a href="https://medium.com/vendasta/why-you-shouldnt-use-here-on-slack-e19e6c392502">Why you shouldn’t use @here on Slack</a></p>
JSDoc typings: all the benefits of TypeScript, with none of the drawbacks2021-07-20T12:30:00+00:00http://roderick.dk//2021/07/20/jsdoc-typings-all-the-benefits-of-typescript-with-none-of-the-drawbacksMorgan Roderickmorgan@roderick.dk<h2 id="jsdoc-typings">JSDoc typings</h2>
<p>An in depth exploration of how far you can get with using JSDoc (and the TypeScript compiler) without resorting to writing TypeScript or having a build step in your project.</p>
<p>Link: <a href="https://gils-blog.tayar.org/posts/jsdoc-typings-all-the-benefits-none-of-the-drawbacks/">JSDoc typings: all the benefits of TypeScript, with none of the drawbacks</a></p>
Two headphones with a Mac2021-05-24T09:21:00+00:00http://roderick.dk//2021/05/24/two-headphones-with-a-macMorgan Roderickmorgan@roderick.dk<h1 id="two-headphones-with-a-mac">Two headphones with a Mac</h1>
<p>My partner and I travelled back to Berlin from Las Palmas on a flight on Saturday. Since it was not a long haul flight, there would be no in-flight entertainment. We wanted to wanted to watch series and movies together using my computer, while both using noise cancelling headphones.</p>
<p>This turned out to be surprisingly easy to do.</p>
<p>I’ll be sure to do this for our journey, which I hope to make by train. That would make watching a couple of lectures or interesting talks from conferences quite enjoyable.</p>
<p>Link: <a href="https://eshop.macsales.com/blog/45707-how-to-use-two-pairs-of-bluetooth-headphones-simultaneously-on-mac/">How to use two pairs of bluetooth headphones simultaneously on mac</a></p>
trapped in the technologist factory2021-05-04T07:37:00+00:00http://roderick.dk//2021/05/04/trapped-in-the-technologist-factoryMorgan Roderickmorgan@roderick.dk<blockquote>
<p>This means startups don’t adopt new technologies despite their immaturity, they adopt them because of that immaturity. This drives a constant churn of novelty and obsolescence, which amplifies the importance of a technologist’s skillset, which drives startups to adopt new technologies.</p>
</blockquote>
<p>Link: <a href="https://ideolalia.com/essays/trapped-in-the-technologist-factory.html">trapped in the technologist factory</a></p>
Being glue2020-12-04T15:50:00+00:00http://roderick.dk//2020/12/04/being-glueMorgan Roderickmorgan@roderick.dk<blockquote>
<p>Stop interviewing, stop organising the off-sites, stop onboarding, stop fielding requests from users, stop anything that sounds like team building. Stop helping other people with their work. Archive mail. Quit slack channels. Do not curate the team roadmap.</p>
<p>Crucially: don’t catch things that are about to drop. That’s incredibly hard for a lot of us, but remember that the rest of the team already does this.</p>
<p>Stop being the unofficial lead. (If you’re in the same situation and you’re the official lead, consider stopping that too!)</p>
</blockquote>
<p>Link: <a href="https://noidea.dog/glue">Being glue</a></p>
The (extremely) loud minority2020-11-12T19:58:00+00:00http://roderick.dk//2020/11/12/the-extremely-loud-minorityMorgan Roderickmorgan@roderick.dk<blockquote>
<p>It’s understandable to think that JavaScript frameworks and their communities are eating the web because places like Twitter are <em>awash with very loud voices from said communities</em>.
Always remember that although a <strong>subset of the JavaScript community can be very loud</strong>, they represent a <strong>paltry portion of the web as a whole</strong>. This means that when <em>they</em> say something like “CSS sucks” — what they mean is “CSS sucks for a small subset of less than 1 percent of the web”.</p>
</blockquote>
<p>Link: <a href="https://hankchizljaw.com/wrote/the-(extremely)-loud-minority/">The (extremely) loud minority</a></p>
mdn.io, I'm feeling lucky2020-08-04T14:37:00+00:00http://roderick.dk//2020/08/04/mdn-io-i-m-feeling-luckyMorgan Roderickmorgan@roderick.dk<h1 id="mdnio-im-feeling-lucky">mdn.io, I’m feeling lucky</h1>
<p>I often need to look up details in the <a href="https://developer.mozilla.org/en-US/">Mozilla Developer Network documentation</a> (MDN). It’s a great resource, that keeps getting better every year.</p>
<p>A few years ago, I learned that lovely people have set up a very convenient “url shortener” / “search service” to do an “I’m feeling lucky” search on the MDN documentation.</p>
<p>In your browser’s URL bar, type <code class="language-plaintext highlighter-rouge">mdn.io/‰s</code>, where <code class="language-plaintext highlighter-rouge">%s</code> is your search string. Hit <kbd>Enter</kbd> and arrive at the best matching page on MDN.</p>
<p>Example:</p>
<p><code class="language-plaintext highlighter-rouge">mdn.io/function.apply</code> takes you to <code class="language-plaintext highlighter-rouge">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply</code></p>
<p>I use this as my primary way of navigating MDN.</p>
<p>You can <a href="https://github.com/lazd/mdn.io">read the source of mdn.io on GitHub</a>.</p>
Using HTTPie with mkcert2020-07-28T10:03:00+00:00http://roderick.dk//2020/07/28/using-httpie-with-mkcertMorgan Roderickmorgan@roderick.dk<h2 id="using-httpie-with-mkcert">Using HTTPie with mkcert</h2>
<p>In order to get the development environment on <code class="language-plaintext highlighter-rouge">localhost</code> closer to the production environment, I’m using HTTPS on <code class="language-plaintext highlighter-rouge">localhost</code>. This helps me with discovering bugs much earlier, which saves a lot of time.</p>
<p>I use the <a href="https://blog.filippo.io/mkcert-valid-https-certificates-for-localhost/">excellent tool <code class="language-plaintext highlighter-rouge">mkcert</code></a> for managing the certificates locally. <code class="language-plaintext highlighter-rouge">mkcert</code> is built exactly for this purpose and removes most of the friction.</p>
<p>I regularly use <a href="https://httpie.org"><code class="language-plaintext highlighter-rouge">httpie</code></a> to interact with HTTP servers.</p>
<p>However, <code class="language-plaintext highlighter-rouge">httpie</code> doesn’t know about about the certificate authority installed locally by <code class="language-plaintext highlighter-rouge">mkcert</code>, so we’ll have to help it a bit.</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http <span class="nt">--verify</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span>mkcert <span class="nt">--CAROOT</span><span class="si">)</span><span class="s2">/rootCA.pem"</span> https://localhost.myapp.org:8443/some/path
</code></pre></div></div>
<p>Since I don’t want to type that on every invocation, I’ve added it as an alias in <code class="language-plaintext highlighter-rouge">.bash_profile</code>.</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">alias </span><span class="nv">http</span><span class="o">=</span><span class="s2">"http --verify=</span><span class="se">\"</span><span class="si">$(</span>mkcert <span class="nt">--CAROOT</span><span class="si">)</span><span class="s2">/rootCA.pem</span><span class="se">\"</span><span class="s2">"</span>
</code></pre></div></div>
<p>And then I can use <code class="language-plaintext highlighter-rouge">httpie</code> as normal</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http https://localhost.myapp.org:8443/some/path
</code></pre></div></div>
Link: Teams Solve Problems Faster When They’re More Cognitively Diverse2020-01-25T12:23:00+00:00http://roderick.dk//2020/01/25/link-teams-solve-problems-faster-when-they-re-more-cognitively-diverseMorgan Roderickmorgan@roderick.dk<blockquote>
<p>If cognitive diversity is what we need to succeed in dealing with new, uncertain, and complex situations, we need to encourage people to reveal and deploy their different modes of thinking. We need to make it safe to try things multiple ways. This means leaders will have to get much better at building their team’s sense of psychological safety.</p>
</blockquote>
<p>Link: <a href="https://hbr.org/2017/03/teams-solve-problems-faster-when-theyre-more-cognitively-diverse">Teams Solve Problems Faster When They’re More Cognitively Diverse</a></p>
Tips for joyful video calls2020-01-19T14:50:00+00:00http://roderick.dk//2020/01/19/tips-for-joyful-video-callsMorgan Roderickmorgan@roderick.dk<h1 id="tips-for-joyful-video-calls">Tips for joyful video calls</h1>
<p>A lot of my work in the last decade has been with partially or entirely distributed teams. I expect that to be the case going forwards as more and more software engineering work switches to distributed / remote teams.</p>
<p>To communicate with other members in the distributed team, I use video calls for:</p>
<ul>
<li>pair programming</li>
<li>the daily standup call</li>
<li>1-1s</li>
<li>the weekly leadership call</li>
<li>company all hands / town hall</li>
<li>catching up with friends</li>
</ul>
<p>This is post is for sharing some things I’ve learned that give me a more joyful experience with video calls. Maybe some of the tips can improve your experience.</p>
<p>First, some tips specific to using <a href="https://zoom.us">Zoom.us</a>. Then some tips that apply to all video calls, when working in a distributed team.</p>
<h2 id="zoom-screen-settings">Zoom: screen settings</h2>
<p>In the General tab of settings, you’ll find the screen settings. These are my recommended settings.</p>
<p><img src="/images/joyful-video-calls/screen-settings.png" alt="zoom screen settings" /></p>
<h3 id="use-dual-monitors">“Use dual monitors”</h3>
<p>If you ever use more than one monitor, this setting is great. It allows you to keep one window with the feed of the participants and one window with anything that is being shared by or with you.</p>
<p>When you only have one screen connected, things are as if this setting was off. Set and forget. Sorted.</p>
<h3 id="full-screen-settings">Full screen settings</h3>
<p>You’ll want the two settings for full screen <strong>turned off</strong>. Switching between applications when Zoom is in full screen mode is confusing and frustrating. You’ll end up back in the main window, not the call and will be looking for ways to switch between the zoom windows.</p>
<p>Just turn these off.</p>
<h3 id="maximize-zoom-window-when-a-participant-shares-their-screen">“Maximize Zoom window when a participant shares their screen”</h3>
<p>This feature makes up for the confusing full screen support. This great for calls that have any kind of screen sharing.</p>
<p>You’ll love it. Set and forget.</p>
<h3 id="scale-to-fit-shared-content-to-zoom-window">“Scale to fit shared content to Zoom window”</h3>
<p>This is a good default for most screen sharing calls. You can always adjust the scaling in individual calls, though I rarely need to.</p>
<h2 id="zoom-video-settings">Zoom: Video settings</h2>
<p><img src="/images/joyful-video-calls/video-settings.png" alt="zoom video settings" /></p>
<p>There are few interesting things to say about the video settings.</p>
<h3 id="mirror-my-video">“Mirror my video”</h3>
<p>Does what it says on the tin, makes it feel like you’re looking into a mirror, which is how we’re used to seeing ourselves.</p>
<h3 id="turn-off-my-video-when-joining-a-meeting">“Turn off my video when joining a meeting”</h3>
<p>In my circles, it is considered good form to enter meetings with video feed turned off and only turn it on when you’ve settled in and are ready to be seen by the other participants.</p>
<h2 id="zoom-audio-settings">Zoom: Audio settings</h2>
<p><img src="/images/joyful-video-calls/audio-settings.png" alt="zoom audio settings" /></p>
<h3 id="join-audio-by-computer-when-joining-a-meeting">“Join audio by computer when joining a meeting”</h3>
<p>If you’re like me, and rarely dial in using your computer, you’ll want to use the audio from the computer (and not some phone call). This should be on, to save you from selecting audio source every time you join a call.</p>
<h3 id="mute-microphone-when-joining-a-meeting">“Mute microphone when joining a meeting”</h3>
<p>Just like “Turn off my video when joining a meeting”, this setting is considered good form. Once you’re ready for other participants to hear sound from your location, you can turn it on.</p>
<h3 id="do-not-prompt-to-join-audio-when-joining-a-meeting-using-3rd-party-audio">“Do not prompt to join audio when joining a meeting using 3rd party audio”</h3>
<p>This is a complement to “Join audio by computer when joining a meeting”. If you’re already dialed in for audio on your phone, you know what you’re doing and Zoom won’t get in your way.</p>
<h3 id="press-and-hold-space-key-to-temporarily-unmute-yourself">“Press and hold SPACE key to temporarily unmute yourself”</h3>
<p><a href="https://en.wikipedia.org/wiki/Push-to-talk">Push-to-talk</a> should be familiar to anyone using walkie talkies or gamers that have participated in an <a href="https://en.wikipedia.org/wiki/Massively_multiplayer_online_role-playing_game">MMOPRG</a>, where many people are trying to have a conversation at the same time.</p>
<p>When muted, you can press and hold <kbd>SPACE</kbd> key to temporarily unmute yourself. In group discussions, it is often best to keep your audio input muted, until you actually want to say something.</p>
<p>I use this setting all the time.</p>
<h2 id="use-a-good-microphone">Use a good microphone</h2>
<p>Avoid using your laptop’s built-in microphone(s).</p>
<p>The microphones built into laptops are omnidirectional and capture a lot of backgound noise, even the echo of your voice in an otherwise silent room.</p>
<p>A dedicated, high quality microphone would be the gold standard, but is also unnecessary unless you spend most of your day on calls or do professional recording of voice, for podcasts, etc.</p>
<p>Headsets and headphones (the ones that came with your smartphone) can be good compromise. They give significant improvement of the audio for the people you’re communicating with. We want to be understood, why else join the call at all?</p>
<h3 id="microphone-recommendations">Microphone recommendations</h3>
<ul>
<li><a href="https://www.bluedesigns.com/products/yeti/">Blue yeti</a> — probably the best microphone I’ve had the pleasure of using. These are amazing. Recommeded for when you have a dedicated desk and are willing to spend a little time to learn to use them. It is possible to configure them for multiple participants, read the manual.</li>
<li><a href="https://www.jabra.com/business/speakerphones/jabra-speak-series">Jabra Speak</a> — this series of speakerphones are great for conference calls, especially if there are two or more participants in the same room. Also great, if you don’t feel like wearing headphones</li>
<li>Most noise cancelling headphones have good, built-in microphone for calls</li>
<li><a href="https://www.apple.com/shop/product/MNHF2AM/A/earpods-with-35-mm-headphone-plug">Apple EarPods</a> — for the sound quality they provide, I think these are a great, affordable choice.</li>
</ul>
<h2 id="avoid-making-calls-in-locations-with-a-flutter-echo">Avoid making calls in locations with a flutter echo</h2>
<p>Sadly, a lot of office space, meeting rooms and in-office “phone booths” have really terrible acoustic properties when it comes to understanding human voices.</p>
<p>One phenomenon that you often experience in these locations is a flutter echo.</p>
<blockquote>
<p>Flutter echoes result from repeated sound reflections between parallel walls with insufficient absorption; they are mostly perceived as disturbing and can noticeably impair speech intelligibility.</p>
</blockquote>
<p>See <a href="https://download.spsc.tugraz.at/thesis/BA_Giller.pdf">Prevention of Flutter Echoes in Architecturally Demanding Spaces
</a></p>
<p>It is very easy to detect a flutter echo. Wait for a quiet moment, clap a few times with seconds between each clap. Observe how long the clap echoes in the room.</p>
<p>Generally, the bigger the room, the worse the flutter echo gets and speech intelligibility in worsened.</p>
<p>Multiple sound sources in the same room amplify this problem.</p>
<p>Welcome to the open office plan.</p>
<p><img src="/images/joyful-video-calls/this-is-fine.jpg" alt="this is fine comic" /></p>
<p>The effect of the flutter echo on speech intelligibility is even worse for somone trying to understand you through a microphone in an echoey room.</p>
<p>Even the best microphones cannot cope with bad acoustics. If they could, there wouldn’t be an enitre industry dedicated towards building sound recording studios.</p>
<p><strong>Avoid making calls in locations with a flutter echo.</strong></p>
<p>Create or seek out locations with more human-friendly acoustics. You’ll be happier and so will the participants in your call.</p>
<h2 id="use-ai-noise-cancelling">Use AI noise cancelling</h2>
<p>Someone at work introduced me to <a href="https://ref.krisp.ai/u/u0f5a22bc8?utm_source=refprogram&utm_campaign=41297&locale=en-GB">krisp.ai</a>, which is a great little application that runs on your computer and filters out noise in audio streams in real time.</p>
<p>The results are truly impressive: people in my calls rarely notice the street noise invading the co-working space or the occasional ambulance passing by.</p>
<p>krips doesn’t do well with flutter echoes of voices, so the above recommendation still stands: avoid flutter echoes.</p>
<p>krisp can even do noise cancelling on the input stream from the remote end.</p>
<p><a href="https://ref.krisp.ai/u/u0f5a22bc8?utm_source=refprogram&utm_campaign=41297&locale=en-GB">Sign up for a free trial of krisp using my link</a>, and we both get extension on our free trials :)</p>
HWC Berlin, 2020-01-292020-01-19T11:28:00+00:00http://roderick.dk//2020/01/19/hwc-berlin-2020-01-29Morgan Roderickmorgan@roderick.dk<h2 id="hwc-berlin-2020-01-29">HWC Berlin, 2020-01-29</h2>
<p><img src="/images/homebrew-website-club.jpg" alt="Homebrew Website Club retro graphics image" /></p>
<p>On Wednesday 2020-01-29 at 18.30 there will be another <a href="https://indieweb.org/Homebrew_Website_Club">Homebrew Website Club</a> in Berlin.</p>
<h3 id="venue">Venue</h3>
<p>The event will be hosted in the eyeo office.</p>
<p><a href="https://goo.gl/maps/DxVLE6f6xVh2gtSAA">
Zimmerstraße 69<br />
10117 Berlin<br />
Germany<br />
</a></p>
<blockquote>
<p>Ring eye/o GmbH doorbell which is located in Zimmerstr. 69, between ishin and Viet bowl. The door on the street is always open, the next one isn’t, and the office is at the first floor on the left</p>
</blockquote>
<p>There will be a few signs with Homebrew Website Club on them, to make it easy to find the right door.</p>
<h3 id="food--drink">Food & drink</h3>
<p>Bring your own, or eat before. There is a working kettle and microwave in the kitchen.</p>
<h3 id="structure">Structure</h3>
<p>We will try to follow the <a href="https://indieweb.org/Homebrew_Website_Club#structure">recommended structure</a>. This means we will have a “Quiet Writing Hour”, which I am very excited about.</p>
<p>Hope to see you there!</p>
Available for hire!2020-01-16T10:59:00+00:00http://roderick.dk//2020/01/16/available-for-hireMorgan Roderickmorgan@roderick.dk<h1 id="available-for-hire">Available for hire!</h1>
<p>Full-stack software engineer with a bent towards web standards, quality and longevity of applications available for hire.</p>
<p>I have worked professionally as a software engineer since the late 90s. I’ve seen a good breadth and depth of applications over the years, having worked on green field, established and legacy applications.</p>
<p>I enjoy improving existing applications as much as working on green field applications.</p>
<h2 id="happiness-looks-like">Happiness looks like</h2>
<h3 id="organisation">Organisation</h3>
<ul>
<li><a href="https://www.forbes.com/sites/rasmushougaard/2019/03/05/the-power-of-putting-people-first/">People</a> <a href="https://www.inc.com/t-mobile/benefits-of-a-people-first-culture.html">first</a> <a href="https://blog.walkingthetalk.com/archetype-in-focus-the-people-first-culture">organisations</a></li>
<li>Diversity and inclusion</li>
<li>Effective, open, bi-directional communication (<a href="https://en.wikipedia.org/wiki/Nonviolent_Communication">NVC</a>)</li>
</ul>
<h3 id="product--project">Product / project</h3>
<ul>
<li><a href="https://producttribe.com/ux-design/user-centered-design-guide">Users</a> <a href="https://www.interaction-design.org/literature/article/5-stages-in-the-design-thinking-process">first</a> <a href="https://medium.com/@jaf_designer/designing-digital-products-user-first-bbf6be44ac3a">thinking</a></li>
<li><a href="https://www.amazon.com/User-Story-Mapping-Discover-Product/dp/1491904909/">User Story Mapping</a></li>
<li><a href="https://lithespeed.com/throw-agile-estimation-vs-noestimates/">NoEstimates</a>, <a href="https://medium.com/serious-scrum/the-logic-of-noestimates-4238e0be3bb6">forecasting</a></li>
<li>Open minded pragmatism</li>
</ul>
<h3 id="technology">Technology</h3>
<ul>
<li><a href="https://leanweb.dev">Lean Web</a></li>
<li><a href="https://en.wikipedia.org/wiki/Progressive_enhancement">Progressive Enhancement</a></li>
<li><a href="https://en.wikipedia.org/wiki/Web_standards">Web standards</a></li>
<li><a href="https://www.ecma-international.org/ecma-262/">ECMA-262</a></li>
<li><a href="https://www.w3.org/WAI/">Accessiblity (WAI)</a></li>
<li><a href="https://css-tricks.com/snippets/css/system-font-stack/">System fonts</a></li>
</ul>
<h2 id="what-i-am-hoping-to-find-in-my-next-role">What I am hoping to find in my next role</h2>
<p>I am hoping to find a diverse team in a diverse organisation (or one that is trending that way). I regularly contribute to open source and hope to continue that work in my next role, perhaps in combination with mentoring of other engineeers.</p>
<h2 id="ambitions">Ambitions</h2>
<p>My personal ambitions are not tied to specific outcomes, but to keep moving in a positive direction. To keep learning and growing.</p>
<p>Having said that, I am looking for opportunities that will allow me to pursue a role as Principal Engineer or Head of Engineering.</p>
<h2 id="locations">Locations</h2>
<ul>
<li>Berlin, Germany</li>
<li>Las Palmas de Gran Canaria, Spain</li>
<li>Remote</li>
</ul>
<h2 id="interested">Interested?</h2>
<p>Grab a <a href="http://roderick.dk/cv/cv.pdf">PDF version of my CV</a> and get in touch.</p>
Link: Putting devs before users: how frameworks destroyed web performance2020-01-11T12:34:00+00:00http://roderick.dk//2020/01/11/link-putting-devs-before-users-how-frameworks-destroyed-web-performanceMorgan Roderickmorgan@roderick.dk<blockquote>
<p>A well built, performant website can be created with any framework or type of technology in existence. It may be harder with some than others, but it can be done.</p>
<p><strong>The issue is the developer and designer mindset in many companies.</strong></p>
<p>With said mindset being that web development and design should be ‘fun’. I fully believe a lot of developers and software enginers put their job satisfaction above their users or customers.</p>
</blockquote>
<p>Link: <a href="https://uxdesign.cc/putting-devs-before-users-how-frameworks-destroyed-web-performance-6b2c2a506aab">Putting devs before users: how frameworks destroyed web performance</a></p>
plete: 2KB autocomplete with zero dependencies2020-01-07T21:43:00+00:00http://roderick.dk//2020/01/07/plete-2kb-autocomplete-with-zero-dependenciesMorgan Roderickmorgan@roderick.dk<h2 id="plete-2kb-autocomplete-with-zero-dependencies">plete: 2KB autocomplete with zero dependencies</h2>
<p>For a project at work, we needed an autocomplete component, that meets the following criteria:</p>
<ol>
<li>zero dependencies</li>
<li>decent WAI-ARIA / accessibility support</li>
<li>reasonable license</li>
<li>good test coverage</li>
<li>remote filtering</li>
<li>custom rendering of options</li>
<li>separation of presentation from the value selected</li>
</ol>
<p>I am a firm believer in open web standards. Whenever feasible, I prefer to <a href="https://leanweb.dev">apply lean web principles and leverage the full feature set of the web platform</a>.</p>
<p>While there is a <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist"><code class="language-plaintext highlighter-rouge"><datalist></code> element</a> in the HTML Living Standard spec, it is not up to par for the requirements listed above.</p>
<p>The first four requirements are easily met by <code class="language-plaintext highlighter-rouge"><datalist></code>, as it’s native to the platform. However, the last three requirements cannot be met by <code class="language-plaintext highlighter-rouge"><datalist></code>, so it is not relevant for my application.</p>
<p><a href="http://lea.verou.me/2015/02/awesomplete-2kb-autocomplete-with-zero-dependencies/">Lea Verou came to similar conclusions</a>, and created <a href="http://leaverou.github.io/awesomplete/"><code class="language-plaintext highlighter-rouge">Awesomeplete</code></a>, which has been a great inspiration.</p>
<p>The remote filtering requirement is unavoidable. For our project, the autocomplete component will have to filter multiple datasets, each having more than 30,000 entries. These datasets are expected to grow. There simply is no <em>responsible</em> way to send that much data to the client to be used in a <code class="language-plaintext highlighter-rouge"><datalist></code> element.</p>
<p>I spent some time surveying the autocomplete component landscape as of late 2019, hoping to find a suitable component. None was found.</p>
<p>For a few days, I considered contributing async/remote filtering to <a href="http://leaverou.github.io/awesomplete/"><code class="language-plaintext highlighter-rouge">Awesomeplete</code></a>, but thought it would be too invasive. I also considered contributing accessiblity improvements and test coverage to other candidates, but decided against it.</p>
<p>Like Lea, I eventually came to the conclusion that the best path forwards, would be write my own autocomplete component.</p>
<p>I give you <a href="https://plete.dev"><code class="language-plaintext highlighter-rouge">plete</code></a>, “a vanilla js autocomplete component that supports remote filtering.”</p>
<p>Documentation at <a href="https://plete.dev">https://plete.dev</a>.</p>
HWC Berlin, 2020-01-152020-01-07T19:05:00+00:00http://roderick.dk//2020/01/07/hwc-berlin-2020-01-15Morgan Roderickmorgan@roderick.dk<h2 id="hwc-berlin-2020-01-15">HWC Berlin, 2020-01-15</h2>
<p><img src="/images/homebrew-website-club.jpg" alt="Homebrew Website Club retro graphics image" /></p>
<p>On Wednesday 2020-01-15 at 18.30 there will be another <a href="https://indieweb.org/Homebrew_Website_Club">Homebrew Website Club</a> in Berlin.</p>
<h3 id="venue">Venue</h3>
<p>The event will be hosted in the eyeo office.</p>
<p><a href="https://goo.gl/maps/DxVLE6f6xVh2gtSAA">
Zimmerstraße 69<br />
10117 Berlin<br />
Germany<br />
</a></p>
<blockquote>
<p>Ring eye/o GmbH doorbell which is located in Zimmerstr. 69, between ishin and Viet bowl. The door on the street is always open, the next one isn’t, and the office is at the first floor on the left</p>
</blockquote>
<p>There will be a few signs with Homebrew Website Club on them, to make it easy to find the right door.</p>
<h3 id="food--drink">Food & drink</h3>
<p>Bring your own, or eat before. There is a working kettle and microwave in the kitchen.</p>
<h3 id="structure">Structure</h3>
<p>We will try to follow the <a href="https://indieweb.org/Homebrew_Website_Club#structure">recommended structure</a>. This means we will have a “Quiet Writing Hour”, which I am very excited about.</p>
<p>Hope to see you there!</p>
Homebrew Website Club, 2019-10-302019-10-29T10:58:00+00:00http://roderick.dk//2019/10/29/homebrew-website-club-2019-10-30Morgan Roderickmorgan@roderick.dk<h2 id="homebrew-website-club-2019-10-30">Homebrew Website Club, 2019-10-30</h2>
<p><img src="/images/homebrew-website-club.jpg" alt="Homebrew Website Club retro graphics image" /></p>
<p>The next <a href="https://indieweb.org/Homebrew_Website_Club">Homebrew Website Club</a> in Berlin will be on October 30th at 18.30.</p>
<h3 id="venue">Venue</h3>
<p>We will be hosted by my former client, employer <a href="https://zalando.de">Zalando SE</a>, in one of their offices.</p>
<p><a href="https://www.google.com/maps/place/M%C3%BChlenstra%C3%9Fe+25,+10243+Berlin/@52.505676,13.4408892,17.5z/data=!4m5!3m4!1s0x47a84e4f6a2213e3:0xadde84f313f308f9!8m2!3d52.5054036!4d13.4398896">Zalando SE<br />
Mühlenstraße 25<br />
10243 Berlin<br /></a></p>
<p>There will be a few signs with Homebrew Website Club on them, to make it easy to find and the front desk know we’re coming.</p>
<h3 id="food--drink">Food & drink</h3>
<p>Zalando are treating us to pizza and drinks 👍</p>
<h3 id="structure">Structure</h3>
<p>We will try to follow the <a href="https://indieweb.org/Homebrew_Website_Club#structure">recommended structure</a>. This means we will have a “Quiet Writing Hour”, which I am very excited about.</p>
<p>Hoping to see you there!</p>
HWC, 2019-10-022019-09-27T10:29:00+00:00http://roderick.dk//2019/09/27/hwc-2019-10-02Morgan Roderickmorgan@roderick.dk<h2 id="homebrew-website-club-2019-10-02">Homebrew Website Club, 2019-10-02</h2>
<p><img src="/images/homebrew-website-club.jpg" alt="Homebrew Website Club retro graphics image" /></p>
<p>The next <a href="https://indieweb.org/Homebrew_Website_Club">Homebrew Website Club</a> in Berlin will be on October 2nd at 18.30.</p>
<h3 id="venue">Venue</h3>
<p><a href="https://www.iamfy.co">Fy!</a><br />
Hinterhof Rechts - 5’<br />
Glogauer Strasse 5<br />
10999 Berlin</p>
<p>There will be a few signs with Homebrew Website Club on them, to make it easy to find.</p>
<h3 id="structure">Structure</h3>
<p>We will try to follow the <a href="https://indieweb.org/Homebrew_Website_Club#structure">recommended structure</a>. This means we will have a “Quiet Writing Hour”, which I am very excited about.</p>
<p>See you there?</p>
The Lean Web book2019-09-17T09:11:00+00:00http://roderick.dk//2019/09/17/the-lean-web-bookMorgan Roderickmorgan@roderick.dk<h2 id="the-lean-web-book">The Lean Web book</h2>
<p>The <a href="https://leanweb.dev/ebook/">Lean Web book</a> is very good and recommended for anyone buidling things for the web.</p>
<p><a href="https://gomakethings.com">Chris Ferdinandi</a> has managed to capture many of the thoughts and ideas, that many of us of have been thinkging about since the “JavaScript revolution” started.</p>
<p>There’s <a href="https://leanweb.dev/talk/">a talk</a> too, if you’re more into that.</p>
<p>Via <a href="https://adactio.com/links/15817">adactio</a></p>
Why should I self-publish on the web?2019-09-13T00:00:00+00:00http://roderick.dk//2019/09/13/why-should-i-self-publishMorgan Roderickmorgan@roderick.dk<h2 id="why-should-i-self-publish-on-the-web">Why should I self-publish on the web?</h2>
<p>Here’s yet another example of what can happen, when you give control over your content to 3rd parties.</p>
<p>They put up a pay wall (or the equivalent thereof, you pay with your identity):</p>
<p><img src="/images/medium-pay-wall.png" alt="Medium's pay wall" /></p>
<p>Medium has decided that their commercial goals are more important than the author’s need to have their audience able to read their content.</p>
<p>This is far from a unique case, nor one that is specific to Medium. But, it beautifully illustrates why we need to be in control of our own content on the web.</p>
<p>If you’re in Berlin and interested in self-publishing on the web, then join us at <a href="/2019/09/06/homebrew-website-club-berlin/">Homebrew Website Club</a>.</p>
<p>If you’re not in Berlin, then perhaps one of the other <a href="https://indieweb.org/Homebrew_Website_Club">Homebrew Website Club chapters</a> could work for you, or you could start one in your area or create a virtual chapter.</p>
A couple of things about the climate crisis2019-09-11T00:00:00+00:00http://roderick.dk//2019/09/11/a-couple-of-things-about-the-climate crisisMorgan Roderickmorgan@roderick.dk<h2 id="a-couple-of-things-about-the-climate-crisis">A couple of things about the climate crisis</h2>
<p>It seems the world is finally waking up to the fact that we have a climate crisis.</p>
<p>We owe a great thanks to <a href="https://en.wikipedia.org/wiki/Greta_Thunberg">Greta Thunberg</a> and all the children and young adults that are striking to keep society and governments aware of the crisis.</p>
<h3 id="what-can-we-do">What can we do?</h3>
<p>I don’t think of myself as a great world citizen and am trying to do better. Here are a couple of things that I think are worth doing in pursuit of that goal.</p>
<h4 id="join-the-global-climate-strike">Join the Global Climate Strike</h4>
<p>On September 20th and 27th there will be <a href="https://globalclimatestrike.net">global climate strikes</a>, where they’re encouraging everyone to attend.</p>
<p>You’ll find me at Brandenburger Tor in Berlin, Germany.</p>
<h4 id="offset-your-emissions">Offset your emissions</h4>
<p>I am using <a href="https://www.atmosfair.de/en/">atmosfair</a> to offset the emissions from my flights. I’ve offset all my flights from 2018 onwards, and will continue to do so until it is no longer needed (or I stop flying).</p>
<p>If you can afford to fly, you can afford to offset your emissions.</p>
Homebrew Website Club, Berlin2019-09-06T00:00:00+00:00http://roderick.dk//2019/09/06/homebrew-website-club-berlinMorgan Roderickmorgan@roderick.dk<h2 id="homebrew-website-club-berlin">Homebrew Website Club, Berlin</h2>
<p><img src="/images/homebrew-website-club.jpg" alt="Homebrew Website Club retro graphics image" /></p>
<blockquote>
<p>Homebrew Website Club is a growing world-wide network of meetups for everyone who wants to take back their web experience from social media silos, and own their online identities & content, or just want support with blogging!</p>
<p>Want to blog more but struggling with:</p>
<ul>
<li>ideas</li>
<li>momentum</li>
<li>confidence</li>
<li>writing skills</li>
</ul>
<p>Join a gathering of like-minded people and get friendly support with writing, creating, and anything to do with using and improving your own website!</p>
</blockquote>
<p>In collaboration with a few other web afficionados, I will try to restart <a href="https://indieweb.org/Homebrew_Website_Club">Homebrew Website Club</a> in Berlin.</p>
<h3 id="what-to-expect">What to expect?</h3>
<p>We will probably try to follow <a href="https://indieweb.org/Homebrew_Website_Club#Structure">the suggested structure</a>, as much as organising and limitations of the venue allows for.</p>
<p>Since this will be the first event in a few years, and with new organisers, expect for it to take a few events for us to find the format that works in this group.</p>
<h3 id="who-is-it-for">Who is it for?</h3>
<p>Everyone!</p>
<blockquote>
<p>Homebrew Website Club is a growing world-wide network of meetups for everyone who wants to take back their web experience from social media silos, and own their online identities & content, or just want support with blogging!</p>
</blockquote>
<h3 id="when">When?</h3>
<p>The first event will be on <a href="https://indieweb.org/events/2019-09-18-homebrew-website-club">Wednesday, 2019-09-18</a> from 18.30.</p>
<h3 id="venue">Venue</h3>
<p>The event will be hosted by <a href="https://www.signavio.com">Signavio</a></p>
<p><a href="https://www.signavio.com">Signavio</a><br />
Kurfürstenstraße 111,<br />
10787 Berlin</p>
Choose Boring Technology2019-09-01T21:14:00+00:00http://roderick.dk//2019/09/01/choose-boring-technologyMorgan Roderickmorgan@roderick.dk<h2 id="choose-boring-technology">Choose Boring Technology</h2>
<blockquote>
<p>If you’re giving individual teams (or gods help you, individuals) free reign to make local decisions about infrastructure, you’re hurting yourself globally.
It’s freedom, sure. You’re handing developers a ball of chain and padlocks and telling them to feel free to bind themselves to the operational toil that will be with them until the sweet release of grim death.</p>
</blockquote>
<p>– Dan McKinley in <a href="http://boringtechnology.club/">Choose Boring Technology</a></p>
<p>If your work is in creating and maintaining software, you should read this.</p>
Pick Your Culture First and Foremost2019-09-01T20:20:00+00:00http://roderick.dk//2019/09/01/pick-your-culture-first-and-foremostMorgan Roderickmorgan@roderick.dk<blockquote>
<h3 id="pick-your-culture-first-and-foremost">Pick Your Culture First and Foremost</h3>
<p>Learning how to pick your battles is also about learning how to pick your company and pick your boss, because your job really shouldn’t be all or even mostly about battles. Going through this exercise of solving an unowned problem is fun once in a while, but it’s a real drag when you feel like you’re surrounded by such problems, you can’t ignore them, and you’re powerless to fix them. That is a good sign that it’s time to find a new job, preferably somewhere that is more in tune with your way of doing things. Life is so much more fun when you have people around you that you trust to solve problems, even the problems you have a lot of opinions about.</p>
</blockquote>
<p>– Camille Fournier, in <a href="https://medium.com/@skamille/opp-other-peoples-problems-d7eb174724ee">OPP (Other People’s Problems)</a>, via <a href="https://simonwillison.net">Simon Willison</a></p>
Red bell, green bike2019-08-31T00:00:00+00:00http://roderick.dk//2019/08/31/red-bell-green-bikeMorgan Roderickmorgan@roderick.dk<h2 id="red-bell-green-bike">Red bell, green bike</h2>
<p>Some years ago, when I still lived in Malmö, I bought a <a href="https://www.pilencykel.se/en/pilen-lyx-gents-duragreen-brooks-b66-brown/">Pilen Lyx </a> bicycle. Actually, I ended up buying two. The first one got stolen within the first year, probably by the gang of bicycle thieves that were caught with a van full of stolen, new bicycles within a year.</p>
<p>Anyway, my <em>second</em> <a href="https://www.pilencykel.se/en/pilen-lyx-gents-duragreen-brooks-b66-brown/">Pilen Lyx</a> looked like this:</p>
<p><img src="/images/2019-08-31/1-800.jpg" alt="My nearly new pilen bicycle" /></p>
<p>I love this bicycle. Of the bicycles I’ve owned, this is my favourite.</p>
<p>When I moved to Berlin, it moved with me. We’ve been all over the city together. In the company of Tammi and her merry crew of friends, we have even ventured out of the city.</p>
<p>One summer I lent the bicycle to a cousin of a friend; a young woman visiting Berlin from North America. She explored the city on the bicycle and took it to places it had never seen before. It became the transportation backbone of her summer romance in Berlin. I couldn’t have been happier.</p>
<p>Coincidentally, the same summer my <a href="https://en.wikipedia.org/wiki/Saab_9-5#Aero">Saab 9-5 Aero</a> was the chosen vehicle to take friends to a hospital in Skåne, Sweden, where they would give birth to their first child. A story for another day.</p>
<h3 id="back-in-berlin">Back in Berlin…</h3>
<p>Bicycle paths in Berlin are not always marked well. Well meaning, even native Berliner, pedestrians wander into the bike lanes all the time. It is what it is. A quick signal with the bell followed by a smile, usually clears up the bike path quickly. No harm, no foul.</p>
<p>A few weeks ago, while enjoying riding at speed down Danziger Strasse, the Pilen branded bell on my bicycle rattled loose, jumped into the street and shattered everywhere.</p>
<p>Being bell-less might work in smaller/other cities. Not so much here. Losing the ability to produce an audible warning signal on your bike in Berlin makes things <em>challenging</em>.</p>
<p>Luckily, we have plenty of friendly bicycle shops. I visited one of my local ones, and got a new loud bell fitted on my trusty bicycle.</p>
<p><img src="/images/2019-08-31/2-800.jpg" alt="Red bell, green bike" /></p>
<p>I wasn’t planning on getting a red bell, but it was the best colour they had of the really <strong>loud</strong> ones. I think the contrast works well with the green bicycle. It’ll certainly make it easy to find my bicycle in a cluster of bicycles.</p>
<p><img src="/images/2019-08-31/3-800.jpg" alt="Red bell stands out in a group of bicycles" /></p>
<p>Once again, Berlin should be able to hear me coming!</p>
Avoid double exclamations in JavaScript2018-09-10T00:00:00+00:00http://roderick.dk//2018/09/10/avoid-double-exlamationsMorgan Roderickmorgan@roderick.dk<h2 id="avoid-double-exclamations-in-javascript">Avoid double exclamations in JavaScript</h2>
<p>There is a common misuse of JavaScript’s type coercion that I see in code reviews. It’s the terse use of two exclamation marks to convert a <a href="https://developer.mozilla.org/en-US/docs/Glossary/Truthy">truthy</a> value to a <code class="language-plaintext highlighter-rouge">Boolean</code> value.</p>
<p>Here’s an example:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">someValue</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">I like apple pie</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">userLikesPie</span> <span class="o">=</span> <span class="o">!!</span><span class="nx">someValue</span><span class="p">;</span>
<span class="c1">// userLikesPie is now `true`</span>
</code></pre></div></div>
<p>I think this is a misuse for two reasons:</p>
<ol>
<li>it obscures intent for people that are not fully aware of JavaScript coercion</li>
<li>it is easy to introduce a mistake that can be difficult to detect</li>
</ol>
<p>As for the first point, you could argue that it is the reader’s responsibility to educate themself in order to fully understand the code. However, there isn’t much value in winning that argument if the reader misunderstands the code and introduces new bugs.</p>
<p>Even seasoned writers of the JavaScript will be able to casually introduce subtle and difficult to find regressions, when playing around with the code in order to understand how it behaves. These changes can hide in a large diff and sneak past even the most diligent code reviews.</p>
<p>Let’s illustrate with an example:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// as in the example above:</span>
<span class="c1">// the first exclamation mark coerces and negates a truthy expression to `false`</span>
<span class="c1">// second exclamation mark negates `false` to `true`</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!!</span><span class="nx">someValue</span> <span class="o">&&</span> <span class="nx">someOtherValue</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// some action</span>
<span class="p">}</span>
<span class="c1">// will anyone detect the mistake of removing one exclamation mark?</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">someValue</span> <span class="o">&&</span> <span class="nx">someOtherValue</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// some action</span>
<span class="p">}</span>
<span class="c1">// or detect the mistake of adding third exclamation mark?</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!!!</span><span class="nx">someValue</span> <span class="o">&&</span> <span class="nx">someOtherValue</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// some action</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Instead of using double exclamation marks, which opens the door for these regressions, I recommend using the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean"><code class="language-plaintext highlighter-rouge">Boolean</code></a> function to coerce values to booleans. Using this pattern makes it difficult for these mistakes to hide.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="nb">Boolean</span><span class="p">(</span><span class="nx">someValue</span><span class="p">)</span> <span class="o">&&</span> <span class="nb">Boolean</span><span class="p">(</span><span class="nx">someOtherValue</span><span class="p">))</span> <span class="p">{</span>
<span class="c1">// some action</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Since we’re already working in this area of the codebase, we can improve it further by introducing a constant to label the condition that we’re examining. This will make the both the context and the author’s intent clearer, which in turn makes it less likely that future developer will introduce regressions.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">someConditionIsMet</span> <span class="o">=</span> <span class="nb">Boolean</span><span class="p">(</span><span class="nx">someValue</span><span class="p">)</span> <span class="o">&&</span> <span class="nb">Boolean</span><span class="p">(</span><span class="nx">someOtherValue</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">someConditionIsMet</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// some action</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="bonus-use-boolean-in-iteration">Bonus: use <code class="language-plaintext highlighter-rouge">Boolean</code> in iteration</h3>
<p>You can also use <code class="language-plaintext highlighter-rouge">Boolean</code> in iteration, which would be a lot less elegant with <code class="language-plaintext highlighter-rouge">!!</code>.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">values</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">{},</span> <span class="kc">undefined</span><span class="p">,</span> <span class="p">[],</span> <span class="kc">null</span><span class="p">,</span> <span class="dl">'</span><span class="s1">apple pie</span><span class="dl">'</span><span class="p">,</span> <span class="dl">''</span><span class="p">,</span> <span class="kc">false</span><span class="p">,</span> <span class="kc">true</span><span class="p">,</span> <span class="p">];</span>
<span class="kd">const</span> <span class="nx">truthyValues</span> <span class="o">=</span> <span class="nx">values</span><span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nb">Boolean</span><span class="p">);</span>
<span class="c1">// [1, {}, [], "apple pie", true]</span>
</code></pre></div></div>
cv as markdown2014-08-28T00:00:00+00:00http://roderick.dk//2014/08/28/cv-as-markdownMorgan Roderickmorgan@roderick.dk<h1 id="cv-as-markdown">cv as markdown</h1>
<p>For a while I’ve had a <a href="http://getbootstrap.com">Bootstrap</a> based cv on this site. While it showed that I am capable of writing HTML, it was a pain to edit. As most people will attest to, keeping your cv up to date is one of their least favourite tasks. Adding HTML doesn’t make it any more enjoyable.</p>
<p>I wanted to switch to having the source of my cv in <a href="http://daringfireball.net/projects/markdown/">Markdown</a> for a number of reasons:</p>
<ul>
<li>It’s as easy as writing an email</li>
<li>It’s familiar, I use it every day for
<ul>
<li><a href="https://help.github.com/articles/creating-a-pull-request">pull requests on GitHub</a></li>
<li>writing documentation for the software I work on</li>
</ul>
</li>
<li>I can paste the source document into a plain text email, and everyone can immediately read it</li>
<li>I can easily generate binary formats for recruiters that prefer that</li>
<li>It’s easy to read diffs in git</li>
</ul>
<p>It took me a bit to do all the editing from HTML to Markdown, but now my <a href="/cv/cv.md">cv is available as Markdown</a>. From now on, updating it will be as easy as all the other editing I do on a daily basis.</p>
<h2 id="converting-markdown-to-pdf">Converting Markdown to PDF</h2>
<p>Some recruiters request a PDF (or other binary) version, so I’ll have to generate one, and <a href="http://jekyllrb.com">Jekyll</a> (which I use for building this site) isn’t going to do it for me.</p>
<p>Enter <a href="http://johnmacfarlane.net/pandoc/index.html">pandoc</a>, “a universal document converter”.</p>
<p>On OSX, installing it is fairly easy with <a href="http://brew.sh">Homebrew</a></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>brew <span class="nb">install </span>pandoc
</code></pre></div></div>
<p>Before you pat yourself on the shoulder for a job well done, you’ll still need a working TeX distribution on your machine so pandoc can create PDFs. I ended up using the <a href="http://www.tug.org/mactex/morepackages.html">BasicTeX distribution</a> of MacTeX.</p>
<p>Installation was as easy as installing any regular application on OSX, and now I can generate the PDF in a single command</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pandoc cv/cv.md <span class="nt">-o</span> cv/cv.pdf
</code></pre></div></div>
<p>The <a href="/cv/cv.pdf">PDF version of my cv</a> is now available :-)</p>
<p>Sure, it’s not the sexiest PDF the world has seen, but I am optimising for authoring pleasure and for making it easy to read.</p>
<h2 id="build-on-deploy">Build on deploy</h2>
<p>In the normal Jekyll workflow, Jekyll builds your site out of the source files and pours them into a <code class="language-plaintext highlighter-rouge">_site</code> folder (removing anything that was already there). Jekyll does not convert Markdown to PDF, so that’ll have to happen after the site is generated and before deploy.</p>
<p>I use a <a href="http://en.wikipedia.org/wiki/Rake_(software)">Rakefile</a> to build and deploy this site, so with a few updates, <code class="language-plaintext highlighter-rouge">rake</code> can now be used for generating a PDF version of the cv.</p>
<p>The Rakefile now looks like this</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">desc</span> <span class="s1">'Build CV to PDF with pandoc'</span>
<span class="n">task</span> <span class="ss">:cv</span> <span class="o">=></span> <span class="p">[</span><span class="ss">:build</span><span class="p">]</span> <span class="k">do</span>
<span class="n">sh</span> <span class="s1">'pandoc _site/cv/cv.md -o _site/cv/cv.pdf'</span>
<span class="k">end</span>
<span class="n">desc</span> <span class="s1">'Build site with Jekyll'</span>
<span class="n">task</span> <span class="ss">:build</span> <span class="k">do</span>
<span class="n">sh</span> <span class="s1">'jekyll build'</span>
<span class="k">end</span>
<span class="n">desc</span> <span class="s1">'Build and deploy'</span>
<span class="n">task</span> <span class="ss">:deploy</span> <span class="o">=></span> <span class="p">[</span><span class="ss">:build</span><span class="p">,</span> <span class="ss">:cv</span><span class="p">]</span> <span class="k">do</span>
<span class="n">sh</span> <span class="s1">'rsync -a --delete --delay-updates --progress -e ssh _site/ morgan@roderick.dk:/dana/data/www.roderick.dk/docs/'</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">jekyll</span><span class="p">(</span><span class="n">opts</span> <span class="o">=</span> <span class="s1">''</span><span class="p">)</span>
<span class="n">sh</span> <span class="s1">'rm -rf _site'</span>
<span class="n">sh</span> <span class="s1">'jekyll '</span> <span class="o">+</span> <span class="n">opts</span>
<span class="k">end</span>
</code></pre></div></div>
<p>The source of this website is <a href="https://github.com/mroderick/blog.jekyll">available on GitHub</a>, some of it has an MIT license.</p>
Full Frontal Conf 20122012-11-13T00:00:00+00:00http://roderick.dk//2012/11/13/full-frontal-conf-2012Morgan Roderickmorgan@roderick.dk<h1 id="full-frontal-conf-2012">Full Frontal Conf 2012</h1>
<p>This was my third time attending the Full Frontal conference, so I thought that this year I should actually take time to write a little blog post about it.</p>
<p>I took a week off from work to be fully able to enjoy visiting Brighton and seeing friends. Experience has shown me that in the week around Full Frontal, the city is full of geeks and there is much socialising to do. This year was no exception.</p>
<p>Apart from Async, there was also a NodeCopter event in Brighton (on Saturday). I missed the end of day demos that were open to all, but from observing twitter, it seemed to be a great success.</p>
<h2 id="async">Async</h2>
<p>Every year, on the evening before Full Frontal, there is an <a href="http://lanyrd.com/2012/asyncjs-showntell-2012/">International Show’n’Tell</a> at <a href="http://asyncjs.com/showntell-2012/">Async</a>.</p>
<p>It’s like a regular JavaScript user group, but with added attendees from far and wide. I think I won this year’s showing of hands on who has traveled the farthest to get to Full Frontal conf.</p>
<p>The Async special event schedule is a couple of hours of lightning talks, and then off to the pub for socialising. This year didn’t disappoint, there were some great talks there. I got to open with a little <del>talk</del> rant about focusing on mobile web, people seemed amused, so I am happy. (<a href="https://speakerdeck.com/mrgnrdrck/focusing-on-mobile-web">Slides here</a>).</p>
<h2 id="full-frontal">Full Frontal</h2>
<p>After each year I think that it would be difficult to make this conference much better, and yet Remy and Julie (and a small army of dedicated crew) are able to improve on an already very well curated conference again and again.</p>
<h3 id="venue">Venue</h3>
<p>As is tradition, Full Frontal was held at <a href="http://www.picturehouses.co.uk/cinema/Duke_Of_Yorks/">The Duke of York’s Picturehouse</a>. It’s a great venue for a conference, and I think that the fact that there is a hard limit on the amount of tickets that can be sold for the conference works to their advantage.</p>
<h3 id="talks">Talks</h3>
<p>It is really hard to pick a favourite talk from this year’s conference, but I think it will have to be John Allsop’s talk <a href="http://2012.full-frontal.org/#john">Is HTML relevent in the era of web apps?</a></p>
<p>Videos of all the talks from this year’s conference will be made available online for free in the near future, so you can watch all of them, and decide for yourself which one was the best. I enjoyed all of them.</p>
<h2 id="future">Future</h2>
<p>I hope to return to Brighton for next year’s Full Frontal conference.</p>
<p>I have even been considering creating a local JavaScript conference in Copenhagen/Malmö, and if I do, it would be greatly inspired by how Full Frontal conf is run.</p>
Simulate slow web connections2012-05-11T00:00:00+00:00http://roderick.dk//2012/05/11/simulate-slow-web-connectionsMorgan Roderickmorgan@roderick.dk<h1 id="simulate-slow-web-connections">Simulate slow web connections</h1>
<p>While you’re working on your own computer and accessing webapps running on that computer, response times are going to be <strong>fast</strong>. Most of the day, this is what we want. Working on your local machine, your webapp should be as fast as you can possibly make it.</p>
<p>But, for some situations, we need to examine how our application behaves when network connections are suboptimal.</p>
<p>On unix based systems there are a multitude of ways to slow down connection speeds of the entire system. Asking on Twitter, I learned that Apple recently released <a href="http://mattgemmell.com/2011/07/25/network-link-conditioner-in-lion/">Network Link Conditioner</a> for OSX Lion.</p>
<p>But, I really don’t want to slow down my entire system all day, just because I happen to want to test specific behaviour of just one of the hundreds of applications running on my computer. Then what?</p>
<p>What I need is to run a local proxy, that can slow down trafic and simulate slow web connections.</p>
<h2 id="charles-proxy">Charles Proxy</h2>
<p>My weapon of choice is <a href="http://www.charlesproxy.com/">Charles Proxy</a>. It is reasonably priced and is available on Windows, Mac OSX and Linux.</p>
<blockquote>
<p>Charles is an HTTP proxy / HTTP monitor / Reverse Proxy that enables a developer to view all of the HTTP and SSL / HTTPS traffic between their machine and the Internet. This includes requests, responses and the HTTP headers (which contain the cookies and caching information).</p>
</blockquote>
<p>I often use Charles Proxy to verify that servers are sending the correct caching headers, or to inspect the exact requests that are being sent by browsers.</p>
<p>However, today we’re going to look at how we can use Charles Proxy to simulate slow network connections.</p>
<h3 id="1-connect-to-the-proxy">1. Connect to the proxy</h3>
<p>First, we need to make sure we are connecting through the the Charles proxy. For this example we will use the option to have Charles automatically configure Firefox. In the Proxy menu, choose “Mozilla Firefox Proxy”.</p>
<p><img src="/images/2012-05-11-simulate-slow-web-connections/charles-firefox-proxy.png" alt="Choose "Mozilla Firefox Proxy"" /></p>
<p>When enabling this option, Charles will set the proxy settings in Firefox to be similar to these.</p>
<p><img src="/images/2012-05-11-simulate-slow-web-connections/firefox-proxy-settings.png" alt="Automatic proxy settings in Firefox" /></p>
<p>If you set the option to use recording as shown in the first screenshot, you will be able to see network trafic in the left hand pane.</p>
<p><img src="/images/2012-05-11-simulate-slow-web-connections/charles-recording-is-working.png" alt="Image of recording of network trafic in Charles Proxy" /></p>
<p>(Yes, I am writing this in Finland, and Google is still deciding that I want Finnish even though my request clearly states that I prefer “en-us”, which they support.)</p>
<h3 id="2-enable-bandwidth-throttling">2. Enable bandwidth throttling</h3>
<p>Now that we have it up and running and we can record all the trafic, let’s activate bandwidth throttling!</p>
<p>On OSX you can turn throttling on and off using ⌘T. As you can see from the following screenshot, there are plenty of parameters to define the characteristics of the network provided through the proxy.</p>
<p><img src="/images/2012-05-11-simulate-slow-web-connections/charles-throttling-options.png" alt="Throttling options in Charles Proxy" /></p>
<h2 id="3-bonus-simulate-slow-connection-while-testing-your-app-from-ipad-iphone-android-tablets-anything-really">3. Bonus: simulate slow connection while testing your app from iPad, iPhone, Android tablets, anything really.</h2>
<p>Now for the killer feature, that got me all excited and inspired me to write this post.</p>
<p>Using the Reverse Proxies feature, you can provide a throttled proxy to any device on your local network.</p>
<p>To use it, go to the Reverse Proxies options page in the Proxy menu.</p>
<p>Here you should add a new reverse proxy. The Local Port is the port on the local system that remote clients should connect to. The Remote Host should be 127.0.0.1 (the local system) and the Remote Port is the port on your local system that your webapp is running on.</p>
<p>Here’s an example.</p>
<p><img src="/images/2012-05-11-simulate-slow-web-connections/charles-reverse-proxy.png" alt="Throttling options in Charles Proxy" /></p>
<p>I would like remote clients to connect on port <strong>58549</strong><br />
I would like to direct trafic to localhost, e.g. <strong>127.0.0.1</strong><br />
My web application is running on port <strong>8000</strong></p>
<p>My computer’s name is morgbook, so the bonjour name that it publishes on the local network is morgbook.local.</p>
<p>In this example, if I want to test stuff on my iOS device with full speed of the wifi, I would connect to <a href="http://morgbook.local:8000">http://morgbook.local:8000</a>, and if I want to test with reduced speed on my iOS device, I would connect to <a href="http://morgbook.local:58549">http://morgbook.local:58549</a>. (This is true for any device on the local network, even my own computer).</p>
<p>With the combination of the throttling feature and the reverse proxy, we no longer need the automatic configuration of proxies in Firefox, and can easily see in the address field in any browser, if it’s accessing our webapp on a slow connection.</p>
<p>If we wanted to, we could easily simulate a slow connection to any webserver on the internet and provide that slow connection to your local devices. I’ll leave that as exercises to the reader.</p>
Speaking at Community Day 20122012-05-03T00:00:00+00:00http://roderick.dk//2012/05/03/speaking-at-community-dayMorgan Roderickmorgan@roderick.dk<h1 id="speaking-at-community-day-2012">Speaking at Community Day 2012</h1>
<p>A while a ago I was approached by <a href="http://twitter.com/#!/dalager">@dalager</a>, who asked if I would be interested in giving my introductory talk about “<a href="http://communityday2012.c1preprod01.composite.net/Program/Javascript-Closures">Closures, this, call and apply</a>” to a local audience at <a href="http://communityday2012.c1preprod01.composite.net/Program">Community Day</a>.</p>
<p>I am pretty much always excited about the opportunity to exchange knowledge and ideas with my tribe. So, after figuring out that I would in fact be in the area at the time of the conference, I jumped at the opportunity. With the current schedule, I’ll be speaking in the afternoon… immediately after lunch.</p>
<p>If you’re attending Community Day, you should check out the <a href="http://communityday2012.c1preprod01.composite.net/Program">schedule</a>, there are a lot of interesting talks packed into just one day. Firguring out what talks to attend is going to be difficult.</p>
<p>Personally, I am looking forward to the <a href="http://communityday2012.c1preprod01.composite.net/Program/Deconstructing-Agile">Deconstructing Agile</a> and <a href="http://communityday2012.c1preprod01.composite.net/Program/Kiss-My-sASS">Kiss my sASS</a> talks.</p>
<p>I’ll post the slides here after the talk.</p>
<p>See you there!</p>
<h2 id="update---not-speaking">Update - not speaking</h2>
<p>I have to be in Helsinki, Finland this Thursday for a workshop with a new client, so I won’t be able to speak at Community Day this year. The work for the new client is VERY exciting, and I’ll be blogging about the work soon. But, missing Community Day sucks. Next year!</p>
<p>If you have something you’d like to share with the great community in Copenhagen, <a href="http://twitter.com/#!/dalager">@dalager</a> is looking for a replacement speaker.</p>
Blog makeover2011-12-27T00:00:00+00:00http://roderick.dk//2011/12/27/blog-makeoverMorgan Roderickmorgan@roderick.dk<h1 id="blog-makeover">Blog makeover</h1>
<p>Finally, I’ve gotten round to migrating my blog from <a href="http://webby.rubyforge.org/">Webby</a> to <a href="https://github.com/mojombo/jekyll">Jekyll</a>. I guess it really is true that the shoemaker’s children go barefoot.</p>
<p>There are a few reasons for my move away from Webby and into the open arms of Jekyll.</p>
<ul>
<li>I got really tired of writing Textile, even for the small amounts I write on this website, it got tedious. With Jekyll I write Markdown, and it’s much more enjoyable.</li>
<li>Jekyll has an active community. The community around Webby is very small, and there are very few updates to the software.</li>
<li>People <a href="https://github.com/mojombo/jekyll/wiki/Sites">share their Jekyll sites on github</a>, so we can even learn from each other.</li>
<li>It seems I am always working on my website during xmas.</li>
<li>My dislike for writing Textile actually stifled my urge to write mostly anything on the old blog.</li>
</ul>
<p>While I still don’t have a new design (as in created by an actual designer), I am happier with the un-design of the current state than I ever was with the previous one.</p>
<p>For this makeover, I guess the majority of the time has been spent converting Textile to Markdown by hand. Some time was also sunk into making sure I would have a reasonable setup for Apache2. All in all, I am very happy with the conversion and hope that there will be much more writing in near future.</p>
<p>If you want to hack around with this site, or have a correction, the <a href="https://github.com/mroderick/blog.jekyll">source is on GitHub</a></p>
<p>Happy New Year!</p>
Code Retreat Berlin2011-07-10T00:00:00+00:00http://roderick.dk//2011/07/10/code-retreat-berlinMorgan Roderickmorgan@roderick.dk<h1 id="code-retreat-berlin">Code Retreat Berlin</h1>
<p>On Saturday 2011-07-09 I attended <a href="coderetreat-berlin.de/">Code Retreat Berlin</a>, these are my notes.</p>
<p>For those that have not been to or heard of code retreats, let me just quickly sketch out the concept. A code retreat is a place where programmers can practice their craft and improve their collaborative skills. Just like musicians need to practice, so do programmers.</p>
<p>The day is divided up into six sessions of 45 minutes with a little retrospective break in between, and of course a lunch break. During the sessions you pair up with another programmer, and do pair programming, working on <a href="http://www.conwaylife.com/wiki/Conway's_Game_of_Life">Conway’s Game of Life</a>. Not surprisingly, the sessions were over much too quickly, just as the going was getting good.</p>
<p>At the end of every session, you delete the code, and only keep the learnings.</p>
<h2 id="sessions">Sessions</h2>
<p>The instructor suggested that we move out of our comfort zones and try new languages. I felt that the important learnings would come from practicing TDD and Pairing, not trying to get a new language to run on my computer, or trying to understand the syntax of the code that the driving partner was writing.</p>
<p>I can learn new languages and stumble around on my own, or with a dedicated guide in other contexts, so I was quite happy to work with JavaScript at every session.</p>
<p>I had pairing sessions with @szafranek, ‘Daniel’, ‘Constantin’ and @til. In one session, we didn’t write one line of code, but spent our time discussing implementation strategies. In another session, I gave an introduction to the finer points of JavaScript, using Conway’s Game of Life as a vehichle for good examples.</p>
<p>At the very last session, @til and I put together all the pieces I had on my comptuer (not taking direction well, I stashed the code after each session) and made a <strong>working</strong> implementation of Conway’s Game of Life. It was very satisfying to have something that’s actually working, just like a musician, I like to play the entire thing and not just practice scales all day.</p>
<h2 id="my-learnings">My learnings</h2>
<p>These are some of my learnings from pairing with others at the retreat</p>
<ul>
<li>Pairing, when succesful, is very efficient and makes for high quality code</li>
<li>The driver of the pair needs to communicate what he’s doing at all times, a bit like thinking out loud. Ex: “I will validate the input of this function” or “just making sure that null values won’t break the program”.</li>
<li>The navigator needs to have the bigger picture, and should communicate where the pair is going, and of course point out typos and small mistakes. Ex: “You’ll need a function to determine how many neighbours a cell has” or “you can isolate that chunk into it’s own function”.</li>
<li>TDD is <em>still</em> very good for making high quality code</li>
<li>TDD <em>still</em> won’t help you if you don’t know where you’re going. Writing tests first will not fix the problem of not knowing exactly what you need to do. Spend time on understanding the problem, do reseearch online, read books. This is not really possible during a code retreat, which is why Conway’s Game of Life is a good problem to work on.</li>
</ul>
<h2 id="wrap-up">Wrap up</h2>
<p>Code Retreat Berlin was a great experience. For me there is great joy in understanding problems and creating elegant solutions to them. The format of a code retreat feels contradictory to my urge to <em>finish</em> what I am working on, but after a while, you get used to it, and you can focus on practicing.</p>
<p>One thing I would like to see different in future code retreats is some Venn diagram posted on a wall or website, suggesting pairing partners based on proficiency with programming languages.</p>
jQuery Data Link considered harmful2010-11-03T00:00:00+00:00http://roderick.dk//2010/11/03/jquery-data-link-considered-harmfulMorgan Roderickmorgan@roderick.dk<h1 id="jquery-data-link-considered-harmful">jQuery Data Link considered harmful</h1>
<p>“Considered harmful” has always been good link bait.</p>
<p>I am not trying to start a flamewar, but merely express my concerns over the recent decisions of the jQuery team to actively endorse plugins that deserves no special treatment from any other plugins out there.</p>
<p>If you have different opinions, please do respond in the comments or write a blog post expressing them.</p>
<h2 id="extending-globals-with-interesting-side-effects">Extending globals with interesting side effects</h2>
<p>When Prototype was first released, everyone was <strong>really</strong> excited and could suddenly do a lot more with JavaScript across browsers, that would have been considered almost a black art before (to some it still is).</p>
<p>Prototype allowed us previously unseen productivity as the library matured and evened out the playing field between browser capabilities, quirks and different interpretation of specs.</p>
<p>You no longer had to know every little browser quirk to be able to work successfully with JavaScript, Prototype was the catalyst that allowed a lot newcomers to JavaScript to pick up the tools and get some actual work done.</p>
<p>On the whole Prototype played a crucial role in speeding up the Ajax revolution, and has inspired many others to build excellent JavaScript frameworks and libraries. We owe a lot of thanks to the creators, maintainers and contributors of Prototype.</p>
<p>But, Prototype is not all double rainbows and have certainly made some mistakes that they’re still paying for. Over the years the Prototype library has been getting a lot of grief over extending the native prototypes and extending the DOM, both of which are considered bad practices.</p>
<p>For a history lesson on why all of this is considered bad practice:</p>
<ul>
<li><a href="http://erik.eae.net/archives/2005/06/06/22.13.54/">http://erik.eae.net/archives/2005/06/06/22.13.54/</a></li>
<li><a href="http://perfectionkills.com/whats-wrong-with-extending-the-dom/">http://perfectionkills.com/whats-wrong-with-extending-the-dom/</a></li>
<li><a href="http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/">http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/</a></li>
<li><a href="http://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/">http://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/</a></li>
</ul>
<p>What the whole discussion about not extending globals and not modifying objects you don’t own boils down to is this:</p>
<ul>
<li>Collisions causes very hard to find bugs</li>
<li>Avoiding collisions is very, very difficult</li>
<li>DEVELOPERS DON’T LIKE SURPRISES</li>
</ul>
<h2 id="data-in-the-dom-is-the-new-extended-prototype-h-global-scope">Data in the DOM is the new extended prototype ^h global scope</h2>
<p>Fast forward to present day.</p>
<p>Today, the most popular JavaScript library is undeniably jQuery.</p>
<p>jQuery is where a lot of newcomers to JavaScript will start. This is where they will pick up the tools, the practices and look for guidance. With the current landscape of libraries, that’s not a bad choice.</p>
<p>Just like Prototype paved the way for developers to get started with JavaScript, jQuery today makes it <em>easy</em> to get started and to get some work done.</p>
<p>There is plenty of good learning material about jQuery to absorb out there, both on the internet and even in bookstores and libraries.</p>
<p>The jQuery team has been very vigilant in not leaking anything into the global scope, not extending the globals or extending the DOM. The api is documented and very thoroughly tested.</p>
<p>On the whole, jQuery tries incredibly hard to not create collisions and not surprising it’s users.</p>
<p>Sure there are still a few surprises: jQuery custom events are using the DOM to store data about subscribers to specific events. But, that’s actually reasonable compromise when you consider that they found it important to have the events bubble and be just like the native events of the DOM. It is unfortunate that they’re simply stored under a name of “events”, and doesn’t use a more unique key like “jquery-custom-events” … I’ve already discovered one clash with this, leading to unexpected side effects.</p>
<p>Clearly, the maintainers of jQuery have taken the lessons from the mistakes of Prototype to heart.</p>
<p>Until now.</p>
<h3 id="jquery-data-link-plugin">jQuery Data Link plugin</h3>
<p>The jQuery team is now making the same mistakes that the Prototype team got chastised over, maybe not in jQuery Core itself, but with accepting overly complex and mostly untested plugins as official ones.</p>
<p>One of these is the <a href="https://github.com/jquery/jquery-datalink">Data Link plugin</a>, which allows developers to link DOM elements to JavaScript objects and vice versa.</p>
<p>We’ve seen this pattern before … we’ve agreed that having a direct and strong coupling between the DOM and our code is just plain stupid.</p>
<p>Data Link makes heavy use of the <code class="language-plaintext highlighter-rouge">changeData</code> event introduced in jQuery 1.4.3, and seems to work almost automagically… too automagically.</p>
<p>I am surprised that someone as experienced as John Resig is <a href="http://blog.jquery.com/2010/10/04/new-official-jquery-plugins-provide-templating-data-linking-and-globalization/">actually endorsing this</a> misguided practice.</p>
<p>The plugin has even <a href="http://api.jquery.com/category/plugins/data-link/">made it’s way into the official documentation of jQuery</a>, even though it can by no stretch of the imagination be considered of the same quality as the rest of the official jQuery code.</p>
<p>Data Link <em>has no automated test cases</em>. Go <a href="https://github.com/jquery/jquery-datalink">see for yourself at GitHub</a>.</p>
<p>If there are no test cases, how are we supposed to assess the maturity of the code? How are we going to contribute to it it, without causing defects?</p>
<p>Unsurprisingly, Data Link originates from Redmond, the same company that “blessed” frontend developers with the much hated ViewState and hijacking as much as they could in our browsers, effectively creating a breeding ground for collisions and very strong ties between the client side code and server side code.</p>
<h2 id="collisions-made-easy-with-data-link">Collisions made easy with Data Link</h2>
<p>I present to you: an easy to follow recipe for creating collisions with Data Link.</p>
<p>Imagine this: you’re building an app where you would like to use Data Link to have easy updates of your JavaScript objects whenever form fields change, using the “dataChange” event. And, having the form elements automatically updated whenever your JavaScript object changes, seems handy as well.</p>
<p>There’s plenty documentation on how to achieve this on the <a href="https://github.com/jquery/jquery-datalink">Data Link plugin page on GitHub</a>.</p>
<p>Now imagine that you’d like to use some of the elegant features of HTML5, like <a href="http://diveintohtml5.org/forms.html">placeholder attribute</a>. Modern browsers already support this, and there are several <a href="https://github.com/mathiasbynens/Placeholder-jQuery-Plugin">good</a> <a href="http://robertnyman.com/2010/06/17/adding-html5-placeholder-attribute-support-through-progressive-enhancement/">examples</a> on how to retrofit older browsers to enhance the user experience.</p>
<p>And voila! you’ve now made sure that your JavaScript objects automatically gets populated with the example text that you use in the placeholder attributes. Well done!</p>
<p>Now imagine that you’re using two different plugins that rely on Data Link, and you’ve got a recipe for some really, really hard to find collisions.</p>
<p>But that’s OK, because you’re a JavaScript ninja and know the internals of jQuery (and all the plugins) like the back of your own hand and jQuery has always been your friend.</p>
<p>… or perhaps you’re new to JavaScript and have chosen to use jQuery because it’s the popular choice and get’s endorsed by large multinationals. Well, if this is the case, you’re screwed, jQuery just became a LOT harder for you to use, and teaches you absolutely nothing.</p>
<h2 id="simplicity-and-uni-lateral-control-over-open-source">Simplicity and uni-lateral control over open source</h2>
<p>In a comment to the question of <a href="http://www.quora.com/How-could-YUI3-improve-its-image-compared-to-jQuery-MooTools-etc/answer/John-Resig?srid=5i2">How could YUI3 improve its image compared to jQuery</a> John states</p>
<blockquote>
<p>Simplicity is far harder to get right than building complex applications.</p>
</blockquote>
<p>He couldn’t be more right.</p>
<p>Data Link is by no means simple, and it’s use will lead to a a lot of interesting collisions.</p>
<p>Accepting Data Link as an official plugin and having jQuery endorse it, is in my opinion a mistake, especially considering it’s maturity.</p>
<p>In the very same comment, John also states</p>
<blockquote>
<p>Yahoo completely controls the direction and destiny of YUI. This should not be the case …</p>
</blockquote>
<p>This seems to suggest that we can talk Resig out of actively pushing Data Link, and focus his efforts on making jQuery itself the best it can be.</p>
<p>What do you think?</p>
Introducing PubSubJS, a Library for doing publish/subscribe in JavaScript2010-10-12T00:00:00+00:00http://roderick.dk//2010/10/12/introducing-pubsubjs-a-library-for-doing-publish-subscribe-in-javascriptMorgan Roderickmorgan@roderick.dk<h1 id="introducing-pubsubjs-a-library-for-doing-publishsubscribe-in-javascript">Introducing PubSubJS, a Library for doing publish/subscribe in JavaScript</h1>
<p>For quite a while, I have been working on a large web application for a client. For <a href="http://en.wikipedia.org/wiki/Publish/subscribe">publish/subscribe</a> style messaging in the web frontend, we use jQuery custom events triggered on the body element. This is quite a neat trick to ensure loose coupling of modules, since you’re really just tracking what the user does, and not what module happened to generate the message.</p>
<p>This approach has been introduced to my team by me, and I have been very eager to help my team mates understand how to use it.</p>
<p>I have been so satisfied with this approach, that I’ve even given a talk about it the <a href="http://groups.google.com/group/js-berlin">JS Berlin meetup</a>. Others have also been quite taken with this approach, some are listed in the footnotes.</p>
<p>Recently, I’ve become less and less satisfied with this approach.</p>
<p>One of the problems you eventually will run into with using jQuery custom events for publish/subscribe, is that they’re syncronous, so you will end up triggering new events, before you’re done executing the handlers for the current event.</p>
<p>It get’s messy, trust me.</p>
<h2 id="so-why-a-new-library">So why a new library?</h2>
<p>Well, there are actually a number of reasons, that ultimately led me to look for a better way of doing publish/subscribe messaging in <a href="https://developer.mozilla.org/en/JavaScript">JavaScript</a>.</p>
<p>I wanted something that would meet most of these requirements:</p>
<ul>
<li>Published under a reasonable software license ( CC, MIT, BSD, Apache, WTFPL, etc)</li>
<li>All messages should be passed async be default, anything else is just confusing</li>
<li>No use of DOM (it’s slow, and storing state in something you have no control over is silly)</li>
<li>Pure <a href="https://developer.mozilla.org/en/JavaScript">JavaScript</a>, no library dependencies</li>
<li>No side-effects, jQuery modifies subscribers (adding an “id” property to the functions)</li>
<li>Should be able to run outside browsers</li>
<li>Should have up to date documentation (or at least aligned with the codebase)</li>
<li>Tests are important, ok?</li>
<li>Small(ish)</li>
</ul>
<p>Well, it turned out that my searches on the internet came up empty (my Google-fu could be better), so I decided to write an implementation myself. I call it <a href="http://github.com/mroderick/PubSubJS">PubSubJS</a>.</p>
<p>I’ve published it at <a href="http://github.com/mroderick/PubSubJS">http://github.com/mroderick/PubSubJS</a>, you could take it for a spin, run the tests if you like, even fork it and contribute to it.</p>
<h2 id="so-what-can-this-pubsubjs-do">So what can this PubSubJS do?</h2>
<p>Not a lot.</p>
<p>Basically, you can subscribe to messages, publish messages (with a payload) and unsubscribe from messages. If you’re feeling adventurous (or really believe that you have 100% understanding of the consequences), you can also force message publication to be syncronous.</p>
<p>Let’s see some code already!</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// subscribing to messages is quite easy,</span>
<span class="c1">// first we'll create a subscriber function</span>
<span class="kd">var</span> <span class="nx">logToConsole</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span> <span class="nx">message</span><span class="p">,</span> <span class="nx">data</span> <span class="p">){</span>
<span class="c1">// once a message arrives, it'll get logged to the console</span>
<span class="c1">// data passed in messages can be whatever you want</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span> <span class="nx">message</span><span class="p">,</span> <span class="nx">data</span> <span class="p">);</span>
<span class="p">};</span>
<span class="c1">// every subscription gives you a token,</span>
<span class="c1">// you should keep it if you want to unsubscribe</span>
<span class="kd">var</span> <span class="nx">token</span> <span class="o">=</span> <span class="nx">PubSub</span><span class="p">.</span><span class="nx">subscribe</span><span class="p">(</span> <span class="dl">'</span><span class="s1">some message</span><span class="dl">'</span><span class="p">,</span> <span class="nx">logToConsole</span> <span class="p">);</span>
<span class="c1">// publishing messages is also quite easy</span>
<span class="nx">PubSub</span><span class="p">.</span><span class="nx">publish</span><span class="p">(</span> <span class="dl">'</span><span class="s1">some message</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">hello world!</span><span class="dl">'</span> <span class="p">);</span>
<span class="c1">// now let's unsubscribe from this message</span>
<span class="nx">PubSub</span><span class="p">.</span><span class="nx">unsubscribe</span><span class="p">(</span> <span class="nx">token</span> <span class="p">);</span>
</code></pre></div></div>
<p>So, as you can see, it’s fairly simple to work with.</p>
<p>To illustrate the difference in execution speed of working with <a href="https://developer.mozilla.org/en/JavaScript">JavaScript</a> and JavaScript + DOM, I’ve created a <a href="http://jsperf.com/">JSPerf.com</a> testpage, that <a href="http://jsperf.com/pubsubjs-vs-jquery-custom-events">compares PubSubJS performance to jQuery custom events</a>. You should go check it out.</p>
<h2 id="so-should-i-use-it">So, should I use it?</h2>
<p>No! … Well, maybe …</p>
<p>If you’re building larger web applications where you need to have loose coupling between your modules / components / widgets / whatnots, then publish/subscribe <em>can</em> be the answer you’re looking for.</p>
<p>If you happen to build larger web applications with Dojo and need publish/subscribe, then I recommend you look at the implementation that’s already IN Dojo, or get in touch with <a href="http://www.rebeccamurphey.com/">Rebecca Murphey</a> ;-)</p>
<p>Consider this: publish/subscribe is a bit like explosives. In the hands of thoughtful experts, you can expect to have a sky scraper demolished safely and in a reasonable time frame. In the hands of amateurs, working with explosives, you’ll end up with some very noisy and messy situations when you least expect it. And sure, every once in a while, even experts make mistakes.</p>
<p>“So why even write a publish/subscribe library?” you may ask, and the answer is simple: I need it, just like demolition experts need access to high grade, stable and predictable explosives.</p>
<p>Don’t say I didn’t warn you.</p>
<hr />
<ul>
<li><a href="http://code.quirkey.com/sammy/">Sammy.js</a> also uses jQuery custom events. I am however trying to convince Aaron to use pure JavaScript publish/subscribe messaging instead.</li>
<li><a href="http://enterprisejquery.com/2010/09/creating-an-ajax-component-handling-errors-and-loading-notifications-with-publish-and-subscribe/">Handling Errors and Loading Notifications with Publish and Subscribe</a></li>
</ul>
<p>After writing PubSubJS, I discovered that Peter Higgins has implemented <a href="http://github.com/phiggins42/bloody-jquery-plugins/blob/master/pubsub.js">publish/subscribe for jQuery</a></p>
Introducing FailFast, a JavaScript library for failure2010-09-02T00:00:00+00:00http://roderick.dk//2010/09/02/introducing-failfast-a-javascript-library-for-failureMorgan Roderickmorgan@roderick.dk<h1 id="introducing-failfast-a-javascript-library-for-failure">Introducing FailFast, a JavaScript library for failure</h1>
<p>Tomorrow I will be attending <a href="http://2010.dconstruct.org/">dConstruct 2010</a>, which I am very excited about. I flew in a day early, so I could get some time to enjoy Brighton. One of the first stops has been <a href="http://theskiff.org/">The Skiff</a>, “a nice little place to work in the middle of Brighton”.</p>
<p>The Skiff is indeed a very nice place: very few interruptions and very friendly people. While sitting at my visitors desk, I’ve managed to finally finish a little JavaScript library, that has been a very long time in the making: <a href="http://github.com/mroderick/FailFast">FailFast</a>. All it took was tidying up the documentation and writing the last few missing unit tests.</p>
<h2 id="the-idea-behind-failfast">The idea behind FailFast</h2>
<p>The goal of FailFast is to help you provide immediate and visible failure.</p>
<blockquote>
<p>Failfast refers to a lightweight form of FaultTolerance, whereby an application or system service terminates itself immediately upon encountering an error. This is done upon encountering an error so serious that it is possible that the process state is corrupt or inconsistent, and immediate exit is the best way to ensure that no (more) damage is done. Common errors that cause failfast include access violations and numeric exceptions, but may also involve internal consistency checks. This is an easy way to increase the reliability and predictability of a system.</p>
</blockquote>
<p>I’ve been working on FailFast as a library for a few years now (yeah, I know), but the ideas are far from new. These are some of the resources that have influenced me to write this little library.</p>
<ul>
<li><a href="http://martinfowler.com/ieeeSoftware/failFast.pdf">Fail Fast by Jim Shore</a></li>
<li><a href="http://www.c2.com/cgi/wiki?FailFast">Failfast on C2 wiki</a></li>
<li><a href="http://en.wikipedia.org/wiki/Fail-fast">Fail-fast on Wikipedia</a></li>
</ul>
<h2 id="how-to-use-failfast">How to use FailFast</h2>
<p>As with most programming practices, using a library such as FailFast, you should strive keep your code expressive and must consider future maintenance of the system you’re building. Just as with writing unit tests, if you go completely overboard and test everything you can possibly think of into minute detail, you will find yourself with some very <em>in</em>-flexible code that will resist your best refactoring efforts.</p>
<p>As a rule of thumb, I use FailFast to give precise and early feedback on failures when working with other developers (or just future-me, who thinks that past-me is somewhat retarded).</p>
<p>You could use it for all the public methods of a library, or even just a component of a system, where other developers might not have in-depth understanding of the underlying complexities or external dependencies. By building an abraction to an underlying system, you should also protect the users of that abstraction from the weird errors it might produce.</p>
<p>Let’s get you started with writing (fast) failing code!</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">divide</span><span class="p">(</span> <span class="nx">dividend</span><span class="p">,</span> <span class="nx">divisor</span> <span class="p">){</span>
<span class="nx">FailFast</span><span class="p">.</span><span class="nx">assertNumber</span><span class="p">(</span> <span class="nx">dividend</span><span class="p">,</span> <span class="dl">'</span><span class="s1">divide: you must pass a number as the "dividend" argument</span><span class="dl">'</span> <span class="p">);</span>
<span class="nx">FailFast</span><span class="p">.</span><span class="nx">assertNumber</span><span class="p">(</span> <span class="nx">divisor</span><span class="p">,</span> <span class="dl">'</span><span class="s1">divide: you must pass a number as the "divisor" argument</span><span class="dl">'</span> <span class="p">);</span>
<span class="nx">FailFast</span><span class="p">.</span><span class="nx">assert</span><span class="p">(</span> <span class="nx">divisor</span> <span class="o">!==</span> <span class="mi">0</span><span class="p">,</span> <span class="dl">'</span><span class="s1">divide: cannot divide with a divisor of zero</span><span class="dl">'</span> <span class="p">);</span>
<span class="k">return</span> <span class="nx">dividend</span> <span class="o">/</span> <span class="nx">divisor</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">divide</span><span class="p">(</span> <span class="dl">"</span><span class="s2">1</span><span class="dl">"</span><span class="p">,</span> <span class="mi">2</span> <span class="p">)</span> <span class="c1">// will throw exception</span>
<span class="nx">divide</span><span class="p">(</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span> <span class="p">)</span> <span class="c1">// will throw exception</span>
<span class="nx">divide</span><span class="p">(</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span> <span class="p">)</span> <span class="c1">// will return 0.5</span>
</code></pre></div></div>
<p>Our <code class="language-plaintext highlighter-rouge">divide</code> function will free us from unusable error messages and long stack traces, by throwing errors whenever bad input values are being passed. If a console (like Firebug, Safari, Chrome) is available, the error will also be logged to the console.</p>
<p>FailFast has a number of different assertions to help us write better code:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">assert</span> <span class="p">:</span> <span class="kd">function</span><span class="p">(</span> <span class="nx">exp</span><span class="p">,</span> <span class="nx">msg</span> <span class="p">)</span>
<span class="nx">assertBoolean</span> <span class="p">:</span> <span class="kd">function</span><span class="p">(</span> <span class="nx">exp</span><span class="p">,</span> <span class="nx">msg</span> <span class="p">)</span>
<span class="nx">assertNotNull</span> <span class="p">:</span> <span class="kd">function</span><span class="p">(</span> <span class="nx">exp</span><span class="p">,</span> <span class="nx">msg</span> <span class="p">)</span>
<span class="nx">assertNumber</span> <span class="p">:</span> <span class="kd">function</span> <span class="p">(</span> <span class="nx">exp</span><span class="p">,</span> <span class="nx">msg</span> <span class="p">)</span>
<span class="nx">assertNormalNumber</span> <span class="p">:</span> <span class="kd">function</span><span class="p">(</span> <span class="nx">exp</span><span class="p">,</span> <span class="nx">msg</span> <span class="p">)</span>
<span class="nx">assertObject</span> <span class="p">:</span> <span class="kd">function</span><span class="p">(</span> <span class="nx">exp</span><span class="p">,</span> <span class="nx">msg</span> <span class="p">)</span>
<span class="nx">assertInstanceOf</span> <span class="p">:</span> <span class="kd">function</span> <span class="p">(</span> <span class="nx">klass</span><span class="p">,</span> <span class="nx">exp</span><span class="p">,</span> <span class="nx">msg</span> <span class="p">)</span>
<span class="nx">assertHasProperty</span> <span class="p">:</span> <span class="kd">function</span><span class="p">(</span> <span class="nx">object</span><span class="p">,</span> <span class="nx">propertyName</span><span class="p">,</span> <span class="nx">msg</span> <span class="p">)</span>
<span class="nx">assertString</span> <span class="p">:</span> <span class="kd">function</span><span class="p">(</span> <span class="nx">exp</span><span class="p">,</span> <span class="nx">msg</span> <span class="p">)</span>
<span class="nx">assertArray</span> <span class="p">:</span> <span class="kd">function</span><span class="p">(</span> <span class="nx">exp</span><span class="p">,</span> <span class="nx">msg</span> <span class="p">)</span>
<span class="nx">assertFunction</span> <span class="p">:</span> <span class="kd">function</span><span class="p">(</span> <span class="nx">exp</span><span class="p">,</span> <span class="nx">msg</span> <span class="p">)</span>
</code></pre></div></div>
<p>Most of these are really just convinience wrappers for the <code class="language-plaintext highlighter-rouge">assert</code> function, but they do help make the code that uses FailFast much more expressive.</p>
<h2 id="get-involved">Get involved</h2>
<p>If you find flaws, or have ideas for improving FailFast, please fork the repository on GitHub and get involved.</p>
Juicer 1.0.0 Released2010-02-26T00:00:00+00:00http://roderick.dk//2010/02/26/juicer-1-0-0-releasedMorgan Roderickmorgan@roderick.dk<h1 id="juicer-100-released">Juicer 1.0.0 Released</h1>
<p>Earlier today <a href="http://cjohansen.no/en/">Christian Johansen</a> pushed the button and <a href="http://groups.google.com/group/juicer-dev/browse_thread/thread/1ce8b35ab2ccccae">published Juicer v1.0.0 as a gem</a>.</p>
<p>For those unfamiliar with <a href="http://github.com/cjohansen/juicer">Juicer</a>, it’s an open source Ruby based tool that allows you to merge and minify your JavaScript and CSS files. Internally, Juicer uses <a href="http://www.jslint.com/">JSLint</a> to keep your JavaScript in good shape and supports both YUI Compressor and Google Closure Compiler to make your CSS and JavaScript files as small as possible.</p>
<p>I have written about <a href="/2009/11/04/speeding-up-your-webby-site-with-juicer/">speeding up your Webby site with Juicer</a> previously, and with the new version there are even more features to like. These are the new features that exites me the most</p>
<ul>
<li>Support for <a href="http://code.google.com/closure/compiler/">Google Closure Compiler</a></li>
<li>Support for embedding images into stylesheets using data-uri’s (my contribution)</li>
<li>Ruby 1.9 support</li>
</ul>
<p>Christian has done a lot of work tidying up the codebase, making it very flexible and easy to work with. So if Juicer also exites you, I suggest you get involved in making it even better.</p>
<ul>
<li><a href="http://github.com/cjohansen/juicer">Juicer on Github</a> - includes all the details you need to get started with Juicer</li>
<li><a href="http://groups.google.com/group/juicer-dev">Juicer Google Group</a> - where you go to discuss all things Juicer</li>
</ul>
IE8 Getting EcmaScript 262 rev. 5 Compliant Native JSON2010-02-26T00:00:00+00:00http://roderick.dk//2010/02/26/ie8-getting-ecmascript-262-rev5-compliant-native-jsonMorgan Roderickmorgan@roderick.dk<h1 id="ie8-getting-ecmascript-262-rev-5-compliant-native-json">IE8 Getting EcmaScript 262 rev. 5 Compliant Native JSON</h1>
<p>Earlier this week, Microsoft posted an article with details on udpates to the native JSON implementation in IE8.</p>
<blockquote>
<p>Because of the new ECMAScript specification changes, some customers have reported issues. These issues are caused by deviations between the native JSON feature in Internet Explorer 8 and the final specification. An update is now available to address these customer issues and improve JSON interoperability of Internet Explorer 8. This update enables JSON interoperability of Internet Explorer 8 to keep in conformance with the new “ECMAScript, fifth edition” standard specification.</p>
</blockquote>
<p>According to the <a href="http://support.microsoft.com/kb/976662">Microsoft Knowledgebase article</a>, these updates are already being pushed via Windows Update to Windows versions with IE8 support.</p>
<p>Getting standards compliant native JSON support in what is soon to become the most popular browser on the planet, will certainly make lives easier for everyone working with JSON in browsers, and will help keep our JavaScript frameworks lean and fast.</p>
<h2 id="why-should-i-care">Why should I care?</h2>
<p>This update might seem like small potatoes at first sight, but this update hints at something much, much bigger.</p>
<p>To my knowledge, this is the first time that Microsoft have fixed non-compliant implementations in published versions of Internet Explorer. It also means that IE8 wont’ be bug-for-bug compatible between builds, which is perfectly acceptable to me. Developers deal with browser inconsistencies every day, but it’s not every day we get news as significant as this.</p>
<p>This shift in strategy, could actually mean that Microsoft plan on continually updating the current Internet Explorer with smaller enhancements, and leave the previous strategy of only improving standards support with a new generation of IE.</p>
<p>Who knows, they might even be planning a v8.1 of Internet Explorer, with even more significant upgrades to standards support?</p>
Speeding Up Your Webby Site With Juicer2009-11-04T00:00:00+00:00http://roderick.dk//2009/11/04/speeding-up-your-webby-site-with-juicerMorgan Roderickmorgan@roderick.dk<h1 id="speeding-up-your-webby-site-with-juicer">Speeding Up Your Webby Site With Juicer</h1>
<p>On this blog I use several stylesheets to keep things (somewhat) organised. This allows me to upgrade my <code class="language-plaintext highlighter-rouge">coderay.css</code> file or my <a href="http://devkick.com/lab/tripoli/">Tripoli CSS</a> stylesheets without having to reorganise everything.</p>
<p>But, just because I like to organise my code into managable chunks, doesn’t mean that I have to degrade the performance of the site for the visitors.</p>
<p>To help me improve performance by both reducing total transfer size and amount of requests for stylesheets, I’ve added <a href="http://github.com/cjohansen/juicer">Juicer</a> to the mix.</p>
<p>Juicer requires a few gems and Java (as it uses <a href="http://developer.yahoo.com/yui/compressor/">YUI Compressor</a> internally to minify stylesheets), but if you’re still reading, this should not be a problem for you.</p>
<h2 id="the-stylesheets">The stylesheets</h2>
<p>Firstly, I’ve created two <em>driver</em> stylesheets, that is responsible for importing the other stylesheets in the correct order.</p>
<p>First, the stylesheet for modern browsers.</p>
<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">/* master.modern.css - holds stylesheets for modern browsers */</span>
<span class="k">@import</span> <span class="sx">url(/stylesheets/tripoli/tripoli.simple.css)</span><span class="p">;</span>
<span class="k">@import</span> <span class="sx">url(/stylesheets/coderay.css)</span><span class="p">;</span>
<span class="k">@import</span> <span class="sx">url(/stylesheets/base.css)</span><span class="p">;</span>
</code></pre></div></div>
<p>Second, the stylesheet older versions of Internet Explorer</p>
<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">/* master.ie7.css - loads stylesheets for IE7 and lower */</span>
<span class="k">@import</span> <span class="sx">url(/stylesheets/tripoli/tripoli.simple.css)</span><span class="p">;</span>
<span class="k">@import</span> <span class="sx">url(/stylesheets/tripoli/tripoli.simple.ie.css)</span><span class="p">;</span>
<span class="k">@import</span> <span class="sx">url(/stylesheets/coderay.css)</span><span class="p">;</span>
<span class="k">@import</span> <span class="sx">url(/stylesheets/base.css)</span><span class="p">;</span>
<span class="k">@import</span> <span class="sx">url(/stylesheets/ie7.css)</span><span class="p">;</span>
</code></pre></div></div>
<p>Steve Souders has explained that <a href="http://stevesouders.com/blog/2009/04/09/dont-use-import/">you should not use @import</a> in your stylesheets, as it will block parallel downloads. But, don’t worry, Juicer will combine all of these stylesheets into one and all will be well in the world.</p>
<h2 id="the-rake-file">The rake file</h2>
<p>To control the behaviour of Juicer, I’ve created a little rake task.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># juicer.rake</span>
<span class="n">namespace</span> <span class="ss">:juicer</span> <span class="k">do</span>
<span class="n">namespace</span> <span class="ss">:merge</span> <span class="k">do</span>
<span class="n">desc</span> <span class="s1">'Merges stylesheets'</span>
<span class="n">task</span> <span class="ss">:stylesheets</span> <span class="k">do</span>
<span class="n">sh</span> <span class="s1">'juicer merge content/stylesheets/master.modern.css -o content/stylesheets/master.modern.min.css --document-root content --force'</span>
<span class="n">sh</span> <span class="s1">'juicer merge content/stylesheets/master.ie7.css -o content/stylesheets/master.ie7.min.css --document-root content --force'</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>You should update the rake task with the correct paths and filenames for your site.</p>
<h2 id="updating-the-sitefile">Updating the Sitefile</h2>
<p>In order for Webby to generate these new files, you will need to update your <code class="language-plaintext highlighter-rouge">Sitefile</code>, and instruct Webby to run the merge task with every build. To do this you simply add a dependency for the built-in build tasks.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># add these lines to your Sitefile</span>
<span class="n">desc</span> <span class="s2">"Build the website"</span>
<span class="n">task</span> <span class="ss">:build</span> <span class="o">=></span> <span class="p">[</span><span class="ss">:configure_basepath</span><span class="p">,</span> <span class="s1">'juicer:merge:stylesheets'</span> <span class="p">]</span>
<span class="n">desc</span> <span class="s2">"Rebuild the website"</span>
<span class="n">task</span> <span class="ss">:rebuild</span> <span class="o">=></span> <span class="p">[</span><span class="ss">:configure_basepath</span><span class="p">,</span> <span class="s1">'juicer:merge:stylesheets'</span> <span class="p">]</span>
<span class="n">desc</span> <span class="s2">"Continuously build the website"</span>
<span class="n">task</span> <span class="ss">:autobuild</span> <span class="o">=></span> <span class="p">[</span><span class="ss">:configure_basepath</span><span class="p">,</span> <span class="s1">'juicer:merge:stylesheets'</span> <span class="p">]</span>
</code></pre></div></div>
<p>Using the new merged stylesheets couldn’t be easier, you just reference them by their new names <code class="language-plaintext highlighter-rouge">master.modern.min.css</code> and <code class="language-plaintext highlighter-rouge">master.ie7.min.css</code>.</p>
<h2 id="results">Results</h2>
<p>For this blog, the result is ~2kb and 2 or 4 connection requests saved, if your site has bigger and/or more stylesheets, you’re going to see even better results.</p>
<p>As an added bonus, Juicer also adds cache buster suffixes to all image references in the stylesheets (this is configurable), so now I can safely turn on expiration headers for these images and my (repeat) visitors can enjoy an even faster site.</p>
Perfect Pitch2009-11-03T00:00:00+00:00http://roderick.dk//2009/11/03/perfect-pitchMorgan Roderickmorgan@roderick.dk<h1 id="perfect-pitch">Perfect Pitch</h1>
<p><a href="http://adactio.com/journal/1623/">Perfect Pitch</a> is an article by Jeremy Keith that discusses some recent issues and misuses of DMCA unfairly to destroy competitors search engine rankings.</p>
<p>It all started out as an innocent comment about attaining <a href="http://www.thesession.org/discussions/display/21250">Perfect Pitch</a> on The Session.</p>
<p>This is really just another one of those examples of American legislation that got implemented without any real thought of the consequences or of how it could be misused, not entirely unlike the Intellectual Property and Patents legislation in the U.S. <em>GO Lobbyists!!!</em></p>
<p>Help Jeremy out, and create your own Perfect Pitch post and even better, link to the other two.</p>
Combining JavaScript Files - Juicer vs Sprockets2009-10-04T00:00:00+00:00http://roderick.dk//2009/10/04/combining-javascript-files-juicer-vs-sprocketsMorgan Roderickmorgan@roderick.dk<h1 id="combining-javascript-files---juicer-vs-sprockets">Combining JavaScript Files - Juicer vs Sprockets</h1>
<p>Currently working on a project that has well defined use of “namespaces” and structured use folders for its JavaScript files. I wanted to investigate the options for combining and minifying JavaScript files.</p>
<p>I need a tool that:</p>
<ul>
<li>can be run from command line (my team uses many different editors and IDEs)</li>
<li>will work on both Windows and Unix based platforms</li>
<li>does not require huge, obscure configuration files</li>
<li>can merge sources recursively</li>
<li>has an acceptable software license (MIT / Apache / BSD)</li>
<li>is thorougly tested</li>
<li>is extensible</li>
<li>can work with any JavaScript framework</li>
</ul>
<p>I settled for trying out <a href="http://github.com/cjohansen/juicer">Juicer</a> and <a href="http://getsprockets.org">Sprockets</a>, since both tools met the requirements and were the only high-quality tools on my radar.</p>
<p>Feel free to suggest more tools to try out in the comments.</p>
<p>Both Juicer and Sprockets use Ruby, so make sure you have a recent Ruby and Rubygems installed if you want to experiment with them. Most developers that care enough about good frontend performance seem to have Ruby anyway these days.</p>
<p>I tested the tools with Ruby 1.8.7 on OS X 10.6.1.</p>
<h2 id="juicer">Juicer</h2>
<p>License: MIT</p>
<p>URL: <a href="http://github.com/cjohansen/juicer">http://github.com/cjohansen/juicer</a></p>
<p>I first became aware of Juicer when Christian Johansen released the 0.2.0 version to the public about six months ago. Since then I have been wanting to try it out for work related projects.</p>
<h3 id="installation">Installation</h3>
<p>Installation of Juicer is pretty straight forward</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gem <span class="nb">install </span>juicer
<span class="nv">$ </span>juicer <span class="nb">install </span>yui_compressor
<span class="nv">$ </span>juicer <span class="nb">install </span>jslint
</code></pre></div></div>
<h3 id="usage">Usage</h3>
<p>Using Juicer for JavaScript dependency management is pretty straight forward, in your code you simply specify dependencies with the @depend keyword and juiced picks up on this and merges the files automagically.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* My script file
*
* @depend jquery-1.2.0.js
*/</span>
<span class="kd">var</span> <span class="nx">myNS</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">myObject</span> <span class="o">=</span> <span class="p">{}</span>
<span class="p">};</span>
</code></pre></div></div>
<p>To merge the dependencies into the file you simply run</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">$</span> <span class="nx">juicer</span> <span class="nx">merge</span> <span class="nx">myfile</span><span class="p">.</span><span class="nx">js</span>
</code></pre></div></div>
<p>This will produce a new file, <code class="language-plaintext highlighter-rouge">myfile.min.js</code>, which contains all dependencies merged in. It parses each dependency and resolves it’s dependencies as well. The file will be stripped of all comments and minified, this is highly configurable, if you know how to use <a href="http://developer.yahoo.com/yui/compressor/">YUI Compressor</a> (and you should know this).</p>
<h3 id="bonus-features">Bonus features</h3>
<ul>
<li>Builtin use of <a href="http://www.jslint.com/">JsLint</a></li>
<li>Builtin use of <a href="http://developer.yahoo.com/yui/compressor/">YUI Compressor</a></li>
<li>Can merge CSS files</li>
<li>Can create cache buster urls for assets referenced by css files</li>
<li>Can cycle asset hostnames for asset urls in css files</li>
</ul>
<h2 id="sprockets">Sprockets</h2>
<p>License: MIT</p>
<p>URL: <a href="http://getsprockets.org">http://getsprockets.org</a></p>
<p>To my knowledge, Sprockets was released at around the same time as Juicer, both projects seemed to be blissfully unaware of each other. Sprockets is created by Sam Stephenson of Prototype fame.</p>
<h3 id="installation-1">Installation</h3>
<p>Installing Sprockets is a no brainer, if you have ruby</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gem <span class="nb">install</span> <span class="nt">--remote</span> sprockets
</code></pre></div></div>
<p>This will give you a gem, with all you need to run Sprockets, including a “sprocketize” command.</p>
<h3 id="usage-1">Usage</h3>
<p>Using Sprockets for JavaScript dependency management is very easy, you specify dependencies in your source code with the <code class="language-plaintext highlighter-rouge">//= require</code> notation, and it will resolve the dependencies for you.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//= require "jquery-1.2.0"</span>
<span class="cm">/**
* My script file
*/</span>
<span class="kd">var</span> <span class="nx">myNS</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">myObject</span> <span class="o">=</span> <span class="p">{}</span>
<span class="p">};</span>
</code></pre></div></div>
<p>To merge the dependencies in, you simply run the <code class="language-plaintext highlighter-rouge">sprocketize</code> command on the file, specifying where the output should go.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>sprocketize myfile.js <span class="o">></span> myfile.combined.js
</code></pre></div></div>
<p>This creates the merged file, with all dependencies merged in, neat and to the point. Sprockets has many subtleties that allows for greater control and for easier reading of the dependency directives. Luckily, it’s very well documented, reading the documentation for the finer points is recommended.</p>
<h3 id="bonus-features-1">Bonus features</h3>
<ul>
<li>Bundling of assets, to create release builds with all dependencies like CSS, images, flash files. Very neat.</li>
<li>Support for insertion of constants into the code (like version numbers, authors, i18n, etc)</li>
<li>Sprockets is really a well structured Ruby library, so you can just keep extending and building on it</li>
<li>Rails plugin (well, only a bonus if you use Rails)</li>
<li>CGI script for serving outside Rails</li>
</ul>
<p>Sprockets does not come with JsLint or YUI Compressor builtin, you will have to add this to your build script yourself. This should not be that much of an issue, as you will probably want to be able to create several diffent builds for yourself anyway.</p>
<h2 id="the-verdict">The verdict</h2>
<p>Sprockets seem very well suited for framework authors, not surprising since it originated from the Prototype JS framework.</p>
<p>Juicer has some very compelling features for optimizing the use of CSS files and resources referenced by these files.</p>
<p>Both Juicer and Sprockets are carefully crafted tools and show great maturity. Both projects encourage contributions and are both hosted on GitHub, so collaboration is really easy.</p>
<p>Setting up each tool and using it for merging dependencies for a large project with many JavaScript files took me about half an hour.</p>
<p>I can only recommend that you try out both tools and see which one fits best with YOUR plans for World Domination™.</p>
Installing Mercurial With Bash Completion from MacPorts2009-08-28T00:00:00+00:00http://roderick.dk//2009/08/28/installing-mercurial-with-bash-completionMorgan Roderickmorgan@roderick.dk<h1 id="installing-mercurial-with-bash-completion-from-macports">Installing Mercurial With Bash Completion from MacPorts</h1>
<p>Now that Snow Leopard is out, I ran into a few issues with some of my installed ports. Upgrading them to run on the new 64-bit OS also gave me some grief.</p>
<p>I decided to just start over with a clean slate for all my ports.</p>
<p>Make sure to install the latest XCode (and perhaps Apple’s X11 from the optional installs) from the Snow Leopard DVD. Once that is done, you should install v1.8.0 of MacPorts. As usual, <a href="http://www.MacPorts.org/install.php">there are detailed instructions on the MacPorts website</a>.</p>
<p>You can find details on <a href="http://trac.MacPorts.org/wiki/FAQ#uninstall">how to uninstall your installed ports</a> on the MacPorts wiki.</p>
<p>If you’re installing Mercurial from MacPorts, do get the bash_completion variant, as it’s much nicer to work with on a daily basis.</p>
<p><em>At the time of writing, python26 won’t install from MacPorts on Snow Leopard</em>. Python 2.6 is a requirement for Mercurial. The issue is <a href="http://trac.MacPorts.org/ticket/20284">very actively being worked on by your friendly MacPorts maintainers</a>, so just have a little patience.</p>
<p>While we wait patiently, you can always take the opportunity to learn more about Mercurial, there are several good resources:</p>
<ul>
<li><a href="http://hgbook.red-bean.com/">Mercurial: The definitive guide</a> is a freely available online, and will be printed by O’Reilly later this year.</li>
<li><a href="http://peepcode.com/products/meet-mercurial">PeepCode screencast: Meet Mercurial</a> by Dan Benjamin</li>
<li><a href="http://hivelogic.com/articles/meet-mercurial/">Meet Mercurial</a>, article where Dan Benjamin introduces us to his screencast and offers a little background.</li>
<li><a href="http://mercurial.selenic.com/wiki/">Mercurial Wiki</a></li>
<li><a href="http://importantshock.wordpress.com/2008/08/07/git-vs-mercurial/">Git vs. Mercurial: Please Relax</a> … I enjoyed this thoroughly.</li>
<li><a href="http://bitbucket.org/">BitBucket</a> hosts your Mercurial repositories, if you can’t be bothered doing it yourself (it’s really not that hard). Very nice for collaboration though.</li>
</ul>
<p>Once the python26 port is working on Snow Leopard (probably fixed by the time you read this), you should treat yourself to having bash completion for Mercurial.</p>
<p>All you need to do to attain bliss, is just to instruct MacPorts to install the bash completion variant.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>port <span class="nb">install </span>mercurial +bash_completion
</code></pre></div></div>
<p>Such a long post for a little port statement :-)</p>
<p><em>Update</em>: You can also install <a href="http://mercurial.berkwood.com/">pre-built binaries</a> while we wait for the fix to the MacPorts version, that’s what I’ve done.</p>
<p><em>Update - 2009-09-12</em>: The awesome MacPorts maintainers have fixed python26 port some days ago, so there are no longer any problems installing Mercurial with bash completion from MacPorts.</p>
TextMate snippet for creating Low Pro Behaviors2009-08-16T00:00:00+00:00http://roderick.dk//2009/08/16/textmate-snippet-for-creating-low-pro-behaviorsMorgan Roderickmorgan@roderick.dk<h1 id="textmate-snippet-for-creating-low-pro-behaviors">TextMate snippet for creating Low Pro Behaviors</h1>
<h2 id="behaviours">Behaviours</h2>
<p>To encapsulate complex javascript behaviour on websites, I have been using <a href="http://www.danwebb.net/lowpro">Dan Webb’s Low Pro</a> library for several years. Low Pro allows you to create self-contained Behavior classes, which avoids polluting the global namespace with variables and makes for very easy re-use of code.</p>
<p>I’ve previously given a little <a href="http://roderick.dk/blog/2009/05/07/introduction-to-low-pro-for-prototype/">introduction to Low Pro for Prototype</a> at a local Meetup event, where I show an example of creating your own behaviours.</p>
<h2 id="textmate-snippet">Textmate snippet</h2>
<p>Today, I finally got around to creating a <a href="http://gist.github.com/168604">TextMate snippet for creating new Behaviors</a>.</p>
<p><a href="http://manual.macromates.com/en/snippets">TextMate snippets</a> are an easy way of optimising your daily coding, by automating the writing of some of your code. They’re surprisingly simple to work with.</p>
<blockquote>
<p>In the simplest case, you can use snippets to insert text that you do not want to type again and again, either because you type it a lot, or because the actual text to insert is hard to remember (like your bank account details or the HTML entities for the Apple modifier keys).</p>
</blockquote>
<p>Activating the snippet and filling in the options (class name, default options, etc) will give you something like this:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* class MyBehavior
* Behavior class for managing behavior of ...
* See http://www.danwebb.net/2006/9/3/low-pro-unobtrusive-scripting-for-prototype
**/</span>
<span class="kd">var</span> <span class="nx">MyBehavior</span> <span class="o">=</span> <span class="nx">Behavior</span><span class="p">.</span><span class="nx">create</span><span class="p">({</span>
<span class="na">options</span> <span class="p">:</span> <span class="p">{</span>
<span class="na">myOption</span> <span class="p">:</span> <span class="dl">'</span><span class="s1">myOptionDefaultValue</span><span class="dl">'</span>
<span class="p">},</span>
<span class="cm">/**
* MyBehavior#initialize( [ opts = { myOption : 'myOptionDefaultValue' }] )
* - options (Object): Will be merged with the default options, good for
* overriding texts, urls, dom references, etc
* Gets called when the element is loaded
**/</span>
<span class="na">initialize</span> <span class="p">:</span> <span class="kd">function</span><span class="p">(</span> <span class="nx">opts</span> <span class="p">){</span>
<span class="k">this</span><span class="p">.</span><span class="nx">options</span> <span class="o">=</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">merge</span><span class="p">(</span> <span class="nx">opts</span> <span class="p">).</span><span class="nx">toObject</span><span class="p">();</span>
<span class="c1">// alert( this.options.myOption )</span>
<span class="p">}</span>
<span class="p">);</span>
</code></pre></div></div>
<p>The snippet is <a href="http://gist.github.com/168604">available on github</a>, should you feel the need to customize or improve it.</p>
<p><a rel="license" href="http://creativecommons.org/licenses/by-sa/2.5/dk/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/2.5/dk/80x15.png" /></a></p>
Disable Webpage Preview Images in Safari 4 Final2009-08-03T00:00:00+00:00http://roderick.dk//2009/08/03/disable-webpage-preview-images-in-safari-4-finalMorgan Roderickmorgan@roderick.dk<h1 id="disable-webpage-preview-images-in-safari-4-final">Disable Webpage Preview Images in Safari 4 Final</h1>
<p>I’ve finally managed to switch off the final remnant of the Top Sites feature in Safari 4, the automatic generation of ‘Webpage Previews’</p>
<p>I’ve previously written about how to <a href="http://roderick.dk/blog/2009/07/02/reclaim-disk-space-from-safari-4/">Reclaim Disk Space From Safari 4</a>, where I detailed how to set up a job to cleanup the Webpage Previews cache folder.</p>
<p>Luckily, that exercise has now become obsolete, thanks to reports on several sites, which I can’t remember.</p>
<p>Below are listed the Terminal commands to verify disk use and apply the changes to Safari.</p>
<h2 id="verify-size-of-folder">Verify size of folder</h2>
<p>To make sure that our fix is in fact working, let’s measure the current size of the folder.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">du</span> <span class="nt">-h</span> ~/Library/Caches/com.apple.Safari/Webpage<span class="se">\ </span>Previews
248M /Users/morgan/Library/Caches/com.apple.Safari/Webpage Previews
</code></pre></div></div>
<p>Then let’s empty the folder</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">rm</span> ~/Library/Caches/com.apple.Safari/Webpage<span class="se">\ </span>Previews/<span class="k">*</span>
</code></pre></div></div>
<p>And let’s verify that the folder is indeed empty.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">du</span> <span class="nt">-h</span> ~/Library/Caches/com.apple.Safari/Webpage<span class="se">\ </span>Previews
0B /Users/morgan/Library/Caches/com.apple.Safari/Webpage Previews
</code></pre></div></div>
<h2 id="apply-fix">Apply fix</h2>
<p>Apply the following fix to disable generation of Webpage Preview images.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>defaults write com.apple.Safari DebugSnapshotsUpdatePolicy <span class="nt">-int</span> 2
</code></pre></div></div>
<p>And don’t forget to restart Safari (so, I suggest you bookmark this page)</p>
<h2 id="verify-fix">Verify fix</h2>
<p>Browse around to your favorite websites for awhile, and then just re-run the command to measure disk use.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">du</span> <span class="nt">-h</span> ~/Library/Caches/com.apple.Safari/Webpage<span class="se">\ </span>Previews
0B /Users/morgan/Library/Caches/com.apple.Safari/Webpage Previews
</code></pre></div></div>
<p>The fix has been applied and tested with Safari 4.0.2 on OS X Leopard.</p>
<p>Please report successes and failures in the comments.</p>
Setting Up Virtual Hosts on OS X Leopard2009-07-08T00:00:00+00:00http://roderick.dk//2009/07/08/setting-up-virtual-hosts-on-os-x-leopardMorgan Roderickmorgan@roderick.dk<h1 id="setting-up-virtual-hosts-on-os-x-leopard">Setting Up Virtual Hosts on OS X Leopard</h1>
<p>Working with a new client and getting back to my roots of doing pure frontend development, I had to set up a virtual host for development on my MBP.</p>
<p>When working with Rails, I usually just use <code class="language-plaintext highlighter-rouge">script/server</code> and/or Passenger to serve my applications… in this situation i just needed to serve some static files.</p>
<p>I found <a href="http://mark-kirby.co.uk/2008/setting-up-virtual-hosts-on-os-x-leopard/">Mark Kirby’s excellent tutorial on Setting up virtual hosts on OS X Leopard</a> and am posting it here, so I won’t forget in the future.</p>
Reclaim Disk Space From Safari 42009-07-02T00:00:00+00:00http://roderick.dk//2009/07/02/reclaim-disk-space-from-safari-4Morgan Roderickmorgan@roderick.dk<h1 id="reclaim-disk-space-from-safari-4">Reclaim Disk Space From Safari 4</h1>
<p>Having a MacBook Pro that seems to be continually low on disk space, I set out to tidy up a bit using the <a href="http://www.omnigroup.com/applications/omnidisksweeper/">excellent and free OmniDiskSweeper</a>. It will help you identify where all your disk space is going. Use with caution though, and always have a recent backup.</p>
<p>After tidying up all over the file system, I noticed that the Safari cache was enourmous … 1.2GB in my case. Further investigation revealed that most of that space was taken up by Webpage Previews, used by the top sites feature in Safari 4. As I don’t care for that feature, I have disabled it with the following command</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>defaults write com.apple.Safari DebugSafari4IncludeTopSites <span class="nt">-bool</span> NO
</code></pre></div></div>
<p>But, that doesn’t prevent Safari 4 from writing a lot of files into the filesystem. So either I would have to remove them manually at intervals … but most developers prefer to automate trivial tasks.</p>
<h2 id="enter-scripting">Enter scripting</h2>
<p>OS X has excellent support for creating your own scripts and will allow you to do pretty much everything using the terminal, including creating your own scripts.</p>
<p>So, to remove all the unwanted files from the filesystem, I created the following script, which I named <code class="language-plaintext highlighter-rouge">remove_webpage_previews</code></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
find ~/Library/Caches/com.apple.Safari/Webpage<span class="se">\ </span>Previews <span class="nt">-mtime</span> +1 <span class="nt">-and</span> <span class="nt">-not</span> <span class="nt">-type</span> d <span class="nt">-delete</span>
</code></pre></div></div>
<p>It finds all non-directory entries in the Webpage Previews folder with a modification time greater than one day. If you like using the top sites feature, you might want to use something like 14-30 days.</p>
<p>I keep scripts such as these in <code class="language-plaintext highlighter-rouge">~/bin</code>, but you may keep them elsewhere.</p>
<p>To make the script executable, you need to set it as executable in the filesystem using the following command:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">chmod</span> +x ~/bin/remove_webpage_previews
</code></pre></div></div>
<h3 id="testing-the-script">Testing the script</h3>
<p>First, measure how much space is currently being taken up by webpage previews</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">du</span> <span class="nt">-h</span> ~/Library/Caches/com.apple.Safari/Webpage<span class="se">\ </span>Previews
867M
</code></pre></div></div>
<p>Run the cleanup script, this might take up to a few minutes to execute, if you have many files … I had a few thousand to begin with.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>bin/remove_webpage_previews
</code></pre></div></div>
<p>Measure again, hopefully you should see a difference</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">du</span> <span class="nt">-h</span> ~/Library/Caches/com.apple.Safari/Webpage<span class="se">\ </span>Previews
252M
</code></pre></div></div>
<h2 id="automation---enter-lingon">Automation - Enter Lingon</h2>
<p>If your script is succesful, you should register it with <code class="language-plaintext highlighter-rouge">launchd</code>, and have it run automatically at intervals.</p>
<p>For this purpose, I use the very nice tool <a href="http://tuppis.com/lingon/">Lingon</a> by Peter Borg.</p>
<p>I’ve set up my script to run every 6 hours, when I am logged in.</p>
<p><img src="/images/lingon-remove-webpage-previews.png" alt="Lingon Remove Webpage Previews" /></p>
<p>That is it, your computer will now automatically cleanup webpage previews, and your disk won’t fill up as fast :-)</p>
LowPro Updated for Firefox 3.52009-07-02T00:00:00+00:00http://roderick.dk//2009/07/02/lowpro-updated-for-firefox-3.5-compatibilityMorgan Roderickmorgan@roderick.dk<h1 id="lowpro-updated-for-firefox-35">LowPro Updated for Firefox 3.5</h1>
<p>Firefox 3.5 was recently released, and offers significant updates. If you have not upgraded yet, you should <a href="http://mozilla.org/firefox">do so now</a>.</p>
<p>In the <a href="http://groups.google.com/group/low-pro">LowPro community</a>, we have been tracking compatibility with the upcoming Firefox. The existing LowPro was compatible with Firefox 3.5RC2, but incompatible with the final release of Firefox 3.5.</p>
<p>So, if you are using LowPro, <em>you should upgrade with a new version of LowPro today</em>.</p>
<p>You can either go for <a href="http://github.com/danwrong/low-pro">Dan Webb’s original version</a> or try out <a href="http://github.com/mroderick/lowpro">my minification-friendly fork</a> (there is a minified version in dist).</p>
Introduction to Low Pro for Prototype2009-05-07T00:00:00+00:00http://roderick.dk//2009/05/07/introduction-to-low-pro-for-prototypeMorgan Roderickmorgan@roderick.dk<h1 id="introduction-to-low-pro-for-prototype">Introduction to Low Pro for Prototype</h1>
<p>Tonight I gave a lightweight introduction to <a href="http://lowprojs.com">Low Pro</a> for Prototype at the <a href="http://www.meetup.com/The-Oresund-JavaScript-Meetup/">Öresund JavaScript meetup</a>.</p>
<p>For those that missed it, or just want to study the example again, you can <a href="/presentations/introduction-to-low-pro-for-prototype/Introduction-to-Low-Pro-for-Prototype.pdf">see the slides as a PDF</a>, <a href="/presentations/introduction-to-low-pro-for-prototype/intro.html">see the sample</a> or <a href="presentations/introduction-to-low-pro-for-prototype/Introduction-to-Low-Pro-for-Prototype.zip">download a zip file with everything</a>.</p>
<p>The meetup was very informal and there were also two other presentations: Mats Bryntse gave an overview of “What’s new in EcmaScript 3.1” and Rasmus Olausson showed us a “Hello world with Google Web Toolkit” as well as how to beat his Sudoku webapp :-)</p>
<p>After the presentations were well tucked away, we talked about who and what we’d like to see at <a href="http://www.oredev.org/">Öredev 2009</a>.</p>
IE6 Background flicker once again2009-03-27T00:00:00+00:00http://roderick.dk//2009/03/27/ie6-background-flicker-once-againMorgan Roderickmorgan@roderick.dk<h1 id="ie6-background-flicker-once-again">IE6 Background flicker once again</h1>
<p>Every once in awhile you come across one of those Internet Explorer 6 issues that tries it’s hardest to be really annoying. Today was one of those days with IE.</p>
<p>Having flown out to work directly with a client’s web team yesterday, I spent some time today cursing at IE6 and trying to deal with a weird flickering of the webpage, apparently caused by hovering over a menu.</p>
<p>After about 40 minutes, I had the palm–meets–forehead “heureka” moment, and recognised that the bug I was seeing was in fact the infamous IE6 background flicker bug, which I’ve exterminated on other sites before.</p>
<p>In order not to forget about the solution immediately, I am posting it here. Perhaps it may also shortcut the synapses of another developer and save them some time trying to squash this bug.</p>
<p>I cannot take credit for the solution, I am just posting my preferred version of it here for posterity. The solution is very simple, albeit a bit obscure.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// prevent background flickering bug in Internet Explorer 6</span>
<span class="k">try</span> <span class="p">{</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">execCommand</span><span class="p">(</span><span class="dl">"</span><span class="s2">BackgroundImageCache</span><span class="dl">"</span><span class="p">,</span><span class="kc">false</span><span class="p">,</span><span class="kc">true</span><span class="p">));</span>
<span class="p">}</span> <span class="k">catch</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{}</span>
</code></pre></div></div>
<p>To avoid pollution the rest of the website for users with modern browsers, I prefer to stick this in my IE6.js file and load it using conditional comments.</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"><!--[if lte IE 7]>
<script type="text/javascript" src="/javascripts/ie6.js"></script>
<![endif]--></span>
</code></pre></div></div>
<p>This is yet another example of developers using Internet Explorers misguided proprietary extensions to counter some of all the obscsure bugs.</p>
<h2 id="when-should-i-use-this">When should I use this?</h2>
<p>You should be using this fix on every site that uses background images and mouse over effects … so basically, you should <em>always</em> be using this for sites that need to support IE6, and so should I.</p>
<p>Thankfully, we’re seeing the start of a global movement to be rid of IE6 once and for all, and soon we will be able to throw out all the weird fixes for Internet Explorer 6.</p>
<p>Recently, DR (Denmarks Radio) announced that they’re <a href="http://www.version2.dk/artikel/10451-dr-dropper-internet-explorer-6">dropping IE6 for IE8 on the machines of 3.000 employees</a> … and with more and more organisations finally moving out of the dark ages, we can finally lay this old horse to rest.</p>
<h2 id="this-fix-seen-elsewhere">This fix seen elsewhere</h2>
<ul>
<li><a href="http://misterpixel.blogspot.com/2006/09/forensic-analysis-of-ie6.html">A forensic analysis of the IE6 BackgroundImageCache command identifier</a></li>
<li><a href="http://evil.che.lu/2006/09/25/no-more-ie6-background-flicker">No more IE6 background flicker</a></li>
</ul>
<h2 id="update---fixing-it-server-side">Update - Fixing it server side</h2>
<p><a href="http://www.robertnyman.com">Robert Nyman</a> pointed me towards <a href="http://dean.edwards.name/my/flicker.html">Dean Edwards’ solution using expiration headers</a>, which you should be setting anyway, see (<a href="http://developer.yahoo.com/performance/rules.html#expires">YDN article - Add an Expires or a Cache-Control Header</a>).</p>
<p>To improve user experience, we’ve been adding cache-control headers to just about everything for quite some time, so maybe that is why IE6 background flickering is a problem we don’t encounter that frequently anymore.</p>
<p>It’s good to know that you have options.</p>
Sitemaps With Webby2009-03-23T00:00:00+00:00http://roderick.dk//2009/03/23/sitemaps-with-webbyMorgan Roderickmorgan@roderick.dk<h1 id="sitemaps-with-webby">Sitemaps With Webby</h1>
<p>As a followup to my two part article about <a href="/2009/03/16/creating-sitemaps-with-comatose-cms/">Creating Sitemaps with Comatose CMS</a>, I wanted to share with you, how I am currently implementing Sitemaps on this blog.</p>
<p>After taking a stab at implementing my own solution for about 10 minutes (with <a href="http://webby.rubyforge.org/">Webby</a>, you get surprisingly far in 10 minutes), I used my google-fu and found an article about <a href="http://www.opensourcery.co.za/2008/10/19/easy-googleyahoo-sitemaps-with-webby">Easy Google/Yahoo! Sitemaps with webby</a>. Implementation took about 5 minutes, and I have have a fully functional Sitemap.</p>
Adding Page Caching to Sitemaps2009-03-17T00:00:00+00:00http://roderick.dk//2009/03/17/adding-page-caching-to-sitemapsMorgan Roderickmorgan@roderick.dk<h1 id="adding-page-caching-to-sitemaps">Adding Page Caching to Sitemaps</h1>
<p>The shortest distance between two points is not a straight line. The shortest distance is zero. Admittedly, we’re not about to fold space or do time travel, but you get the idea.</p>
<p>Likewise, for any web framework, the fastest way to deliver content to clients is to not use the framework at all, but let the webserver serve static files to clients.</p>
<p>In Rails this means using page caching and leave the heavy lifting to the webserver. Keeping your cache fresh and still maintaining stellar performance might seem like a daunting task, but Rails gives you quite a bit of help, so it is actually not that hard to do.</p>
<p>In this post I will take you through the steps to add page caching to our Sitemap, that we created in <a href="/blog/2009/03/16/creating-sitemaps-with-comatose-cms.html.">Creating Sitemaps with Comatose CMS</a></p>
<h2 id="enable-page-caching-for-our-sitemap">Enable page caching for our Sitemap</h2>
<p>As you can see below, enabling page caching is as simple as just adding one extra line in a controller</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">## app/controllers/info_controller.rb</span>
<span class="k">class</span> <span class="nc">InfoController</span> <span class="o"><</span> <span class="no">ApplicationController</span>
<span class="n">caches_page</span> <span class="ss">:sitemap</span>
<span class="k">def</span> <span class="nf">sitemap</span>
<span class="n">respond_to</span> <span class="k">do</span> <span class="o">|</span><span class="nb">format</span><span class="o">|</span>
<span class="nb">format</span><span class="p">.</span><span class="nf">xml</span> <span class="k">do</span>
<span class="vi">@website_url</span> <span class="o">=</span> <span class="s1">'http://example.com'</span>
<span class="vi">@pages</span> <span class="o">=</span> <span class="no">ComatosePage</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="ss">:all</span><span class="p">,</span> <span class="ss">:conditions</span> <span class="o">=></span> <span class="s2">"full_path not like ''"</span><span class="p">)</span>
<span class="n">render</span> <span class="ss">:action</span> <span class="o">=></span> <span class="s1">'sitemap'</span><span class="p">,</span> <span class="ss">:layout</span> <span class="o">=></span> <span class="kp">false</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<h3 id="verify-caching">Verify caching</h3>
<p>To verify that we are have succesfully enabled page cache, let’s update the development environment to mimick the production environment.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">## config/environments/development.rb</span>
<span class="n">config</span><span class="p">.</span><span class="nf">action_controller</span><span class="p">.</span><span class="nf">perform_caching</span> <span class="o">=</span> <span class="kp">true</span>
</code></pre></div></div>
<p>Then we need to restart the server, do a request to <a href="http://localhost:3000/sitemap.xml">http://localhost:3000/sitemap.xml</a> and you should see something like the following in your log.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Processing InfoController#sitemap <span class="o">(</span><span class="k">for </span>127.0.0.1 at 2009-03-17 17:04:26<span class="o">)</span> <span class="o">[</span>GET]
Parameters: <span class="o">{</span><span class="s2">"action"</span><span class="o">=></span><span class="s2">"sitemap"</span>, <span class="s2">"controller"</span><span class="o">=></span><span class="s2">"info"</span><span class="o">}</span>
SQL <span class="o">(</span>0.2ms<span class="o">)</span> SET NAMES <span class="s1">'utf8'</span>
SQL <span class="o">(</span>0.1ms<span class="o">)</span> SET <span class="nv">SQL_AUTO_IS_NULL</span><span class="o">=</span>0
ComatosePage Load <span class="o">(</span>1.5ms<span class="o">)</span> SELECT <span class="k">*</span> FROM <span class="sb">`</span>comatose_pages<span class="sb">`</span> WHERE full_path not like <span class="s1">''</span>
Rendering info/sitemap
ComatosePage Columns <span class="o">(</span>2.0ms<span class="o">)</span> SHOW FIELDS FROM <span class="sb">`</span>comatose_pages<span class="sb">`</span>
Cached page: /sitemap.xml <span class="o">(</span>0.7ms<span class="o">)</span>
Completed <span class="k">in </span>16ms <span class="o">(</span>View: 9, DB: 4<span class="o">)</span> | 200 OK <span class="o">[</span>http://localhost/sitemap.xml]
</code></pre></div></div>
<p>The line we’re looking for is <code class="language-plaintext highlighter-rouge">Cached page: /sitemap.xml (0.7ms)</code></p>
<p>In your public folder you should also see a <code class="language-plaintext highlighter-rouge">sitemap.xml</code> file.</p>
<p>If everything is configured correctly, subsequent requests to <code class="language-plaintext highlighter-rouge">/sitemap.xml</code> should not show up in the applications log, as the webserver is now serving the static file and not using Rails at all :-)</p>
<h2 id="add-a-cache-sweeper">Add a cache sweeper</h2>
<p>Now that we can succesfully cache the sitemap, we need to make sure it stays fresh, when content in Comatose is updated.</p>
<p>Rails provides us with Cache Sweepers, which is kind of like an observer, but specialised. Let’s create a cache sweeper that observes ComatosePage, and deletes the cached sitemap.xml when pages are saved or destroyed.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">## app/sweepers/comatose_sweeper.rb</span>
<span class="k">class</span> <span class="nc">ComatoseSweeper</span> <span class="o"><</span> <span class="no">ActionController</span><span class="o">::</span><span class="no">Caching</span><span class="o">::</span><span class="no">Sweeper</span>
<span class="n">observe</span> <span class="no">ComatosePage</span>
<span class="k">def</span> <span class="nf">after_save</span><span class="p">(</span><span class="n">page</span><span class="p">)</span>
<span class="n">expire_cache</span><span class="p">(</span><span class="n">page</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">after_destroy</span><span class="p">(</span><span class="n">page</span><span class="p">)</span>
<span class="n">expire_cache</span><span class="p">(</span><span class="n">page</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">expire_cache</span><span class="p">(</span><span class="n">page</span><span class="p">)</span>
<span class="c1"># Use the ApplicationController, as were outside the scope</span>
<span class="c1"># of the executing controller</span>
<span class="no">ApplicationController</span><span class="p">.</span><span class="nf">expire_page</span><span class="p">(</span> <span class="s2">"/sitemap.xml"</span> <span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Finally, we need to tell Comatose to use the sweeper.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">## config/initializers/comatose.rb</span>
<span class="c1"># set a cache sweeper to react when comatose expires pages from it's page caching</span>
<span class="no">ComatoseAdminController</span><span class="p">.</span><span class="nf">send</span> <span class="ss">:cache_sweeper</span><span class="p">,</span>
<span class="ss">:comatose_sweeper</span><span class="p">,</span> <span class="ss">:only</span> <span class="o">=></span> <span class="s1">'expire_cms_page'</span>
</code></pre></div></div>
<h3 id="verify-cache-sweeper">Verify cache sweeper</h3>
<p>To verify that your cache sweeper is working, all you need to is to is to save a page in Comatose and then verify the absense of <code class="language-plaintext highlighter-rouge">sitemap.xml</code> from the public folder.</p>
<h2 id="finally">Finally</h2>
<p>That’s it! You know have a Comatose based Sitemap that will only be generated when there are changes.</p>
<p>P.S. Don’t forget to set your development environment to NOT use caching anymore.</p>
<h2 id="resources">Resources</h2>
<ul>
<li><a href="http://www.railsenvy.com/2007/2/28/rails-caching-tutorial">Rails Envy: Ruby on Rails Caching Tutorial</a></li>
<li><a href="http://www.railsenvy.com/2007/3/20/ruby-on-rails-caching-tutorial-part-2">Rails Envy: Ruby on Rails Caching Tutorial - Part 2</a></li>
<li><a href="http://railslab.newrelic.com/scaling-rails">Scaling Rails Screencasts</a></li>
</ul>
Creating Sitemaps with Comatose CMS2009-03-16T00:00:00+00:00http://roderick.dk//2009/03/16/creating-sitemaps-with-comatose-cmsMorgan Roderickmorgan@roderick.dk<h1 id="creating-sitemaps-with-comatose-cms">Creating Sitemaps with Comatose CMS</h1>
<p>For some time now, I’ve been using <a href="http://github.com/darthapo/comatose/tree/master">Comatose CMS</a> for client sites. It is quite possible the smallest Rails based CMS, having only the features you need for most sites and flexible enough to allow you to extend it if you need to.</p>
<p>Whenever you’re doing content publishing, you should make it as easy as possible for search engines to find and catalog our content. In this post I will show you how you can create a simple <a href="http://www.sitemaps.org">Sitemap</a> from a Comatose CMS.</p>
<p>Here is how I have created Sitemaps from Comatose. The code samples have been extracted from client projects.</p>
<h2 id="routing">Routing</h2>
<p>First we will map <code class="language-plaintext highlighter-rouge">/sitemap.xml</code> to an action on controller.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># routes.rb</span>
<span class="no">ActionController</span><span class="o">::</span><span class="no">Routing</span><span class="o">::</span><span class="no">Routes</span><span class="p">.</span><span class="nf">draw</span> <span class="k">do</span> <span class="o">|</span><span class="n">map</span><span class="o">|</span>
<span class="n">map</span><span class="p">.</span><span class="nf">connect</span> <span class="s2">"sitemap.xml"</span><span class="p">,</span> <span class="ss">:controller</span> <span class="o">=></span> <span class="s2">"info"</span><span class="p">,</span> <span class="ss">:action</span> <span class="o">=></span> <span class="s2">"sitemap"</span>
<span class="k">end</span>
</code></pre></div></div>
<h2 id="action">Action</h2>
<p>In the action of the controller, we will build a collection of pages to include in the sitemap. By not iterating over the <code class="language-plaintext highlighter-rouge">children</code> collection of each page, we avoid creating numerous calls to the database. Instead we will just use an SQL based find to create our collection.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># info_controller.rb ( or other public controller )</span>
<span class="k">def</span> <span class="nf">sitemap</span>
<span class="n">respond_to</span> <span class="k">do</span> <span class="o">|</span><span class="nb">format</span><span class="o">|</span>
<span class="nb">format</span><span class="p">.</span><span class="nf">xml</span> <span class="k">do</span>
<span class="vi">@website_url</span> <span class="o">=</span> <span class="s1">'http://www.hamsterboy.dk'</span>
<span class="vi">@pages</span> <span class="o">=</span> <span class="no">ComatosePage</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="ss">:all</span><span class="p">,</span> <span class="ss">:conditions</span> <span class="o">=></span> <span class="s2">"full_path not like ''"</span><span class="p">)</span>
<span class="n">render</span> <span class="ss">:action</span> <span class="o">=></span> <span class="s1">'sitemap'</span><span class="p">,</span> <span class="ss">:layout</span> <span class="o">=></span> <span class="kp">false</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<h2 id="rendering-sitemap">Rendering sitemap</h2>
<p>After finding the pages, all we need to do is to render them as a sitemap.</p>
<p>As you will note, the frontpage of the site gets special treatment. It’s lastmod attribute is set to the current time (as you probably have content from other sources than your Comatose CMS) and more importantly, we’re setting a <em>different priority</em> from all the other pages. Search engines need to know which content is more important on your site, and Google Webmaster Tools will give you warnings if all your pages have the same priority.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># sitemap.rxml</span>
<span class="n">xml</span><span class="p">.</span><span class="nf">instruct!</span>
<span class="n">xml</span><span class="p">.</span><span class="nf">urlset</span> <span class="s2">"xmlns"</span> <span class="o">=></span> <span class="s2">"http://www.sitemaps.org/schemas/sitemap/0.9"</span> <span class="k">do</span>
<span class="c1"># create an entry for the frontpage</span>
<span class="n">xml</span><span class="p">.</span><span class="nf">url</span> <span class="k">do</span>
<span class="n">xml</span><span class="p">.</span><span class="nf">loc</span> <span class="s2">"</span><span class="si">#{</span><span class="vi">@website_url</span><span class="si">}</span><span class="s2">/"</span>
<span class="n">xml</span><span class="p">.</span><span class="nf">lastmod</span> <span class="n">w3c_date</span><span class="p">(</span> <span class="no">Time</span><span class="p">.</span><span class="nf">now</span> <span class="p">)</span>
<span class="n">xml</span><span class="p">.</span><span class="nf">changefreq</span> <span class="s2">"weekly"</span>
<span class="n">xml</span><span class="p">.</span><span class="nf">priority</span> <span class="mf">1.0</span>
<span class="k">end</span>
<span class="c1"># create an entry for each of the pages from the find method</span>
<span class="vi">@pages</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">page</span><span class="o">|</span>
<span class="n">xml</span><span class="p">.</span><span class="nf">url</span> <span class="k">do</span>
<span class="n">xml</span><span class="p">.</span><span class="nf">loc</span> <span class="s2">"</span><span class="si">#{</span><span class="vi">@website_url</span><span class="si">}</span><span class="s2">/</span><span class="si">#{</span><span class="n">page</span><span class="p">.</span><span class="nf">full_path</span><span class="si">}</span><span class="s2">"</span>
<span class="n">xml</span><span class="p">.</span><span class="nf">lastmod</span> <span class="n">w3c_date</span><span class="p">(</span><span class="n">page</span><span class="p">.</span><span class="nf">updated_on</span><span class="p">)</span>
<span class="n">xml</span><span class="p">.</span><span class="nf">changefreq</span> <span class="s2">"weekly"</span>
<span class="n">xml</span><span class="p">.</span><span class="nf">priority</span> <span class="mf">0.9</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<h2 id="formatting-dates-as-w3c-dates">Formatting dates as W3C dates</h2>
<p>Almost there… to avoid repetition, I’ve created a little helper for formatting the dates for sitemaps in the <a href="http://www.w3.org/TR/NOTE-datetime">W3C Datetime</a> format.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nn">SitemapHelper</span>
<span class="k">def</span> <span class="nf">w3c_date</span><span class="p">(</span><span class="n">date</span><span class="p">)</span>
<span class="n">date</span><span class="p">.</span><span class="nf">utc</span><span class="p">.</span><span class="nf">strftime</span><span class="p">(</span><span class="s2">"%Y-%m-%dT%H:%M:%S+00:00"</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<h2 id="final-result">Final result</h2>
<p>Testing the above code on a virgin Comatose database at <a href="http://localhost:3000/sitemap.xml">http://localhost:3000/sitemap.xml</a>, you should see something like this</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><?xml version="1.0" encoding="UTF-8"?></span>
<span class="nt"><urlset</span> <span class="na">xmlns=</span><span class="s">"http://www.sitemaps.org/schemas/sitemap/0.9"</span><span class="nt">></span>
<span class="nt"><url></span>
<span class="nt"><loc></span>http://example.com/<span class="nt"></loc></span>
<span class="nt"><lastmod></span>2009-03-16T08:41:23+00:00<span class="nt"></lastmod></span>
<span class="nt"><changefreq></span>weekly<span class="nt"></changefreq></span>
<span class="nt"><priority></span>1.0<span class="nt"></priority></span>
<span class="nt"></url></span>
<span class="nt"></urlset></span>
</code></pre></div></div>
<p>That’s it, your site is now a little easier for search engines to catalog.</p>
<h2 id="where-do-i-go-from-here">Where do I go from here?</h2>
<p>Well, that is entirely up to you. If you have any other kind of content that you’re publishing on your site, it should not be too hard to extend the sitemap to include that as well.</p>
<p>Please do note that this post only describes Sitemap in it’s simplest form, there are limitations as your sitemaps grows, and there are options to create more specialized sitemaps as well.</p>
<h3 id="resources">Resources</h3>
<ul>
<li><a href="http://github.com/darthapo/comatose/tree/master">Comatose CMS</a></li>
<li><a href="http://www.sitemaps.org/">Sitemap</a></li>
<li><a href="http://www.google.com/webmasters/tools/">Google Webmaster Tools</a></li>
</ul>
Hello world, webby!2009-03-11T00:00:00+00:00http://roderick.dk//2009/03/11/hello-world-webbyMorgan Roderickmorgan@roderick.dk<h1 id="hello-world-webby">Hello world, webby!</h1>
<p>You might wonder what is going on with this site right now, and it might look very incomplete at the moment you are viewing it.</p>
<p>I am rebuilding the website using <a href="http://webby.sourceforge.org">Webby</a>, a small web generation tool. It is purely a learning experience, but with a very tangible end goal: an easy-to-manage blog.</p>
<p>Predictions are that the site will be updated at highly irregular intervals, as I am hacking away at just about everything at once.</p>
How to create un-indexable content for missing javascript warnings2008-11-20T00:00:00+00:00http://roderick.dk//2008/11/20/un-indexable-javascript-warningsMorgan Roderickmorgan@roderick.dk<h1 id="how-to-create-un-indexable-content-for-missing-javascript-warnings">How to create un-indexable content for missing javascript warnings</h1>
<p>At Gazebo we love to use unobtrusive enhancement to make our solutions available to the biggest possible audience, and greatly improve the experience for users with sophisticated user-agents.</p>
<p>This usually means:</p>
<ul>
<li>Create semantic, valid markup, which can be read by any browser, including phones</li>
<li>Add styling via CSS, to make it look nice in modern, sophisticated browsers</li>
<li>Sprinkle a little javascript, to make it all <em>behave</em> nicely for supported user-agents</li>
</ul>
<p>To control decoration, when javascript IS available, I usually add <code class="language-plaintext highlighter-rouge">js-enabled</code> or something similar to the classname of the <code class="language-plaintext highlighter-rouge"><body></code> element. This allows me differentiate the styling of widgets for when javascript is available, and allows a controlled fallback decoration, for when it is not.</p>
<p>This is all nice and dandy, but sometimes javascript IS a fundamental requirement of your application, and then it’s a whole different mess of issues. This post will give you the details on how to deal with one of these issues.</p>
<h2 id="avoiding-getting-your-warnings-indexed-by-search-engines">Avoiding getting your warnings indexed by search engines</h2>
<p>One project we’re currently working on, is entirely depending on javascript to allow the user interaction with the application. Because of this requirement, we wanted to play nice, and tell users without javascript, that it is a requirement to use the web app.</p>
<p>But, and here’s the kicker, I didn’t want every page on the site indexed by Google to have a big fat warning, telling users to go elsewhere.</p>
<p>So, how does one go about providing users with nice friendly warnings, without spamming the search engine indexes with useless warnings, that say absolutely nothing about your site?</p>
<p>So far, the only solution I have been able to come up with is this:</p>
<ul>
<li>Add a <noscript> element to the page to contain the warning(s). This takes care of the visiblity problems, as it is only visible to users without javascript. But unfortunately, search engines will still index it as regular content.</li>
<li>To prevent indexing, place the content in a separate file, and load that file using an iframe inside the noscript tag, thus: <code class="language-plaintext highlighter-rouge"><noscript><iframe src="fancy-javascript-required-warning.html" /></noscript></code></li>
<li>Lastly, don’t forget to modify your robots.txt to make sure search engines will know to exclude the warning message from the index</li>
</ul>
<p>And that’s it … you can now create nice, user-friendly warnings about javascript being a requirements for your application, without ruining your SEO efforts :-)</p>
<p>This a repost from the Gazebo blog, as it is no longer maintained, and I didn’t want my posts from that blog to disappear.</p>
Fixing Bus Error / Segfault in Rcov2008-11-16T00:00:00+00:00http://roderick.dk//2008/11/16/fixing-bus-error-segfault-in-rcovMorgan Roderickmorgan@roderick.dk<h1 id="fixing-bus-error--segfault-in-rcov">Fixing Bus Error / Segfault in Rcov</h1>
<p>We have recently run into problems with “rcov”:http://eigenclass.org/hiki/rcov crashing with seemingly random errors, like</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/Library/Ruby/Gems/1.8/gems/activesupport-2.1.1/lib/active_support/core_ext/symbol.rb:11: <span class="o">[</span>BUG] Bus Error ruby 1.8.6 <span class="o">(</span>2008-03-03<span class="o">)</span> <span class="o">[</span>universal-darwin9.0]
</code></pre></div></div>
<p>Having CruiseControl.rb suddenly claim that all builds are broken, get’s to be very annoying. Working on a large project without coverage reports is just not the same, once you get hooked on thoroughly testing the application you’re working on.</p>
<p>After some hunting around on Google, it turns out that <a href="http://eigenclass.org/hiki/rcov-0.8.1">others</a> have run into <a href="http://rspec.lighthouseapp.com/projects/5645/tickets/309-fix-for-rcov-segfault">similar problems</a>.</p>
<p>Chad Humphries has kindly put together a <a href="http://github.com/spicycode/rcov/tree/master">replacement rcov gem (spicycode-rcov)</a> to use, while we wait for <a href="http://eigenclass.org/hiki/rcov">the original rcov</a> to be updated.</p>
<p>To use the spicycode-rcov gem, you must first get rid of your old rcov gem:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>gem uninstall rcov
</code></pre></div></div>
<p>And then just install spicycode-rcov</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nb">sudo </span>gem <span class="nb">install </span>spicycode-rcov
</code></pre></div></div>
<p>The requirements for building spicycode-rcov should be the same as building the original rcov, so if you got that working already, you should have no problems.</p>
<p>This was originally posted by me on the Gazebo blog at 2008-11-16 at 07:36. That blog is no longer updated, so I have moved the post here.</p>