<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Software and Other Mysteries]]></title>
  <link href="http://blog.brannstrom.io/atom.xml" rel="self"/>
  <link href="http://blog.brannstrom.io/"/>
  <updated>2022-07-06T11:23:49+02:00</updated>
  <id>http://blog.brannstrom.io/</id>
  <author>
    <name><![CDATA[Erik Brännström]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Normalization of Unicode Equivalent Animals]]></title>
    <link href="http://blog.brannstrom.io/2022/07/normalization-of-unicode-equivalent-animals/"/>
    <updated>2022-07-06T11:21:02+02:00</updated>
    <id>http://blog.brannstrom.io/2022/07/normalization-of-unicode-equivalent-animals</id>
    <content type="html"><![CDATA[<p>A while back, a customer reported that something was off when searching in our application. When searching for &ldquo;Akilleshäl&rdquo; (Swedish word for &ldquo;Achilles heel&rdquo;, which is a query I just made up) they only got a result for &ldquo;Akilleshäl 1&rdquo; and not &ldquo;Akilleshäl 2&rdquo;. Weird!</p>

<p>I started to look into it and noticed that both results were returned when searching for the part of the word leading up to the very non-English letter of &ldquo;ä&rdquo;, but once that letter was added, the second result disappeared.</p>

<p>The horror slowly began to dawn on me: I was dealing with a character encoding issue.</p>

<p>Time to dig in. I launched the Rails console, fetched the strings and started to cut into the them.</p>

<p><code>"Akilleshäl" == "Akilleshäl"</code> returned <code>false</code>. Some more cutting. <code>"ä" == "ä"</code> returned <code>false</code>.</p>

<p>Since I was pretty sure this was encoding related, I used the <code>String#bytes</code> method on both characters.</p>

<p><code>"ä".bytes =&gt;  [195, 164]</code>
<code>"ä".bytes =&gt;  [97, 204, 136]</code></p>

<p>As the saying goes:</p>

<blockquote><p>If it looks like a duck, swims like a duck, and quacks like a duck, then it is either a duck or a unicode equivalent animal.</p></blockquote>

<p>Yes, <a href="https://en.wikipedia.org/wiki/Unicode_equivalence">Unicode equivalence</a> is a thing. The byte sequences above will render identical characters, even though they mean slightly different things. In UTF-8, the bytes 195 and 164 are interpreted as &ldquo;Latin Small Letter A with Diaeresis&rdquo;, or &ldquo;ä&rdquo;.</p>

<p>The other byte sequence means &ldquo;Latin Small Letter A&rdquo; (97) followed by &ldquo;Combining <a href="https://en.wikipedia.org/wiki/Diaeresis_(diacritic">Diaeresis</a>)&rdquo; (204+136). More simply put, take the letter &ldquo;a&rdquo; and slap two dots on top of it. Or &ldquo;ä&rdquo;.</p>

<p>Great, now I understand why it doesn&rsquo;t work, but I still have no idea what to do about it. I tried to string words together to get Google to lead me to a solution - only marginally more evolved than a monkey in the <a href="https://en.wikipedia.org/wiki/Infinite_monkey_theorem">infinite monkey theorem</a> - until I finally stumbled on the magic word: normalization.</p>

<p>As it turns out, <a href="https://unicode.org/reports/tr15/">Unicode normalization is standardized by the Unicode Consortium</a>. There are a bunch of different algorithms, which I did not have the mental energy to read, but the important point is that they will turn both byte sequences above into the same byte sequence.</p>

<p>Luckily, <a href="https://bugs.ruby-lang.org/issues/10084">Ruby introduced <code>String#unicode_normalize</code> in version 2.2</a>. Let&rsquo;s take it for a spin!</p>

<p><code>[97, 204, 136].pack("c*").force_encoding("UTF-8").unicode_normalize.bytes =&gt; [195, 164]</code></p>

<p>Boom!</p>

<p>Let&rsquo;s just quickly go through what happened here. The 3-byte sequence is packed into a string, then Ruby is told to interpret this as UTF-8 before applying the default Unicode normalization algorithm. Finally, the byte sequence is returned, which now matches &ldquo;Latin Small Letter A with Diaeresis&rdquo;. Or &ldquo;ä&rdquo;.</p>

<p>It was now possible fix the specific issue that got this snowball rolling. I was interested in finding all records where the name was not normalized and normalize it, which looked something like this:</p>

<p> <code>Model.pluck(:id, :name).reject { _1.unicode_normalized? }.each { |id, name| Model.find(id).update(name: name.unicode_normalize) }</code></p>

<p>The reason for plucking <code>id</code> and <code>name</code> first was to not crash the Rails console running on Heroku due to excessive memory use (a full ActiveRecord object uses more memory than just a number and a string). If you have even more data and you&rsquo;re running PostgreSQL 13, a more efficient approach (I assume) is to use the <a href="https://www.postgresql.org/docs/13/functions-string.html">built-in <code>IS NORMALIZED</code> function</a> and only query the affected records from the database.</p>

<p>To ensure we avoid this problem down the line, we are also applying the normalization on relevant fields for all future records in our ActiveRecord models by extending the String type used by the attributes API - but that deserves a blog post of its own.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Rabbit Hole of Hosting]]></title>
    <link href="http://blog.brannstrom.io/2020/02/the-rabbit-hole-of-hosting/"/>
    <updated>2020-02-14T16:54:18+01:00</updated>
    <id>http://blog.brannstrom.io/2020/02/the-rabbit-hole-of-hosting</id>
    <content type="html"><![CDATA[<p>I recently published my <a href="https://blog.brannstrom.io/2020/02/the-greatness-of-boring/">first blog post in almost four years</a>. It turned out to be a less than straight forward journey, so I thought I&rsquo;d share the adventures I experienced while venturing into the rabbit hole.</p>

<ol>
<li><p>Search for credentials to the server where the <strong>only</strong> copy of my blog existed. Found them well hidden in an old <a href="https://1password.com">1Password</a> vault.</p></li>
<li><p>Clone the Git repo of my blog from that server.</p></li>
<li><p>Write a blog post. <em>This did not take as long as the rest of these steps.</em></p></li>
<li><p>Find out how to use <a href="http://octopress.org/">Octopress 2</a>. To be clear, that is an older version of a static site generator that seems to have been unmaintained for quite a few years now.</p></li>
<li><p>Remember my weird af deployment method. How to deploy, you wonder? From my laptop I commit the newly generated site, push to a remote repository on the server, SSH into the folder from which nginx serves the files (which is on the same server) and git pull. Genius.</p></li>
<li><p>By this point, the post was actually published, but I realized that the blog wasn&rsquo;t served via HTTPS, which just feels unacceptable in the day and age of <a href="https://letsencrypt.org/">Let&rsquo;s Encrypt</a>.</p></li>
<li><p>As I was going to setup Let&rsquo;s Encrypt, I also realized that the server was running <a href="https://ubuntu.com/">Ubuntu</a> 14.04.5, which was released mid-2016.</p>

<p><em>I&rsquo;m not sure if I should give myself credit for telling my wife somewhere around this step that I would regret doing this.</em></p></li>
<li><p>Before upgrading I checked if there were any backups of the droplet on <a href="https://www.digitalocean.com/">Digital Ocean</a>. The answer was no. I enabled backups, but the first backup would not run until next morning, so they would not cover me right now.</p></li>
<li><p>Instead I shut down the instance and took a snapshot which I could recover from later, if necessary.</p></li>
<li><p>Upgrade server from Ubuntu 14 to 16 and then straight on to 18. What could go wrong?</p></li>
<li><p>Something went wrong. The upgrade broke an old site running on <a href="https://codeigniter.com/">CodeIgniter</a> 2 and PHP 5, which I had no intention of spending much – or preferably any – time maintaining. The problem was that only PHP 7 was installed now, which didn&rsquo;t play well with the site.</p></li>
<li><p>I found an <a href="https://deb.sury.org/">alternative package repository</a> from which I could install PHP 5.6.</p></li>
<li><p>The version of CodeIgniter the site was using had an issue with PHP 5.6, so I <a href="https://stackoverflow.com/questions/28348879/only-variable-references-should-be-returned-by-reference-codeigniter">monkey-patched the framework core files</a> to fix the error. ¯\_(ツ)_\/¯</p></li>
<li><p>No errors anymore, but the site was only displaying a blank page. After some searching it turned out to be a missing PHP 5 mysql package.</p></li>
<li><p>I was finally ready to set up Let&rsquo;s Encrypt, which was already running for the site I had just broken. I upgraded LE and made sure everything was still working for both the new setup and the old.</p></li>
<li><p>Profit?</p></li>
</ol>


<p>This is the kind of moment that reminds me of what working in tech is all about: perseverance and Google.</p>

<p>In unrelated news, I&rsquo;m taking suggestions on which static site generator to use moving forward.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Greatness of Boring]]></title>
    <link href="http://blog.brannstrom.io/2020/02/the-greatness-of-boring/"/>
    <updated>2020-02-01T16:01:13+01:00</updated>
    <id>http://blog.brannstrom.io/2020/02/the-greatness-of-boring</id>
    <content type="html"><![CDATA[<p>New is always better, I often say, half-jokingly. There&rsquo;s a heart of truth to it. I enjoy unboxing a new phone or, most recently, getting our first brand new <a href="https://www.kia.com/se/nya-bilar/nya-optima-sportswagon-plugin-hybrid/upptack/">car</a> at the dealership. There&rsquo;s a satisfaction in the exploration of newness and, hopefully, an element of happy surprise.</p>

<p>New is always better used to be less of a joke. Perhaps it&rsquo;s because there are fewer surprises these days. That third camera in your iPhone? It&rsquo;s obviously not as exciting as when your phone got its first camera. Or perhaps it&rsquo;s because I&rsquo;m older. Jaded, even?</p>

<p>I think <a href="https://reactjs.org/">React</a> was the last time I felt genuinely excited about a new technology. It was late 2013 and React was only a few months old. There was no <a href="https://redux.js.org/">Redux</a>, only vague mentions of something called Flux and top-down data flow. I enjoyed exploring the ideas and discussions that took place, both in the React community but also in the JavaScript community as a whole.</p>

<p>As it happens, six years later, I still use React. It&rsquo;s less exciting these days. I try to keep tabs on what&rsquo;s happening in the community and the ideas that are being explored. Not because I&rsquo;m waiting to jump on <em>The Next Big Thing</em>, but simply because I want understand how future developments will affect what we&rsquo;re doing today.</p>

<p>The tech stack I&rsquo;m currently working with, besides React and JS, is Ruby on Rails running on Heroku with a Postgres database and a Redis store. There&rsquo;s no TypeScript. No Cassandra. No Kubernetes. No Go.</p>

<p>By all means, it&rsquo;s not PHP 3 and Mootools or, God forbid, Java. (That last part may or may not have been a joke.) But it&rsquo;s not really&hellip; shiny.</p>

<p>You know what it is, though? It&rsquo;s dependable. It&rsquo;s well documented. It&rsquo;s easy to use.</p>

<p>As someone who once spent two weeks debugging a concurrency issue with a custom built Java SAML2 authentication module in a custom built Java HTTP server, I&rsquo;ve come to appreciate dependability, good documentation and ease of use. (Also, I realize why I may or may not have joked about Java.)</p>

<p>I&rsquo;m gonna steal a quote from my friend <a href="https://bjoreman.com/">@bjoreman</a>, but I figure it&rsquo;s okay, since he stole it from Andy Hunt. Just let this mother of dragons sink in, and enjoy the rest of your day:</p>

<p><strong>Boring has its place.</strong></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[A Fortnight Without Twitter]]></title>
    <link href="http://blog.brannstrom.io/2016/02/a-fortnight-without-twitter/"/>
    <updated>2016-02-06T12:56:03+01:00</updated>
    <id>http://blog.brannstrom.io/2016/02/a-fortnight-without-twitter</id>
    <content type="html"><![CDATA[<p>Twitter, I think we need to spend some time apart. Really, it&rsquo;s not you, it&rsquo;s me! Scrolling through the never-ending feed that is Twitter is more than a habit. It has crept into my muscle memory. More than once I&rsquo;ve been watching an episode on Netflix and suddenly realized I don&rsquo;t really understand what is happening because I&rsquo;ve been mindlessly scanning through new tweets. Or I&rsquo;ve become bored because there is a full <em>minute</em> until the bus arrives, so I better see what&rsquo;s going on in the world.</p>

<p>My feed is almost exclusively filled with very clever people writing about programming languages, software design and new technology. There are so many cool ideas and shiny new things that there is no chance of me keeping up. I&rsquo;m lagging behind. Shit! I should really learn Go now, so I&rsquo;m ready when all other server-side languages are phased out. Oh, is Go old? Damn it, I&rsquo;m too late! Elixir is still hot, right? Okay, I can learn Elixir, looks easy enough. I just have to understand GraphQL and how to integrate that into an existing React application first. Though, perhaps Meteor would be a good fit? Got to look into that first. Oh, here&rsquo;s a post on Medium about how to stay productive! If I read that, perhaps I will manage to do everything else.</p>

<p>Twitter is stressing me out. I&rsquo;m entirely sure that there is some cognitive bias that makes me feel this way, so add that to the list of things that I need to read up on. With all the developer evangelists, core contributors and successful start-up founders keeping my feed constantly updated, this also means that keeping up with the state of things has become more and more about consumption.</p>

<p>Almost all of my time spent on devices is spent consuming things. Blog posts, tweets, videos, games, music. The lack of me producing something by myself adds another layer of stress, but how can I write something insightful about Javascript if I don&rsquo;t fully understand the inner workings of V8, Chakra and Spidermonkey? The logic goes that to produce, I need to consume, but there is not enough time to consume which means there is never enough time to produce.</p>

<p>Taking a short break from consuming Twitter is an experiment. A few years back I actually wrote about the joy of not being connected for a few days. It turns out, I fell back in the same pattern pretty quickly. This time, I will uninstall Tweetbot from my phone, tablet and computer for a fortnight. Why a fortnight you ask? Because it sounds Shakespearian, that&rsquo;s why.</p>

<p>All other social networks will remain. I currently spend around five minutes a day on Instagram and along the lines of thirty minutes <em>a week</em> on Facebook, so they are not really time sinks at the moment. I&rsquo;m curious to see if I will begin to fill the void by reading status updates by my high school classmates, or if this in any way helps with the admittedly small problems described above. Perhaps I&rsquo;ll take up App.net or Ello. Just kidding.</p>

<p>See you in two weeks, Twitter. Probably.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Year Without Pants]]></title>
    <link href="http://blog.brannstrom.io/2015/07/the-year-without-pants/"/>
    <updated>2015-07-29T21:56:00+02:00</updated>
    <id>http://blog.brannstrom.io/2015/07/the-year-without-pants</id>
    <content type="html"><![CDATA[<p>A few weeks back I attended <a href="https://www.react-europe.org/">React Europe</a> in Paris. It was on its own a very interesting conference with tons of great talks, all <a href="https://www.youtube.com/channel/UCorlLn2oZfgOJ-FUcF2eZ1A">available on YouTube</a>. This post, however, will not deal with the awesomeness of Redux or the potential of GraphQL.</p>

<p>At the <a href="http://automattic.com/">Automattic</a> (most notably the company behind <a href="https://wordpress.com/">Wordpress.com</a>) conference booth I was able to get my hands on a book called <a href="http://amzn.to/1eA9rBk">&ldquo;The Year Without Pants: Wordpress.com and the Future of Work&rdquo;</a> by Scott Berkun. I covers the author&rsquo;s experience of working as a team lead at Automattic for about two years, and since that sounds fairly boring, I think we understand the reason for the click-baity title.</p>

<p>So, seriously, about the title. It is a reference to the fact that Automattic is a fully distributed company, and as such one could very well be in a meeting with any number of colleagues whilst wearing nothing but tighty-whities. That&rsquo;s a damn good title. I&rsquo;m assuming the subtitle was added later when someone realized that only &ldquo;The Year Without Pants&rdquo; sounds like a movie starring <a href="http://www.imdb.com/name/nm0136797/">Steve Carell</a> and/or <a href="http://www.imdb.com/name/nm0781981/">Jason Segel</a>.</p>

<p>The reason I wanted to read this book was my interest in the postmodern view of management. I say postmodern both because it makes me sound smart, but also because it really is a reaction against the the typical <em>modern</em> 20<sup>th</sup> century way of managing employees:</p>

<ul>
<li>fixed hours</li>
<li>fixed location</li>
<li>money as motivation</li>
<li>management hierarchies</li>
</ul>


<p>I&rsquo;m interested in this because I think the old way has gotten a lot of things wrong, especially when it comes to jobs with at least an ounce of creativity involved. At the same time, I always feel skeptical whenever someone starts talking about flat organizations and no management.</p>

<p>Scott Berkun was hired at a time when Automattic was growing rapidly. Previously the founder and CEO of the company, <a href="http://ma.tt/">Matt Mullenweg</a> (who is also one of the creators of <a href="https://wordpress.org/">Wordpress</a>), could have complete insight to everything that was going on while letting people work on pretty much whatever they felt like. This is sometimes referred to as &ldquo;no management&rdquo;, a term I know has also previously been used at for example GitHub. This is obviously not true, since any company that lacks management won&rsquo;t be a company for very long, so let&rsquo;s instead call it a &ldquo;light organization&rdquo;. As more people were hired, however, the organization needed to gain some weight.</p>

<p>This is the very core of the book. How can a light organization grow without causing chaos? Which features of the old way of doing business are needed, and which can be ignored? And how do you introduce such practices without negatively impacting the company culture?</p>

<p>For example, the problem of managing a growing number of employees was dealt with by introducing a hierarchy. As far as I can remember, that word is not actually used in the book, but the employees where divided into small teams, where every team had a team lead. Berkun, who had a lot of experience as a manager at Microsoft, was hired as one of those leads.</p>

<p>That being said, the hierarchy at Automattic was a lot less rigid than the ones you will typically find at major (or minor for that matter) companies. People were still distributed and had access to most of what happened in all the other teams, not only the one they currently belonged to, but they were also expected to work on specific parts of the system.</p>

<p>At times the book reads a little bit like a sales pitch, but I do think that the author manages to point out the problems that will inevitably appear when working with a postmodern style of management. One such example is how when people get to choose which task to work on, they usually go with the low hanging fruit, the fruit which seems tastiest, or the fruit that just exploded on millions of users. Less often will people choose a tough, boring task even though it would greatly improve the experience of the end user. Apologies for not bringing the analogy all the way home.</p>

<p>All in all, <a href="http://amzn.to/1eA9rBk">&ldquo;The Year Without Pants: Wordpress.com and the Future of Work&rdquo;</a> is definitely worth your time. It&rsquo;s easy to read and it&rsquo;s interesting to follow how Scott Berkun tries to apply his experience in management while simultaneously adapting to the culture at Automattic.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[contextmenu event in Firefox]]></title>
    <link href="http://blog.brannstrom.io/2014/04/contextmenu-event-in-firefox/"/>
    <updated>2014-04-18T17:34:00+02:00</updated>
    <id>http://blog.brannstrom.io/2014/04/contextmenu-event-in-firefox</id>
    <content type="html"><![CDATA[<p>I&rsquo;ve been working on a small context menu library in Javascript. Basically it lets you register a listener on a DOM element along with a flag specifying which types of clicks should render the context menu. Also, let&rsquo;s save the discussion of whether creating your own custom right-click menu is a good idea or not for another time.</p>

<p>The menu worked fine in Chrome and Safari, but when I tried it out in Firefox there was an issue. When right-clicking, the menu would appear but when the mouse button was released, the menu disappeared again.</p>

<p>Technically, the library works like this. When a right-click menu is registered, an event listener is added to the specified DOM element for the contextmenu event. The listener shows the menu and adds a new event listener to the document which is responsible for closing the menu whenever the user clicks outside the menu&rsquo;s boundaries.</p>

<p>The contextmenu event is a non-standard event, but it is implemented by all the major browsers. Firefox, Chrome and Safari all consider this to be a mouse event, though in the draft of HTML 5.1 the contextmenu event is not necessarily considered to be a mouse event.</p>

<p>As I said, Firefox would open the menu and quickly close it again, and given the above description I started looking into which events were fired. I wrote a small test page which registered listeners for mousedown, mouseup, click and contextmenu on a div and the document, in both the capture and bubble phase. This is the event order in Chrome:</p>

<ol>
<li>mousedown (capture) on document</li>
<li>mousedown (capture) on DIV</li>
<li>mousedown (bubble) on DIV</li>
<li>mousedown (bubble) on document</li>
<li>contextmenu (capture) on document</li>
<li>contextmenu (capture) on DIV</li>
<li>contextmenu (bubble) on DIV</li>
<li>contextmenu (bubble) on document</li>
<li>mouseup (capture) on document</li>
<li>mouseup (capture) on DIV</li>
<li>mouseup (bubble) on DIV</li>
<li>mouseup (bubble) on document</li>
</ol>


<p>Safari acts the same for the first two events, but never fires a mouseup event. And this is what happens in Firefox:</p>

<ol>
<li>mousedown (capture) on document</li>
<li>mousedown (capture) on DIV</li>
<li>mousedown (bubble) on DIV</li>
<li>mousedown (bubble) on document</li>
<li>contextmenu (capture) on document</li>
<li>contextmenu (capture) on DIV</li>
<li>contextmenu (bubble) on DIV</li>
<li>contextmenu (bubble) on document</li>
<li>mouseup (capture) on document</li>
<li>mouseup (capture) on DIV</li>
<li>mouseup (bubble) on DIV</li>
<li>mouseup (bubble) on document</li>
<li>click (capture) on document</li>
<li>click (bubble) on document</li>
</ol>


<p>As you can see, there is a slight difference between Chrome and Firefox. Logically, I think it is reasonable to do as Firefox does and fire a click event. But look a little closer on the click event. It only appears two times, both on the document. In other words, it never hits the div on which the click originated, though the target property correctly references the div.</p>

<p>After some googling, I managed to find a <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=569071">bug report on Bugzilla</a> for this issue which was marked as invalid without any real reason other than &ldquo;there is no specification&rdquo;. I&rsquo;ve added a comment on the issue with the hope of getting an explanation, but until then I wanted to share this in case other people run into the same problem.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Confirming destructive UI actions]]></title>
    <link href="http://blog.brannstrom.io/2014/03/confirming-destructive-ui-actions/"/>
    <updated>2014-03-16T13:05:00+01:00</updated>
    <id>http://blog.brannstrom.io/2014/03/confirming-destructive-ui-actions</id>
    <content type="html"><![CDATA[<p>The other day I was adding a delete action for an application. I added the standard red button and was just about to implement the default confirmation dialog (&ldquo;Are you sure you want to delete this item? OK / Cancel&rdquo;) before realizing how dialogs in general annoy me.</p>

<p>The problem, as I see it, is that there is somewhat of a context switch. You leave the application and are sent to Dialog Land. Admittedly, you seldom stay long in Dialog Land, but you are broken out of your current flow. It can be argued that this is the point, since this break of context means the user is forced to consider if they really do want the go through with the action. We should of course do this in the case of irreversible actions, but is a modal dialog really the only way?</p>

<p>My idea was to keep the user in the same place visually by simply replacing the action button with a confirmation button on click, requiring an additional click to go through with the action.</p>

<p><img class="center" src="http://blog.brannstrom.io/images/posts/ui/action-confirm.png"></p>

<p>There are two problems with this. First of all, the user might not even notice that something has changed. The buttons still have the same colors and are about the same size, so there is not enough of a visual cue that another action is required. Secondly, the immediate switch means that an involuntary double click will lead to a confirmation.</p>

<p>The second point is easily solved by adding a delay before the action can actually be confirmed. A few hundred milliseconds is enough for that. We can however use this time to also visually indicate that something has happened by changing the text and indicating that the button is inactive. To make sure the user has time to realize this, the delay needs to be at the very least half a second, and I personally found around one second to be a decent trade-off between usability and user safety.</p>

<p><img class="center" src="http://blog.brannstrom.io/images/posts/ui/action-wait-confirm.png"></p>

<p>The remaining problem as I see it is that a user who is 100% sure that they want to perform this action is forced to wait. Especially if they are performing this action repeatedly, it will get annoying pretty quickly.</p>

<p>One idea, which I haven&rsquo;t implemented yet, is allowing the user to bypass the confirmation step by holding Command/Control while clicking the button. The risk however is that this forms a behavior with the users where they always perform actions this way, effectively removing the safety net.</p>

<p>As always, I&rsquo;d love some input. Is this over-engineering for a problem which already has a solid and accepted UI pattern? Is it reasonable to allow a user to bypass confirmation of dangerous actions? Lets hear it in the comments.</p>

<p>EDIT: I posted a <a href="https://gist.github.com/erikbrannstrom/9688540">Gist containing a sample implementation</a> of this confirmation button in Javascript and React.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[It would be great if the app...]]></title>
    <link href="http://blog.brannstrom.io/2013/08/it-would-be-great-if-the-app-did-dot-dot-dot/"/>
    <updated>2013-08-17T16:43:00+02:00</updated>
    <id>http://blog.brannstrom.io/2013/08/it-would-be-great-if-the-app-did-dot-dot-dot</id>
    <content type="html"><![CDATA[<p>My main project at work has been developing an authentication plugin implementing the SAML2 protocol. For the last three months I&rsquo;ve also been developing a web-based issue tracking system, with the goal of unifying our internal workflow as well as improve communication on user reported issues with our customers. In my last post, <a href="http://blog.streambur.se/2013/08/the-mythical-man-month/">The Mythical Man-Month</a>, I quoted the following sentence which resonated with my experience from these (and previous) projects.</p>

<blockquote><p>Both the actual need and the user&rsquo;s perception of that need will change as programs are built, tested and used.</p></blockquote>

<p>The most common realization of these changing needs is probably the feature creep. A person who has two problems, A and B, and get access to a system that solves A would obviously like it to also handle B. Lets call this the &ldquo;one system fallacy&rdquo;.</p>

<p>This is a belief that there should be one system to rule them all, so to speak, though this rarely leads to a good end result. What one usually would like, however, is multiple applications that complement and integrate with each other. For example, I&rsquo;m sure someone, sometime thought that adding a word processor to Gmail would be great. It wouldn&rsquo;t have been. A much smarter move was building a separate application for the word processor, but which shares the same login as the one I use for my e-mail.</p>

<p>Another problem is that often times people are not really stating their problems, but rather their ideas of solutions to problems. In one of my courses at <a href="http://www.chalmers.se/">Chalmers</a> I heard an anecdote about the development of a new American fighter jet (I&rsquo;m paraphrasing, but if anyone knows the source, please share). The company that got the order received a requirement stating that the plane should have a top speed of mach 5. This wasn&rsquo;t feasible so the team tried to locate the source of the requirement. After much searching, it turns out it came from the pilots. When asked why, they said they needed to be able to outrun missiles fired from a MiG.</p>

<p>In other words, the problem was not that the plane was too slow, the problem was that they would get shot down by the enemy. A much more practical solution was to improve the electronic countermeasures. In the sphere of web development, the requirements we get can be something along the lines of changing the color of the links or adding file uploads to our comments. Either way, it is important to understand what the problem is.</p>

<p>Once you understand the problem, you need to understand how critical a solution is. This is sometimes obvious. Implementing a Tetris easter egg would probably fall on the opposite side of the scale from a bug causing the system to crash whenever a user logs on. Other times it is less clear, but I&rsquo;ve found that important things tend to pop up multiple times from multiple sources. If you&rsquo;re unsure, give it a lower priority and wait.</p>

<p>When communicating your the plan regarding the suggestion to the user: underpromise and overdeliver. Not everyone agrees with this tactic, but dealing with changing requirements means you are unable to promise much even for seemingly simple suggestions. Once you do implement something, let them know and they&rsquo;ll be grateful (and most likely be ready with a few more suggestions).</p>

<p>I&rsquo;ve heard lists are a great way to get readers, though I couldn&rsquo;t bring myself to use that selling point in the title. Instead, lets half-ass it and summarize the steps that should be taken when receiving a suggestion.</p>

<ol>
<li><p><strong>Listen</strong>. Don&rsquo;t be an asshole, hear your user out.</p></li>
<li><p><strong>Identify the real problem</strong>. At first the suggestion might not make sense, but it may very well lead to an important change or addition once you grasp the underlying issue.</p></li>
<li><p><strong>Prioritize</strong>. I rarely say no to suggestions, but I&rsquo;m also careful to point out when something is technically challenging or might be out of scope. Underpromise, overdeliver.</p></li>
</ol>


<p>Have I missed something? Am I wrong? What are your experiences with dealing with changing requirements in a light-weight development setting?</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Mythical Man-Month]]></title>
    <link href="http://blog.brannstrom.io/2013/08/the-mythical-man-month/"/>
    <updated>2013-08-10T19:52:00+02:00</updated>
    <id>http://blog.brannstrom.io/2013/08/the-mythical-man-month</id>
    <content type="html"><![CDATA[<p>There are a few books that are recurring on the &ldquo;top 10 books every software engineer must read&rdquo;-lists on the Internet, and one of them is <a href="http://en.wikipedia.org/wiki/The_Mythical_Man-Month">The Mythical Man-Month</a>. I&rsquo;ve been trying to read more nonfiction lately, and especially books that deal with software and its development process. As a result I&rsquo;ve had The Mythical Man-Month on my nightstand for the last few weeks.</p>

<p>The book was originally published in 1975 and received an update for its 20th anniversary, which included a few extra chapters. The author, Fred Brooks, received a <a href="http://en.wikipedia.org/wiki/Turing_Award">Turing Award</a> for his efforts in the field of computing in 1999.</p>

<p>Okay, enough with the backstory. As can be expected from a forty year old book, anachronisms are plentiful. This was a time were the available amount of memory was measured in bytes without any prefix, documentation was updated, printed and physically distributed and, perhaps most importantly, computer-time was a scarce resource.</p>

<p>The problem with the book is its age, by which I don&rsquo;t mean these kinds of anachronisms. Our field has thankfully moved forward somewhat in the last 40 years, even though <a href="http://vimeo.com/71278954">Bret Victor might not agree</a>. Instead, the main problem is that during this period in time (60s and 70s), the reigning development process was what we refer to as <a href="http://en.wikipedia.org/wiki/Waterfall_model">waterfall</a>.</p>

<p>I should be fair and point out that this very problem is highlighted by Brooks in the last chapter, which was added in 1995 and contains his own reflections on what had changed in the last 20 years. The fact still remains though that large portions of the book deal with typical waterfall model problems. The most prominent such problem is perhaps how to better create system specifications that are complete and correct, a task which for most real systems is unfeasible.</p>

<p>There are however good points that are valid even today. For example, when defining milestones for a project, they &ldquo;must be concrete specific, measurable events defined with knife-edge sharpness&rdquo; so that team members have no way of fooling themselves that something is &ldquo;basically&rdquo; finished.</p>

<p>The author is also obviously aware of the problems with changing requirements, stating that &ldquo;both the actual need and the user&rsquo;s perception of that need will change as programs are built, tested and used&rdquo;.</p>

<p>The book is interesting, but assuming you are working in a fairly modern organization (by which I mean you don&rsquo;t strictly follow the waterfall model) I don&rsquo;t believe it will push you or your manager to enlightenment. The best part of the book was actually the new chapter discussing the differences in the field between 1975 and 1995, so if you want to read it I would recommend you do so with the goal of better understanding the earlier days of software engineering, rather than learning how to structure the perfect organization.</p>

<p>Finally, I do not wish to imply that dealing with changing requirements is a solved problem. Agile methodologies have given us better tools, but there is a reason that we are not all using the same process. It seems Fred Brooks was correct when writing that &ldquo;structuring an organization for change is much harder than designing a system for change&rdquo;.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Your vs. My]]></title>
    <link href="http://blog.brannstrom.io/2013/02/your-vs-my/"/>
    <updated>2013-02-24T16:58:00+01:00</updated>
    <id>http://blog.brannstrom.io/2013/02/your-vs-my</id>
    <content type="html"><![CDATA[<p>I read an interesting post by Dustin Curtis a while back called <a href="http://dcurt.is/yours-vs-mine">Yours vs. Mine</a>. It dealt with wording in user interfaces, and the argument he made was that <em>my</em> refers to something that is an extension of myself, whereas <em>your</em> more closely resembles another social being that we can communicate with. In other words, the difference was wheter or not we consider the user interface to be a part of us or simply something we communicate with, and in his opinion (spoiler alert!) &ldquo;Your stuff&rdquo; would be the way to go.</p>

<p>As I read the the text, Dustin really won me over. However, as I&rsquo;ve been working on a side project lately, using <em>your</em> just didn&rsquo;t feel right. I tried to think about the reason for this, and I believe I came to a conclusion.</p>

<p>I think the basic argument of whether or not the interface is communicating with us as a seperate entity is correct. The problem is that sometimes interfaces do both. In my opinion, using the word <em>my</em> feels like it refers to something I have created, and <em>your</em> refers to something the system provides for me. As an example, consider the website of a news paper. There are two types of users, readers and writers, who each have access to a different interface because their purpose for entering the site is different (consuming and producing, respectively). Now consider the navigation item &ldquo;My articles&rdquo;. In which interface would this feel most appropriate? For the consumer it may refer to a page with articles that the system believes I would enjoy (though I agree the title could have been a bit more clear on that), and the producer could perhaps get a list of articles he or she has written.</p>

<p>This is highly unscientific, but <em>my</em> seems to have a stronger sense of ownership than <em>your</em>. If I see &ldquo;Your messages&rdquo; on a site, I think of communication and messages other people have sent me, whereas &ldquo;My messages&rdquo; more sounds like messages I have written. Put differently, <em>your</em> sounds like something for me to consume and <em>my</em> something I have produced.</p>

<p>This is where it becomes a little bit complicated though, because if the choice of wording is linked to consuming vs. producing, there will often be a need for both words on a site. This would however be an issue all of its own, since I believe most people would find it strange to have &ldquo;Your messages&rdquo; next to &ldquo;My articles&rdquo;.</p>

<p>A third, and of course valid, option would be to just drop the possessive pronoun altogether, but this could cause the interface to lose some of its personality. In the end, I guess it comes down to simply making a choice and sticking with it, but if anyone has a quantifiable way of deciding, feel free to share in the comments.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Adding a disk to DNS-320 with fun_plug]]></title>
    <link href="http://blog.brannstrom.io/2013/02/adding-a-disk-to-dns-320-with-fun-plug/"/>
    <updated>2013-02-12T18:55:00+01:00</updated>
    <id>http://blog.brannstrom.io/2013/02/adding-a-disk-to-dns-320-with-fun-plug</id>
    <content type="html"><![CDATA[<p>Since about a year back, all our media at home is stored on a NAS (D-Link DNS-320), which simplifies things since we are laptop-based. I originally put in an old 1 TB drive I had lying around, but as you might expect it finally filled up.</p>

<p>Since the DNS-320 has two slots, I bought a Western Digital Red 3TB SATA III, which should fill our needs at home for some time. One of the nice things with getting a NAS was that adding a disk should be pretty much plug-and-play. Thus I inserted the new drive, entered the web interface for the NAS and begun formatting. Initialization went fast, but then progress halted at 0% when formatting. I aborted and retried, but to no avail.</p>

<p>After a while I finally manged to find a solution. I shut down the NAS, removed the original disk which was in the left slot, inserted the new 3 TB disk in that slot and booted up. Formatting now magically started working.</p>

<p>Both disks were now available, but there was a new problem. The DNS-320 runs Linux and by using a little hack known as <a href="http://nas-tweaks.net/40/installation-of-the-fonz-funplug-0-5-for-ch3snas-ch3mnas-dns-323-and-many-more/">fun_plug</a>, we can gain access to the OS and install additional software on the device, such as a web server or a torrent client. This hack was installed on the original disk, but even though both disks were identified, fun_plug wouldn&rsquo;t start.</p>

<p>As I searched for a solution on this problem, I found a wiki for DNS-323 where <a href="http://dns323.kood.org/information:known_issues">the same problem was described</a>. It turns out that fun_plug needs to be on the right-most disk in order to start up, so I had to make sure the original disk which had it installed resided in the right slot.</p>

<p>Mission accomplished.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Why I Use Firefox]]></title>
    <link href="http://blog.brannstrom.io/2012/08/why-i-use-firefox/"/>
    <updated>2012-08-26T17:45:00+02:00</updated>
    <id>http://blog.brannstrom.io/2012/08/why-i-use-firefox</id>
    <content type="html"><![CDATA[<p>I think <a href="https://www.google.com/chrome/">Google Chrome</a> is a great browser and I use it on a regular basis. At the moment, I think their built-in developer tools are superior to those in <a href="http://www.mozilla.org/en-US/firefox/fx/#desktop">Mozilla Firefox</a> and the process sandboxing works better. That said, Firefox has the killer Awesomebar which kicks Google&rsquo;s Omnibar out of the water and the ecosystem of extensions is a strong card for Mozilla. In my opinion these two browsers, which are the common choices for people especially in tech, are head-to-head when it comes to features.</p>

<p>How about performance then? When Chrome began to overtake Firefox, performance was one of they key reasons that made people switch. Its Javascript engine was much faster and the browser consumed less memory. Since then things have evened out. Chrome started a speed war which was great for users, since it forced the other major browsers to follow suit. The same has been true for memory and start-up times, though perhaps more quitely. <a href="">Lifehacker&rsquo;s latest browser test</a> (June 12, 2012) revealed that Chrome is still kicking ass on the JS side, where as Firefox leads the way in memory and tab-loding.</p>

<p>As you see, I consider Firefox and Chrome to be more or less equal when it comes down to features and performance (and I could very well add <a href="http://www.opera.com/browser/">Opera</a> and <a href="http://www.apple.com/safari/">Safari</a> to the list). That brings me to the idea behind the browser, what drives the development.</p>

<p>I believe the Internet should be free and open, and because of that I prefer to support a browser whose only interest is promoting a free and open web. Can we so easily separate the tool from the idea? Can we really trust that commercial interests in the browser market will not spill over and influence the web? My answer would be no, because it is only reasonable that Google&rsquo;s bottom line is an important factor in the future development of Chrome.</p>

<p>That is why I choose Firefox.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Open-sourcing production code]]></title>
    <link href="http://blog.brannstrom.io/2012/08/open-sourcing-production-code/"/>
    <updated>2012-08-18T13:08:00+02:00</updated>
    <id>http://blog.brannstrom.io/2012/08/open-sourcing-production-code</id>
    <content type="html"><![CDATA[<p>One of my very first projects that actually made it to real users was <a href="http://skivsamlingen.se/">Skivsamlingen</a>, developed in the dawn of my PHP days. Skivsamlingen means The Record Collection, and is not surprisingly a web application where users can list all their records.</p>

<p>The size of the target group has admittedly decreased somewhat since the era of iTunes, Spotify and Grooveshark, among others, begun, but there are still active users on the site. These users are the reason I felt I had to clear my conscience for barely working on the site for many years. Possible solutions are to make time for the site, take it down, or simply make other people work on it.</p>

<p>I chose the latter. By <a href="https://github.com/erikbrannstrom/skivsamlingen">making the code public at Github</a>, the users themselves get the chance to improve on it. There are however some things you need to keep in mind before throwing your code out there, especially if it is an older project that might not have been developed according to all of today&rsquo;s best practices.</p>

<h2>1. Remove sensitive data</h2>

<p>First of all, make sure that any sensitive data is removed from  files that will be made public. This includes passwords to your database and mail provider, encryption keys, API keys for third-party services and anything else that shouldn&rsquo;t end up in the wrong hands. If this information has already been put under version control, simply removing those lines is of course not enough.</p>

<p>The first step is to find all these bits and pieces of information and gather these in a configuration file (or similar) that contains information that should not be available to other people. Make sure to add this file to your list of ignored files (.gitignore, if using Git). I for example had a global salt used when hashing user passwords that was located in the user model, which was under version control.</p>

<p>The second step is therefore to remove all traces of your secrets from old commit data. If you are using Git, then you will use the <code>git filter-branch</code> command. GitHub has a <a href="https://help.github.com/articles/remove-sensitive-data">guide on removing sensitive data</a> which is very useful for this. They also mention another important thing, namely changing any passwords used by the application, just in case something is missed.</p>

<h2>2. Code review</h2>

<p>Grab a cup of coffee. You will most likely need it. The next step is going through your code, line by line, and continually ask yourself, where does this input come from? Am I enforcing any validation on this input? Where is it used? Is it properly escaped?</p>

<p>The goal is of course to cover your bases in terms of SQL and XSS injections, CSRF, session management and all the other possible attack scenarios that are available. For those of you who barely understood what I was just talking about, I <em>highly</em> recommend you to visit <a href="https://www.owasp.org/">OWASP</a>, and especially make sure you grasp the concepts in <a href="https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project">OWASP Top 10</a>. Actually, I recommend it anyway. These are the must-haves of security.</p>

<p>I, for example, found a SQL injection vulnerability in the record listings. The sorting worked by adding the direction, ascending (ASC) or descending (DESC), to the URL. This parameter was then put directly into the SQL query that fetches the list of records. A stupid mistake, of course, but one that was easy to make, especially when new to the game. Try to patch these things up, so not to make life easier for potential attackers.</p>

<h2>3. Upgrade libraries</h2>

<p>Once you have gone through your own code, some time should be spent on any external dependencies. Most of us use frameworks and libraries to speed up the development, and especially when a project has gone unattended for a while, these things tend to have moved on without you. Outdated libraries with known security flaws are common points of attack, since the problems are typically well-known and easy to exploit.</p>

<p>Not surprisingly, my site was running version 1.7.2 of <a href="http://codeigniter.com/">CodeIgniter</a> which was released in September 2009. That&rsquo;s three years ago. The latest update put the version number to 2.1.2 and was released June 2012. Looking through the change log revealed quite a few fixed security problems, as well as other improvements.</p>

<h2>Final words</h2>

<p>The steps described above can of course be applied to your code base even if you are not planning to go open-source. I don&rsquo;t believe that open-sourcing code is always the way to go, obviously. The risks must always be weighted against the potential rewards, and these are fundamentally different for a small, non-profit project and a large business application.</p>

<p>On the other hand, I don&rsquo;t buy the argument that revealing your code would make your site less secure. This concept is called <a href="http://en.wikipedia.org/wiki/Security_through_obscurity">security through obscurity</a> and may work as an additional layer of security, but it does not by itself secure a flawed application.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Spotify Apps 101]]></title>
    <link href="http://blog.brannstrom.io/2012/08/spotify-apps-101/"/>
    <updated>2012-08-09T17:14:00+02:00</updated>
    <id>http://blog.brannstrom.io/2012/08/spotify-apps-101</id>
    <content type="html"><![CDATA[<p>This weekend, the <a href="http://www.wayoutwest.se/en">Way Out West festival</a> is held in <a href="http://en.wikipedia.org/wiki/Slottsskogen">Slottsskogen</a> in Göteborg. I had originally not planned to go, but when I heard that there was a <a href="http://wowhack.splashthat.com/">hackathon</a> - which in itself is a tempting prospect - where you got a free pass just for participating, my plans changed.</p>

<p>I teamed up with <a href="http://twitter.com/rickard_olsson">@rickard_olsson</a>, <a href="http://twitter.com/jensljungblad">@jensljungblad</a> and <a href="https://twitter.com/_sandrahansson">@_sandrahansson</a> with the goal of creating our first Spotify app. In 24 hours we did just that, and the result was a music quiz app called Quizify (the number of apps named -ify was staggering). It was a great hack and we hope to get the chance again next year!</p>

<p>Anyhow! I thought I&rsquo;d share my experience of doing app development for Spotify.</p>

<h2>Resources</h2>

<p>The app itself is built purely using Javascript, HTML and CSS which is rendered by Chromium inside Spotify. There are <strong><a href="https://developer.spotify.com/technologies/apps/guidelines/02_app-design-guidelines.html">design guidelines</a></strong> that deal with how you should design your app, but the most useful resource is probably the Javascript API.</p>

<p>The <strong><a href="https://developer.spotify.com/technologies/apps/docs/">Spotify JSDocs</a></strong> are okay. Not more, not less. There is a clear warning on the top of the page that they are preliminary, but more than that, they are very sparse. It&rsquo;s not a very big API, so it&rsquo;s easy enough to get around and find what you need, but don&rsquo;t expect verbose descriptions of methods or events (what&rsquo;s the practical difference between SEARCHTYPE.NORMAL and SEARCHTYPE.SUGGESTION?). There are code examples for a few common tasks, such as searching and authenticating users using Facebook or other third-party services, but once again they are limited in numbers.</p>

<h2>Architecture</h2>

<p>To me, Javascript is typically something that is added on top of an application, instead of being the foundation as it is in this case. This probably led to a less-than-perfect architecture. For new projects I would suggest using the index page as a combined layout page and front controller. Layout because it beats copy-pasting all that markup between files, and front controller because any spotify:your_app:param links will be sent to your index.</p>

<p>From there you can load any content you need from other files based on the URL, which consequently means you should use spotify: URIs inside your app as well rather than link to your html-files (which is exactly what we did, unfortunately). This is mentioned fleetingly (sort of) in the <a href="https://developer.spotify.com/technologies/apps/guidelines/01_integration-guidelines.html">integration guidelines</a>, but deserves a lot more attention in my opinion.</p>

<h2>Backend</h2>

<p>Many apps require a backend, and there is honestly not too much to say here. We used Heroku to host a small RESTful API built in <a href="http://www.sinatrarb.com/">Sinatra</a> and a Postgres database. Just make sure to add the domain of your backend application to the RequiredPermissions in the manifest.json file, because otherwise Spotify will block all your AJAX requests there. The same goes for any outgoing requests, such as third-party authentication. This is covered in the <a href="https://developer.spotify.com/technologies/apps/tutorial/">official tutorial</a>, but I wanted to mention it so you don&rsquo;t forget and spend 20 minutes debugging dropped AJAX requests. Not that it happened to me or anything&hellip;</p>

<h2>Future</h2>

<p>From what I understood, there have been some concerns raised by the record labels regarding the apps. I don&rsquo;t know exactly why, but I assume this is why there has been relatively little activity since the initial announcement that Spotify was becoming an app platform. It seems however that these issues are soon to be resolved, which hopefully means new momentum for the project in terms of both features and documentation. Perhaps there might even be opportunities to monetize the apps, but I wouldn&rsquo;t expect that anytime soon.</p>

<p><img src="https://dl.dropbox.com/u/9360009/quizify.png"></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Going offline]]></title>
    <link href="http://blog.brannstrom.io/2012/08/going-offline/"/>
    <updated>2012-08-04T19:11:00+02:00</updated>
    <id>http://blog.brannstrom.io/2012/08/going-offline</id>
    <content type="html"><![CDATA[<p>Yesterday I got back from a five-day trip to neighboring Denmark. It was a welcome break from my thesis work, but it turned out to also be a break from something more time consuming than that.</p>

<p>We had rented a house in <a href="http://en.wikipedia.org/wiki/Vorup%C3%B8r">Vorupør</a>, population 606, in the Thy National Park. It is not the end of the world, and we could of course have picked up a Danish newspaper whenever we went grocery shopping, and had World War 3 begun we would most likely have heard about it from the locals, but as it was we stayed pretty much in the dark when it came to anything outside Thy.</p>

<p>Before arriving there, I had expected some 3G or at least some EDGE availability (for a price, of course) and the occasional wi-fi connection, but no luck. I suspect the end result was a personal record in the longest consecutive time spent offline, at least for quite a few years, with no Internet for four full days.</p>

<p>Is this really blog worthy, one might ask? A fair question indeed, but I found this experience to be rather interesting because I hadn&rsquo;t realized how much time I spend online. It&rsquo;s not only that almost everything I do on my computer requires an Internet connection, but every time I have a moment to spare that does not require my full attention I reflexively pull out my iPhone to check my e-mail, Twitter, Reeder, Facebook or whatever else I haven&rsquo;t done in the last two minutes. It is an action that is rarely caused by a consious decision, but rather it seems to stem purely from muscle memory.</p>

<p>This idea that constantly staying connected might not be all that it&rsquo;s cracked up to be is of course not revolutionary. Studies have shown that <a href="http://www.anxietyuk.org.uk/2012/07/for-some-with-anxiety-technology-can-increase-anxiety/">social networking sites may contribute to anxiety</a>, and even people in Silicon Valley who deal these digital drugs <a href="http://www.nytimes.com/2012/07/24/technology/silicon-valley-worries-about-addiction-to-devices.html">acknowledge the importance of disconnecting</a> once in a while.</p>

<p>I cannot claim to have come back as a completely different person. Obviously I am back online again, and I wouldn&rsquo;t want it any other way. I do however feel that disconnecting has given me a boost in creativity with new ideas for projects as well as providing well-needed focus on existing problems. Even though it has been almost 24 hours since I went online, I still haven&rsquo;t even opened my Twitter feed. Not because I&rsquo;ve told my self not to, but because it hasn&rsquo;t crossed my mind (until now).</p>

<p>What it turns out I missed the most was actually just keeping tabs on what goes on in the world. Especially since the Olympics were ongoing, it was frustrating to not know what was happening. This feeling was a lot stronger than any thoughts of what people might have posted on Twitter or Facebook (thank God, &lsquo;cause if it hadn&rsquo;t been I would&rsquo;ve been worried).</p>

<p>The most interesting part now is to see if my Reflexive Online Refreshing Syndrome (ROFS - I made that up) has been cured or at least lessened for a significant amount of time, or if I will be back to normal in a few days time. Even without any scientific proof I dare go out on a limb and claim that ROFS causes a massive amount of time - and in the end, money - to be wasted both at home and at work, and as such I hope to avoid going back.</p>

<p>Since four day long flight-modes are seldom possible, I will have to rely on common sense. I would love to hear how other people do this. Do you disconnect fully for a fixed amount of time per day? Do you use recurring intervals, such as one hour online, one hour offline? Or do you simply rely on will power to avoid your Internet extravagances?</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[From Wordpress to Octopress]]></title>
    <link href="http://blog.brannstrom.io/2012/07/from-wordpress-to-octopress/"/>
    <updated>2012-07-23T21:45:00+02:00</updated>
    <id>http://blog.brannstrom.io/2012/07/from-wordpress-to-octopress</id>
    <content type="html"><![CDATA[<p>I thought I would give a quick summary of how I went about migrating from Wordpress to Octopress. It was, in face, a much smoother process than I had expected.</p>

<p>To avoid manually converting all my posts I used <a href="https://github.com/thomasf/exitwp">exitwp</a>. Okay, admittedly I was actually in the process of doing this manually when I was hit by the realization that there must be a better way, as it turned out there was. I use Mac OS X Lion which comes bundled with Python, which is neat considering exitwp is written in Python. If you don&rsquo;t use Mac, you&rsquo;re on your own for this.</p>

<p>Anyway, start off by cloning the exitwp repo. The program has a few dependencies, and if you don&rsquo;t already have them installed, the best way of grabbing them is probably using <a href="http://www.pip-installer.org/">Pip</a>. Pip is a package manager of sorts for Python (I&rsquo;m not a Python guy) and it will make your life much easier (I guess).</p>

<p>Once installed, run you run the pip install command in the exitwp folder, which installs the dependencies. You are now set for the actual conversion. Below you will see the commands that you either already typed, or will copy-paste in about two seconds.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>git clone https://github.com/thomasf/exitwp
</span><span class='line'><span class="nv">$ </span>curl https://raw.github.com/pypa/pip/master/contrib/get-pip.py <span class="p">|</span> sudo python
</span><span class='line'><span class="nv">$ </span><span class="nb">cd </span>exitwp
</span><span class='line'><span class="nv">$ </span>sudo pip install --upgrade  -r pip_requirements.txt
</span></code></pre></td></tr></table></div></figure>


<p>Next step is getting your data from Wordpress. Thankfully the folks at WP has made this easy. Simply log in to your admin area, go to <code>Tools -&gt; Export</code> and grab all your posts as XML. Save the XML file in your exitwp/wordpress-xml directory.</p>

<p>Now all that remains is running <code>python exitwp.py</code> and your posts will be converted to Octopress-compatible markdown files in the exitwp/build directory. Move the newly generated files to your Octopress source/_posts folder and you will soon be able to relax.</p>

<p>By now your blog should be working, and if it doesn&rsquo;t I&rsquo;m afraid you will actually have to read the text on all those other sites. A few tweaks remain if you wish to remain somewhat backward compatible when replacing the Wordpress site with your fancy new Octopress ditto.</p>

<p>If you used tags in WP for your posts, the converter will unfortunately still lists them in the post header as tags. You will have to change all <code>tags:</code> to <code>categories:</code>. A quick search-and-replace should do the trick. Secondly, since categories were called tags, and were thus located at /tag/ in the URL hierarchy, you might want to set <code>category_dir: tag</code> in _config.py to remain backward compatible.</p>

<p>Speaking of backward compatability. If you also want to make sure that old permalinks will still work, you might have to change the permalink setting as well. I set mine to <code>/:year/:month/:title/</code>, which was the same as I had in WP.</p>

<p>That was it for me at least. I hope your ride will be just as smooth if you decide to make the switch.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Lazy Sunday]]></title>
    <link href="http://blog.brannstrom.io/2012/07/lazy-sunday/"/>
    <updated>2012-07-21T13:15:00+02:00</updated>
    <id>http://blog.brannstrom.io/2012/07/lazy-sunday</id>
    <content type="html"><![CDATA[<p>I made a startling realization the other day. I&rsquo;m lazy. Sure, I work and study just as much as I should during the weeks, I exercise about four times a week and I walk my dog. It is not that kind of lazy. It&rsquo;s in my admittedly well-earned spare time that I am lazy.</p>

<p>As university, and later work, started taking up more time, I made up for it by doing less when I am not working. Don&rsquo;t get me wrong, I belong to the group of people that believe that <a href="http://www.alternet.org/visions/154518/why_we_have_to_go_back_to_a_40-hour_work_week_to_keep_our_sanity?page=entire">overtime is unproductive</a> and even <a href="http://www.npr.org/blogs/health/2012/01/26/145912523/working-long-hours-can-be-depressing-truly">hurtful in the long haul</a> - all hail the 40 hour week! What I mean is that spare time does not have to equal ass-on-couch-time.</p>

<p>If I were to take the Proust Questionnaire in Vanity Fair (why that would ever happen is beside the point), my answer to the question of my greatest extravagance would have to be TV-shows. I absolutely love TV-shows. Nothing wrong with that, but the problem is that all those <a href="http://www.imdb.com/title/tt1439629/">20</a> or <a href="http://www.imdb.com/title/tt1632701/">40</a> or <a href="http://www.imdb.com/title/tt0944947/">60</a> minutes of TV start to add up when one episode is followed by another and so on. It&rsquo;s probably not close to crack cocaine on the addiction scale, but it is a time sink.</p>

<p>I am sure that most people have these time sinks, whether it is TV-shows, movies, shopping, sleeping or something else. These are all great things, but I realize that they are well complemented with reading a book (<a href="http://en.wikipedia.org/wiki/Fifty_Shades_of_Grey">Fifty Shades of Grey</a> does not count) or a magazine (the ones by actual journalists), writing a journal, learning a second/third/fourth language or working on a side project.</p>

<p>Why would you want to do this? It is basically all about self-improvement, and even though self-improvement have become something of a farce with highly paid coaches and quasi-science, it doesn&rsquo;t take a genius to guess that there is a link between improving upon oneself and your confidence and happiness, which in turn is linked to success. If you are interested in the topic I can recommend both the paper <a href="http://textedu.com/f2/download/the-benefits-of-frequent-positive-affect-does-happiness-lead-to-success.pdf">&ldquo;The benefits of frequent positive affect: does happiness lead to success?&rdquo;</a> by Lyubomirsky et. al. and the book <a href="http://www.amazon.co.uk/59-Seconds-Think-little-change/dp/023074429X">&ldquo;59 Seconds&rdquo;</a> by Richard Wiseman.</p>

<p>Now wrap up your procrastination and go read a book.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Xdebug in Netbeans on a MAMP setup]]></title>
    <link href="http://blog.brannstrom.io/2011/04/xdebug-in-netbeans-on-a-mamp-setup/"/>
    <updated>2011-04-09T15:07:21+02:00</updated>
    <id>http://blog.brannstrom.io/2011/04/xdebug-in-netbeans-on-a-mamp-setup</id>
    <content type="html"><![CDATA[<p>I have been doing a lot of PHP development for my bachelor thesis over the last few months. We are working in a team of six and it is not always trivial to keep track of all the changes to the code, and debugging code you are not all that familiar with is a pain in the ass. I am coding in <a href="http://netbeans.org/index.html">Netbeans 7.0 beta 2</a> with MAMP Pro 1.9 taking care of the server. To resolve my debugging issue I decided it was time I got Xdebug into the mix. It should also be noted that I&rsquo;m using PHP 5.3, but I believe all of this should work just the same for 5.2 if you just replace the version number wherever it appears.</p>

<p>MAMP actually comes bundled with Xdebug, though it is not enabled by default. The first thing I did was to upgrade the version of Xdebug to 2.1.0. I don&rsquo;t think this is required, but it sure didn&rsquo;t hurt. Just download the <a href="http://code.activestate.com/komodo/remotedebugging/">PHP Remote Debugging Client</a> from the the boys at ActiveState and replace the <em>xdebug.so</em> in your <em>/Applications/MAMP/bin/php5.3/lib/php/extensions/no-debug-non-zts-20090626</em> folder (the date on the end might be different, but just go with what you find!) with the one unzipped from the downloaded file.</p>

<p>The next step is to enable Xdebug which we do in the php.ini file. Open up MAMP, select File -> Edit Template -> &lsquo;PHP 5.3.2 php.ini&rsquo; from the menu and modify the end of the file so that it looks (somewhat) like the one below. This is just an example however, and these INI-settings are basically a mash-up of all the tips I found  while googling the matter. Especially note that the <em>xdebug.default_enable</em>, _ xdebug.remote_autostart<em> and </em>xdebug.idekey_ settings are not mentioned in  the <a href="http://wiki.netbeans.org/HowToConfigureXDebug">NetBeans Wiki&rsquo;s guide</a>, so it might be that  they are not required. Also be really sure the Zend Optimizer line is commented out, since it apparently interferes with Xdebug.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[xdebug]
</span><span class='line'>xdebug.default_enable=1
</span><span class='line'>zend_extension="/Applications/MAMP/bin/php5.3/lib/php/extensions/no-debug-non-zts-20090626/xdebug.so"
</span><span class='line'>xdebug.remote_enable=1
</span><span class='line'>xdebug.remote_log="/var/log/xdebug.log"
</span><span class='line'>xdebug.remote_host=localhost
</span><span class='line'>xdebug.remote_handler=dbgp
</span><span class='line'>xdebug.remote_port=9000
</span><span class='line'>xdebug.remote_autostart=1
</span><span class='line'>xdebug.idekey="netbeans-xdebug"
</span><span class='line'>
</span><span class='line'>[Zend]
</span><span class='line'>;MAMP_zend_optimizer_MAMP</span></code></pre></td></tr></table></div></figure>


<p>After this step I wasted a lot of time on trying to find out why NetBeans couldn&rsquo;t connect to Xdebug. Finally I rebooted my computer and everything was suddenly working. My best guess is that this was due to a conflict on port 9000 (possibly with Skype). Feel free to try it out with only restarting the MAMP server but remember to do a full reboot if things still aren&rsquo;t working.</p>

<p>By now you should be up and running. NetBeans debugging functionality is pretty straightforward, however you might want to check out the <a href="http://netbeans.org/kb/docs/php/debugging.html">official documentation</a> to get started. Hope this saves someone else a few hours, and feel free to share your tips in the comments!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Co-editing using PlainText / Dropbox]]></title>
    <link href="http://blog.brannstrom.io/2011/01/co-editing-using-plaintext-dropbox/"/>
    <updated>2011-01-02T00:39:21+01:00</updated>
    <id>http://blog.brannstrom.io/2011/01/co-editing-using-plaintext-dropbox</id>
    <content type="html"><![CDATA[<p>Happy new year! Over the last six months I&rsquo;ve become the proud owner of both an iPhone and an iPad. Indeed, the fanboy accusations are getting hard to dismiss. Anyhow, my fiancée also got an iPhone and I thought I should do something useful with that.</p>

<p>I guess most people have heard of the amazing (and free!) <a href="https://www.dropbox.com/referrals/NTkzNjAwMDk5?src=global0">Dropbox</a>. In short, it is a file sharing service that integrates directly with your file system. Simply drop a file into the Dropbox folder and - wham! - you can now access it via the web, a mobile application or another computer, or share files with your friends and family. Other applications can utilize this great feature, and one of those is <a href="http://www.hogbaysoftware.com/products/plaintext">PlainText</a>. It is an iOS text-editing application that syncs all files using Dropbox.</p>

<p>One lacking feature of PlainText though, is that it does not give you the option of sharing files and folders with others, which would be really useful for, say, grocery shopping. I realized it would be pretty sweet if whenever Emelie or I thought of something we needed to get at the store, we just wrote it down in an app and both of us would have instant access to the list, so it wouldn&rsquo;t matter which one of us went shopping. Since PlainText uses Dropbox, this is in fact a rather simple thing to set up.</p>

<p>First of all I created a new folder in PlainText, since I want easy control over which files to share. This folder will be synced using Dropbox so after it has been created, manually share the folder with whomever you&rsquo;d like either by right-clicking the folder on your computer or via the web interface. When you share a folder within another folder, the receiving user will have it appear at the lowest level in his or her Dropbox folder structure, so make sure they move the shared folder inside their PlainText folder.</p>

<p>And, voilà! Time to get the freaky co-editing started! If the folder does not show up, or disappears after it&rsquo;s been shared, do a hard restart of the application on your device. It did the trick for me.</p>

<p>Do you have a nice Dropbox trick? Or simply know of a free app that does this same thing, only ten times better? Share in the comments.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Empty inbox brings peace of mind]]></title>
    <link href="http://blog.brannstrom.io/2010/08/empty-inbox-brings-peace-of-mind/"/>
    <updated>2010-08-04T22:35:59+02:00</updated>
    <id>http://blog.brannstrom.io/2010/08/empty-inbox-brings-peace-of-mind</id>
    <content type="html"><![CDATA[<p>Let&rsquo;s cut the crap: I&rsquo;m a fan-boy, plain and simple. I&rsquo;m an Apple fan-boy and I&rsquo;m a Google fan-boy. I love the simplicity of the products they create, and for the most part everything just works. I&rsquo;ve been using Gmail since 2004 when it was still in closed beta and have never felt the need to use anything else. Somehow though, it took me almost six years to realize I was using it all wrong.</p>

<p>For all this time I have been lazily reading and composing mail, using a few filters to get those incoming messages bagged and tagged but keeping every single e-mail in the inbox. It was only a month or so ago I realized the beauty of the Archive button, which was only sporadically used before. Since then I&rsquo;ve got a very clear work-flow for dealing with all my mail.</p>

<p>The main goal is to keep your inbox empty. If you haven&rsquo;t seen an empty inbox since the last trembling months of the last millennium you have no idea what you&rsquo;re missing. It really gives a feeling of peace to see that nothingness stare back at you - no judgment for not replying, no expectation to be populated, just a blank slate. This is not always possible though, but most of the time I do manage to keep it empty.</p>

<p>Whenever a new e-mail pops in, I read it. Now, that&rsquo;s not so hard? Once read I decide if I can answer it right at this moment, and if I can, I do. Thereafter I archive the conversation and move on. Archiving obviously also goes for informational messages that does not need any reply. Those e-mails that I expect to be able to answer in the next day or two are allowed to remain read in the inbox. That&rsquo;s pretty much it!</p>

<p>Now, you may ask yourself &ldquo;How about e-mails that I won&rsquo;t be able to give an answer to until a further date?&rdquo;. The answer to that is for you to reply immediately and write exactly that, and we are magically back to step one. For those really important e-mails that I might need to reference for longer periods of time I like to use the Star feature of Gmail.</p>

<p>Is the clutter-free inbox the way of the future or a pointless Getting Things Done-inspired waste of time? Go for comments.</p>
]]></content>
  </entry>
  
</feed>
