Karim Hamidou2024-02-09T21:02:44+00:00http://khamidou.com/Karim Hamidoucontact@khamidou.comDrawing Donuts!2021-07-07T00:00:00+00:00http://khamidou.com/programming/drawing-donutsDrawing Donuts!Revisiting Infinity Pools2021-06-06T00:00:00+00:00http://khamidou.com/revisiting-infinity-pools<p>A few years back (4 years already!) I built <a href="/infinity-pools.html">Infinity Pools</a>, an extension to block the constantly refreshing feeds from Facebook and Twitter. Unfortunately, after a few months, both websites changed how they refresh their feeds and the extension broke.</p>
<p>A couple weeks ago, I decided to take another stab at it. I’ve always felt it made more sense to block websites after a certain amount of time, so I decided to go with that.</p>
<p>After doing that, I had to decide what to put on the timeout page. I’ve always been a big fan of confetti and balloons animations so I started with a simple balloon animation that <a href="https://codepen.io/moettinger/pen/YVPzNX">I found on codepen.io</a>.</p>
<p>The result was pretty cool but the animation wasn’t super smooth (most likely because it relies on JQuery’s animation framework).</p>
<p><img src="/images/infinity_pools/css_balloons.png" alt="balloons" /></p>
<p><br /></p>
<p>To improve that, I decided to port the example code to Canvas. I figured it’d be a fun way to practice some animation drawing, a thing I hadn’t done any since using GDI+ on Windows.</p>
<p>Using Canvas was relatively straightforward, although the API has some interesting edge cases around using Retina screens. I also ran into some weird screen tearing issues that made me not use rotations altogether, since I really didn’t want to relearn college matrix algebra 😅</p>
<p>Here’s the final result:</p>
<iframe src="/infinity_pools/frame.html" width="1024" height="800"></iframe>
<p>Of course, you can find the source code for this extension on <a href="https://github.com/khamidou/infinity-pools/">Github</a>.</p>
How to write a good engineering job post2018-10-25T00:00:00+00:00http://khamidou.com/how-to-write-good-engineering-job-post<p>Writing a job post feels like pulling teeth, which is why most job posts end up reading like an ambitious mission statement (<em>“We want to disrupt the pizza delivery market!”</em>) followed by laundry list of requirements (<em>Python! Javascript! Mongo! AWS!</em>).</p>
<p>Luckily, there’s a better way to do this – and once you know the proper structure it will be a lot easier, too! It will help you attract candidates who are interested in your culture and technical challenges.</p>
<p>This is a modest guide on how to do it. I’ve included a lot of examples because I think it’s the best way to learn – feel free to click on any screenshot to get to the bigger version.</p>
<p><strong>Table of contents</strong></p>
<ol class="no_toc" id="markdown-toc">
<li><a href="#how-to-structure-a-job-post" id="markdown-toc-how-to-structure-a-job-post">How to structure a job post</a> <ol>
<li><a href="#what-the-role-is" id="markdown-toc-what-the-role-is">What the role is</a></li>
<li><a href="#what-you-need-to-know" id="markdown-toc-what-you-need-to-know">What you need to know</a></li>
<li><a href="#why-were-cool" id="markdown-toc-why-were-cool">Why we’re cool</a></li>
</ol>
</li>
<li><a href="#watch-out-for-biases" id="markdown-toc-watch-out-for-biases">Watch out for biases!</a></li>
<li><a href="#wrap-up" id="markdown-toc-wrap-up">Wrap-up</a></li>
</ol>
<h2>The first role of a job post is selling</h2>
<p>The most important thing to remember when writing a job post is that you’re trying to get a candidate interested in your company.</p>
<p>Generally, candidates are interested by three things (in this order<sup id="fnref:spacex" role="doc-noteref"><a href="#fn:spacex" class="footnote" rel="footnote">1</a></sup>):</p>
<ol>
<li>your company culture: Does it have work-life balance? Is the company diverse? Will my colleagues be nice?</li>
<li>opportunities for growth: If I want to lead a team, will I be able to do it in a few years? Can I do public speaking?</li>
<li>your company’s mission: Is it going to make the world a better place?</li>
</ol>
<p>That means that you’re going to have to put these three things front and center. I know that this sounds easier said than done – don’t worry we’ll be diving into specific examples you can later use as inspiration.</p>
<h1 id="how-to-structure-a-job-post">How to structure a job post</h1>
<p>Like the best classical essays, most job posts follow a three-part structure. Generally it looks like this:</p>
<ol>
<li>What the role is</li>
<li>What you need to know</li>
<li>Why we’re cool</li>
</ol>
<p>For example, here’s a great job post from Stripe that follows this structure to a tee (click to zoom):</p>
<p><a href="/images/job_posts/stripe-web-engineer-annotated.png">
<img alt="stripe" src="/images/job_posts/stripe-web-engineer-annotated.png" />
</a></p>
<p>Let’s dive into each part to see what makes them tick.</p>
<h2 id="what-the-role-is">What the role is</h2>
<p>I know it can be very tempting to say something like “well, on a day-to-day basis you’ll be fixing bugs and implementing features. You might have to talk to customers.”. On the contrary, you need to be as detailed as possible to give your reader a clear idea of the job.</p>
<p>Here’s a great example of this, one of Nylas’ engineering job posts, written by my colleague <a href="http://evanmorikawa.com/">Evan Morikawa</a>:</p>
<p><a href="/images/job_posts/nylas-job-description.png">
<img alt="nylas job description" src="/images/job_posts/nylas-job-description.png" />
</a></p>
<p>Obviously, Nylas is still a pretty small company so it’s easier to give meaningful examples of work! However, this is also possible for a bigger company. Here’s how Square does it for example:</p>
<p><a href="/images/job_posts/square-job-description.png">
<img alt="square job description" src="/images/job_posts/square-job-description.png" />
</a></p>
<p>This is a pretty masterful description! On the one hand you have an introduction paragraph that shows how important the team is for the success of the company (“This work has direct impact on Square’s profitability and financial success.”). On the other hand you have a detailed list of what you’ll work on, as well as a couple hard problems to keep you up at night.<sup id="fnref:specific" role="doc-noteref"><a href="#fn:specific" class="footnote" rel="footnote">2</a></sup></p>
<h2 id="what-you-need-to-know">What you need to know</h2>
<p>Lots of companies have long lists of requirements. This is far from ideal, because first, how many hard requirements do you have? Most of the things that end up on a requirements list are at best nice to have.<sup id="fnref:bash" role="doc-noteref"><a href="#fn:bash" class="footnote" rel="footnote">3</a></sup></p>
<p>However, long lists of requirements have a more pernicious effect – they can intimidate some people who would otherwise apply. <a href="https://en.wikipedia.org/wiki/Impostor_syndrome">Impostor syndrome</a> is a real thing.</p>
<p>To make sure you’re not letting anybody out, it’s best to keep requirements list as short as possible. Here’s a good example from Clever:</p>
<figure>
<a href="/images/job_posts/clever-requirements.png">
<img src="/images/job_posts/clever-requirements.png" alt="" />
</a>
<figcaption></figcaption>
</figure>
<p>Most engineers spend as much time dealing with people as they do dealing with technical issues, so remember to not get bogged down with technical requirements. They’re important, sure, but a good rule of thumb is that roughly half of your requirements should be non-technical.</p>
<h2 id="why-were-cool">Why we’re cool</h2>
<p>Finally, you need to explain why someone would join your startup over any other startup. This is certainly the most tricky part of writing a job post, since it’s kind of hard to sum up what makes your company special.</p>
<p>One of the best ways to write a “Why we’re cool” section is to sit down and write what makes the culture of your company great. This means writing down the big things (Do you have a mission? Do you value autonomy? What about work-life balance?) as well as the smaller ones (What’s your open source policy? Does everybody eat lunch at their desks or do people go out together?)</p>
<p>Don’t be afraid to get into as much detail as you want – there are hundreds of startups in the bay area using Python. There are thousands using Node. None have your unique company culture and that’s what you need to put forward.</p>
<p>Here’s a breakdown of the “Why we’re cool” section of another Stripe job posting<sup id="fnref:whatcani" role="doc-noteref"><a href="#fn:whatcani" class="footnote" rel="footnote">4</a></sup>. Pay attention to all the unique selling points they have:
<img src="/images/job_posts/stripe-cool.png" alt="stripe cool description" /></p>
<p>This job posting hits all the notes – from the big things (the mission: increasing the GDP of the Internet) to the smaller ones (everybody having lunch together).</p>
<p>If you’re looking for more inspiration, <a href="/images/job_posts/github-cool.png">Github</a> and – in a more corporate style – <a href="/images/job_posts/splunk-cool.png">Splunk</a> have good “why we’re cool” sections.</p>
<h1 id="watch-out-for-biases">Watch out for biases!</h1>
<p>Make sure that your job post isn’t unconsciously biased towards certain categories. One example I can remember is an old Nylas job posting<sup id="fnref:retired" role="doc-noteref"><a href="#fn:retired" class="footnote" rel="footnote">5</a></sup> that had an interesting metaphor about the job of an SRE being like working at a pit stop on an F1 racing team. I remember finding this working uncomfortable because it makes the job sound way more stressful than it is – which would cause some good, qualified applicants to not apply.</p>
<p>I know it’s easy to say “look for your own unconscious bias in the post you wrote”, but what helps would be to ask a diverse set of your coworkers whether they’d consider applying after reading your job post.</p>
<p>You could also use a tool like <a href="http://gender-decoder.katmatfield.com/">Kat Matfield’s gender decoder</a> to “lint” your post and make sure it’s gender neutral.</p>
<h1 id="wrap-up">Wrap-up</h1>
<p>Hopefully, with the right structure in place writing a job post isn’t going to feel like pulling teeth anymore!
Please let me know if you have questions or comments – send me an email at <em>hello</em> at khamidou.com.</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:spacex" role="doc-endnote">
<p>Obviously, the order is going to be a little different if you’re, say, SpaceX. You’ll get a lot more mission-driven people. <a href="#fnref:spacex" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:specific" role="doc-endnote">
<p>In general, it’s better to be very specific about what the job will entails, because it helps the reader imagine what they’ll be doing. <a href="#fnref:specific" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:bash" role="doc-endnote">
<p>Does an SRE need to know Bash? Maybe – or maybe they can figure it out on the job. <a href="#fnref:bash" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:whatcani" role="doc-endnote">
<p>What can I say? They have great job postings! <a href="#fnref:whatcani" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:retired" role="doc-endnote">
<p>we’ve retired this job posting a long time ago! <a href="#fnref:retired" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
The scripting ideology2018-04-17T00:00:00+00:00http://khamidou.com/programming/scripting-ideology<p>The other day I randomly came across one of Larry Wall’s keynotes, <a href="http://www.wall.org/~larry/pm.html">Perl, the first postmodern language</a>. It’s a fascinating read and really articulates what makes scripting languages different from other languages.</p>
<p>I remember when I started using Python, after years of using C. It felt like I finally found a tool that fit my hand. Why that?</p>
<p>Besides convenience reasons<sup id="fnref:gc" role="doc-noteref"><a href="#fn:gc" class="footnote" rel="footnote">1</a></sup>, I think the main reason is ideological. C and Python (and scripting languages in general) have opposite worldviews.</p>
<p>C programmers are supposed to know what they’re doing, and the compiler stays mostly out of your way. This leads to a culture of inscrutable programs<sup id="fnref:ken-thompson" role="doc-noteref"><a href="#fn:ken-thompson" class="footnote" rel="footnote">2</a></sup> and manual memory management. You don’t stumble into writing a C program; you have to carefully plan the structure of the program ahead of time.</p>
<p>Scripting languages have the opposite view. They’re interactive; they’re playful; they let you figure things out as you go. That’s why most of them have a <a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop">repl</a>, late-binding, and are kind of multiparadigm.</p>
<p>You don’t have to be an exceptional programmer to use them – you can just make it up as you go, and it’s going to be mostly alright. As a life philosophy, it kinds of beats C’s “everything must be perfect or your program crashes”.</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:gc" role="doc-endnote">
<p>I’m not going to lie, garbage collection and a huge built-in standard library were big, though. <a href="#fnref:gc" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:ken-thompson" role="doc-endnote">
<p>Which reminds me of this joke from the <a href="http://web.mit.edu/~simsong/www/ugh.pdf">Unix haters handbook</a>: Ken Thompson has an automobile which he helped design. Unlike most automobiles, it has neither speedometer, nor gas gauge, nor any of the other numerous idiot lights which plague the modern driver. Rather, if the driver makes a mistake, a giant “?” lights up in the center of the dashboard. “The experienced driver,” says Thompson, “will usually know what’s wrong.” <a href="#fnref:ken-thompson" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Let's build an online code sandbox!2018-01-02T00:00:00+00:00http://khamidou.com/programming/sandboxLet's build an online code sandbox!Infinity Pools2017-12-29T00:00:00+00:00http://khamidou.com/infinity-pools<p>Every social media website, from the big ones to the smaller ones (i.e: Pocket) have some sort of infinite feed that you can keep scrolling, basically forever. One of my 2018 resolutions is to spend a bit less time inside these “infinite pools”.</p>
<p>Of course, I used this resolution as an excuse to play with the extension APIs for Chrome, Safari and Firefox, and ended up building an extension to hide the feeds from Facebook and Pocket. It’s called “Infinite Pools” and you can look at the source on <a href="https://github.com/khamidou/infinity-pools">Github</a> or get it for <a href="https://raw.github.com/khamidou/infinity-pools/master/InfinityPools.crx">Chrome</a> and <a href="https://raw.github.com/khamidou/infinity-pools/master/infinity_pools-1.0-an%2Bfx.xpi">Firefox</a>.</p>
<p>We’ll see how effective these are!</p>
Mapping Needles in San Francisco2017-09-21T00:00:00+00:00http://khamidou.com/mapping-heroin-use-san-francisco<p>My biggest shock when moving to San Francisco was seeing the heartbreaking number of people living in the streets. I have the feeling that in the last few years, things have been getting worse. There are more people on the street, more tent campments and more drug use.</p>
<p>I just learnt through <a href="http://katiehempenius.com/post/drug-markets-of-san-francisco/">this very cool article</a> about the city of San Francisco’s <a href="https://datasf.org/opendata/">open data initiative</a>, so I decided to check if my perception was true or not.</p>
<p>I won’t bore you with technical details<sup id="fnref:details" role="doc-noteref"><a href="#fn:details" class="footnote" rel="footnote">1</a></sup>, but it wasn’t too hard to plot on a map all the places where people reported needles. Here’s an animated GIF over the years:</p>
<p><img src="/images/needles/animation_small.gif" alt="needles animation" /></p>
<center>
<a href="/images/needles/animation.gif">(bigger version)</a>
</center>
<p>There is one caveat to this graph though: it seems that most of the GPS data comes from the SF 311 app, where people can report streetcleaning issues. It’s very likely that we’re only plotting partial data between 2008 and 2011.</p>
<p>And if you’re curious, here’s a complete map of where people have found needles in the city. Sounds like you should move to the Presidio if you want to avoid them.</p>
<p><img src="/images/needles/needles.png" alt="needles across the city" /></p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:details" role="doc-endnote">
<p>It was pretty simple to make these maps. I just had to download the data from the city’s website. They provide it in CSV which made it super easy to parse it with a Python script.</p>
<p>After that, I used <a href="http://www.sethoscope.net/heatmap/">heatmap</a> to plot the data on a map and <a href="https://www.imagemagick.org/script/index.php">ImageMagick</a> to generate an animated GIF from it. Check out the <a href="https://github.com/khamidou/needles">github repo</a> if you’re curious about the exact incantations I used. <a href="#fnref:details" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Beware of proxy metrics!2017-08-24T00:00:00+00:00http://khamidou.com/beware-proxy-metrics<p>Palantir is well known for its grueling interview process. It’s pretty common for new applicants to go through a dozen(!) interviews.<sup id="fnref:itw" role="doc-noteref"><a href="#fn:itw" class="footnote" rel="footnote">1</a></sup></p>
<p>I don’t think anyone made a conscious decision to have things this way – nobody called a Monday morning meeting to make their hiring process horrible.</p>
<p>Instead, they probably started with a sensible interview process<sup id="fnref:otherwise" role="doc-noteref"><a href="#fn:otherwise" class="footnote" rel="footnote">2</a></sup>, which slowly evolved over time.</p>
<p>I have an armchair theory about this. When you’re a big, successful company like Palantir, you get a lot of people interested in working with you. Most of them aren’t good fits, so your goal is to zero in on the ones who are.</p>
<p>In this case, it can be very tempting to define a single proxy metric to track the process. After all, if you can get all the stakeholders to agree on a single metric, they could just optimize the damn thing and make everybody happy.</p>
<p>But, here’s the issue. Unlike regular metrics (e.g: monthly revenue, 90th percentile API latency), proxy metrics only measure what you think the problem is, so whatever you end up optimizing will end up landing you inside a local maximum.</p>
<p>Voilà, you have a recipe for ending up with a broken process! So, next time you think about optimizing a process, take and step back and make sure you’re not looking at a proxy metric.</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:itw" role="doc-endnote">
<p>(Note: I’m not singling out Palantir here - they just happened to be at the top of <a href="https://www.reddit.com/r/cscareerquestions">/r/cscareerquestions</a> today. Other tech companies are also well known for their drawn-out, or sometimes plain ridiculous hiring processes.) <a href="#fnref:itw" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:otherwise" role="doc-endnote">
<p>otherwise they wouldn’t be where they are today <a href="#fnref:otherwise" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
The Internet is amazing!2017-07-29T00:00:00+00:00http://khamidou.com/internet-is-amazing<p>The other day I stumbled upon a fascinating sub-subculture – people making and wearing parody shirts of popular brands. It’s fascinating to see people trying to make brand logos their own.</p>
<p>For example, Patagucci was a short-lived brand based that sold Patagonia-inspired clothing:</p>
<p><img src="/images/tee-shirts/patagucci.jpeg" alt="Pataguccia sweater" /></p>
<p>They unfortunately had to shutdown after receiving a <a href="https://www.scribd.com/document/294002329/Patagonia-v-Patagucci-trademark-complaint-pdf">Cease and Desist</a> from Patagonia, but this doesn’t seem to have deterred other fans. There are literally dozens of takes on their iconic logo. <a href="/images/tee-shirts/fratagonia.png">Fraternities sell Fratagonia tee-shirts</a>. <a href="/images/tee-shirts/deadagonia.jpg">Even Grateful Dead fans have their own</a>.</p>
<p>I found this really inspiring, so I decided to try to make my own Patagonia-inspired tee-shirt. It turns out it was surprisingly easy, thanks to the Internet.</p>
<p>The first thing to do was to decide what the logo would be about. Since I live in California, I decided it would be about… California<sup id="fnref:california" role="doc-noteref"><a href="#fn:california" class="footnote" rel="footnote">1</a></sup>.</p>
<p>The second thing I had to decide on was the logo. The Patagonia logo is pretty interesting because it’s not a completely abstract form – it’s the outline of Mt Fitz Roy, in… Patagonia. I could have simply pasted California on the logo but that wouldn’t cut it. I needed something Californian.</p>
<p>That’s when it hit me – why not replace Mt Fitz Roy by the most iconic skyline in California – el Capitan? Doing so would be above my drawing abilities, but I was able to find a good illustrator on fiverr to draw it:</p>
<p><img src="/images/tee-shirts/california-logo.png" alt="California logo" /></p>
<p>After that it was pretty easy to find an online tee-shirt printing service that would print a tee-shirt with this logo. Three weeks later I received my tee-shirt by mail:</p>
<p><img src="/images/tee-shirts/california.jpg" alt="California tee-shirt" /></p>
<p>This is fascinating because all of this happened only because of the Internet. It’s easy to get fixated on the bad aspects of technologies. It’s also important to remember that the they let people to do amazing things<sup id="fnref:lol" role="doc-noteref"><a href="#fn:lol" class="footnote" rel="footnote">2</a></sup> every day. We should be grateful for it.</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:california" role="doc-endnote">
<p>One thing to know about Californians if you’ve never been there is that they’re really proud to live in California. It’s pretty common to see locals wearing California tee-shirts and sweaters, which is something you will not see in any other place.</p>
<p>It’s also why Antony Kiedis has written hundreds of songs about California. <a href="#fnref:california" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:lol" role="doc-endnote">
<p>I’m not talking about this humble tee-shirt of course! I’m thinking about real art. <a href="#fnref:lol" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Let's build a tiny Lisp interpreter in Python!2017-07-01T00:00:00+00:00http://khamidou.com/lisp.pyLet's build a tiny Lisp interpreter in Python!Blocking distractions, automatically2017-06-18T00:00:00+00:00http://khamidou.com/blocking-distractions<p>A couple months ago I started noticing that my habit of checking reddit in small moments of downtime – like while waiting for a build – was pretty disruptive. It’s hard to get back to work after having been distracted by random stories of startup glory and drama.</p>
<p>It turns out a lot of people have this exact same problem, and there’s a <a href="https://www.rescuetime.com/">small</a> <a href="https://heyfocus.com/">cottage</a> <a href="https://selfcontrolapp.com/">industry</a> <a href="https://freedom.to">of apps</a> for that. I don’t like installing random apps from the Internet, so I came up with a different solution: blocking reddit from <code class="language-plaintext highlighter-rouge">/etc/hosts</code>.</p>
<p>That worked well but I’d often forget to block reddit after reading it, which means I’d still mindlessly end up in some Internet rabbit hole while waiting for something to complete. To work around this I decided to write a simple Python script that would automatically block distractions. You can see it <a href="https://raw.githubusercontent.com/khamidou/dotfiles/master/bin/block-distractions">here</a>.<sup id="fnref:friction" role="doc-noteref"><a href="#fn:friction" class="footnote" rel="footnote">1</a></sup></p>
<p>I’m running this as a cron job every 15 minutes, and it seems to work, for now. We’ll see how effective it is after a couple weeks.</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:friction" role="doc-endnote">
<p>What I like the most about this approach is its friction. If I want to unblock reddit, for example, I have to login as root, open the file, comment out the entry and then quit. That’s a lot of steps just for checking out reddit!</p>
<p>It’s also something I have to do over and over because the computer keeps resetting the file. <a href="#fnref:friction" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
The day Google DDoSed us2017-04-16T00:00:00+00:00http://khamidou.com/programming/the-day-google-ddosed-us<p>There’s an interesting post about <a href="https://medium.com/figma-design/an-alternative-approach-to-rate-limiting-f8a06cf7c94c">rate-limiting</a> making the rounds on social media. Reading it reminded me of the day where we got involuntarily DDoSed by Google.</p>
<p>If you have a Gmail account, the <a href="https://nylas.com">Nylas API</a> uses the <a href="https://developers.google.com/google-apps/calendar/overview">Google Calendar API</a> to sync your calendars and events. The Google calendar API is really well thought-out, and has one awesome feature: webhooks. The API lets you programatically register an URL to be pinged whenever the calendar is updated.<sup id="fnref:know" role="doc-noteref"><a href="#fn:know" class="footnote" rel="footnote">1</a></sup></p>
<p>Webhooks are great because they let us stop needlessly polling the Google calendar API, while at the same time getting results way faster than before. Unfortunately, we made one tiny bugs when implementing the code that would subscribe to those webhooks.</p>
<p>Here’s the code we used to subscribe to those webhooks (you can also find it on <a href="https://github.com/nylas/sync-engine/blob/b91b94b9a0033be4199006eb234d270779a04443/inbox/events/remote_sync.py">GitHub</a>).</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">def</span> <span class="nf">_refresh_gpush_subscriptions</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">with</span> <span class="n">session_scope</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">namespace_id</span><span class="p">)</span> <span class="k">as</span> <span class="n">db_session</span><span class="p">:</span>
<span class="n">account</span> <span class="o">=</span> <span class="n">db_session</span><span class="p">.</span><span class="n">query</span><span class="p">(</span><span class="n">Account</span><span class="p">).</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">account_id</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="p">.</span><span class="n">provider</span><span class="p">.</span><span class="n">push_notifications_enabled</span><span class="p">(</span><span class="n">account</span><span class="p">):</span>
<span class="k">return</span>
<span class="k">if</span> <span class="n">account</span><span class="p">.</span><span class="n">needs_new_calendar_list_watch</span><span class="p">():</span>
<span class="n">expir</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">provider</span><span class="p">.</span><span class="n">watch_calendar_list</span><span class="p">(</span><span class="n">account</span><span class="p">)</span>
<span class="k">if</span> <span class="n">expir</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
<span class="n">account</span><span class="p">.</span><span class="n">new_calendar_list_watch</span><span class="p">(</span><span class="n">expir</span><span class="p">)</span>
<span class="n">cals_to_update</span> <span class="o">=</span> <span class="p">(</span><span class="n">cal</span> <span class="k">for</span> <span class="n">cal</span> <span class="ow">in</span> <span class="n">account</span><span class="p">.</span><span class="n">namespace</span><span class="p">.</span><span class="n">calendars</span>
<span class="k">if</span> <span class="n">cal</span><span class="p">.</span><span class="n">needs_new_watch</span><span class="p">())</span>
<span class="k">for</span> <span class="n">cal</span> <span class="ow">in</span> <span class="n">cals_to_update</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">expir</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">provider</span><span class="p">.</span><span class="n">watch_calendar</span><span class="p">(</span><span class="n">account</span><span class="p">,</span> <span class="n">cal</span><span class="p">)</span>
<span class="k">if</span> <span class="n">expir</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
<span class="n">cal</span><span class="p">.</span><span class="n">new_event_watch</span><span class="p">(</span><span class="n">expir</span><span class="p">)</span>
<span class="k">except</span> <span class="n">HTTPError</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span>
<span class="p">...</span></code></pre></figure>
<p>We basically look if we need to register webhooks for the calendar list (<code class="language-plaintext highlighter-rouge">watch_calendar_list()</code>) and the calendars themselves (<code class="language-plaintext highlighter-rouge">cal.needs_new_watch()</code>). If it’s the case, we subscribe to the webhooks.</p>
<p>And here’s the method we use to check that a calendar needs to be watched:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">def</span> <span class="nf">needs_new_watch</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="p">...</span>
<span class="k">return</span> <span class="p">(</span>
<span class="bp">self</span><span class="p">.</span><span class="n">gpush_expiration</span> <span class="ow">is</span> <span class="bp">None</span> <span class="ow">or</span>
<span class="bp">self</span><span class="p">.</span><span class="n">gpush_expiration</span> <span class="o"><</span> <span class="n">datetime</span><span class="p">.</span><span class="n">utcnow</span><span class="p">()</span>
<span class="p">)</span></code></pre></figure>
<p>Aaaand this is where the bug lies! When watching calendars we’d never set an expiration date on them. That means, we’d subscribe to them, again and again, <em>thousands of times for each calendar</em>.</p>
<p>For a while, it worked because (I assume) Google had some sort of safety measure to prevent shooting yourself in the foot. One day though, they disabled it.</p>
<p>We woke up to thousands of requests per second coming from Google, with no way to disable them. We had to implement a hotfix in our rate-limiting code exclusively for the Google webhooks and fix the original bug by setting an expiration date for those webhooks. To this day, we’re still receiving requests from those accounts.</p>
<p><strong>What can we take away from this?</strong></p>
<p>First, your rate-limiting logic is the last line of defense between your API and an outage. It’s worth it to have it spend some time making sure the code is reliable and easy to extend. You’ll need it the day where you have to deploy a hotfix to prevent a long outage.</p>
<p>Second, it’s very hard to catch such a bug. A good rule of thumb though, is to always set an expiration date to any resource you request.</p>
<p>Until next time!</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:know" role="doc-endnote">
<p>You kind of know where it’s going, right? <a href="#fnref:know" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
TCPDump cheatsheet2017-01-29T00:00:00+00:00http://khamidou.com/tcpdump<p>TCPDump is a super useful tool with a ton of options. I’ve made a cheatsheet to remember the most useful ones. You can find it <a href="tcpdump.pdf">here</a>.</p>
3 Things I Learned the hard way about distributed systems2016-06-08T00:00:00+00:00http://khamidou.com/three-things-learned-about-distributed-systems<p>There’s a lot of blog posts about scaling distributed systems to hundreds of thousands users, but not many are about the basics mistakes you’ll make when trying to build one.</p>
<p>In this post, I’ll share three things I wish I had learned in college (instead of the hard way 😁!).</p>
<h2 id="1-limits-are-everything">1. Limits are everything</h2>
<p>I learned this pretty quickly: you can not expect an external service to always work. Even big companies like Google and Amazon have outages, and you need to prepare for it. This means, setting timeouts when querying an API.</p>
<p>This also works the other way around — if you have an external API, limit the maximum number of requests per customers. Accidental DDoSes are a thing.</p>
<h2 id="2-forget-about-this-fancy-algorithm">2. Forget about this fancy algorithm<sup id="fnref:database" role="doc-noteref"><a href="#fn:database" class="footnote" rel="footnote">1</a></sup></h2>
<p>Some engineers like fancy algorithms — I know I used to, too. I’ve changed my mind after getting regular on-call time. The complicated algorithm you wrote at 11AM will not make any sense when you’ll get paged 2 months later at 3AM.</p>
<p>I now try to write the dumbest, most obvious code possible. My 3AM self appreciates it.</p>
<h2 id="3-pick-your-fights">3. Pick your fights</h2>
<p>Nowadays programming mean relying on hundreds of thousands of lines of code you haven’t written.<sup id="fnref:rails" role="doc-noteref"><a href="#fn:rails" class="footnote" rel="footnote">2</a></sup> You are going to run into weird interactions between different libraries. You may waste a lot of time trying to debug them.<sup id="fnref:funstory" role="doc-noteref"><a href="#fn:funstory" class="footnote" rel="footnote">3</a></sup></p>
<p>A lot of engineers love debugging complex problems, especially if it involves low-level bits and pieces (I know I do!). Unfortunately, not every problem is worth solving, and a simple service restart may be the solution to this problem. You’ll have to accept it and move on, as hard as it may be.</p>
<p>Thanks for reading!</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:database" role="doc-endnote">
<p>(or database, language, library) <a href="#fnref:database" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:rails" role="doc-endnote">
<p>Just think about all the lines of code an HTTP request goes through before hitting your Rails controller. <a href="#fnref:rails" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:funstory" role="doc-endnote">
<p>Fun story: I once spent several days chasing a weird OpenSSL memory leak in the <a href="https://github.com/nylas/sync-engine">Nylas Sync Engine</a>. I gave up after reading way too many core dumps.</p>
<p>Eventually, we solved the problem by restarting our service once a day (which isn’t a bad idea either!) <a href="#fnref:funstory" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
3 Things I Learned as an Engineer Doing Customer Support2015-12-08T00:00:00+00:00http://khamidou.com/three-things-learned-engineer-support<p>I work at <a href="https://nylas.com/">Nylas</a> as an engineer on the API team. We’re still pretty small, so engineers in my team also have to handle customer support duties. It’s great for customers because they get to talk directly to the person who wrote the API they’re using<sup id="fnref:gruff" role="doc-noteref"><a href="#fn:gruff" class="footnote" rel="footnote">1</a></sup>.</p>
<p>With 2015 coming to an end, I decided to recap the most important things I learned about customer support.</p>
<h3 id="1-customer-support-is-about-people-i-know-i-know">1. Customer support is about people (I know, I know.)</h3>
<p>Many engineers come to customer support with a problem-solving mindset. It’s very easy to start thinking of your support queue as a list of problems to solve instead of as a list of <em>customers</em> having <em>problems</em>. It’s also a great way to make your customer feel like another email on the way to Inbox zero.<sup id="fnref:notmuch" role="doc-noteref"><a href="#fn:notmuch" class="footnote" rel="footnote">2</a></sup></p>
<p>So, before jumping into troubleshooting mode, get back to your customers. A simple <em>“I’m sorry you’re having this problem! We’re looking into it”</em> goes a long way.</p>
<h3 id="2-follow-up-follow-up-follow-up">2. Follow up follow up follow up.</h3>
<p>Solving problems is good — following up when things take time is better. Is there a bug on your side that will take more than two days to solve? Send an update email. Is a release getting delayed because something unexpected came up? Update your customers.</p>
<p>You get the gist — it’s <strong>better to overcommunicate than to solve problems silently</strong>.</p>
<h3 id="3-youre-going-to-need-a-system-eventually">3. You’re going to need a system, eventually.</h3>
<p>In the early days of a startup nobody has a fixed role, so everyone does a little bit of customer support. Eventually — and this happens to every company — you’ll find yourself stretched out. You’ll start dropping emails, or not getting back to customers for days.</p>
<p>This can be very frustrating both to your customers and you. That’s when you’ll need to build a support system — either something off-the-shelf like Zendesk, or a bunch of scripts (like we do), to make sure that no email is falling through the cracks.</p>
<p>That’s all folks!</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:gruff" role="doc-endnote">
<p>Mostly — engineers can be pretty gruff. (I know I was!). <a href="#fnref:gruff" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:notmuch" role="doc-endnote">
<p>i.e: not much <a href="#fnref:notmuch" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Sales page teardown: Workshop2015-03-25T00:00:00+00:00http://khamidou.com/sales-page-teardown-workshop<p>Ah the life of the beginning freelancer. Landing contracts. Writing code. Arguing with cheap clients. Looking for contracts (actually spending an awful lot of time on the latter).</p>
<p><a href="http://letsworkshop.com/">Workshop</a> is a service which sends you ten high-quality leads every day. They’ve got an awesome sales pitch which resonated deeply with me<sup id="fnref:feast" role="doc-noteref"><a href="#fn:feast" class="footnote" rel="footnote">1</a></sup>. Let’s see what makes it so good.</p>
<h2 id="aside-telling-people-what-youre-about">Aside: telling people what you’re about</h2>
<p>Before diving into the main body copy, let’s talk about the first screen because it’s <strong>exceedingly great</strong>.
It’s very obvious the author spent a lot of time on it.<sup id="fnref:firstline" role="doc-noteref"><a href="#fn:firstline" class="footnote" rel="footnote">2</a></sup></p>
<p>Tons of web pages seem to assume that people have the patience to sit through 4 or 5 screens before deciding whether to close the page or not<sup id="fnref:parallax" role="doc-noteref"><a href="#fn:parallax" class="footnote" rel="footnote">3</a></sup>. This one doesn’t — the first screen is actually a condensed version of the sales pitch. It answers the three questions everybody asks themselves when landing on a new website:</p>
<p><img src="/images/workshop_teardown/1.png" class="img-responsive" /></p>
<p>You couldn’t be clearer. The first screen has everything you need to know about the service, maybe subscribe and get on with your life. Bonus points for having a drawing here – it gets the point across really well, without a lot of words.</p>
<h2 id="body-copy">Body copy</h2>
<p>Let’s look at the first two paragraphs.</p>
<p><img src="/images/workshop_teardown/2.png" class="img-responsive" />
<img src="/images/workshop_teardown/3.png" class="img-responsive" /></p>
<p>What’s happening here? Two things: <a href="#problems">making readers realize they have a problem</a> and <a href="#selling">selling them on a solution</a>.</p>
<h3 id="problems">Making readers realize they have a problem</h3>
<p>The writer starts with a long paragraph about the difficulties of freelancing. He has a deep understanding of his audience it shows. He manages to articulate what makes freelancing hard: having to run a business while all you want to do is code/design.</p>
<p>The following paragraph is really smart because it’s not asking for a sale right away. Instead the author paints us the picture of a life without having to look for leads. How great would it be?</p>
<p>When writing a sales page, you have to keep in mind that people in general tend to forget about their pains. We get numb to them. That’s why you need to present an alternative.</p>
<h3 id="selling">Selling them on a solution</h3>
<p>The writer finally introduces its service. This paragraph, is really, really well written. Look at it:</p>
<p><img src="/images/workshop_teardown/5.png" class="img-responsive" /></p>
<p>It’s just does so many things right! In a single paragraph, the writer:</p>
<ol>
<li>Introduces the service</li>
<li><span style="background-color: #ff99cc">Gets a couple sales objections out of the way</span>(is it actually used by people? Will I need to get involved?)</li>
<li><span style="background-color: #99FF99;">Anchors the price</span>(the “it’s the cost of a cup of coffee everyday” line is a bit cliché but it’s because so effective)</li>
<li><span style="background-color: #ffff99">Positions the service</span> “You’re not buying workshop because it’s cheap, you’re buying it because it <em>works</em>”).
That’s a really smart way to position yourself. After all, when the main alternative to your service is manually checking job boards, you can not compete on price nor on quantity. Quality is where things are at.</li>
</ol>
<h2 id="handling-customer-objections">Handling customer objections</h2>
<p>The final part of the sales page is a FAQ followed by a short testimonial. I don’t have much to say about it (it’s still great though!) apart from the opening sentence, which I like a lot.</p>
<p><img src="/images/workshop_teardown/7.png" class="img-responsive" />
<img src="/images/workshop_teardown/8.png" class="img-responsive" /></p>
<p>Having numbers like this make things reassuring. That’s definitely something I’m going to reuse<sup id="fnref:nitpick" role="doc-noteref"><a href="#fn:nitpick" class="footnote" rel="footnote">4</a></sup>.</p>
<p>My only gripe is that there should be more testimonials. Sure, Ruben Gamez’s testimonial is quite good and he’s a celebrity of sorts in some circles but it kind of feels out of place with the rest of the page.</p>
<p>After all, this page is mostly for freelancers who have a hard time coming up with leads. What is more convincing: a testimonial from a freelancer just like you or one from someone who probably works fulltime on a <a href="http://bidsketch.com">SaaS service</a>?</p>
<h2 id="closing-thoughts">Closing thoughts</h2>
<p>As a web developer I know that there’s a lot of different verticals. For example, it’s unlikely to find a Rails programmer who would know how to customize your wordpress website.</p>
<p>One way to grow the service would be to branch into specific specialities — for example having a weekly email for Rails developers. The problem is coming up with leads. Would it be possible to come up with 10 high-quality Rails leads a week? Surely but this would be harder than coming up with generic leads.</p>
<p>The simplest way to grow this service would probably be branching into different specialities. What about copywriters? Illustrators? These are disciplines where there could be a lot of demands and where the returns would be higher.</p>
<hr />
<p><strong>Key takeaway:</strong> Don’t try to sell your service too early. Tell a story.</p>
<hr />
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:feast" role="doc-endnote">
<p>I still get occasional shivers when reading the expression “feast or famine”. <a href="#fnref:feast" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:firstline" role="doc-endnote">
<p>Take the opening line. <em>“I send people who need websites your way.”</em> <br />The wording is simple but doesn’t say a lot about the leads you’re getting — what kind of budget do they have? — so the author followed up with <em>“This week alone I’ve sent more than <strong>$159,215 worth of work</strong>.”</em>. This is one example among many others. <a href="#fnref:firstline" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:parallax" role="doc-endnote">
<p>I’m looking at you, fancy parallax sales page. <a href="#fnref:parallax" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:nitpick" role="doc-endnote">
<p>Ok, so this is probably the nitpick of nitpicks — and maybe my programmer brain taking over — but I’ve got a hard time parsing <em>“There’s zero risk for the first 30 days”</em>. Does it means there’s actual risks after the first month?</p>
<p>What about having instead a line like “Try it risk-free for 30 days”? <a href="#fnref:nitpick" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Sales page teardown: Snappy2015-01-06T00:00:00+00:00http://khamidou.com/sales-page-teardown-snappy<p>Let’s try something a little different. I’ve always loved picking apart great sales pages to see what makes them tick.</p>
<p><a href="https://besnappy.com/">Snappy</a> is a customer support webapp which targets small to medium-sized companies. They have a great sales page which uses customer quotes really well.</p>
<h2 id="introduction">Introduction</h2>
<p><img src="/images/snappy_teardown/1.png" class="img-responsive" /></p>
<p>This is the first thing you see about snappy. The design is quite minimalist, but there are links to all the important pages, including my favorite one, the login page.<sup id="fnref:loginpage" role="doc-noteref"><a href="#fn:loginpage" class="footnote" rel="footnote">1</a></sup></p>
<p>The tagline is clear and direct. It’s a good idea to have a customer testimonial from the get-go — it’s always reassuring to see an app is used by real persons. However, the quote itself is a little too non-specific for my taste:</p>
<p><em>“Snappy allows us to get rid of all of the problems of email”</em>.</p>
<p>Sure, email has a lot of problems, but does Snappy solve mine? The role of the first screen is to make the reader read the rest of the page. Opening with a quote about a very specific problem of email support (e.g: the number of dropped support emails before and after snappy) would make the copy much more compelling.<sup id="fnref:abtests" role="doc-noteref"><a href="#fn:abtests" class="footnote" rel="footnote">2</a></sup></p>
<h2 id="story">Story</h2>
<p>The next screen shows a small screenshot of Snappy followed by four paragraphs of sales text. It’s a <em>very good idea</em> to tease us with this image before getting to the wall of text.</p>
<p><img src="/images/snappy_teardown/2.png" class="img-responsive" />
<img src="/images/snappy_teardown/3.png" class="img-responsive" />
<img src="/images/snappy_teardown/4.png" class="img-responsive" /></p>
<p>The role of this part is to make the reader realize she has a support email problem. It tells a story, which is the most important thing in sales page. The story itself is good<sup id="fnref:unread" role="doc-noteref"><a href="#fn:unread" class="footnote" rel="footnote">3</a></sup> — and the outline is very clear (which is great for skimmers!). However, there’s a couple things which could be better.</p>
<p>First, some sentences are way too long. <em>“Do you remember the first time you answered a paying customer’s email, quickly and courteously, with joy and even honor at the opportunity to solve a problem, delivering exactly the solution they needed, right when they needed it?”</em></p>
<p>Long and meandering sentences like this one run out of steam quickly. Shorter phrases are easier to grasp, and pack more punch. (In this case, I would rewrite the previous sentence like this: <em>“Do you remember the first time you answered a customer’s email? How quickly you replied — the joy you felt about solving their problem? Do you remember how thrilled they were to see their problem solved?”</em>)</p>
<p>Second, and this is very subjective, but the parts could flow a little better. In particular, I feel like part two and three could be merged together. They’re about the same thing after all.</p>
<p>Still, these are minor complaints which could get smoothed out with a little editing.</p>
<p>The next part is <em>brillant</em>! Most sales pages would jump straight to the presentation of the product. The snappy guys chose to feature a great customer quote. <strong>“We ain’t going back”</strong>. This is gold!</p>
<p><img src="/images/snappy_teardown/5.png" class="img-responsive" /></p>
<h2 id="benefits">Benefits</h2>
<p>We get to the meat of the sales pitch with the long list of benefits Snappy brings. This is pretty much your standard list of benefits. Once again, I really like how the designers peppered customer testimonials to break the monotony.</p>
<p><img src="/images/snappy_teardown/6.png" class="img-responsive" />
<img src="/images/snappy_teardown/7.png" class="img-responsive" />
<img src="/images/snappy_teardown/8.png" class="img-responsive" /></p>
<p>Unfortunately they didn’t follow their idea all the way through: they’ve got a great quote about how easy it is to set up Snappy, but it floats at the bottom of the page instead of supporting the main pitch:</p>
<p><img src="/images/snappy_teardown/10.png" class="img-responsive" /></p>
<h2 id="pricing-grid">Pricing grid</h2>
<p>The next section is the pricing grid. I really like how their design reminds the reader of the hidden costs of using Gmail for support. It’s a great way to make choosing Snappy obvious.</p>
<p><img src="/images/snappy_teardown/9.png" class="img-responsive" /></p>
<p>One weird thing with this pricing model is that they’re charging the same flat-rate per seat whatever the number of users. Surely the usefulness of Snappy increases with the number of support persons, which implies higher prices?<sup id="fnref:gmailuse" role="doc-noteref"><a href="#fn:gmailuse" class="footnote" rel="footnote">4</a></sup></p>
<h2 id="wrap-up">Wrap-up</h2>
<p>The page wraps things up quickly by presenting the team<sup id="fnref:aboutpage" role="doc-noteref"><a href="#fn:aboutpage" class="footnote" rel="footnote">5</a></sup>, showing one last testimonial and suggesting taking the product tour.</p>
<p><img src="/images/snappy_teardown/11.png" class="img-responsive" /></p>
<p>It would be awesome to have a link to talk to support directly — this a helpdesk solution after all. I looked at a few other helpdesk webapps<sup id="fnref:saaswebapps" role="doc-noteref"><a href="#fn:saaswebapps" class="footnote" rel="footnote">6</a></sup> and none of them displayed a prominent link to contact support. Either they all forgot about it or there’s a specific reason — maybe spending too much time on unqualified leads?</p>
<hr />
<h2 id="conclusion">Conclusion</h2>
<p>All in all, this is a great sales page! It has a couple minor problems, but nothing that couldn’t be improved with some patient testing.</p>
<p><strong>Key takeaway:</strong> Customer testimonials are great. Use them to support your pitch.</p>
<hr />
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:loginpage" role="doc-endnote">
<p>You’d be surprised by the number of webapps that forget this. <a href="#fnref:loginpage" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:abtests" role="doc-endnote">
<p>Of course, they’ve probably A/B tested a bunch of quotes and this one came out ahead, but still. <a href="#fnref:abtests" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:unread" role="doc-endnote">
<p>Especially the bit about marking emails as unread. I do this all the time! <a href="#fnref:unread" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:gmailuse" role="doc-endnote">
<p>This also applies to using Gmail or Outlook. The hidden cost of using Outlook for a single user is probably 100$/month but it increases significantly (read: non-linearly) with the number of users. <a href="#fnref:gmailuse" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:aboutpage" role="doc-endnote">
<p>It would be nice to have a link to a brief “About us/History of the company” page. It’s important for the reader to know that this is not a fly-by-night operation. For example, 37signals/Basecamp has an awesome <a href="https://basecamp.com/about">about page</a> which presents the company while resolving tons of customer objections. Litterally every paragraph deals with a separate concern a client may have. <a href="#fnref:aboutpage" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:saaswebapps" role="doc-endnote">
<p><a href="http://freshdesk.com/">Freshdesk</a>, <a href="https://frontapp.com/">Front</a> and <a href="http://www.zendesk.com/">Zendesk</a> <a href="#fnref:saaswebapps" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Overriding vagrant settings2014-09-25T00:00:00+00:00http://khamidou.com/tips/overriding-vagrant-settings<p>This tip courtesy of my colleague <a href="https://www.dlitz.net/">Dwayne Litzenberger</a>.</p>
<p><a href="http://www.vagrantup.com/">Vagrant</a> is a great tool. My only gripe with it is that it forces everyone to share the same vm settings, which can be painful, especially when you have a slow computer. It seems there’s a <code class="language-plaintext highlighter-rouge">~/.vagrant.d</code> directory for specifying overrides but it’s run <em>before</em> <code class="language-plaintext highlighter-rouge">Vagrantfile</code>, which makes it useless to override variables defined in <code class="language-plaintext highlighter-rouge">Vagrantfile</code>.</p>
<p>There’s a variety of methods for <a href="http://stackoverflow.com/questions/13065576/override-vagrant-configuration-settings-locally-per-dev">doing</a> <a href="https://github.com/reidab/citizenry/blob/master/Vagrantfile">this</a> but the cleanest way is adding the following lines of code to the end of your <code class="language-plaintext highlighter-rouge">Vagrantfile</code>:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># Local Vagrantfile overrides.</span>
<span class="no">Dir</span><span class="p">.</span><span class="nf">glob</span><span class="p">(</span><span class="s1">'Vagrantfile.local.d/*'</span><span class="p">).</span><span class="nf">sort</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">path</span><span class="o">|</span>
<span class="nb">load</span> <span class="n">path</span>
<span class="k">end</span>
<span class="no">Dir</span><span class="p">.</span><span class="nf">glob</span><span class="p">(</span><span class="s1">'Vagrantfile.local'</span><span class="p">).</span><span class="nf">sort</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">path</span><span class="o">|</span>
<span class="nb">load</span> <span class="n">path</span>
<span class="k">end</span></code></pre></figure>
<p>This code loads everything under Vagrantfile.local.d/ and <code class="language-plaintext highlighter-rouge">Vagrantfile.local</code>. For instance, my <code class="language-plaintext highlighter-rouge">Vagrantfile.local</code> contains:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="no">Vagrant</span><span class="p">.</span><span class="nf">configure</span><span class="p">(</span><span class="no">VAGRANTFILE_API_VERSION</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
<span class="c1"># Use fewer memory and CPU resources</span>
<span class="n">config</span><span class="p">.</span><span class="nf">vm</span><span class="p">.</span><span class="nf">provider</span> <span class="ss">:virtualbox</span> <span class="k">do</span> <span class="o">|</span><span class="n">vbox</span><span class="p">,</span> <span class="n">override</span><span class="o">|</span>
<span class="n">vbox</span><span class="p">.</span><span class="nf">memory</span> <span class="o">=</span> <span class="mi">256</span>
<span class="n">vbox</span><span class="p">.</span><span class="nf">cpus</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">end</span></code></pre></figure>
Implementing async/await in javascript with Sweet.js2014-07-20T00:00:00+00:00http://khamidou.com/programming/await-statement-in-javascript<p>Ever since I went back to Javascript, I’ve been missing C#’s async/await system.
With C# you can mark some methods <code class="language-plaintext highlighter-rouge">async</code>. Afterwards, you can call them “synchronously” using the <code class="language-plaintext highlighter-rouge">await</code> keyword. Behind the scenes, the compiler rewrites the code to use callbacks.</p>
<p>For example, C# lets you write something like this:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">var</span> <span class="nx">status</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">$</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">"</span><span class="s2">/login</span><span class="dl">"</span><span class="p">);</span> <span class="c1">// await returns a status object.</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">status</span><span class="p">.</span><span class="nx">success</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// whatever</span>
<span class="p">}</span></code></pre></figure>
<p>And it gets compiled to this:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">$</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">"</span><span class="s2">/login</span><span class="dl">"</span><span class="p">).</span><span class="nx">done</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">status</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">status</span><span class="p">.</span><span class="nx">success</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// whatever </span>
<span class="p">}</span>
<span class="p">}).</span><span class="nx">fail</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">status</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">status</span><span class="p">.</span><span class="nx">success</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// whatever </span>
<span class="p">}</span>
<span class="p">});</span></code></pre></figure>
<p>To me, it’s a net win in terms of readability because I’ve never really liked callbacks. They’re an implementation detail and I’d rather have them swept under the rug.</p>
<p>Last week I heard of <a href="http://sweetjs.org/">sweet.js</a>, a macro compiler for Javascript, so I decided to try to implement some sort of <code class="language-plaintext highlighter-rouge">await</code> functionality with macros.</p>
<h1 id="the-basics-of-sweetjs">The basics of Sweet.js</h1>
<p>Sweet.js lets you define <em>syntaxic sugar</em>, i.e, macros which get expanded at compile time.</p>
<p>A sweet.js macro has two parts, a matching expression and a replacement expression.</p>
<p>Let’s go back to C macros because sweet’s macros will be easier to understand this way. In C, a macro is a statement which defines an expression and a replacement for this expression. During the compilation, the macro is expanded by the preprocessor.</p>
<p>Here’s the simplest macro of all, a greet function.</p>
<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="cp">#define greet(name) printf("hello #name")</span></code></pre></figure>
<p>This is the equivalent sweetjs macro:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">macro</span> <span class="nx">greet</span> <span class="p">{</span>
<span class="nx">rule</span> <span class="p">{</span>
<span class="p">(</span><span class="nx">$name</span><span class="p">:</span><span class="nx">lit</span><span class="p">)</span>
<span class="p">}</span> <span class="o">=></span> <span class="p">{</span>
<span class="cm">/* replace everything with this text. */</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">hello </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">$name</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">greet</span><span class="p">(</span><span class="dl">'</span><span class="s1">Paul</span><span class="dl">'</span><span class="p">);</span> <span class="c1">// output: 'console.log('hello ' + 'Paul');'</span></code></pre></figure>
<p>There’s several important things.</p>
<ol>
<li>
<p>First you can see sweet has a little more syntax than the C preprocessor. A macro is defined inside a <code class="language-plaintext highlighter-rouge">macro</code> block. Inside this block you can have several rules of the form <code class="language-plaintext highlighter-rouge">{ pattern } { replacement }</code>.</p>
</li>
<li>
<p>The rules for matching macros are similar to regexps. The block <code class="language-plaintext highlighter-rouge">($name:lit)</code> means: “match one litteral between two parentheses and assign it to the variable <code class="language-plaintext highlighter-rouge">$name</code>”.</p>
</li>
<li>
<p>The replacement block contains the replacement text and can optionally call javascript code.</p>
</li>
</ol>
<p>So, we’ve got a macro and it gets expanded at compile-time. However, because of the way we wrote it, it will trigger an error if we pass it more than one argument. Let’s fix this.</p>
<h1 id="handling-multiple-parameters">Handling multiple parameters</h1>
<p>Sweetjs has a specific syntax for defining variadic macros: a <code class="language-plaintext highlighter-rouge">...</code> will match any token similar to the previous match:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">macro</span> <span class="nx">greet</span> <span class="p">{</span>
<span class="nx">rule</span> <span class="p">{</span>
<span class="p">(</span><span class="nx">$name</span><span class="p">:</span><span class="nx">lit</span> <span class="p">(,)</span> <span class="p">...)</span> <span class="c1">// "(,)" means don't capture commas.</span>
<span class="p">}</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">hello </span><span class="dl">"</span><span class="p">,</span> <span class="nx">$name</span> <span class="p">(,)</span> <span class="p">...)}</span>
<span class="p">}</span>
<span class="nx">greet</span><span class="p">(</span><span class="dl">'</span><span class="s1">Paul</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">Ringo</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">George</span><span class="dl">'</span><span class="p">);</span>
<span class="c1">// output: console.log('hello ', 'Paul', 'Ringo', 'George');</span></code></pre></figure>
<p>Again, here are some important changes:</p>
<ol>
<li>We don’t want to match commas, so ask the compiler to ignore them by using <code class="language-plaintext highlighter-rouge">(,)</code>.</li>
<li>The ‘…’ token itself. The tokens matched are exposed in the replacement rule as <code class="language-plaintext highlighter-rouge">...</code>.</li>
</ol>
<p>Now, let’s try to define a small macro to do simplify those messy jQuery ajax calls.</p>
<h1 id="handling-async-ajax-calls">Handling async AJAX calls</h1>
<p>The jQuery guys, knowing how painful it is to use callbacks, have defined a promise interface. It allows us to chain calls in a pseudo-procedural type:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"> <span class="nx">$</span><span class="p">.</span><span class="kd">get</span><span class="p">({</span><span class="dl">"</span><span class="s2">/api.json</span><span class="dl">"</span><span class="p">})</span>
<span class="p">.</span><span class="nx">done</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span> <span class="p">})</span>
<span class="p">.</span><span class="nx">fail</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span> <span class="p">});</span></code></pre></figure>
<p>I still find this too annoying. Let’s simplify things with this macro:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">let</span> <span class="kd">var</span> <span class="o">=</span> <span class="nx">macro</span> <span class="p">{</span>
<span class="nx">rule</span> <span class="p">{</span>
<span class="nx">$result</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">$</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">$x</span><span class="p">);</span>
<span class="nx">$rest</span>
<span class="p">...</span>
<span class="p">}</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">$result</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">$x</span><span class="p">).</span><span class="nx">done</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">$result</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">$rest</span>
<span class="p">...</span>
<span class="p">}).</span><span class="nx">fail</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">$result</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">$rest</span>
<span class="p">...</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">var</span> <span class="nx">result</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">$</span><span class="p">.</span><span class="kd">get</span><span class="p">({</span><span class="na">url</span><span class="p">:</span> <span class="dl">"</span><span class="s2">http://google.com</span><span class="dl">"</span><span class="p">});</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">result</span><span class="p">);</span></code></pre></figure>
<p>This compiles to the following javascript:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">var</span> <span class="nx">result$511</span><span class="p">[</span><span class="o">^</span><span class="nx">hygienic</span><span class="p">]</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="kd">get</span><span class="p">({</span> <span class="na">url</span><span class="p">:</span> <span class="dl">'</span><span class="s1">http://google.com</span><span class="dl">'</span> <span class="p">}).</span><span class="nx">done</span><span class="p">(</span>
<span class="kd">function</span> <span class="p">(</span><span class="nx">result$512</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">result$512</span><span class="p">);</span>
<span class="p">}).</span><span class="nx">fail</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">result$513</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">result$513</span><span class="p">);</span>
<span class="p">});</span></code></pre></figure>
<p>There’s only two major changes between the <code class="language-plaintext highlighter-rouge">greet</code> macro and this one:</p>
<ol>
<li>We’re using variadic parameters differently than in the previous example: instead of capturing function parameters we use them to capture every token after the macro.</li>
<li>We’re redefining <code class="language-plaintext highlighter-rouge">var</code> as a macro. This lets us expands constructs like <code class="language-plaintext highlighter-rouge">var result = await $.get</code>. To get more specific, we’re redefining <code class="language-plaintext highlighter-rouge">var</code> as an anonymous macro because we don’t want sweet to try to expand every <code class="language-plaintext highlighter-rouge">var</code> inside the macro.</li>
</ol>
<p>By the way, do you wonder where these weird <code class="language-plaintext highlighter-rouge">result$511</code> and al come from? It’s because sweet macros are <em>hygienic</em>: when they get expanded, identifiers are renamed to prevent name clashes.</p>
Filtering uncategorized posts with Jekyll2014-06-11T00:00:00+00:00http://khamidou.com/tips/jekyll-filter-uncategorized-posts<p>I’m using <a href="http://jekyllrb.com/">Jekyll</a> to generate this blog. It’s pretty cool once you get the hang of it.
Yesterday I had a problem stackoverflow couldn’t solve: I wanted to filter my blog posts to keep only the ones who weren’t categorized.</p>
<p>I had to write a really simple plugin to do this. Here it is:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">module</span> <span class="nn">Jekyll</span>
<span class="k">module</span> <span class="nn">UncategorizedFilter</span>
<span class="c1"># Returns back all categories related to a primary category</span>
<span class="c1"># e.g. "blog" or "questions"</span>
<span class="k">def</span> <span class="nf">filter_categorized_posts</span><span class="p">(</span><span class="n">posts</span><span class="p">)</span>
<span class="n">filtered</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">post</span> <span class="k">in</span> <span class="n">posts</span>
<span class="k">if</span> <span class="n">post</span><span class="p">.</span><span class="nf">categories</span> <span class="o">==</span> <span class="p">[]</span>
<span class="n">filtered</span><span class="p">.</span><span class="nf">push</span><span class="p">(</span><span class="n">post</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">return</span> <span class="n">filtered</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">Liquid</span><span class="o">::</span><span class="no">Template</span><span class="p">.</span><span class="nf">register_filter</span><span class="p">(</span><span class="no">Jekyll</span><span class="o">::</span><span class="no">UncategorizedFilter</span><span class="p">)</span></code></pre></figure>
<p>To use this plugin, save the code in a folder called _plugins in your jekyll directory.
Here’s how to use it from a template:</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html">{% assign uncategorized_posts = site.posts | filter_categorized_posts %}
{% for post in uncategorized_posts %}
<span class="nt"><li></span>
<span class="nt"><a</span> <span class="na">href=</span><span class="s">"{{site.baseurl}}{{ post.url }}"</span><span class="nt">></span>{{ post.title }}<span class="nt"></a></span>
<span class="nt"></li></span>
{% endfor %}</code></pre></figure>
<p>Hope this helps.</p>
Kite status report 4 - Om nom cookies!2014-05-13T00:00:00+00:00http://khamidou.com/Kite-status-report-4-cookies<p>I spent most of last week working on implementing auth. I knew it’d be painful, but I didn’t thought it’d be that painful. There’s so much implementation details to know about, I’m not even sure I’ve designed something secure even after spending hours on it.</p>
<p>This post is a way to clarify my thoughts on authentication. Sorry if it’s a little dense and hard to follow!</p>
<h3 id="traditional-auth">Traditional auth</h3>
<p>Do you remember when most code ran on the server and Javascript was used to pepper some interactivity on the page? I miss these times. Back then, this is how things worked:</p>
<p><img src="/images/cookies/oldflow.png" alt="How things used to work" /></p>
<p>In this scenario, you had three things to care about:</p>
<ol>
<li>Cookie theft. To prevent an attacker to impersonate an existing user, you would have to make all requests over HTTPS and set all your cookies as “Secure” (the browser sends secures cookies only when it’s connecting over SSL).</li>
<li><a href="http://blog.codinghorror.com/cross-site-request-forgeries-and-you/">Cross Site Request Forgery</a>. This means checking on all non-GET requests that it originated from one of your pages.</li>
<li><a href="https://www.owasp.org/index.php/Session_fixation">Session fixation</a>. This was solved mostly by using cookies instead of passing a session ID parameter to every page.</li>
</ol>
<p>Traditional auth is mostly a solved problem.</p>
<h3 id="client-side-apps">Client-side apps</h3>
<p>We’ve moved on to making apps on the client. For most people this means your app is mostly javascript communicating using JSON with a REST-like backend. Sadly, the protocol haven’t changed, which means there’s an increased attack surface. Additionally to the flaws above, here’s what it’s necessary to look for:</p>
<ul>
<li><a href="http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx/">Json vulnerability</a>. This one is pretty complex. In a few words, an attacker could insert a call to your JSON api in a page and steal data from authentified users. What most apps do in this case is adding nonsensical string at the beginning of the JSON to trigger a syntax error.</li>
<li>
<p>API Cross Site Request Forgery. Really, it’s the same problem as form-based CSRF except it occurs over AJAX calls. Thankfully, AngularJS (the client framework I use) has a solution for this. If you set a cookie named XSRF-TOKEN, Angular will add to each AJAX request a custom header “X-XSRF-TOKEN” which contains the same value as your cookie.</p>
<p>The reasoning is that if the call originated from a malicious website it would not have the custom header because of the same-origin policy.</p>
</li>
</ul>
<h3 id="how-kite-does-authentication">How Kite does authentication</h3>
<p>Because I wanted something simple, I just adapted the traditional auth flow.</p>
<p><img src="/images/cookies/kiteflow.png" alt="Kite auth flow" /></p>
<p>There’s one thing I’m unsure about:</p>
<p>The auth cookie is simply a base64-encoded random number. It’s only an identifier for a server-side session. As such, is it necessary to sign it to prevent tampering? <a href="http://cookies.lcs.mit.edu/pubs/webauth:sec10.pdf">It seems it’s okay to go without using a MAC, if the token is large enough</a> (see section 4.4). Anyway, using a MAC isn’t expensive, so I’ll probably add it sometimes later.</p>
<p><strong>Key takeaway:</strong> Use HTTPS. Sign your cookies.</p>
Kite status report 32014-05-01T00:00:00+00:00http://khamidou.com/kite-status-report-3<p>I haven’t written a status report for a long long time. I got stuck with a DNS bug which took a while to resolve and I got sidetracked by other projects. Things are getting better though: I’ve resolved this DNS bug and I’m halfway through adding multi-user support.</p>
<h3 id="the-dns-bug">The DNS bug</h3>
<p>DNS is complex, and my ISP having some pretty aggressive caching made solving this bug a lesson in patience.
The problem was simple. I setup dogfood.kiteapp.io as a staging server and I wanted to receive emails addressed to it.
Naïvely, I thought adding these lines to my DNS config would work:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dogfood.kiteapp.io. A XXX.XXX.XXX.XXX
dogfood.kiteapp.io MX 10 dogfood.kiteapp.io.
</code></pre></div></div>
<p>If you’re not a DNS expert, you’ll probably think this setup is okay.</p>
<p>You’d be wrong.</p>
<p>Take a closer look. I forgot the final ‘.’ on the line specifying the mail server destination. This means I’ve defined an email server for the subdomain <code class="language-plaintext highlighter-rouge">dogfood.kiteapp.io.kiteapp.io</code>, in the process making all my emails addressed to <code class="language-plaintext highlighter-rouge">dogfood.kiteapp.io</code> go fill the great bucket in the sky.</p>
<p>So, this was a silly bug.</p>
<h3 id="multi-user-support">Multi-user support</h3>
<p>I’ve started working on making Kite support multiple users. This involves refactoring the existing backend code to look in the right directories, handling authentification and adding multi-user support to the angular frontend.</p>
<p>At this point, I’m split between adding multi-user support and adding more features to the UI. I think I’m probably going to polish a little more the single-user experience before thinking of adding something else.</p>
<p>As always, send your comments, features requests and general inquiries at karim @ this domain name.</p>
When programmers write sales pages2014-04-14T00:00:00+00:00http://khamidou.com/software/when-programmers-write-sale-pages<p>Call me weird but I’ve always loved reading longform sales pages. Lately I’ve been reading through some programming ebooks sales pages and I’ve noticed a pattern again and again: every one of <a href="http://createyourproglang.com/">them</a> <a href="http://www.jstorimer.com/products/working-with-unix-processes">is</a> <a href="http://exceptionalruby.com/">extremely</a> <a href="https://www.petekeen.net/mastering-modern-payments">short</a>.</p>
<p>For example, here’s how <a href="http://www.jstorimer.com/products/working-with-unix-processes">Working with unix processes</a> sells itself<sup id="fnref:pick" role="doc-noteref"><a href="#fn:pick" class="footnote" rel="footnote">1</a></sup>.</p>
<p><img src="/images/longform_copy/storimer_benefits.png" alt="storimer benefits" /></p>
<p>Of course the subject is deeply technical, but I’m sure people would have benefited from a little more hand-holding. So, there are real world concerns about spawning shell commands, what are they?</p>
<p>On the other hand, Here’s an excerpt from the landing page of <a href="http://dw-secrets.com">the Ultimate Guide to Disneyworld</a>. It’s an ebook written for middle-aged stay-at-home moms, and it has a great landing page. Here’s how the author sells one of the many chapters of the book (highlighting is mine):</p>
<p><img src="/images/longform_copy/haworth_benefits.png" alt="haworth benefits" /></p>
<p>See the difference?
<strong>The Disneyland ebook is a lot more upfront about the value it will bring out.</strong></p>
<p>Most programmers don’t like to brag. We’d like our products to stand on their own merits. It’s not a good idea to do this on your landing page, though. There’s a lot of potential readers out there who don’t understand the problem enough to make an informed choice and they’re also the ones who need your book the most.</p>
<p><strong>Key takeaway: You shouldn’t expect your customers to understand the value of your product by themselves.</strong></p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:pick" role="doc-endnote">
<p>This is just an example; I’ve got nothing against Jesse Storimer. I actually think his intro text is really really well written. It’s one of the best opening sentences I’ve ever read on a landing page. (Here it is, for the curious:</p>
<blockquote>You're a web developer. A good one. You write Rails apps in your sleep. But you skipped over some fundamentals. You feel like your foundation is lacking. This book will fill that gap.</blockquote>
<p>It really speaks to me.) <a href="#fnref:pick" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
You probably shouldn't leave your job to work on an indie game.2014-03-27T00:00:00+00:00http://khamidou.com/software/you-probably-shouldnt-leave-your-job-to-work-on-an-indie-game<p>A friend of mine always talks about leaving his cushy job at $BIGCORP to go work fulltime on his indie game venture. I don’t think it’s a good idea, and I’ll try to show why in my trademark hand-wavy way.</p>
<!-- more -->
<p>When there’s a lot of demand for a product, concurrents move-in to try to capture some of the market. If the products are very similar — economists say “undifferentiated” — there will be a pricing race to the bottom.</p>
<p>This is what happened to the PC market in the late 90s. In hindsight, Microsoft’s strategy in the 80s and 90s was brilliant. Hardware makers have never been very good at developing software. They’ve never been interested in developing OSes, so they happily gave this responsibility to Microsoft.</p>
<p>The problem is that a Dell and a Compaq PC are essentially the same computer but with a different logo on the box. They both run Windows, so consumers have little incentive to choose a Dell over a Compaq except price. So PC makers competed on price, until they got to the very very thin margins they have today (<a href="http://www.theguardian.com/technology/2014/jan/09/pc-value-trap-windows-chrome-hp-dell-lenovo-asus-acer">about 16$ per PC sold</a>).
Essentially, in their effort to get more shares of the market, the makers all competed to sell more windows copies.<sup id="fnref:pcmarket" role="doc-noteref"><a href="#fn:pcmarket" class="footnote" rel="footnote">1</a></sup></p>
<p>I think there’s an similar phenomenon ongoing for indie games. It’s not very visible yet, except for some genres like roguelikes.</p>
<p>Roguelikes on Steam are priced terribly low; I checked out the prices of a dozen games on Steam and every one of them was priced between 4.99$ and 14.99$.<sup id="fnref:roguelikes" role="doc-noteref"><a href="#fn:roguelikes" class="footnote" rel="footnote">2</a></sup> This is clearly not enough to make a living. So, either all their developers collectively thought “Yep, pricing my game between 4.99$ and 14.99$ feels just right”, or they did this because they had to. Obviously, the latter is more likely.</p>
<p>When you’re the only one to sell something, you can set the price you want (economists call this having “pricing power”). The Kerbal Space Program devs are the only ones to sell a sandbox game where you can build a spacecraft, so the game is priced accordingly at 26.99$. If you decided to release a roguelike at 26.99$, people just wouldn’t buy it because there’s already tons of similar roguelikes they can choose from. Because of this, there’s just some maximum price people expect to pay for a roguelike.<sup id="fnref:AAA" role="doc-noteref"><a href="#fn:AAA" class="footnote" rel="footnote">3</a></sup></p>
<p>Take some time to think about your positioning and how to price your game taking the plunge.</p>
<p><strong>Key takeaway: if you want your game to sell at a good price, you should probably do it in a genre without a lot of concurrents.<sup id="fnref:adventure" role="doc-noteref"><a href="#fn:adventure" class="footnote" rel="footnote">4</a></sup></strong></p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:pcmarket" role="doc-endnote">
<p>More recently, the same thing happened to the app store and the android market. <a href="#fnref:pcmarket" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:roguelikes" role="doc-endnote">
<p>I checked the prices of the following roguelikes on Steam: Spelunky (14.99$), Rogue Legacy (14.99$), FTL (9.99$), Dungeons of Dredmor (4.99$), Risk of Rain (9.99$), the Binding of Isaac (4.99$), Teleglitch (12.99$), the Pit (6.99$), Quest of Dungeon (4.99$).</p>
<p>Average price of my very unscientific sample: <strong>10.99$</strong>. <a href="#fnref:roguelikes" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:AAA" role="doc-endnote">
<p>Actually, AAA studios are in the same situation as indies; they just don’t have the same budget. The solution they found was to outspend and outmarket the competition, which kind of works, most of the time. <a href="#fnref:AAA" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:adventure" role="doc-endnote">
<p>Adventures games. Hardcore strategy games. Simulators (I hear games like <a href="http://store.steampowered.com/app/220260/">Farming Simulator</a> literally print money in Germany). Just don’t do another roguelike. <a href="#fnref:adventure" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Steam, Humble Bundles and sales cannibalization2014-03-09T00:00:00+00:00http://khamidou.com/steam-bundles-and-sales-cannibalization<p>For the longest time, I’ve wondered if Humble Bundles and Steam sales were hurting or helping the video games industry.
There’s not a lot of data about this on the Internet but some indie gamemakers were kind enough to share some numbers on their blogs.</p>
<ul>
<li>
<p>Jason Rohrer, explained in a <a href="http://thecastledoctrine.net/seedBlogs.php?action=display_post&post_id=jasonrohrer_1389812989_0&show_author=1&show_date=1">post</a> why he was refusing to participate in Steam Sales. He also gave a couple figures and graphs about his sales.</p>
</li>
<li>
<p>The creators of Dustforce, Hitbox Team, did a <a href="http://hitboxteam.com/dustforce-sales-figures">year in review</a> post. Dustforce was featured in the Humble Indie Bundle 6. It seems to have made a pretty okay year.</p>
</li>
<li>
<p>PocketWatch Games – whose game Monaco was in last month’s Humble Bundle – wrote a <a href="http://blog.pocketwatchgames.com/post/78594124321/humble-bundle-post-mortem-750k-monacos-sold">postmortem</a>.</p>
</li>
</ul>
<p>In this post, I’ll try to show why I think Steam sales and bundles are mostly a good thing for video games developers.</p>
<p><strong>A warning</strong>: this is mostly going to be some wild speculation, with a few facts peppered here and there. Also, it gets pretty hand-wavy toward the end.</p>
<!-- more -->
<p>So, do sales and bundles affect negatively the revenue of indie game makers? It would be tempting to think this. After all, there’s like five sales a year, so people may be holding on their money waiting for the next steam mega-sale/humble bundle.</p>
<p>I don’t think it’s true, though. Last week, the Monaco team revealed their day-to-day sales during the humble indie bundle 11 (it ran from February 18 to March 4).</p>
<p><img src="/images/steam_bundles/monaco_sales.png" alt="monaco sales" /></p>
<p>It looks like they made a huge number of steam sales <em>during</em> the humble bundle. Don’t forget there’s <a href="http://store.steampowered.com/news/12396/">65 million steam users</a>. The humble indie bundle 11 sold 493,000 copies. It’s probably hard to imagine this in the Internet Echo Chamber, but bundle buyers are a tiny portion of steam users. Steam probably makes the equivalent revenue of a bundle daily.</p>
<p>But, I can already hear you “But Karim, this is a humble bundle. It has five games in it. There’s like five steam mega-sales a year, with almost the whole steam catalog. Surely, people must be keeping their money for the big sale just around the corner.”</p>
<p>Again, I don’t think it’s true. The graph below is Dustforce’s net income for 2012:</p>
<p><img src="/images/steam_bundles/dustforce_net_income.png" alt="dustforce net income" /></p>
<p>There’s two interesting things:</p>
<ol>
<li>
<p>The curve has roughly the same slope before and after the Steam Midweek Madness. This means to me that <strong>most people who bought dustforce then weren’t planning to get it</strong>. Of course, there could be some potential sales cannibalization, but since the sale was so short – only three days, and with 20,000 dollars in profits – I doubt it was significant.</p>
</li>
<li>
<p>Just before the humble bundle the sales have almost tappered off. Again, this could be because of cannibalization, but this would be weird. This is probably just because five months after its release, the game has slipped from public consciousness. The bundle comes, and of course there’s a massive uptick in sales. <br />During the two months period between the bundle and the steam sales, sales are quite good for a six-month old game with almost no promotion. And yet some people would have held on their money waiting for the next big sale, without knowing if Dustforce would be part of the sales? That’s like the definition of people who don’t really want to buy your game.<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">1</a></sup></p>
</li>
</ol>
<p>What if instead, <strong>the people who bought the game during the steam sale weren’t really wanting to get it?</strong></p>
<p>Steam sales are a great thing for game developers. There’s thousands of choices on the steam store. Valve knows nobody will buy every game, so they figured out the best way to get people to buy more games: making them impulse purchases. That’s why there were four big sales last year.<sup id="fnref:segmentation" role="doc-noteref"><a href="#fn:segmentation" class="footnote" rel="footnote">2</a></sup></p>
<p>It works great. How many people have played more than half of the games in their Steam library?</p>
<p>So yeah, Steam sales are a great thing.</p>
<p><strong>Key takeaway: If you’re an indie developer, you should do Steam Sales.</strong></p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:2" role="doc-endnote">
<p>By the way, because of the way Steam sales are organized (almost no sales during the first half of the year and three to four sales in the last six months), it’s probably better to launch a game at the beginning of the year. This way, you can make good sales at the start and use the steam sales to regain some popularity when sales dry up. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:segmentation" role="doc-endnote">
<p>This is market segmentation at work. Sales target buyers who are looking for bargains. There’s a specific submarket of gamers who are okay with playing a game a few years old if they bought it for a lower price. <a href="#fnref:segmentation" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Programming and negativity2014-02-28T00:00:00+00:00http://khamidou.com/programming/programming-and-negativity<p>My uncle is a teacher. When I was a kid, he would often slip into “teacher mode” even not in a school setting. Not only would he lecture us (which I’m glad he did), but he would also try to discipline us as if we were a classroom. Having to write a memoir during your holidays is not fun.</p>
<p>This is to say we often forget how much stuff we unconsciously pick up from work.</p>
<p>This week Github released a new <a href="http://atom.io/">text editor</a>. I haven’t tried it yet, but I’ve seen a lot of negative reactions toward it (“It’s webkit, it’s going to be slow”, “Why would you even use coffeescript”, etc.)
I saw much the same <a href="https://news.ycombinator.com/item?id=3836978">reactions</a> to LightTable a few months ago.</p>
<!-- more -->
<p>As programmers, we spend most of our working days in front of computers, trying to make sense of the stuff and why this crappy API won’t work and IE sucks and so on. We get used to be always on the lookout for potential flaws. It’s a good thing when you’re designing a system, but after some time it becomes an habit you apply everywhere. I know I did.</p>
<p>So I’d like to remind everyone (mostly me actually, since there’s like one and a half readers to my blog) that it’s easy to get trapped in the day-to-day routine and forget what attracted us to computers in the first place. The magic. The ability to get the machine do what you wanted, faster than you. The fun of solving puzzles.</p>
<p>These people are trying to stretch the limits of our machines, don’t hate them for this.</p>
<p>This Alan Perlis quote opens SICP:</p>
<blockquote>
<p>I think that it’s extraordinarily important that we in computer science keep fun in computing.</p>
<p>When it started out, it was an awful lot of fun. Of course, the paying customers got shafted every now and then, and after a while we began to take their complaints seriously. We began to feel as if we really were responsible for the successful, error-free perfect use of these machines.</p>
<p>I don’t think we are. I think we’re responsible for stretching them, setting them off in new directions, and keeping fun in the house. I hope the field of computer science never loses its sense of fun.</p>
<p>Above all, I hope we don’t become missionaries. Don’t feel as if you’re Bible salesmen. The world has too many of those already.</p>
</blockquote>
<p><strong>Key takeaway: Don’t become a bible salesman.</strong></p>
Augeas2014-02-26T00:00:00+00:00http://khamidou.com/augeas<p>I spent the past afternoon wrestling with fabric, Apache, Virtualenv and PostgreSQL.</p>
<p>I was going to write a long post about how Unix is old, creaky and mostly designed to be used with a text editor, when I heard about <a href="http://augeas.net/">Augeas</a>.
Augeas is a tool to modify UNIX config files from the commandline. It’s used by a lot of projects, notably Puppet.</p>
<p>This is how you add an entry in /etc/hosts with augeas:</p>
<blockquote>
<p>set /files/etc/hosts/01/ipaddr 192.168.0.1</p>
</blockquote>
<p>I’m not a fan of representing everything as a tree, but it beats <code class="language-plaintext highlighter-rouge">echo "192.168.0.1 ipaddr" >> /etc/hosts;</code>.</p>
<p>I guess I’ll have to hold on this rant for another day.</p>
vagrant-rails2014-02-22T00:00:00+00:00http://khamidou.com/tips/vagrant-rails<p>I’m learning rails at the moment. Coming from python, the ruby community seems markedly different. One thing doesn’t change, though: package managers suck. I was so confused by rbenv, rvm, bundler and gems that I thought it’d be safer to install it in a virtual machine.</p>
<p>Since it didn’t want to waste my time poking in the dark, I wrote a small tool to do this: <a href="https://github.com/khamidou/vagrant-rails">vagrant-rails</a>. It’s a set of shell scripts to setup a vagrant box with a recent ruby and the latest stable rails version.</p>
<!-- more -->
<p>Also, it’s always interesting to see a different way of solving problems. From my totally newbie point of view, it looks like rails is a lot more integrated than django. For instance, you’ve got to have a javascript runtime to run rails, because of the asset pipeline. This is disconcerting and refreshing at the same time.</p>
<p>Good defaults free you to think about things that matter, but at the same time the C programmer in me worries about the “bloat”. But I guess Rails tries to optimize programmer productivity, not disk space or performance.</p>
Should you justify or left-align text?2014-02-18T00:00:00+00:00http://khamidou.com/justified-left-align<p>I’m just noting this in case I forget. You should <code class="language-plaintext highlighter-rouge">left-align</code> text most of the time.</p>
<!-- more -->
<p>For those who don’t know, justifying text means inserting spaces between words to fill the whole column.</p>
<p>For example, this is some left-aligned text:</p>
<blockquote>
<p style="text-align: left">Well, the way they make shows is, they make one show. That show's called a pilot. Then they show that show to the people who make shows, and on the strength of that one show they decide if they're going to make more shows.
Some pilots get picked and become television programs. Some don't, become nothing. She starred in one of the ones that became nothing.
</p>
</blockquote>
<p></p></p>
<p>And this is some justified text:</p>
<blockquote>
<p style="text-align: justify"> Well, the way they make shows is, they make one show. That show's called a pilot. Then they show that show to the people who make shows, and on the strength of that one show they decide if they're going to make more shows.
Some pilots get picked and become television programs. Some don't, become nothing. She starred in one of the ones that became nothing.
</p>
</blockquote>
<p></p></p>
<p>On the web you should left-align text instead of justifying it, for two reasons:</p>
<ul>
<li>first, if you turn on justifying, you’ll need to have hyphenation enabled too. Otherwise the browser will insert big “bubbles” between your words. The problem is automatic hyphenation is still and draft and <a href="http://caniuse.com/#search=hyphenation">only available on a third of all browsers</a>.</li>
<li>second, most books use justifying, but magazines do use both, so your text won’t look unprofessional.</li>
</ul>
<p>Reference: <a href="http://practicaltypography.com/justified-text.html">Butterick’s practical typography</a></p>
When the intern writes the billing system2014-02-17T00:00:00+00:00http://khamidou.com/billingWhen the intern writes the billing systemRSS and Mailing Lists2014-02-06T00:00:00+00:00http://khamidou.com/RSS-and-mailing-lists<p>Just a quick thought. RSS is very obviously in a bad shape. Mailing lists on the other hand are as good as ever.</p>
<!-- more -->
<p>There’s two reasons for this:</p>
<ul>
<li>RSS got its lunch eaten by alternatives who offered more (Facebook/Twitter/Reddit). Why waste time checking your RSS reader when you’ve already most of it on twitter?</li>
<li>Second, mailing lists are set and forget. You’ve only got to check your inbox from time to time, which you probably already do.</li>
</ul>
<p>There’s one takeaway:</p>
<p><strong>People are busy. If you want them to use your app, make it ‘set and forget’.</strong></p>
<p>By the way, email is a great way to do this because it doesn’t require people to think of your app.
There’s not a whole lot of apps out there who use it in a meaningful way.</p>
Tool Cruft2014-01-22T00:00:00+00:00http://khamidou.com/tool-cruftTool CruftPrice anchoring2014-01-18T00:00:00+00:00http://khamidou.com/anchoring<p>I recently discovered the practice of price anchoring, which is based on a cognitive bias we all have called… <a href="http://en.wikipedia.org/wiki/Anchoring_bias">anchoring</a>.<br />
Put simply, when presented with choices, our brains have a natural tendency to take a decision based on the first choice we’ve seen.<br /></p>
<!-- more -->
<p>Anchoring is why for instance 37signals chose this design:</p>
<p><img src="/images/anchoring/37s_page.png" alt="37signals pricing page" /></p>
<p>Over this older one:</p>
<p><img src="/images/anchoring/37s_old_page.png" alt="37signals old pricing page" /></p>
<p>On the older design, the eye is attracted to the “Plus Plan”, skipping entirely the others.</p>
<p>I suppose that at the time they thought they needed to upsell their users to the “Plus Plan” but then realized they may as well try to sell the others, more expensive plans.</p>
<p>Another interesting example is Apple’s web store:</p>
<p><img src="/images/anchoring/aapl.png" alt="Apple anchoring" /></p>
<p>It really interesting to see how the page design guides the eye. The Mac Pro takes most of the space of the page, even though Apple probably sells more iMacs than Mac Pros. Why then emphasize the Mac Pro other the more popular choice?</p>
<p>The reasoning here is probably that the people who want to get a Mac Pro, will get a Mac Pro. However, there’s probably a large number of potential buyers who are on the fence between a mac and PC. To those buyers, the Mac Pro anchors signals that the iMac is pretty reasonable choice.</p>
<p>Of course, anchoring is nothing revolutionary - it has been used for years - but it’s always interesting to see how the concept is used in the real world.</p>
Kite status report 22014-01-07T00:00:00+00:00http://khamidou.com/kite-status-report-2<p>I just realized that my last status report was exactly one month ago. Well, so much for having semi-regular status reports…</p>
<p>Anyway! Last month was an exciting one. I’m really close to releasing Kite v0.2!
The most important features are:</p>
<ul>
<li>easy deployment. Deploying a fully-featured mail server is litterally one command away</li>
<li>Emails are now grouped by thread.</li>
<li>Partial multiple user support. There’s no auth done yet, so everyone can read your email, but most of the backend works.</li>
</ul>
<p>I’m really excited because if everything goes right, I’ll be able to start dogfooding kite and to get people to, you know, start using it.</p>
An interesting interview with George Clooney2014-01-04T00:00:00+00:00http://khamidou.com/An-interesting-interview-with-clooneyAn interesting interview with George ClooneyBuilding Communities With Software2014-01-03T00:00:00+00:00http://khamidou.com/Building-communities-with-softwareBuilding Communities With SoftwareKite status report 12013-12-07T00:00:00+00:00http://khamidou.com/kite-status-report-1<p>I get a lot of emails asking about my progress on <a href="http://khamidou.github.io/kite">kite</a>, so from now on I’ll regularly share a quick status report.</p>
<!-- more -->
<p>I spent the last four weeks working on backend stuff, in particular:</p>
<ul>
<li>Adding dovecot to the puppet recipe</li>
<li>Rewriting the postfix config</li>
<li>Setting up supervisor to monitor kite’s various daemons</li>
<li>Creating a thread indexing daemon</li>
</ul>
<p><br /></p>
<h4 id="adding-dovecot-to-the-puppet-recipe">Adding dovecot to the puppet recipe</h4>
<p>I’ve had a lot of requests for this one. Obviously, this is very alpha-ish, but it’s possible to read your email using an IMAP client. I’ve still got to figure out how to make filters play along with dovecot, though.</p>
<h3 id="rewriting-the-postfix-config">Rewriting the postfix config</h3>
<p>I had a pretty insane postfix config where all the emails would be forwarded to an user using the <code class="language-plaintext highlighter-rouge">always_bcc</code> rule. Thankfully, I’ve set up a config which makes a lot more sense, using postfix virtual maildirs.</p>
<h3 id="setting-up-supervisor-to-monitor-kites-various-daemons">Setting up supervisor to monitor kite’s various daemons</h3>
<p><a href="http://supervisord.org/">Supervisor</a> is a daemon written in Python used to monitor processes. I mostly use it to restart my daemons when they die.</p>
<p>I spent a lot of time on this one because initially I was using the stock supervisor version from debian. Unfortunately, it’s been
heavily modified to suit the debian standards so it’s outdated and somehow broken. I also had to write an rc.d script because supervisor doesn’t ship with one.</p>
<h3 id="creating-a-thread-indexing-daemon">Creating a thread indexing daemon</h3>
<p>From now on, Kite will display emails grouped by threads. To do this, I’ve written a small program called <a href="https://github.com/khamidou/kite/blob/master/src/back/kite/filterdaemon.py">filterdaemon.py</a>. It uses inotify to find new emails and write them to an index file called threads_index.json. It’s a simple JSON list with metadata about threads.</p>
<p>For those wondering, I didn’t use a database because the emails are text files, so it makes sense to store metadata about the files in text files, too.</p>
<h3 id="whats-next-">What’s next ?</h3>
<p>The two big things on my list are:</p>
<ul>
<li>refactoring the server to handle email threads. It should probably be ready by 2014.</li>
<li>easy vagrant setup. Trying kite in vagrant will be as easy as running “vagrant up” and connecting to 192.168.50.4.</li>
</ul>
<p><br /></p>
<h3 id="contact-questions-remarks">Contact, questions, remarks</h3>
<p>Send me an email at kite at this domain name (sorry for the obfuscated email, I haven’t setup the antispam yet).</p>
<p>Regards,</p>
<p>Karim</p>
Working around redshift's "Provider does not have a valid location available." error2013-10-19T00:00:00+00:00http://khamidou.com/redshift-workaround-bug<p>I recently tried <a href="http://jonls.dk/redshift/">redshift</a>, a program to adjust the screen temperature (the proportion of red and blues) according to the hour of the day.</p>
<p>However, I was bitten by a small bug on the old version of Ubuntu I was using : Redshift would fail to start and complain that it couldn’t find my location.</p>
<!-- more -->
<p>Thankfully, it’s possible to pass redshift the latitude and longitude directly :</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"> redshift <span class="nt">-l</span> 33:-96 </code></pre></figure>
<p>You can find your latitude and longitude using google maps, or <a href="http://universimmedia.pagesperso-orange.fr/geo/loc.htm">this tool</a>.</p>
How to activate a python virtualenv without having to go through dozen of folders2013-03-12T00:00:00+00:00http://khamidou.com/tips/python-virtualenv-activation<p>I’m working on a couple django apps which use separate virtualenvs and I very often have to source the virtualenv activation script.
It got so tedious that I had to write a small script to automate the finding of the activation script.</p>
<!-- more -->
<p>The following python script, named “findact”, searches in the recursively for a file named “activate”. If it is not found, it starts again from the parent directory, and so on.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c1">#!/usr/bin/env python
# find a file named "activate" in a subdir or parentdir of the cwd
# written by karim hamidou. 03/12/13
</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="k">def</span> <span class="nf">visit_dir</span><span class="p">(</span><span class="n">visited_dirs</span><span class="o">=</span><span class="p">[]):</span>
<span class="n">found</span> <span class="o">=</span> <span class="bp">False</span>
<span class="n">initial_dir</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">getcwd</span><span class="p">()</span>
<span class="k">for</span> <span class="n">root</span><span class="p">,</span> <span class="n">dirs</span><span class="p">,</span> <span class="n">files</span> <span class="ow">in</span> <span class="n">os</span><span class="p">.</span><span class="n">walk</span><span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">getcwd</span><span class="p">(),</span> <span class="n">topdown</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="c1"># exclude already visited directories
</span> <span class="k">for</span> <span class="n">vdir</span> <span class="ow">in</span> <span class="n">visited_dirs</span><span class="p">:</span>
<span class="k">if</span> <span class="n">vdir</span> <span class="ow">in</span> <span class="n">dirs</span><span class="p">:</span>
<span class="n">dirs</span><span class="p">.</span><span class="n">remove</span><span class="p">(</span><span class="n">vdir</span><span class="p">)</span>
<span class="k">if</span> <span class="s">"activate"</span> <span class="ow">in</span> <span class="n">files</span><span class="p">:</span>
<span class="n">found</span> <span class="o">=</span> <span class="bp">True</span>
<span class="k">break</span>
<span class="k">if</span> <span class="n">found</span><span class="p">:</span>
<span class="k">print</span> <span class="s">"%s/activate"</span> <span class="o">%</span> <span class="n">root</span>
<span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">if</span> <span class="n">os</span><span class="p">.</span><span class="n">getcwd</span><span class="p">()</span> <span class="o">!=</span> <span class="s">"/"</span><span class="p">:</span>
<span class="n">os</span><span class="p">.</span><span class="n">chdir</span><span class="p">(</span><span class="s">".."</span><span class="p">)</span>
<span class="n">visited_dirs</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">initial_dir</span><span class="p">)</span>
<span class="n">visit_dir</span><span class="p">(</span><span class="n">visited_dirs</span><span class="o">=</span><span class="n">visited_dirs</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="n">visit_dir</span><span class="p">()</span></code></pre></figure>
<p>I added a small function to my shell to source the file, if it is found:</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="k">function </span>act<span class="o">()</span> <span class="o">{</span>
<span class="nv">FILE</span><span class="o">=</span><span class="si">$(</span>findact<span class="si">)</span>
<span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="nt">-eq</span> 0 <span class="o">]</span><span class="p">;</span> <span class="k">then
</span><span class="nb">echo</span> <span class="nt">-n</span> <span class="s2">"Source </span><span class="nv">$FILE</span><span class="s2"> (y/n) ? "</span>
<span class="nb">read </span>yn
<span class="k">case</span> <span class="nv">$yn</span> <span class="k">in</span>
<span class="o">[</span>Yy]<span class="k">*</span> <span class="p">)</span> <span class="nb">source</span> <span class="nv">$FILE</span><span class="p">;</span>
<span class="k">esac
fi</span>
<span class="o">}</span></code></pre></figure>
<p>This way, I can type “act” to load my virtualenv from anywhere in my project directory.</p>
Using Django lazily translated strings in JSON2013-02-20T00:00:00+00:00http://khamidou.com/tips/django-translation-in-json<p>Last week I had to add support for i18n to a django application. Everything went swiftly, except for one thing : I needed to output a translated JSON structure in my HTML and doing this simple with json.dumps triggered a TypeError exception, with the message : “<django.utils.functional.__proxy__ object at 0x987a86c> is not JSON serializable”.</p>
<!-- more -->
<p>The solution to this problem is to define a custom serializer to force the conversion of lazy translated strings (also known as Promise objects) to a string. To do this define the following class :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class LazyEncoder(json.JSONEncoder):
"""Encodes django's lazy i18n strings.
Used to serialize translated strings to JSON, because
simplejson chokes on it otherwise.
"""
def default(self, obj):
if isinstance(obj, Promise):
return force_unicode(obj)
return obj
</code></pre></div></div>
<p>and call simplejson this way :
json.dumps(object, cls=LazyEncoder)</p>
Writing semantic HTML with the Zurb Foundation grid2012-08-22T00:00:00+00:00http://khamidou.com/tips/semantic-code-and-zurb-foundation<p>I’ve recently started to use the excellent <a href="http://foundation.zurb.com/">Zurb
Foundation</a> CSS framework, and I like it a lot. There’s
one problem though: like most grid frameworks, it expects you to use non-semantic class names in your HTML to specify the placement of the elements.</p>
<!-- more -->
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><div class="row">
<div class="two columns" id="navbar">
</div>
<div class="ten columns" id="content">
</div>
</div>
</code></pre></div></div>
<p>Thankfully, if you use Sass, there’s an easy way to drop those non-semantic
class names. The Sass language has a new directive, @extend, which allows a block to integrate the contents of another one.
Using extend, it’s possible to rewrite the previous example as this :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><div class="row">
<div id="navbar">
</div>
<div id="content">
</div>
</div>
</code></pre></div></div>
<p>The SCSS file looks like this:
#navbar {
@extend .two, .columns;
}</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#content {
@extend .ten, .columns;
}
</code></pre></div></div>
<p>The code is now slightly simpler.</p>
Writing a django filter2012-06-06T00:00:00+00:00http://khamidou.com/writing-a-django-filter<p>I recently had to implement a django filter. My problem was that I had an event page similar to the github feed. I wanted to format a date diferently whether the event occured in the current week or at another date. Instead of doing it in code or in the template (bad), I decided to write a filter for that.</p>
<!-- more -->
<h3 id="directory-structure">Directory structure</h3>
<p>Django expects to find the filters and template tag for an application in a specific directory, <em>templatetags</em>.
You’ll have to create this directory if it doesn’t already exist and to add inside it an empty __init__.py file so that python treats the folder as a module.</p>
<h3 id="code">Code</h3>
<p>After that, create a file named “filters.py”. It will hold our new filter. Add the following code in it.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from django import template
from django.contrib.sites.models import Site
from urlparse import urlparse
import datetime
register = template.Library()
@register.filter(name='dayinweek', is_safe=True, expects_localtime=True)
def dayincurrentweek(day):
if day == datetime.date.today():
return "Today"
min_date = datetime.date.today() - datetime.timedelta(7)
if day > min_date and day < datetime.date.today():
return day.strftime("Last %A")
else:
return day.strftime("%B, %d")
</code></pre></div></div>
<p>It’s quite simple: we get a handle on the django template filter registry, and we register a template named dayinweek.
This template takes a datetime.date parameter and returns a string.</p>
<h3 id="usage">Usage</h3>
<p>To reference the filter in your template file you need to add <code class="language-plaintext highlighter-rouge">{% load filters %}</code> at the beginning of your template file.</p>