Jerod Santo2019-11-25T14:15:47-06:00http://jerodsanto.net/Jerod SantoFull Stack Radiohttp://jerodsanto.net/2019/06/full-stack-radio/2019-06-10T00:00:00-05:00
<p>Adam Wathan invited me on his excellent <a href="http://www.fullstackradio.com">Full Stack Radio</a> podcast to talk about building <a href="https://changelog.com">Changelog.com</a> with Elixir and Phoenix. Topics include:</p>
<ul>
<li>How pattern matching works in Elixir and why it’s more powerful than method overloading in other languages</li>
<li>How Elixir’s pipe operator makes the transition from OO to functional programming more natural</li>
<li>Why you don’t need to be intimidated by unfamiliar features like GenServers to use Elixir for web app development</li>
<li>Noticeable differences between working with Rails and Phoenix and what it was like to transition</li>
<li>How the Phoenix ORM makes n+1 queries impossible</li>
<li>Why background tasks are a lot easier in Elixir than in an ecosystem like PHP</li>
<li>What other tools and technology power the Changelog platform</li>
<li>How the Changelog Phoenix app is deployed</li>
</ul>
<p><a href="http://www.fullstackradio.com/116">You can listen to the episode right here.</a></p>
<p>If you like listening to me blather on about software development, also take a listen to <a href="https://changelog.com/backstage/4">Backstage #4</a> where I do exactly that with fellow-developer, Nick Janetakis. And, since we built our own custom platform, I can even do a shiny embed of that episode for ya! 🙌</p>
<audio data-theme="day" data-src="https://changelog.com/backstage/4/embed" src="https://cdn.changelog.com/uploads/backstage/4/backstage-4.mp3" preload="none" class="changelog-episode" controls=""></audio>
<script async="" src="//cdn.changelog.com/embed.js"></script>
Listen to me on SendGrid's podcasthttp://jerodsanto.net/2019/02/listen-to-me-on-sendgrids-podcast/2019-02-13T00:00:00-06:00
<p>I was honored to be interviewed by <a href="https://mobile.twitter.com/thinkingserious">Elmer Thomas</a> for SendGrid’s very cool <a href="https://soundcloud.com/somecodingrequired">Some Coding Required</a> podcast. We talked about my favorite open source project, how open source has impacted my life, and gave some advice for open source contributors and maintainers.</p>
<p>My segment <a href="https://soundcloud.com/somecodingrequired/podcastinit6-oscon-2018-recap#t=7:19">starts right here</a>. Or listen to the whole thing. 14 minutes short.</p>
<iframe width="100%" height="300" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/563488455&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true"></iframe>
Our 2018 State of the "log" addresshttp://jerodsanto.net/2018/12/our-2018-state-of-the-log-address/2018-12-19T00:00:00-06:00
<p>It’s been a good year. Take <a href="https://changelog.com/podcast/328">a listen</a>:</p>
<blockquote>
<p>We’re going behind the scenes to look back at 2018 as we prepare for 2019 and onward. We talk through our most popular episodes, most controversial episodes, and even some of our personal favorites.</p>
</blockquote>
<audio data-theme="night" data-src="https://changelog.com/podcast/328/embed" src="https://cdn.changelog.com/uploads/podcast/328/the-changelog-328.mp3" preload="none" class="changelog-episode" controls=""></audio>
<script async="" src="//cdn.changelog.com/embed.js"></script>
My Favorite Changelog Episodes of 2016http://jerodsanto.net/2016/12/my-favorite-changelog-episodes-of-2016/2016-12-31T00:00:00-06:00
<p>We shipped 44 episodes of The Changelog in 2016. That’s a lot of conversations!</p>
<p>All of our guests are interesting and insightful in their own ways, but there are a handful that continue to resonate with me in my work and life since we spoke with them. Here they are, in chronological order:</p>
<h2 id="nadia-eghbal">Nadia Eghbal</h2>
<p>Nadia’s outsider (turned insider) take on open source and funding sparked debates and actions throughout the year. This topic is so near-and-dear to our hearts that we started an entirely new podcast with Nadia and co-host Mikeal Rogers: <a href="https://changelog.com/rfc">Request For Commits</a>.</p>
<audio src="https://cdn.changelog.com/uploads/podcast/193/the-changelog-193.mp3" preload="none" class="changelog-episode" data-src="https://changelog.com/podcast/193/embed" data-theme="night" controls=""></audio>
<h2 id="matt-mullenweg">Matt Mullenweg</h2>
<p>Matt’s reputation preceeded him, but I was surprised at how soft-spoken, kind, and full of insights he is. I could talk to him for hours on end.</p>
<audio src="https://cdn.changelog.com/uploads/podcast/197/the-changelog-197.mp3" preload="none" class="changelog-episode" data-src="https://changelog.com/podcast/197/embed" data-theme="night" controls=""></audio>
<h2 id="richard-hipp">Richard Hipp</h2>
<p>This might actually be my #1 favorite. Sqlite’s story is inspiring and Richard Hipp is a saint.</p>
<audio src="https://cdn.changelog.com/uploads/podcast/201/the-changelog-201.mp3" preload="none" class="changelog-episode" data-src="https://changelog.com/podcast/201/embed" data-theme="night" controls=""></audio>
<h2 id="yukihiro-matsumoto-matz">Yukihiro Matsumoto (Matz)</h2>
<p>This was the show I was most nervous to record, and with good reason. It’s Matz! He did not disappoint.</p>
<audio src="https://cdn.changelog.com/uploads/podcast/202/the-changelog-202.mp3" preload="none" class="changelog-episode" data-src="https://changelog.com/podcast/202/embed" data-theme="night" controls=""></audio>
<p>(For a behind-the-scenes look at just how nervous we were for this show, listen to <a href="https://changelog.com/spotlight/2">my conversation with Katrina Owen on Spotlight #2</a>)</p>
<h2 id="pieter-hintjens">Pieter Hintjens</h2>
<p>When Adam booked this show with Pieter to talk about his life and pending death, I thought he was nuts. Turned out he was genius, as its perhaps the show we’re most proud of and beloved by tens of thousands. We miss you Pieter!</p>
<audio src="https://cdn.changelog.com/uploads/podcast/205/the-changelog-205.mp3" preload="none" class="changelog-episode" data-src="https://changelog.com/podcast/205/embed" data-theme="night" controls=""></audio>
<h2 id="cory-doctorow">Cory Doctorow</h2>
<p>Cory is one of those guys who you can just wind up and watch him go. This was a challenging conversation, and I mean that in the best sense of the word.</p>
<audio src="https://cdn.changelog.com/uploads/podcast/221/the-changelog-221.mp3" preload="none" class="changelog-episode" data-src="https://changelog.com/podcast/221/embed" data-theme="night" controls=""></audio>
<h2 id="sandi-metz">Sandi Metz</h2>
<p>Last, but certainly not least. Sandi is so smart, so nice, and manages to teach you things while you don’t even realize it. She deserves every bit of credit the greater Ruby community has given her over the years.</p>
<audio src="https://cdn.changelog.com/uploads/podcast/225/the-changelog-225.mp3" preload="none" class="changelog-episode" data-src="https://changelog.com/podcast/225/embed" data-theme="night" controls=""></audio>
<h2 id="up-next">Up Next</h2>
<p>With guests like Linda Liukas, Steve Klabnik, Ashley Willams, and Nathan Sobo already booked, 2017 is shaping up to be another <em>excellent</em> time to be a <a href="https://changelog.com/subscribe">Changelog listener</a>.</p>
<script async="" src="//cdn.changelog.com/embed.js"></script>
5 Answers For Coder Catchup Episode 100http://jerodsanto.net/2016/12/5-answers-for-coder-catchup-episode-100/2016-12-22T00:00:00-06:00
<p>To celebrate episode 100 of Jaymie Jones’ <a href="http://codercatchup.com">Coder Catchup</a> podcast, Jaymie reached out to a handful of people and asked us 5 questions about web development, which he then read on the show.</p>
<p>I was honored to be on the show alongside such great web folks as Chris Coyier, Wes Bos, Adam Stacoviak, Sarah Allen, and more.</p>
<p>Since I wrote my answers to Jaymie in Markdown and shipped them off for him to read, I figured I’d also post them here as well.</p>
<p>But still, you should <a href="http://codercatchup.com/episodes/55598-episode-100-one-hundred">listen to his Episode 100</a> since there are many great answers to the questions below. Enjoy!</p>
<h3 id="if-you-were-starting-fresh-what-would-you-primarily-focus-on-eg-as-a-new-web-designerdeveloper">1. If you were starting fresh, what would you primarily focus on? (e.g. as a new web designer/developer)</h3>
<p>Beginners <em>shouldn’t focus</em> much, I don’t think. This is why many 101 level courses are surveys of an entire field. It’s important to get the lay of the land before focusing in on one or a few things. How else can you get a sense of what’s worth focusing on?</p>
<p>In web development, I think that means learning how the web works as a system. Clients, servers, DNS, HTTP(s), and HTML are the underpinnings of the web that should be understood first. Then, I’d try to use that knowledge to publish a website, soup-to-nuts. Once you can do that on your own, the opportunities really open up for you.</p>
<h3 id="what-is-one-piece-of-advice-you-think-is-most-important-for-web-developersdesigners-going-forward">2. What is one piece of advice you think is most important for web developers/designers going forward?</h3>
<p>Generalize. Technologies come to fame then fall from favor faster than boy bands. If you gained expertise in Thing A by burying your head in it and ignoring Things B, C, and D, your skills may be quite marketable today and <em>completely irrelevant</em> tomorrow. On the other hand, if you keep your eyes on Things A through D while working with maybe B and C, you stand a much better chance of remaining valuable as things change.</p>
<p>If we look at our ongoing education in terms of breadth and depth, my advice (and practice) is to go for breadth habitually and go for depth when the need arises.</p>
<h3 id="what-would-you-do-to-get-out-of-a-slump-or-plateau-with-your-web-career">3. What would you do to get out of a slump or plateau with your web career?</h3>
<p>This depends on what you mean by slump, but I’ll assume it means waning interest in the web and my work on it. In this case, I’ve found that side projects are great slump busters. Working on a side project that I care about energizes me and helps me power through times of low motivation, especially if they’re challenging and push me outside of my comfort zone. Frankly, that’s one of my favorite things about working on Changelog. Producing awesome content for developers is an entirely different challenge from writing software itself. Plus, it usually means hacking on a few things along the way!</p>
<h3 id="what-is-1-thing-you-would-like-to-see-web-developersdesigners-doing-more-of">4. What is 1 thing you would like to see web developers/designers doing more of?</h3>
<p>I’d love to see web developers and designers focus more on the fundamentals and less on bleeding edge features and new techniques. Get the basics right: quality content, ease of use, and speed of delivery. The rest is just icing on the cake.</p>
<h3 id="one-piece-of-advice-of-your-choosing">5. One piece of advice of your choosing</h3>
<p>Listen to <a href="https://changelog.com">more podcasts</a>. :)</p>
Safari does not trigger click events on anchors or buttons containing SVG elementshttp://jerodsanto.net/2015/08/safari-does-not-trigger-click-events-on-anchors-or-buttons-containing-svg-elements/2015-08-18T00:00:00-05:00
<p>This fact will ruin your day if, for instance, you are expecting Rails’ jQuery UJS to Just Work when you add a <code>remote: true</code> or <code>method: :post</code> to that <code>link_to</code> helper. You know, something like this:</p>
<p>It’ll work in Chrome. It’ll work in Firefox. But Safari on the other hand…</p>
<p>Safari will not trigger a <code>click</code> event and whatever JavaScript you were expecting to fire will not. How to fix? In your CSS:</p>
<div class="highlight"><pre><code class="language-css" data-lang="css"><span class="nt">svg</span> <span class="p">{</span>
<span class="k">pointer</span><span class="o">-</span><span class="n">events</span><span class="o">:</span> <span class="k">none</span><span class="p">;</span>
<span class="p">}</span></code></pre></div>
<p>This took me way too long to diagnose. Hopefully this post saves you some time/money!</p>
New Mac: Eventual Installshttp://jerodsanto.net/2015/04/new-mac-eventual-installs/2015-04-11T00:00:00-05:00
<p>It’s been a few weeks since I started the process of setting up my new laptop. I <a href="/2015/03/new-mac-instant-installs/">wrote previously</a> about which apps and tweaks I made immediately after unboxing. Now I’m back to share what I’ve done since.</p>
<p>The most surprising thing to me is that I’m <em>still</em> dual wielding.</p>
<p><img alt="The machines have at least switched sides. Progress!" src="http://jerodsanto.net/drop/macs-side-by-side.jpg" style="max-width: 400px" /></p>
<p>It’s been pretty nice to have the new machine always plugged in and configured with multiple monitors and the old machine floating between the desk, upstairs, and my travel bag. It’s <em>almost</em> as good as having <a href="http://www.thewire.com/technology/2013/03/dave-morin-path-interview/63613/">a day phone and a night phone</a>.</p>
<p>Let’s see what’s changed since last time.</p>
<h2 id="apps">Apps</h2>
<p>I’m still only installing apps out of necessity, but it turns out I need a lot of ‘em!</p>
<p><img alt="Page 2 of LaunchPad" src="http://jerodsanto.net/drop/eventual-installs.png" style="max-width: 512px;" /></p>
<ul>
<li>
<p><a href="http://tapbots.com/tweetbot/mac/">Tweetbot</a> — the best-in-breed Twitter client. It’s getting a bit long in the tooth, but it’s still indespensible. I will buy version 2 as soon as it hits the App Store.</p>
</li>
<li>
<p><a href="http://audacity.sourceforge.net">Audacity</a> — I was hoping to get by with <em>just</em> Audio Hijack, but it turns out Audacity is still better when recording many takes of the same content (for ad reads, intros, etc.). What’s worse: it is brutally ugly on a retina display.</p>
</li>
<li>
<p><a href="http://www.rdio.com">Rdio</a> — I love the web, but for the web services I use all-day-every-day (Slack, Rdio, Harvest), I’ll take the desktop app, please. Even if that app is just wrapping a web view, as is the case with Rdio.</p>
</li>
<li>
<p><a href="http://flexibits.com/Fantastical">Fantastical 2</a> — So much better than Apple’s Calendar it isn’t even funny.</p>
</li>
<li>
<p><a href="http://www.skype.com/">Skype</a> — Skype could’ve gone away if Google hadn’t attached Hangouts to a dead, rotting corpse.</p>
</li>
<li>
<p><a href="http://rowanj.github.io/gitx/">GitX</a> — I hop back and forth between Git’s CLI and GitX. GitX is great for staging changes, especially when staging hunks. There are many GitX forks out there, but I’ve found Rowan James’ to be the best one.</p>
</li>
<li>
<p><a href="http://glui.me">Glui</a> — For capturing, annotating, and sharing screenshots. It’ll post to CloudApp (boo!) or Dropbox (yay!), but mostly I just drag images from Glui to whatever Slack room I’m currently active in.</p>
</li>
<li>
<p><a href="https://eggerapps.at/postico/">Postico</a> — An awesome PostgreSQL client from a former Sequel Pro dev and current maintainer of <a href="http://postgresapp.com">Postgres.app</a>.</p>
</li>
<li>
<p><a href="http://notational.net">Notational Velocity</a> — there is <a href="http://brettterpstra.com/projects/nvalt/">a fork</a> that’s quite popular as well, but I have been happy with NV for private note taking.</p>
</li>
<li>
<p><a href="https://panic.com/transmit/">Transmit</a> — the only thing surprising about seeing Panic’s SFTP/S3 client in this list is that it didn’t make the “Instant Installs” list. Super useful.</p>
</li>
</ul>
<h2 id="tweaks">Tweaks</h2>
<p>I can’t recall <em>all</em> of the little tweaks to the stock OS that I’ve made since my last post.</p>
<p>However, I did revisit my <code>osx</code> script in my dotfiles, which has tons of goodies in it. <a href="https://github.com/jerodsanto/dotfiles/blob/master/osx">Check that out</a> if you’re interested in streamlining OS X for a hacker’s workflow.</p>
<h2 id="next">Next</h2>
<p>So far I’ve been able to go without Sparrow and iTerm, but it hasn’t been easy. If I go the distance with Terminal.app and/or Mail.app I’ll probably write up a little something about it.</p>
<p>Let me know if you’re interested in that or not. I’ve been running low on writing time lately!</p>
New Mac: Instant Installshttp://jerodsanto.net/2015/03/new-mac-instant-installs/2015-03-21T00:00:00-05:00
<p>Spring is in the air and a shiny new 13” MacBook Pro is in my office<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup>.</p>
<p>It will replace the mid-2011 13” MacBook Air that I’m writing this post with. Why aren’t I writing it on my new machine? Because for the first time ever I’ve decided <em>not</em> to migrate. My current install has been through 6 major operating system upgrades, countless experiments, untold hacks, and more. It’s time to start fresh.</p>
<p><img alt="Dual Wielding" src="http://jerodsanto.net/drop/macs-side-by-side.jpg" style="max-width: 400px" /></p>
<p>I’ll be running the two machines side-by-side for the next couple weeks, only loading things I need on to the new one. This means every app has to prove itself to me again. No exceptions.</p>
<h2 id="apps">Apps</h2>
<p>I plan to write up a few posts as I make the transition, documenting what makes the cut and what doesn’t. This post covers the instant installs that I didn’t hesitate to install on day one. Since this is a work machine, these apps are all Serious Business™. You won’t find games or family tree software in this lot. These apps help me make a living.</p>
<p><img alt="This pic might be my first and last real use for LaunchPad" src="http://jerodsanto.net/drop/instant-installs.png" style="max-width: 512px;" /></p>
<ul>
<li>
<p><a href="http://dropbox.com">Dropbox</a> — For file sync and sharing, accept no substitutes. It’s an amazing feeling to load up a new machine with Dropbox, wait a few minutes, and have all my most critical files downloaded and right where I left them.</p>
</li>
<li>
<p><a href="http://sublimetext.com/3">Sublime Text</a> — Speaking of dual wielding, I’m one of those weirdos who uses two text editors: Vim and Sublime Text. ST 3 is an excellent editor, and I’m excited to see its author back from hiatus and making progress once again.</p>
</li>
<li>
<p><a href="http://google.com/chrome">Chrome</a> — I fell out of love with Chrome as a day-to-day browser<sup id="fnref:2"><a href="#fn:2" class="footnote">2</a></sup>, but it still has best-in-class Dev Tools, which is the only reason it makes the cut.</p>
</li>
<li>
<p><a href="http://rogueamoeba.com/audiohijack/">Audio Hijack</a> — Because podcasting.</p>
</li>
<li>
<p><a href="http://kapeli.com/dash">Dash</a> — The best documentation browser I’ve ever used. I almost forgot that it also makes docs available offline until a recent trip to the boondocks reminded me. So great.</p>
</li>
<li>
<p><a href="http://www.acqualia.com/soulver/">Soulver</a> — I always have one or two Soulver sheets open while working. It sits in the sweet spot between Spotlight math and a full-on spreadsheet.</p>
</li>
<li>
<p><a href="http://manytricks.com/moom/">Moom</a> — I wish I didn’t need Moom. OS X should handle window management better<sup id="fnref:3"><a href="#fn:3" class="footnote">3</a></sup>, but it doesn’t. Moom fixes it.</p>
</li>
<li>
<p><a href="http://slack.com">Slack</a> — Slack is team communication done right. Their Mac app, like everything else, is an absolute joy to use.</p>
</li>
</ul>
<h2 id="tweaks">Tweaks</h2>
<p>iCloud now brings many settings with it. I was pleasently surprised to see even my text shortcuts synced over automatically.</p>
<p><img alt="&shrug;" src="http://jerodsanto.net/drop/text-shortcuts.png" style="max-width: 400px;" /></p>
<p>Still, there are many tweaks that don’t fall inside iCloud’s purview. Here are a few I couldn’t live without:</p>
<ul>
<li>
<p><a href="/2015/02/i-fought-the-rsi-and-the-rsi-almost-won/">Make Caps Lock key act as ⌃, disable ⌃ key altogether</a></p>
</li>
<li>
<p>Install <a href="http://font.ubuntu.com">Ubuntu Mono</a>, which is my favorite coding font</p>
</li>
<li>
<p>Hot Corners: upper left = Mission Control, lower right = Sleep Display</p>
</li>
</ul>
<h2 id="next">Next</h2>
<p>There are a few apps I’m trying to live without<sup id="fnref:4"><a href="#fn:4" class="footnote">4</a></sup> and whole boat load of things I haven’t set up yet.</p>
<p>I’ll write another post next week with more apps I end up installing and tweaks I bring over. Follow along on <a href="https://twitter.com/jerodsanto">Twitter</a> or via <a href="/feed.xml">RSS</a><sup id="fnref:5"><a href="#fn:5" class="footnote">5</a></sup> so you won’t miss it!</p>
<div class="footnotes">
<ol>
<li id="fn:1">
<p>3.1 GHz i7, 16GB of RAM, 256GB SSD (for the curious) <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
<li id="fn:2">
<p>I use Safari as my main browser. Having all my browsers synced between my devices via iCloud is its killer feature. <a href="#fnref:2" class="reversefootnote">↩</a></p>
</li>
<li id="fn:3">
<p>This is the <em>one</em> thing Windows does better than OS X, in my experience. <a href="#fnref:3" class="reversefootnote">↩</a></p>
</li>
<li id="fn:4">
<p>Sparrow and iTerm, to name two. <a href="#fnref:4" class="reversefootnote">↩</a></p>
</li>
<li id="fn:5">
<p>It lives! <a href="#fnref:5" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
What Continuity Means to Mehttp://jerodsanto.net/2015/03/what-continuity-means-to-me/2015-03-13T00:00:00-05:00
<p>The features that had me the most excited with the advent of iOS 8 and Yosemite fall under Apple’s <a href="https://www.apple.com/ios/whats-new/continuity/">Continuity</a> umbrella. From the marketing page:</p>
<blockquote>
<p>Apple products have always been designed to work together beautifully. But now they may really surprise you. With iOS 8 and OS X Yosemite, you’ll be able to do more wonderful things than ever before.</p>
</blockquote>
<p>Answer phone calls and send SMS messages from my laptop? Yes! AirDrop between my phone and my Mac? I’ve been asking for that since 2013!</p>
<blockquote class="twitter-tweet" lang="en"><p>Why, oh why, can’t I AirDrop from my Mac to my phone? Seems only logical. Mavericks?</p>— Jerod Santo (@jerodsanto) <a href="https://twitter.com/jerodsanto/status/382505294556721152">September 24, 2013</a></blockquote>
<script async="" src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Unfortunately, sometimes the most-awaited features become the most disappointing.</p>
<blockquote class="twitter-tweet" lang="en"><p>The ONE feature I was looking forward to in iOS 8 / Yosemite – AirDrop between phone and mac – has never worked for me.</p>— Jerod Santo (@jerodsanto) <a href="https://twitter.com/jerodsanto/status/558302237034688512">January 22, 2015</a></blockquote>
<script async="" src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>It turns out that AirDrop’s problem is that my mid-2011 Macbook Air is too old to support the feature<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup>. OK. Apple gets a pass on that one. But what of the other promises? Can Continuity keep them? Not so much:</p>
<blockquote class="twitter-tweet" lang="en"><p>Continuity means never having to say “I missed your iMessage.”</p>— Jerod Santo (@jerodsanto) <a href="https://twitter.com/jerodsanto/status/557733484417273856">January 21, 2015</a></blockquote>
<script async="" src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Now instead of just my phone buzzing incessantly when someone iMessages me, <em>all</em> of my devices beep and buzz. It’s like an Apple-branded flash mob. That’s not all.</p>
<blockquote class="twitter-tweet" lang="en"><p>Continuity means swiping up/away a notification on my phone only to have it appear as unread on my laptop, iPad, and —you guessed it— phone.</p>— Jerod Santo (@jerodsanto) <a href="https://twitter.com/jerodsanto/status/575471839889092608">March 11, 2015</a></blockquote>
<script async="" src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Am I taking crazy pills or should swiping away a notification mark it as acknowledged? iOS doesn’t think so. And thanks to Continuity, Yosemite doesn’t think so either. “Connected like never before” means that both operating systems now propagate their annoying bugs to the other. And there’s more.</p>
<blockquote class="twitter-tweet" lang="en"><p>Continuity means my Mac telling me I missed a call right after I hang up the call.</p>— Jerod Santo (@jerodsanto) <a href="https://twitter.com/jerodsanto/status/564078159369601024">February 7, 2015</a></blockquote>
<script async="" src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Mac-based phone calls might be the most disappointing feature of the lot. The ring is delayed. The connection often fails. When I silence a call on my phone it rings on my Mac instead. It’s a hot mess<sup id="fnref:2"><a href="#fn:2" class="footnote">2</a></sup>.</p>
<hr />
<p>There’s no doubt in my mind that these things are difficult to get right. It’s a cocktail of software, hardware interfaces, networking protocols<sup id="fnref:3"><a href="#fn:3" class="footnote">3</a></sup>, context, presence, and more. But still, I think we’d all be better off if Apple would’ve held off on Continuity until they really had it figured out. Half-baked features are sometimes worse than no features at all.</p>
<p>Oh well, maybe they’ll get it right <a href="http://www.extremetech.com/computing/199090-ios-9-rumored-to-focus-on-stability-performance-increases">in iOS 9</a>.</p>
<div class="footnotes">
<ol>
<li id="fn:1">
<p>We’ll see if it works when my shiny new 13” Retina Macbook Pro arrives next week! <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
<li id="fn:2">
<p>Ironically, as I was writing this a call came in from my phone, which was in the bedroom. I answered it from my Mac and it worked flawlessly. <a href="http://cl.ly/image/1Z190w1F1O0p">See what I mean</a>. <a href="#fnref:2" class="reversefootnote">↩</a></p>
</li>
<li id="fn:3">
<p>I <em>believe</em> the delay between the phone ringing on the phone and the Mac is Bluetooth-related. <a href="#fnref:3" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Trailing Conditionals Considered Harmful Unless Used Sparinglyhttp://jerodsanto.net/2015/03/trailing-conditionals-considered-harmful/2015-03-08T00:00:00-06:00
<p>One Ruby feature that I fell in love with back in the day is the ability to tack conditionals on at the end of a line. For example, this bit of code:</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">if</span> <span class="n">some_condition?</span>
<span class="n">object</span><span class="o">.</span><span class="n">perform_some_action</span>
<span class="k">end</span></code></pre></div>
<p>Can be expressed as a one-liner, like this:</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">object</span><span class="o">.</span><span class="n">perform_some_action</span> <span class="k">if</span> <span class="n">some_condition?</span></code></pre></div>
<p>It’s a small difference, but the latter form often maps more directly to how the author thinks about the problem. It feels even better when teamed with the <code>unless</code> keyword:</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">object</span><span class="o">.</span><span class="n">perform_some_action</span> <span class="k">unless</span> <span class="n">some_condition?</span></code></pre></div>
<p>After years of writing and reading code like this, I’ve slowly grown cold on the style.</p>
<h1 id="why">Why</h1>
<p>The reason why I’m bearish on trailing conditionals may best be expressed by a road sign I saw on a recent road trip down Interstate 80:</p>
<p><img src="http://jerodsanto.net/drop/i-80-closed.jpg" alt="Not the actual sign I saw, but close enough" /></p>
<p>Notice the trailing conditional? A lot can go wrong with signs like these if the driver doesn’t make it to the final line of the text. Why might that happen?</p>
<ul>
<li>The sign could be blocked by some obstruction until the last second</li>
<li>The driver could be distracted by kids, the radio, their phone, etc. until it’s too late</li>
<li>A sign-related exit could be imminent with the driver in the wrong lane<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup></li>
</ul>
<p>In this case, <strong>WHEN FLASHING</strong> is the key indicator on the sign. Why is it the last thing mentioned? In the world of journalism they call this <a href="http://en.wiktionary.org/wiki/bury_the_lead">burying the lead</a>.</p>
<p>If the sign designer place <strong>WHEN FLASHING</strong> first, the driver could often skip the rest of the text altogether<sup id="fnref:2"><a href="#fn:2" class="footnote">2</a></sup>. This saves cognitive overhead that the driver can use elsewhere and avoids potential disasters that might occur if the conditional isn’t understood in time.</p>
<p>In a slightly-tangential way, trailing conditionals violate the <a href="http://en.wikipedia.org/wiki/Principle_of_least_astonishment">Principle of Least Surprise</a>. This principle — as most important things in life — made its way in to a Mitch Hedberg joke, in which he picks a fight with the phrase “Do Not Disturb”:</p>
<iframe width="100%" height="166" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/194783967&color=ff5500&auto_play=false&hide_related=false&show_comments=false&show_user=false&show_reposts=false"></iframe>
<p>The problem is exacerbated when driving 80 MPH on the interstate, but it exists in our code as well. The trailing conditional feels great when you’re <em>writing</em> the code, but it often makes it harder to <em>read</em>. This is most obvious when the operation that precedes the conditional is verbose. Take this fake code, for instance:</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">call_this_really_long_method_that_is_probably_too_long_but_that_will_not_stop_us</span> <span class="k">unless</span> <span class="n">some_condition?</span></code></pre></div>
<p>What if you didn’t scroll over to see the <code>unless</code> at the end? You wouldn’t know what’s going on at all. Admittedly, method names of this length are rare, but <em>it is</em> common to have trailing conditionals nested inside other control structures that have the same effect<sup id="fnref:3"><a href="#fn:3" class="footnote">3</a></sup>.</p>
<p><a href="http://blogs.msdn.com/b/oldnewthing/archive/2007/04/06/2036150.aspx">Code is read much more often than it is written</a>, so we need to optimize for readability over writeability<sup id="fnref:4"><a href="#fn:4" class="footnote">4</a></sup>. Trailing conditionals tend to do the opposite.</p>
<h2 id="but">But</h2>
<p>As with most things in software (and writing), there are exceptions. Some uses of trailing conditionals improve readability. The best case for them in my experience is with <a href="http://en.wikipedia.org/wiki/Guard_(computer_science)">guard clauses</a>. Guard clauses have a few characteristics that make them quite readable with trailing conditionals:</p>
<ul>
<li>They occur at the top of a method, so they are rarely nested themselves</li>
<li>They often return or raise an error, which are brief statements</li>
<li>There are often a few guard clauses together, so vertical brevity aides reading</li>
</ul>
<p>Take a look at this method which returns a <code>price_range</code> string for a given object that responds to <code>price_minimum</code> and <code>price_maximum</code>:</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">price_range</span>
<span class="k">return</span> <span class="vi">@price_range</span> <span class="k">if</span> <span class="n">defined?</span> <span class="vi">@price_range</span>
<span class="k">return</span> <span class="s2">""</span> <span class="k">unless</span> <span class="n">price_minimum</span>
<span class="k">return</span> <span class="s2">""</span> <span class="k">unless</span> <span class="n">price_maximum</span>
<span class="c1"># ... code to determine `minimum` and `maximum` ...</span>
<span class="vi">@price_range</span> <span class="o">=</span> <span class="s2">"</span><span class="si">#{</span><span class="n">minimum</span><span class="si">}</span><span class="s2">-</span><span class="si">#{</span><span class="n">maximum</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span></code></pre></div>
<p>The first line <a href="http://en.wikipedia.org/wiki/Memoization">memoizes</a> the <code>price_range</code>, since this is apparently an expensive computation. Lines 2 and 3 are guard clauses. What would this look like with traditional conditionals?</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">price_range</span>
<span class="k">if</span> <span class="n">defined?</span> <span class="vi">@price_range</span>
<span class="k">return</span> <span class="vi">@price_range</span>
<span class="k">end</span>
<span class="k">unless</span> <span class="n">price_minimum</span>
<span class="k">return</span> <span class="s2">""</span>
<span class="k">end</span>
<span class="k">unless</span> <span class="n">price_maximum</span>
<span class="k">return</span> <span class="s2">""</span>
<span class="k">end</span>
<span class="c1"># ... code to determine `minimum` and `maximum` ...</span>
<span class="vi">@price_range</span> <span class="o">=</span> <span class="s2">"</span><span class="si">#{</span><span class="n">minimum</span><span class="si">}</span><span class="s2">-</span><span class="si">#{</span><span class="n">maximum</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span></code></pre></div>
<p>This code requires more vertical work to parse. There’s a 3rd form it could take, which is to put the conditionals first and still keep each one a one-liner:</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">price_range</span>
<span class="k">if</span> <span class="n">defined?</span> <span class="vi">@price_range</span> <span class="k">return</span> <span class="vi">@price_range</span>
<span class="k">if</span> <span class="o">!</span><span class="n">price_minimum</span> <span class="k">return</span> <span class="s2">""</span>
<span class="k">if</span> <span class="o">!</span><span class="n">price_maximum</span> <span class="k">return</span> <span class="s2">""</span>
<span class="c1"># ... code to determine `minimum` and `maximum` ...</span>
<span class="vi">@price_range</span> <span class="o">=</span> <span class="s2">"</span><span class="si">#{</span><span class="n">minimum</span><span class="si">}</span><span class="s2">-</span><span class="si">#{</span><span class="n">maximum</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span></code></pre></div>
<p>This works for me, but I prefer the return-first form because any time a method returns early we want to know about that <em>ASAP</em>.</p>
<h2 id="so">So</h2>
<p>Think twice before slinging around trailing conditionals. They put the cart before the horse and in extreme cases they cause the reader to miss the horse altogether. This makes them often less readable than the traditional form.</p>
<p>Or maybe Mitch was right and we all just need to read faster!</p>
<div class="footnotes">
<ol>
<li id="fn:1">
<p>This is actually what happened to me. I barely deciphered the correct meaning in time. <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
<li id="fn:2">
<p>The road being closed is the exception, not the common case. This means the lights will rarely flash and the sign is most often irrelevant. <a href="#fnref:2" class="reversefootnote">↩</a></p>
</li>
<li id="fn:3">
<p>This is <a href="http://stackoverflow.com/a/578318">yet another reason</a> that I advocate for 80-characters or less per line. <a href="#fnref:3" class="reversefootnote">↩</a></p>
</li>
<li id="fn:4">
<p>The two are often coupled, but are sometimes at odds. <a href="#fnref:4" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>