<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link rel="hub" href="http://tumblr.superfeedr.com/" xmlns:atom="http://www.w3.org/2005/Atom"/><description></description><title>Bump Dev Blog</title><generator>Tumblr (3.0; @bumpdevblog)</generator><link>http://devblog.bu.mp/</link><item><title>Flock for Android: A Technical Breakdown</title><description>&lt;p&gt;&lt;em style="margin: 0px; padding: 0px; color: #424037; font-size: 12px; line-height: 21.600000381469727px;"&gt;This post was written by Indy and Sam, on Bump&amp;#8217;s client team.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;Flock for Android was just a twinkle in the eye of the Android users at Bump until early October. So when it was time for another hackathon, a few of us got together and threw together an early version of the app you see today. Since then we&amp;#8217;ve been iterating and hardening Flock for Android. In this essay we will go through what it took to bring Flock to Android. &lt;/span&gt;&lt;br/&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt; &lt;/span&gt;&lt;br/&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;An early decision we made was to initially build the app with ICS in mind rather than older versions of Android. We are big fans of UI direction Android has taken since ICS and knew of a lot of great APIs that were introduced with ICS that would make Flock faster and better, and easier to build. Once we had the app working like we wanted, only then did we go back and see how we could make the app work on Gingerbread. This meant that we had to cut out some of the things that make the app super slick, but kept it functional.&lt;/span&gt;&lt;/p&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;We decided not to go back further than Gingerbread. When we looked into it, we noticed market share for OSes pre Gingerbread are shrinking fast. We would open ourselves up for a whole host of bugs if we tried getting the app working with older phones, OSes, and missing APIs. Our small team simply didn&amp;#8217;t have time to deal with that.&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;strong&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;Core&lt;/span&gt;&lt;/strong&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;When we started working on Flock for iOS we knew that we&amp;#8217;d eventually build an Android version. And we followed the same pattern that we used in the Bump app to share code. We wrote a lot of C. In the Bump app we only had our core networking library in C (we have a custom protocol to talk to our servers), but in Flock we wanted to share code higher up the stack. We wrote all of the &amp;#8220;core&amp;#8221; logic in C. This is the layer that translates the packets we use to talk to the server into structures that our UI uses.&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;This C code has been running and been heavily debugged over the months that Flock for iOS has been out, and &amp;#8220;all&amp;#8221; we had to do was plop that C code into the Android app. Whenever you bring C code onto a new platform there is always a bit of work you need to do. But once that was good to go we had a fully functioning core of the app. All we had to do was consume the structures emitted from it.&lt;/span&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;We use inproc zmq sockets to communicate between this core C layer and the Java UI layer. And the data is encoded using Protocol Buffers. We use exactly this structure for the iOS app, with the UI layer in Objective-C instead.&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;strong&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;UI&lt;/span&gt;&lt;/strong&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;While we were in the middle of implementing the iOS app, our design team produced an alternate design of the app, that focused much more on the display and exploration of photos. So when it came time to start implementing the UI, our hackathon team decided to build this design instead of simply porting the iOS UI. This design gives you a feel of exploring a large map of all your events and photos and fit better with the emphasis of larger screen sizes on Android. All the other information is only revealed as needed, giving a much more immersive and engaging experience.&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;Though we all loved this design there were a lot of challenges involved in implementing it. We only have a time to touch on a few for now.&lt;/span&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;The first challenge was to get the basic layout framework working. Like with anything that has an unbounded list of objects we use the trusty ListView class in Android. Each row in this list is an album. Simple enough, we&amp;#8217;ve done this before. However the design called for a horizontal swiping in each row to see the other photos in the album. This seemed like a use of the ViewPager class. Here we ran into our first hiccup.&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;Most places you see ViewPagers used, like the Play Store app and even the Bump app, ViewPagers page through full screen wide pages. There is one primary view that&amp;#8217;s visible and then pages that it dynamically loads on either side of the page depending on which way people swipe. In Flock we wanted each item in our page to be a square with the ability to see a little bit of the page to the right. I thought it was time to start hacking android layouts, or if all else failed rebuild pagers with HorizontalScrollView (sort of how Pulse does it). But after some digging around I ran across a method on PagerAdapter called &lt;a href="http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html#getPageWidth(int)"&gt;getPageWidth&lt;/a&gt;. This was exactly what I was looking for, though it takes a percentage width instead of a an explicit size, but that&amp;#8217;s easy enough do the math for.&lt;/span&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;The second hiccup was how to shoehorn ViewPagers into ListViews. There are two problems with this. View pagers are designed to have vertical scrolling views in them (remember how we mentioned earlier that they are designed to be full screen views), not be contained in views that scroll vertically like ListViews. What this means is that the user must be very exact about scrolling vertically or else the ViewPager would just wiggle slightly left or right instead of letting us scroll vertically.&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;To solve this problem we basically took the approach described in &lt;a href="http://stackoverflow.com/questions/7339558/android-listview-tolerance" title="Android ListView Tolerance"&gt;this stackoverflow answer&lt;/a&gt;. We intercepted touches and detected if there was more vertical distance in a scroll than a horizontal. If so then we gave precedence to the ListView over the ViewPager. This simple trick worked out beautifully.&lt;/span&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;Once we had the basic view framework going we ran into our second major challenge. This was also related with trying to shoehorn ViewPagers into ListViews. The core of this problem is that ViewPagers are not really designed to do view recycling, which is essential to smooth vertical scrolling. Dian Hackborn, an Android framework engineer, had an exasperated reply when someone asked for help in doing this online:&lt;/span&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span style="font-size: medium; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;&lt;span style="font-family: Arial; color: #222222; vertical-align: baseline;"&gt;How exactly do you recycle the list view items correctly?  This is&amp;#8230; crazy. - &lt;a href="https://groups.google.com/d/msg/android-developers/FO-NDXGUiGs/1rZMKf_zL-MJ"&gt;Diane Hackborn&lt;/a&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;Because of this we initially thought we were heading down the wrong path, but there were just &lt;/span&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;too many things we got for free by using ViewPagers as ListView items that we decided to be a little crazy.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong style="font-family: Times; font-size: medium; font-weight: normal;"&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;To get around the lack of view recycling we subclassed PagerAdapter and implemented recycling ourselves. The exposed methods are actually almost identical to a standard BaseAdapter (getView, getItemViewType etc.). We used a map of view type to queues of available pages to store recycled views. Whenever destroyItem is called for a particular view type, we add the corresponding view to the queue for that view type. Whenever instantiate item is called, before actually inflating a new view, we first check to see if we have a saved view in the corresponding queue in the map. &lt;/span&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;While we got reasonable performance using this schema, it wasn’t sufficient. The order of the pages and the types of the pages in each row in Flock is determined by the number of photos in an event. Since most events have different numbers of photos, each row had a different sequence of view types. As the ViewPagers and PagerAdapters were reused during the user’s first few vertical swipes, the adapters were continually being asked to load new view types that other adapters had inflated, but the current one had not. Until every adapter had been asked to inflate a few of every view type we were inflating a lot of views, so there was a prolonged period of poor scrolling when users first opened the app. Since every adapter kept two or three views of each view type around, we were also using a fair amount of memory just keeping views around. The final step to help alleviate over inflating views and reduce memory usage was keep a single global map of view type to queue of views, rather than having each PagerAdapter have their own. Sharing views for pages across rows meant that we didn’t need to inflate as many views for each type and similarly didn’t need to keep as many views for each type around in memory.&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;Along with some timely help from Romain Guy’s blog on &lt;a href="http://www.curious-creature.org/2012/12/01/android-performance-case-study/" title="Android Performance by Romain Guy"&gt;android performance&lt;/a&gt;&lt;/span&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt; and our own efforts at view recycling, we’ve been able to get good scrolling performance despite having complex row views displaying large images with very little padding. There is always room for improvement and we have a few ideas in mind to eliminate the last few scrolling hiccups for users with lots of events in a future version, but on the whole we’re pretty happy with the performance.&lt;/span&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;&lt;strong&gt;Background Location&lt;/strong&gt;&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;One of the really interesting things Flock does is find out the friends you&amp;#8217;re hanging out with to recommend exactly whom to share photos with. To achieve this we need to know where a user is without having them open the app. This is where the differences between iOS and Android API philosophies are really obvious.&lt;/span&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;iOS gives apps a couple ways to do this as very high level APIs. One is to register for SLCs (Significant Location Updates) and a second is to register geo fences (region monitoring). Once you register for these you are at the system&amp;#8217;s mercy to wake up your app when it thinks it&amp;#8217;s right for you. Currently Flock for iOS relies primarily on SLCs, however SLCs didn&amp;#8217;t behave the way we expected them to since they were designed for the opposite use case: moving a &amp;#8220;significant&amp;#8221; distance but not necessarily settling into a new place, which is what Flock needs. SLCs also come at a significant user perception cost because if your app registers for them, iOS will always show a solid location services arrow. &lt;/span&gt;&lt;/strong&gt;&lt;strong style="font-family: Times; font-size: medium; font-weight: normal;"&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;Always&lt;/span&gt;&lt;/strong&gt;&lt;strong style="font-family: Times; font-size: medium; font-weight: normal;"&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt; (Even though iOS&amp;#8217;s internal Traffic monitoring tools on your device use the same APIs but don&amp;#8217;t show the arrow). This gives users the perception that the app always has the GPS on and is constantly consuming large amount of battery power, which is not really the case.&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;Android on the other hand generally gives you access to much lower level data. You can register to listen to location updates on different location providers (GPS, Wi-Fi, Cell Tower Triangulation), and you can set up your app to be woken up at a certain time in the future and check these services yourself. This low level control gives developers a really easy way to shoot themselves in the foot by mistakenly asking for location too often (thus causing massive battery drain). But it also lets us be much more in control with our algorithm, giving us simpler ways to get to the information that we really want.&lt;/span&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;All in all, it was a blast getting the Android version of Flock ready for prime time. We are super excited to have the app out there for general public to use, and drastically increase the number of people you can share photos with on Flock.&lt;/span&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786221902</link><guid>http://devblog.bu.mp/post/40786221902</guid><pubDate>Tue, 18 Dec 2012 15:33:16 -0500</pubDate></item><item><title>My Summer Internship at Bump</title><description>&lt;p&gt;&lt;p class="p1"&gt;&lt;em&gt;This post was written by Andrew, a summer intern on Bump&amp;#8217;s client team.&lt;/em&gt;&lt;/p&gt;
&lt;p class="p1"&gt;Deciding where to intern is a big decision, or at least it was for me. Having never interned at a company before, I didn’t really know what to expect but knew what I wanted. I wanted to work on interesting problems, have freedom to create, and work with great people. With these considerations in mind, I chose to intern at Bump.&lt;/p&gt;
&lt;p class="p1"&gt;&lt;strong&gt;Work&lt;br/&gt;&lt;/strong&gt;I came into Bump as an Android developer. Prior to Bump, I had some experience with the framework – I’d published an app. However, I still had much to learn (better realized after my internship).&lt;/p&gt;
&lt;p class="p1"&gt;One of the most integral skills to software development is being able to reason at multiple levels of abstraction, and this is a skill my experience at Bump helped me hone. The Bump Android app is complex, but necessarily so. The app makes use of many of Android’s facilities, including that for embedded native code. The app must take into account the interaction between UI actions and network events, and does so nicely. When working on the Bump app, the professionalism with which it was created is noticeable. Looking back, I think my appreciation for the app’s structure is a testament to what I learned over the summer regarding modularity and reusable code design. Sure, anybody learns in school how to write generic code inside a few source files, but what about writing a component composed of many source files which must interact with a much larger machine?&lt;/p&gt;
&lt;p class="p1"&gt;Another key skill I developed at Bump was working on a large codebase with other people. I am now infinitely more familiar with git than I was at the start of the summer, including managing projects with submodules. I think the day-to-day aspects of software development such as version control, setting up build environments, and team communication are under-emphasized in school and am glad for the experience I gained at Bump.&lt;/p&gt;
&lt;p class="p1"&gt;&lt;strong&gt;Freedom&lt;br/&gt;&lt;/strong&gt;An aspect of the work I did at Bump that I really enjoyed was the freedom I was given. The nature of the problems I solved at Bump was not “do this in O(whatever) runtime”. No, I was tasked with solving real problems the company faced – high level problems – and was given guidance in solving them. I found this freedom to be pervasive throughout my internship experience. For instance, I needed a lightweight way to log data from tests I was running and, even though I’m an Android developer, was able to play around with CherryPy to write a logging system. If I had questions, I was able to ask one of CherryPy’s lead developers – he works at Bump.&lt;/p&gt;
&lt;p class="p1"&gt;Freedom to do things the way you want is embedded into the culture of Bump. The Android developers use IntelliJ because they like its memory usage and code completion better than Eclipse. However, if you want to use Eclipse, you can. Want to run Eclipse inside an Ubuntu VM? Go for it. How about forgoing the whole thing and just using vim and a terminal? Your choice.&lt;/p&gt;
&lt;p class="p1"&gt;The openness and willingness to try new things as a company is one of my favorite aspects of Bump.&lt;/p&gt;
&lt;p class="p1"&gt;&lt;strong&gt;Life&lt;br/&gt;&lt;/strong&gt;As I’m still in college (Stanford ‘14), life at work was a major factor in deciding where to intern – Bump does not disappoint. I think it’s pretty cool when you can play Berlin-style ping pong and sing karaoke at work. The people at Bump are great and fun to be around. While people take their work seriously, they don’t take themselves too seriously.&lt;/p&gt;
&lt;p class="p2"&gt;Speaking of ‘seriously’, you may be wondering what the hours are like. Most people don’t show up until around 10 which was great for me. People generally leave around 7 but there is no set time. Personally, I’d usually leave around 8, but that was voluntary – I just figured that experiences like these don’t come too often and wanted to make the most of it. However, the culture is flexible – a few days I had to leave around 5:30 and would, no questions asked. The emphasis at Bump is on the actual work you do, not the time. That said, if you don’t want to &lt;em&gt;work&lt;/em&gt;, don’t work at Bump. At Bump, you will work but you’ll have fun doing it.&lt;/p&gt;
&lt;p class="p3"&gt;&lt;strong&gt;Food&lt;br/&gt;&lt;/strong&gt;Food was great – would eat again.&lt;/p&gt;
&lt;p class="p2"&gt;At Bump, you’re surrounded by food. The company has a snack bar and refrigerator of drinks which get replenished weekly. You can have as many snacks/drinks as you want whenever you want. The company provides two catered lunches per week. Lunches range from Indian food to Pakistani to Jamaican. There were times when I would have preferred a burger or pizza, but I took the opportunity as a great time to expand my palate. Most importantly, when Bump gets food catered, there is a lot of it. There are usually leftovers which is awesome for the days following catered lunch days. Bump’s also really close to Castro Street which has more food than you can eat in a summer (I tried) and there is almost always a group willing to go grab something. For the company I’m not sure how the unlimited food model works – my productivity definitely went down during the post-lunch food coma, but for me it was great.&lt;/p&gt;
&lt;p class="p2"&gt;&lt;strong&gt;Should I Work There?&lt;br/&gt;&lt;/strong&gt;If you’re reading this, you’re probably asking yourself that question (otherwise, you have a lot of free time and/or enjoy reading intern blogs).While we both know there’s no definitive answer, Bump has my recommendation. I had a great time interning at Bump and the rest of the interns my year seemed to have very positive experiences as well. Ultimately, you’re going to have to go with your gut. I did, and it was one of the best decisions I’ve made.&lt;/p&gt;&lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786223146</link><guid>http://devblog.bu.mp/post/40786223146</guid><pubDate>Thu, 27 Sep 2012 14:29:00 -0400</pubDate></item><item><title>Martin Gardner had a timing attack for your mind (1956).  </title><description>&lt;p&gt;&lt;p class="p1"&gt;&lt;em&gt;This post was written by Seth, Bump&amp;#8217;s resident iOS Magician.&lt;/em&gt;&lt;/p&gt;

&lt;p style="margin-top: 0px !important; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding: 0px; line-height: 1.4em;"&gt;&lt;span style="line-height: 1.4em;"&gt;&lt;a href="http://en.wikipedia.org/wiki/Martin_gardner"&gt;Martin Gardner&lt;/a&gt; was a math and science writer, who also was a magician. In one of his books, he teaches a magic trick that bears some similarities to a more recent technique for stealing passwords from systems that are using an insecure HMAC checking algorithm.&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin: 15px 0px; padding: 0px; line-height: 1.4em;"&gt;So, let&amp;#8217;s bring together &lt;a href="http://en.wikipedia.org/wiki/HMAC#Security"&gt;HMAC security&lt;/a&gt;, mathematician Martin Gardner, magic, and a timing attack on your brain (and throw in app virality at the end). Do I have your attention yet, Hacker News?&lt;/p&gt;
&lt;p style="margin: 15px 0px; padding: 0px; line-height: 1.4em;"&gt;What is a Timing Attack?&lt;/p&gt;
&lt;p style="margin: 15px 0px; padding: 0px; line-height: 1.4em;"&gt;A &lt;a href="http://en.wikipedia.org/wiki/Timing_attack"&gt;timing attack&lt;/a&gt; uses information leaked by a computer system based on the amount of time it takes for something to happen. For example, let&amp;#8217;s imagine I want to compare two strings for equality (say to check a password (which you would never want to do!)): &amp;#8220;Hello World!&amp;#8221; and &amp;#8220;¡Hola Mundo!&amp;#8221;. A simple algorithm could compare letter by letter, and return false as soon as one character doesn&amp;#8217;t match. In this case, no characters match, so it would return pretty fast. If I were comparing &amp;#8220;Hello World!&amp;#8221; to &amp;#8220;Hello Wormy!&amp;#8221;, the algorithm would have to compare 10 characters, and so would take 10 times as long (factoring out the parts of the function that are run on every call). Using this timing information (on a sufficiently slow machine), you could uncover the password, one letter a time by simply iterating over each possible letter until the algorithm took a little longer, and then proceed to do the next character in the password.&lt;/p&gt;
&lt;p style="margin: 15px 0px; padding: 0px; line-height: 1.4em;"&gt;This overly-simplified timing attack is similar to a real potential attack to using HMACs.&lt;/p&gt;
&lt;p style="margin: 15px 0px; padding: 0px; line-height: 1.4em;"&gt;Magic Trick?&lt;/p&gt;
&lt;p style="margin: 15px 0px; padding: 0px; line-height: 1.4em;"&gt;Martin Gardner described a timing attack on your mind in his book &amp;#8216;&lt;a href="http://www.amazon.com/Mathematics-Magic-Mystery-Dover-Recreational/dp/0486203352"&gt;Mathematics, Magic and Mystery&lt;/a&gt;&amp;#8217; in 1956. It is a magic trick called &amp;#8220;Divining a Number&amp;#8221; which involves discovering the number that your spectator is merely thinking of.&lt;/p&gt;
&lt;p style="margin: 15px 0px; padding: 0px; line-height: 1.4em;"&gt;You may have heard of simpler magic tricks where you ask someone to think of a number, perform some math, and then can tell them the number they end up on. This magic trick is different. You tell them the number they originally thought of, and they never tell you any of the results of their mental math.&lt;/p&gt;
&lt;p style="margin: 15px 0px; padding: 0px; line-height: 1.4em;"&gt;You ask them to think of a number, have them do some mental math, without saying anything, and then you know which number they thought of.&lt;/p&gt;
&lt;p style="margin: 15px 0px; padding: 0px; line-height: 1.4em;"&gt;You discover the thought-of-number by using a timing-attack like process on their mental math. A simple example:&lt;/p&gt;
&lt;p style="margin: 15px 0px; padding: 0px; line-height: 1.4em;"&gt;Think a number: 8 or 9 (a simple choice of two numbers).&lt;/p&gt;
&lt;p style="margin: 15px 0px; padding: 0px; line-height: 1.4em;"&gt;Now, divide that number by 2.&lt;/p&gt;
&lt;p style="margin: 15px 0px; padding: 0px; line-height: 1.4em;"&gt;To be fair, you are probably better at mental math than the average person by virtue of the fact that you are reading this article, but it is signifcantly easier for most people to divide an even number by 2 than an odd number. So, by watching your face as you did this mental math, I could tell you which number you were thinking of. If you were really fast, you were thinking of 8, slow means 9.&lt;/p&gt;
&lt;p style="margin: 15px 0px; padding: 0px; line-height: 1.4em;"&gt;If you add a few more mental math timings, you can expand the original range of choices from 2, up to 10. Martin Gardner describes the whole (rather complicated) procedure in his book.&lt;/p&gt;
&lt;p style="margin: 15px 0px; padding: 0px; line-height: 1.4em;"&gt;Martin Gardner didn&amp;#8217;t invent the technique (he heard about it from Edmund Balducci), and it is based on several tricks found in &amp;#8220;The Magician&amp;#8217;s Own Book&amp;#8221; published in 1862! Timing attacks go way back!&lt;/p&gt;
&lt;p style="margin: 15px 0px; padding: 0px; line-height: 1.4em;"&gt;App Virality?&lt;/p&gt;
&lt;p style="margin-top: 15px; margin-right: 0px; margin-bottom: 0px !important; margin-left: 0px; padding: 0px; line-height: 1.4em;"&gt;I&amp;#8217;m a magician, and also a software engineer at Bump. Part of my job is to explore using the theory behind magic tricks (including mental timing attacks) to improve our app&amp;#8217;s virality. If you want to learn how, or if you want instructions for the full magic trick, e-mail &lt;a rel="noreferrer" style="margin: 0px; padding: 0px; line-height: 1.4em; color: #4183c4;"&gt;&lt;/a&gt;&lt;a href="mailto:seth@bu.mp"&gt;seth@bu.mp&lt;/a&gt;&amp;#160;!&lt;/p&gt;&lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786223985</link><guid>http://devblog.bu.mp/post/40786223985</guid><pubDate>Fri, 17 Aug 2012 10:12:00 -0400</pubDate></item><item><title>A Bump Up - Reflections on Startup Life</title><description>&lt;p&gt;&lt;em&gt;This post was written by Greg, a summer intern on Bump&amp;#8217;s server team.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Internships are such a fantastic opportunity to explore different companies, work cultures, and cities that I sometimes wish I could forever do internships, trying and learning a little bit of everything, everywhere. Alas, there are only a &lt;a href="http://xkcd.com/1070/"&gt;couple&lt;/a&gt; summers as an undergraduate to be an intern, so I wanted to pack in as much learning and fun as possible.&lt;/p&gt;
&lt;p&gt;After a solid first internship with Amazon&amp;#8217;s Kindle division in Seattle last summer, I wanted to explore the opposite end of the tech company spectrum for my second internship, so I could make more well-informed career decisions after graduation. Bump caught my attention very early in the internship search. It was a small company working with open source software developing a truly one-of-a-kind product that makes life easier for tens of millions of users. A userbase of that size provides a great opportunity for machine learning, exposure to real-world architectural and scaling challenges, and a guarantee that my work would have a big impact.&lt;/p&gt;

&lt;p&gt;My interest in Bump only grew during the interview process. Bump&amp;#8217;s programming challenge and interview questions were practical and engaging, which was a refreshing change from the slew of linked-list manipulation, string-integer conversion, and fizzbuzz questions I had been answering in other interviews at the time. Before I knew it, I was on my way to California for the first time, and to the heart of Silicon Valley at that!&lt;/p&gt;
&lt;p&gt;The first week was a bit overwhelming; it took a while to get used to the unstructured start-up environment and to learn who to ask for help. Once past these initial roadbumps however, I’ve gotten the chance to explore a variety of cool projects with the server and data teams and am still learning a ton everyday. In reflecting on my time here, I&amp;#8217;m very grateful for a few qualities of this internship that exceed my experiences from last summer, especially these three things:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Important work. While the project I worked on at Amazon was a neat idea that would have improved the Kindle experience for tens of thousands of people, it was more of a nice-to-have feature than anything else. I found out later that, unfortunately, it was shelved after I left because there were more valuable things to work on. This is not an issue with Bump. Because the company is so small and the userbase is so large, everyone&amp;#8217;s work is critical (even interns’) and there is no shortage of important work to take on. The effort of a single person here can have a very visible impact on the product, and consequently, on the lives of millions of people. It’s exciting that my work on debugging tools and analytics will directly improve the service and experience for all of Bump’s users.&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Speed. I feel like I&amp;#8217;ve accomplished more at Bump already than I did all of last summer. The pace throughout the company is very fast, and it works because everyone has a &amp;#8220;get things done&amp;#8221; mindset. There aren&amp;#8217;t any obligations to distant departments or chains of managers to go through, and everyone in the company is within a 10 second walk of my desk, making it easy to ask questions and clear obstacles. The speed is a great motivator, as well, because progress is evident and exciting as we rapidly approach our goals.  &lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Fun culture. Amazon had very cool weekly tech talks by senior engineers and also brought in various performers and artists (I even got to meet my favorite author, GRRM!). Aside from these events though, the majority of my work culture experience at Amazon was dominated by the company policy of frugality. I have a lot of respect for that policy and all the work Amazon puts into lowering prices and improving service for consumers, but I feel that having a much brighter, more open office with a few games and snacks has greatly improved my mood while at the office. I appreciate that &amp;#8212; when I get stuck on a problem &amp;#8212; I can get up, be active, and talk through the problem with a coworker over a game of ping pong. By the time I return to my desk, I can see the solution to the problem or I will at least have a new perspective or approach for tackling it. Little things like this, plus organized company events such as trivia night and ultimate frisbee matches against other startups have made the entire internship experience more enjoyable.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;
&lt;p&gt;I’ve found that qualities such as these are very important to me not only today as an intern, but also as an eventual career-seeker. Bump has been successful at not only attracting smart, like-minded people, but also cultivating a positive and playful work culture where everyone motivates each other to build the best product they can imagine. Needless to say, I&amp;#8217;m excited to be a part of this team and to continue building and learning here for the rest of the summer!&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786224607</link><guid>http://devblog.bu.mp/post/40786224607</guid><pubDate>Sat, 16 Jun 2012 14:22:00 -0400</pubDate></item><item><title>A Bump Up</title><description>&lt;p class="p1"&gt;&lt;em&gt;This post was written by Greg, a summer intern on Bump&amp;#8217;s server team.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong style="font-family: Times; font-size: medium; font-weight: normal;"&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;Internships are such a fantastic opportunity to explore different companies, work cultures, and cities that I sometimes wish I could forever do internships, trying and learning a little bit of everything, everywhere. Alas, there are only a &lt;/span&gt;&lt;span style="font-size: 15px; font-family: Arial; color: #1155cc; background-color: transparent; vertical-align: baseline;"&gt;&lt;a href="http://xkcd.com/1070/" target="_blank"&gt;couple&lt;/a&gt; &lt;/span&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;summers as an undergraduate to be an intern, so I wanted to pack in as much learning and fun as possible.&lt;/span&gt;&lt;br/&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt; &lt;/span&gt;&lt;br/&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;After a solid first internship with Amazon&amp;#8217;s Kindle division in Seattle last summer, I wanted to explore the opposite end of the tech company spectrum for my second internship, so I could make &lt;/span&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;more well-informed career decisions after graduation. Bump caught my attention very early in the internship search. It was a small company working with open source software developing a truly one-of-a-kind product that makes life easier for tens of millions of users. A userbase of that size provides a great opportunity for machine learning, exposure to real-world architectural and scaling challenges, and a guarantee that my work would have a big impact.&lt;/span&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;My interest in Bump only grew during the interview process. Bump&amp;#8217;s programming challenge and interview questions were practical and engaging, which was a refreshing change from the slew of linked-list manipulation, string-integer conversion, and fizzbuzz questions I had been answering in other interviews at the time. Before I knew it, I was on my way to California for the first time, and to the heart of Silicon Valley at that!&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;The first week was a bit overwhelming; it took a while to get used to the unstructured start-up environment and to learn who to ask for help. Once past these initial roadbumps however, I’ve gotten the chance to explore a variety of cool projects with the server and data teams and am still learning a ton everyday. In reflecting on my time here, I&amp;#8217;m very grateful for a few qualities of this internship that exceed my experiences from last summer, especially these three things:&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong style="font-family: Times; font-size: medium; font-weight: normal;"&gt;&lt;strong style="font-weight: normal;"&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;Important work. While the project I worked on at Amazon was a neat idea that would have improved the Kindle experience for tens of thousands of people, it was more of a nice-to-have feature than anything else. I found out later that, unfortunately, it was shelved after I left because there were more valuable things to work on. This is not an issue with Bump. Because the company is so small and the userbase is so large, everyone&amp;#8217;s work is critical (even interns’) and there is no shortage of important work to take on. The effort of a single person here can have a very visible impact on the product, and consequently, on the lives of millions of people. It’s exciting that my work on debugging tools and analytics will directly improve the service and experience for all of Bump’s users.&lt;br/&gt; &lt;/span&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong style="font-family: Times; font-size: medium; font-weight: normal;"&gt;&lt;strong style="font-weight: normal;"&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;Speed. I feel like I&amp;#8217;ve accomplished more at Bump already than I did all of last summer. The pace throughout the company is very fast, and it works because everyone has a &amp;#8220;get things done&amp;#8221; mindset. There aren&amp;#8217;t any obligations to distant departments or chains of managers to go through, and everyone in the company is within a 10 second walk of my desk, making it easy to ask questions and clear obstacles. The speed is a great motivator, as well, because progress is evident and exciting as we rapidly approach our goals.  &lt;br/&gt; &lt;/span&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong style="font-family: Times; font-size: medium; font-weight: normal;"&gt;&lt;strong style="font-weight: normal;"&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;Fun culture. Amazon had very cool weekly tech talks by senior engineers and also brought in various performers and artists (I even got to meet my favorite author, GRRM!). Aside from these events though, the majority of my work culture experience at Amazon was dominated by the company policy of frugality. I have a lot of respect for that policy and all the work Amazon puts into lowering prices and improving service for consumers, but I feel that having a much brighter, more open office with a few games and snacks has greatly improved my mood while at the office. I appreciate that &amp;#8212; when I get stuck on a problem &amp;#8212; I can get up, be active, and talk through the problem with a coworker over a game of ping pong. By the time I return to my desk, I can see the solution to the problem or I will at least have a new perspective or approach for tackling it. Little things like this, plus organized company events such as trivia night and ultimate frisbee matches against other startups have made the entire internship experience more enjoyable.&lt;/span&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong style="font-family: Times; font-size: medium; font-weight: normal;"&gt;&lt;br/&gt;&lt;span style="font-size: 15px; font-family: Arial; background-color: transparent; vertical-align: baseline;"&gt;I’ve found that qualities such as these are very important to me not only today as an intern, but also as an eventual career-seeker. Bump has been successful at not only attracting smart, like-minded people, but also cultivating a positive and playful work culture where everyone motivates each other to build the best product they can imagine. Needless to say, I&amp;#8217;m excited to be a part of this team and to continue building and learning here for the rest of the summer!&lt;/span&gt;&lt;br/&gt;&lt;/strong&gt;&lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786225477</link><guid>http://devblog.bu.mp/post/40786225477</guid><pubDate>Sat, 16 Jun 2012 13:57:00 -0400</pubDate></item><item><title>From MongoDB to Riak</title><description>&lt;p&gt;&lt;em&gt;This post is written by Tim on Bump&amp;#8217;s server team&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="line-height: 17px; font-family: Arial, sans-serif;"&gt;At Bump Technologies, we recently completed a significant database migration from MongoDB to Riak. Almost all of our users&amp;#8217; data &amp;#8212; the lists of people they&amp;#8217;ve bumped, communications sent and received, handset information, social network OAuth tokens, etc. &amp;#8212; had been stored in MongoDB, but if you open the app today all of these interactions will be backed by Riak.&lt;/span&gt;&lt;/p&gt;
&lt;div style="padding-right: 1px;"&gt;

&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;A few months ago we had migrated our datastore containing individual communication contents from MongoDB to Riak, so these databases and general migration techniques were not entirely foreign to us, but any time you have to move data while keeping the system online, it&amp;#8217;s a unique and complicated challenge.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div style="padding-right: 1px;"&gt;&lt;span style="text-decoration: underline; font-size: medium;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;&lt;strong&gt;Development obstacles&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;

&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;The largest development hurdle was dealing with the structured key-document nature of MongoDB vs. the key-value nature of Riak combined with the latter&amp;#8217;s eventual consistency. At Bump we use Google&amp;#8217;s Protocol Buffers extensively, for serialization to Riak and message passing between the Bump client and the server, and between server application nodes. In addition to being an efficient encoding, it also enforces types and provides for backwards- and forwards-compatibility. MongoDB&amp;#8217;s key-document knowledge and consistency model allow it to support, e.g., atomic list appends, which we would use to add to a user&amp;#8217;s list of communications when they sent one.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;Riak does not have any internal knowledge of how the Protocol Buffers we are storing are formed, and cannot guarantee the same kinds of consistency. Instead, we have to grab the value for the key, update it ourselves, and put it back in. That&amp;#8217;s easy (if a bit more verbose than what MongoDB does), but the difficulty comes when dealing with concurrency. One of our app nodes could get a user&amp;#8217;s record, then append the communication the user just sent, and save it to Riak. The database, being eventually consistent, cannot guarantee that when another app node gets the record it contains the communication just written. If the second app node then makes changes and overwrites the key with their new value, data will be lost. &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;

&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;Riak is pretty smart, though, and will save both of these values. Upon the next get, it will return the two valid values (if, that is, the node has received both!), leaving it up to the app to deal with the multiple truths. With appropriate logic (set unions, timestamps, etc) it is easy to resolve these conflicts, but dealing with this everywhere a database fetch happens is cumbersome. Instead, we&amp;#8217;ve written a thousand-line Haskell program that acts as an interface between the app nodes and the database, which exclusively deals with conflict resolution and sibling merges. Every Riak interaction is done through this tool that we&amp;#8217;ve dubbed /magicd/, which guarantees the app nodes always see a consistent truth. This obviates the largest pain point of eventually consistent databases.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;After evaluating our migration options, we decided to approach it on-the-fly. The other significantly considered technique was migrating in parallel; everywhere Mongo was written we would append a write to Riak, and everywhere a Mongo read was done it would be prefixed with a read from Riak, falling back to Mongo if the data had not been migrated. This two-database parallel approach was appealing in that if something horrible happened during the transition, we could revert to pre-migration behavior (i.e., drop all of the Riak code), and the data would be consistent and up-to-date in Mongo as before.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;

&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;The difficulty with this approach was that, despite almost all of our database interactions being encapsulated in a class, there were a few scattered circumstances in which the database was written to outside of the class. Those instances, of course, were only a grep away, but the significant amount of code / logic duplication for those special-cased interactions was a deterrent.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;Instead, we decided to migrate all of the users&amp;#8217; data on the fly on login. With the first packet received from the handset, we block all other communication until the user has had all of its data written to Riak. It then proceeds as normal, with all other database interactions in the server codebase having been converted to use Riak exclusively. The upside of this compared to the previous parallel approach was simplicity; s/mongo/riak/g and call it a day, instead of handling two data code paths. The downside was that a rollback to Mongo in case of significant errors could lose data, either temporarily if the new data written to Riak was recoverable, or permanently if not. Despite the downside, with extensive testing we were able to ferret out any bugs that would result in data loss, and suffered none on roll out.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;
&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;&lt;strong&gt;&lt;span style="text-decoration: underline;"&gt;Post-deployment obstacles&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;

&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;Significant testing before rollout could nevertheless not definitively show us all of the bugs that existed. Specifically, we encountered a few errors that were only made evident with production data and traffic.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;The first issue we saw after deployment was one of our Redis instances complaining about hitting its maximum connection limit. We use Redis throughout Bump&amp;#8217;s backend, performing a number of duties including queueing, session caching, and even geolocation mapping. Using it as a networked locking mechanism for migration purposes was a natural progression. The code we wrote, now included as part of the diesel async framework we use, did not appropriately close the connection in some circumstances. With that fixed, the Redis connections dropped to a normal and expected number.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;

&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;The second class of issues we encountered was a product of the relaxed schema of Mongo and the strict serialization of Protocol Buffers. There&amp;#8217;s no way to enforce types for values within a Mongo document; an integer may be stored as an integer, or a string representation of the same, for example. Depending on the leniency of application code, this fast-and-loose typing may be acceptable.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;Protocol Buffers are much more strict about the types they accept. If one tries to assign a string to a value defined as an int32 in the protobuf definition file, it will refuse to be serialized. This manifested itself in our code when we tried to serialize the Apple Push Notification Service token; in some circumstances, it contained characters that broke when being parsed as a Protocol Buffers string; changing that type to bytes fixed the issue. This modification of the definition file preserved backwards-compatability because strings and bytes are stored in serialized format in the same way.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;

&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;Unlike JSON/BSON where there is no defined schema and one can throw in any values they desire, Protocol Buffers can specify required fields. A object that must have a user_id, for example, cannot be serialized without that field set. This does wonders when doing client-server communication or serialization to a database, for contracts can be made and consistently followed. During the migration, there were a number of fields that should have been set in Mongo but were not. Luckily, they were comparatively menial values &amp;#8212; last seen Bump version number and locale for a user, for example &amp;#8212; but their lack of existence in Mongo caused their migration pipeline to break. Setting empty locales and 0.0.0 version numbers was deemed a satisfactory resolution considering the importance of the data.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;With the above issues solved, our Python processes stopped spewing hundreds of exceptions, and things on the app node side seemed to be cooling down. At this point, we turned our attention to Riak load; we started to see latencies rise to concerning levels. In addition, we started receiving user reports that database-heavy operations were acting slower than they had prior. Further investigation showed that our magicd processes were pegging the CPU, so as a temporary fix, we increased the number of threads the process would spawn. Benchmarking revealed that magicd was serializing and deserializing every protobuf that went through it; this was only necessary when siblings existed and needed to be resolved, so fixing it so deserialization only occurred when required reduced load to a more manageable level.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;

&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;While this helped magicd CPU requirements, we were still seeing elevated Riak latencies. Investigating the logs showed some particularly abnormal behavior on one node in particular; upon sshing in and poking around, it became apparent that one of its disks had failed. Shutting down the riak daemon on that node caused to latencies fall back to normal levels. After getting the disk issues resolved, we were able to bring the node back online. Thankfully due to Riak&amp;#8217;s destributed nature, a missing node in the cluster was not a problem; we still saw great performance.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-size: medium;"&gt;&lt;strong&gt;&lt;span style="text-decoration: underline;"&gt;Post-Mortem&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;We decided to move to Riak because it offers better operational qualities than MongoDB. Despite the migration hiccups, we&amp;#8217;re pleased with the process and the result. Now we no longer care if one of the nodes kernel panics in the middle of the night; as has happened a few times already. Nagios will email us instead of page us, and over coffee the next morning we&amp;#8217;ll fire up IPMI, reboot the machine, and Riak will read-repair as necessary. No longer will we have to do any master-slave song and dance, nor will we fret about performance, capacity, or scalability; if we need more, we&amp;#8217;ll just add nodes to the cluster. &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;

&lt;div style="padding-right: 1px;"&gt;&lt;span style="font-family: Arial, sans-serif;"&gt;&lt;span style="line-height: 17px;"&gt;If you have any questions about our experience, or want to work with us on this joyful stack (we&amp;#8217;re hiring!) &amp;#8212; shoot me an email: &lt;a href="mailto:timdoug@bu.mp"&gt;timdoug@bu.mp&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786226011</link><guid>http://devblog.bu.mp/post/40786226011</guid><pubDate>Mon, 14 May 2012 17:09:00 -0400</pubDate></item><item><title>git for dropbox users: Don't be afraid!</title><description>&lt;h1&gt;git is awesome&lt;/h1&gt;

&lt;p&gt;We use git at Bump for all sorts of things.  Recently, we’ve started converting our designers and product managers. You can think about git like Dropbox: it takes files on your computer, puts them in the cloud, and lets other people work on them too.  But it has some pretty rocking advantages:&lt;/p&gt;

&lt;h3&gt;Collaboration&lt;/h3&gt;

&lt;p&gt;Like Dropbox, git lets multiple people work on the same files at the same time.  This is great when many people are working on a document together, or a group of people are creating assets for a website.  Everyone can be contributing to the same folder and files, without fear of overwriting eachother’s work, something Dropbox can scew up.&lt;/p&gt;

&lt;h3&gt;Time Machine&lt;/h3&gt;

&lt;p&gt;Even if you don’t have a team of people, git has some awesome-sauce.  It can act like a time machine, allowing you go and see what you did last week, or even last year, help you recover files you deleted, and keep track of progress over time.  It has powerful tools to let you see what you’ve changed over time.&lt;/p&gt;

&lt;h3&gt;And More&lt;/h3&gt;

&lt;p&gt;git is also great for backing things up, so you don’t lose them. It can let you learn about how you work: when do you do your best work? How often do you change everything? There are tools to show you visual differences between versions of images, and all sorts of things.&lt;/p&gt;

&lt;h1&gt;but&lt;/h1&gt;

&lt;p&gt;git is awesome… but conceptually it’s a leap from most people’s mental models of what a file is.&lt;/p&gt;

&lt;p&gt;There are so many wonderful reasons for non-programmers to use git when working with other people (especially programmers) and I’d like to convince you that there are even more awesome rewards down the way of git, but I won’t do that today.&lt;/p&gt;

&lt;p&gt;My goal today:&lt;/p&gt;

&lt;blockquote class="posterous_short_quote"&gt;&lt;p&gt;Provide an analogy to Dropbox to help designers and product managers understand the mental model of how git works.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;It might help you to think about git like Dropbox to start. It’s like Dropbox but with a whole lot more steps. Have faith (for the moment) that the more steps are worth it, and I’ll talk you through the differences.&lt;/p&gt;

&lt;p&gt;First, a quick overview of how Dropbox works: many people can be working on the same file on their own computers, and magically they all get each other’s changes.  Behind the scenes Dropbox is doing all sorts of things to make this work.  With git, you end up helping do some of the behind the scenes work, and git thanks you.&lt;/p&gt;

&lt;h1&gt;As easy as 4… 5… 6!&lt;/h1&gt;

&lt;p&gt;Here is a more explicit model of how Dropbox works.&lt;/p&gt;

&lt;ol&gt;&lt;li&gt;You install Dropbox.&lt;/li&gt;
&lt;li&gt;Someone shares a folder with you.&lt;/li&gt;
&lt;li&gt;Your computer downloads the contents of that folder from the “Cloud”&lt;/li&gt;
&lt;li&gt;You make some changes to a file in the folder and save it.&lt;/li&gt;
&lt;li&gt;Your changes get sent up to the Dropbox “Cloud” immediately&lt;/li&gt;
&lt;li&gt;Everyone else gets your changes downloaded to their computers immediately.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Yay.  This is just like git! Only git lacks some of the “immediately” magic. Steps 4, 5, and 6 don’t happen automatically: you have to tell git when you want it to do each step. Let me break it down for you.&lt;/p&gt;

&lt;h3&gt;4) Saving… are you sure?&lt;/h3&gt;

&lt;p&gt;The first difference is that git doesn’t assume that you want to send every saved change to the cloud. It makes you be explicit about what you want to send to the cloud.&lt;/p&gt;

&lt;blockquote class="posterous_medium_quote"&gt;&lt;p&gt;Whereas Dropbox automatically uploads everything when you save it, git adds a new step: commitment. After you save a file, you must tell git that you are “committed” to this change.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;To do this, you do what is called “staging.” This is really just telling git which changes you were sure about.  This way, git doesn’t waste other people’s time if you make a draft you don’t like.&lt;/p&gt;

&lt;h3&gt;5) Uploading&lt;/h3&gt;

&lt;p&gt;Second difference: Dropbox uploads your files immediately. (It tries to anyway). git isn’t quite as eager to get things into the cloud.&lt;/p&gt;

&lt;blockquote class="posterous_medium_quote"&gt;&lt;p&gt;In git, uploading to the cloud is called “pushing.”  You are literally pushing the changes from your computer up in to the cloud.  Only then will other people be able to download them.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h3&gt;6) Downloading&lt;/h3&gt;

&lt;p&gt;The next difference is downloading. Can you spot the difference? Why, that’s right! While Dropbox downloads the new changes automatically, git waits for you to tell it too.&lt;/p&gt;

&lt;blockquote class="posterous_medium_quote"&gt;&lt;p&gt;You must ask git explicitly to “pull” the changes down from the cloud to your computer.  This gives you the latest greatest copy of the documents, including everyone else’s changes&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Stay strong! Keep faith that even though there is seemingly less magic, and more work, there are reasons for all this mortal toil [sic]!&lt;/p&gt;

&lt;h3&gt;Ordering, or 6… 4… 6… 5…???&lt;/h3&gt;

&lt;p&gt;git requires you to operate with a slightly different order of operations because it is more manual (slightly less magic).&lt;/p&gt;

&lt;p&gt;Before you start changing things, you want to make sure you have the latest and greatest version with everyone else’s changes.  That means the first thing you want to do is download the latest stuff from the cloud (i.e. do a pull).&lt;/p&gt;

&lt;p&gt;Now that you have the latest, you can change it and edit it to your heart’s content.  When you are happy with your changes you are ready to tell git you’re happy (i.e. commit).&lt;/p&gt;

&lt;blockquote class="posterous_short_quote"&gt;&lt;p&gt;You can also rinse lather and repeat step 4 many times, committing small changes before going to the next step.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;But wait a second! What if Brian in marketing changed the document WHILE you were working on it? Because git doesn’t automatically download the changes, your computer (and you, by extension) doesn’t know about the new changes. So this adds another step, redownloading (i.e. doing another pull!)&lt;/p&gt;

&lt;p&gt;Okay, now git knows about your changes, it knows about Brian’s changes, and the only thing left to do is… Push!  Finally we can upload our changes to the cloud for everyone else to see and look at.&lt;/p&gt;

&lt;h3&gt;That’s the gist of git.&lt;/h3&gt;

&lt;p&gt;It’s like Dropbox, but you have to tell it to download, save, download, and upload each time. (Pull, stage &amp;amp; commit, pull, and push)&lt;/p&gt;

&lt;p&gt;If you are digging it so far, let’s tackle some Advanced differences.&lt;/p&gt;

&lt;h1&gt;Advanced Differences&lt;/h1&gt;

&lt;p&gt;There are some other model differences between git and dropbox. The first are conflicts: what happens when two people change the same file. Another big one is the fact that git is “distributed,” i.e. there is no company holding the cloud for you… there can even be multiple clouds.&lt;/p&gt;

&lt;p&gt;Here are some quick overviews of salient differences.&lt;/p&gt;

&lt;h3&gt;Time Travel&lt;/h3&gt;

&lt;p&gt;Every commit makes a little tick on a timeline. git keeps track of EVERY little tick. That means you can zoom back in time, and watch as your document changes from day 0 to present.  You can see every change, along with who made it, and what there “commit message” was. Pretty cool.&lt;/p&gt;

&lt;blockquote class="posterous_short_quote"&gt;&lt;p&gt;git has multi-player undo
You can find out exactly who made the typo, and when and then fix it really easily. (git has really awesome tools for this too).&lt;/p&gt;&lt;/blockquote&gt;

&lt;h3&gt;Conflict&lt;/h3&gt;

&lt;p&gt;What happens when Brian changed that file in the cloud, while you were working on it on your computer? Dropbox takes care of it magically in the cloud, now… it’s your job. The second step 6 (re-pulling changes from the cloud) in your work flow is when you are most likely to have “merge conflicts”.&lt;/p&gt;

&lt;blockquote class="posterous_medium_quote"&gt;&lt;p&gt;Usually git is pretty magical and figures out what to do if both you and Brian were editing the same file.
For example if he changed the title of the document, and you added some foot notes, git will figure it out. However, if you change your salary to $350,000, and Brian changes it to $40, git isn’t going to know what to do.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;If Brian pushed his change first, git will make you fix it.  It will say: “Brian said you make $40 an hour, but you said you make $350,000, who’s right”.  Your call.  Fix it, save it (commit it) and push it it! (but do pull it in case Brian caught his error and changed it to $400,000 while you were typing)&lt;/p&gt;

&lt;h3&gt;Meta Comments&lt;/h3&gt;

&lt;p&gt;Every time you save (commit really) some changes, git asks you for a “commit message”. This is couple of sentences that describe the changes you made: a brief overview so that someone could review the list of changes to this document, without having to read the whole thing.&lt;/p&gt;

&lt;h3&gt;Style&lt;/h3&gt;

&lt;p&gt;Because git is a little more manual, there are a few stylistic changes suggested to make everyone happy.  First of all, small changes.  You should commit every time you finish changing a coherent piece.  I.e. if you are changing your salary, and Brian’s, first make one commit with your increase and a commit message like “merit based salary adjustments”, then adjust Brian’s with a commit message of “balance the budget”. Good (informative) commit messages are very appreciated in git land.&lt;/p&gt;

&lt;p&gt;Due to the nature of fixing conflicts, git also prefers text.  Images are much harder for it (and you) to merge if both people change at once.  So whenever possible use a text format (like html or markdown).&lt;/p&gt;

&lt;h1&gt;Fin&lt;/h1&gt;

&lt;p&gt;Well, I don’t know if I convinced you that you HAVE to use git, but hopefully you understand it a little better now.  If you are already using it, hopefully now it makes a little more sense. At the very least, you are a step closer to being a friend and co-conspirator of git.&lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786227079</link><guid>http://devblog.bu.mp/post/40786227079</guid><pubDate>Wed, 29 Feb 2012 16:44:00 -0500</pubDate></item><item><title>Easy partial screen modals on iOS</title><description>&lt;div class="ii gt"&gt;
&lt;div&gt;
&lt;div style=""&gt;
&lt;div&gt;&lt;span style="color: #424037; font-size: 12px; line-height: 21px;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;This post was written by Anders from Bump&amp;#8217;s iOS team.&lt;/em&gt;&lt;/span&gt;&lt;/div&gt;

&lt;div&gt;Say you would want to present a modal view on an iPhone but you don&amp;#8217;t want it to be full screen. What do you do? Well, there is always the option of just not using presentModalViewController:animated: and performing the animations yourself which also in turn means maintaining view and controller hierarchy yourself. &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt;You could of course subclass UINavigationController and encapsulate all that complexity in a subclass. That would of course mean that you would need to update your code in all places that use the UINavigationController. Another similar approach would be to subclass UIView and override setFrame: to not allow the frame to be set to full screen. Again, that would mean updating all relevant views to subclass your new UIView subclass with the setFrame: logic.&lt;/div&gt;

&lt;div&gt;A different approach which lets you maintain your code pretty much unchanged requires you to change the way UINavigationController itself behaves. The following solution lets you set the frame of your UINavigationControllers view which will then be maintained even if a modal view controller is presented.&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt;All you need to to is call a static initializer method on this new NPNavigationController class:&lt;/div&gt;

&lt;div&gt;&lt;span style="color: #4d8186;"&gt;&lt;span style="color: #000000;"&gt;[&lt;/span&gt;BPNavigationController&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #30595d;"&gt;setup&lt;/span&gt;&lt;span style="color: #000000;"&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt;Now you can set the UINavigationControllers view frame. Like so:&lt;/div&gt;

&lt;div&gt;&lt;span style="color: #7141a3;"&gt;&lt;span style="color: #4d8186;"&gt;navigation&lt;/span&gt;&lt;span style="color: #000000;"&gt;.&lt;/span&gt;view&lt;span style="color: #000000;"&gt;.&lt;/span&gt;frame&lt;span style="color: #000000;"&gt; = &lt;/span&gt;&lt;span style="color: #3e227c;"&gt;CGRectMake&lt;/span&gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #2834cf;"&gt;0.0f&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #2834cf;"&gt;20.0f&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #2834cf;"&gt;320.0f&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #2834cf;"&gt;440.0f&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt;If at any later point you present a modal view controller in a navigation controller that modal view controller will only be as big as the frame of the navigations controllers view.&lt;/div&gt;

&lt;div&gt;How is this magic achieved? Behold:&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div&gt;&lt;div class="data"&gt;
    &lt;table class="lines highlight" cellspacing="0" cellpadding="0"&gt;&lt;tr&gt;&lt;td class="line_numbers"&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L1" id="file-bpnavigationcontroller-h-L1"&gt;1&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L2" id="file-bpnavigationcontroller-h-L2"&gt;2&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L3" id="file-bpnavigationcontroller-h-L3"&gt;3&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L4" id="file-bpnavigationcontroller-h-L4"&gt;4&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L5" id="file-bpnavigationcontroller-h-L5"&gt;5&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L6" id="file-bpnavigationcontroller-h-L6"&gt;6&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L7" id="file-bpnavigationcontroller-h-L7"&gt;7&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L8" id="file-bpnavigationcontroller-h-L8"&gt;8&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L9" id="file-bpnavigationcontroller-h-L9"&gt;9&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L10" id="file-bpnavigationcontroller-h-L10"&gt;10&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L11" id="file-bpnavigationcontroller-h-L11"&gt;11&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L12" id="file-bpnavigationcontroller-h-L12"&gt;12&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L13" id="file-bpnavigationcontroller-h-L13"&gt;13&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L14" id="file-bpnavigationcontroller-h-L14"&gt;14&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L15" id="file-bpnavigationcontroller-h-L15"&gt;15&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L16" id="file-bpnavigationcontroller-h-L16"&gt;16&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L17" id="file-bpnavigationcontroller-h-L17"&gt;17&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L18" id="file-bpnavigationcontroller-h-L18"&gt;18&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L19" id="file-bpnavigationcontroller-h-L19"&gt;19&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L20" id="file-bpnavigationcontroller-h-L20"&gt;20&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L21" id="file-bpnavigationcontroller-h-L21"&gt;21&lt;/span&gt;
          &lt;span rel="file-bpnavigationcontroller-h-L22" id="file-bpnavigationcontroller-h-L22"&gt;22&lt;/span&gt;
        &lt;/td&gt;
        &lt;td class="line_data" width="100%"&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC1"&gt;&lt;span class="c1"&gt;//&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC2"&gt;&lt;span class="c1"&gt;//  BPNavigationController.h&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC3"&gt;&lt;span class="c1"&gt;//  StatusBarSize&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC4"&gt;&lt;span class="c1"&gt;//&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC5"&gt;&lt;span class="c1"&gt;//  Created by Anders Borch on 10/16/11.&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC6"&gt;&lt;span class="c1"&gt;//  Copyright (c) 2011 Bump. All rights reserved.&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC7"&gt;&lt;span class="c1"&gt;//&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC8"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC9"&gt;&lt;span class="cp"&gt;#import &amp;lt;UIKit/UIKit.h&amp;gt;&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC10"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC11"&gt;&lt;span class="k"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;BPNavigationController&lt;/span&gt;&amp;#160;: &lt;span class="nc"&gt;UINavigationController&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC12"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC13"&gt;&lt;span class="cm"&gt;/*!&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC14"&gt;&lt;span class="cm"&gt; @method setup&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC15"&gt;&lt;span class="cm"&gt; @abstract Setup UINavigationController to handle non-fullscreen modals.&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC16"&gt;&lt;span class="cm"&gt; @discussion&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC17"&gt;&lt;span class="cm"&gt; This will replace the implementation of presentModalViewController:animated: with a new implementation &lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC18"&gt;&lt;span class="cm"&gt; which retains the original frame of the UINavigationController#view and pushes a &lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC19"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC20"&gt;&lt;span class="k"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC21"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-bpnavigationcontroller-h-LC22"&gt;&lt;span class="k"&gt;@end&lt;/span&gt;&lt;/div&gt;
        &lt;/td&gt;
      &lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;</description><link>http://devblog.bu.mp/post/40786228793</link><guid>http://devblog.bu.mp/post/40786228793</guid><pubDate>Tue, 18 Oct 2011 15:12:00 -0400</pubDate></item><item><title>Who said Android apps can’t look good?</title><description>&lt;p&gt;&lt;span style="color: #424037; font-size: 12px; line-height: 21px;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;This post was written by Indy from Bump&amp;#8217;s Android team.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Today we are releasing Bump 2.4 or what we have been calling the Visual Refresh&lt;/span&gt;&lt;span&gt;. Earlier this year we hired our first (and so far only, &lt;a href="http://bu.mp/jobs" target="_blank" style="color: #0000cc;"&gt;we&amp;#8217;re hiring&lt;/a&gt;) badass visual designer, Shona Dutta. Since then she’s been on a crusade to make our apps and everything else we present (including the recent &lt;a href="http://blog.bu.mp/thank-you-bump-users-all-50000000-of-you" target="_blank" style="color: #0000cc;"&gt;&lt;span&gt;infographic&lt;/span&gt;&lt;/a&gt;) look as awesome as our technology.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;So when it was time for the Android app to get it’s much needed facelift we wanted to jump on it right away. Unfortunately we were still finishing up some other major features in the app, so our team’s summer intern Will Whitney, cut a branch and started churning away (If you’re an awesome Android dev, this is why we need you, there are too many things to get done and we are currently only two people). He left about a month ago, and finally in the last two weeks we had the time to finish up the work he started.&lt;/p&gt;
&lt;p&gt;In the last 10 months we’ve learned a lot about the ins and outs and how to build a great app on Android. One of the things we learned quickly was people rightfully bagged on Android apps not looking as good as their iOS counterparts. But the reasons they pointed to were just plain wrong.&lt;/p&gt;
&lt;p&gt;It’s a common misunderstanding that Android apps are harder to program than iOS. People say it’s because the lifecycle behind Activities (Android’s rough equivalents of iOS UIViewControllers) are hard to work with. Not true, I think reading through the &lt;a href="http://developer.android.com/reference/android/app/Activity.html" target="_blank" style="color: #0000cc;"&gt;&lt;span&gt;documentation&lt;/span&gt;&lt;/a&gt; on that once should clear up a lot of confusion. People say it’s because the UI code is a bunch of messy xml. Not true, yes it’s xml, but it’s xml used in the way it should: declaratively and in a DRY manner. The xml based layouts are what make UI programming quite a lot nicer: one because it forces view code to be purely view code; two because simple parameter tweaking can produce great results.&lt;/p&gt;
&lt;p&gt;In fact I joke with our iOS team that android UI is ridiculously fast to iterate on. Case and point is the global network status bar we have on top of the new app. Whenever the network goes down or is unavailable on any screen of the app a thin black bar rolls down above the whole UI (squeezing the content area below it) letting the user know what went wrong. This simple squeezing of the UI and adding a view on top of every screen took less than two hours to put together.&lt;/p&gt;
&lt;p&gt;The real reason Android Apps historically haven’t looked good is because people haven’t put in the same care in building those apps. From a business sense that made sense in the past. Android has never been the primary platform for app users. But the rate of growth of the platform is phenomenal, and even if you believe that in general an Android user is less likely to use apps than an iOS user, the raw numbers should shock you into putting the same care into your Android app as your iOS app.&lt;/p&gt;
&lt;p&gt;So it’s finally here: &lt;a href="https://market.android.com/details?id=com.bumptech.bumpga" target="_blank" style="color: #0000cc;"&gt;&lt;span&gt;Bump 2.4 for Android&lt;/span&gt;&lt;/a&gt;. An App that finally looks as good as it works.&lt;/p&gt;
&lt;div class="p_embed p_image_embed"&gt;
&lt;img alt="Ss-480-1-7" height="854" src="http://getfile0.posterous.com/getfile/files.posterous.com/temp-2011-09-30/xAtEFcloBpaqCwiEIgdrdwxoicbFhBwlDCqenDdJbgBkJiuyyJHHniIbpIii/ss-480-1-7.jpeg.scaled500.jpg" width="480"/&gt;&lt;img alt="Ss-480-2-6" height="854" src="http://getfile5.posterous.com/getfile/files.posterous.com/temp-2011-09-30/BtIosoFkibvsAuDIshgJFjBpwwBpCtJkjglmAyelxrHiqsbiBshHxbgcqyii/ss-480-2-6.jpeg.scaled500.jpg" width="480"/&gt;&lt;div class="p_see_full_gallery"&gt;&lt;a href="http://devblog.bu.mp/who-said-android-apps-cant-look-good"&gt;See the full gallery on Posterous&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt; &lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786228091</link><guid>http://devblog.bu.mp/post/40786228091</guid><pubDate>Fri, 30 Sep 2011 13:48:41 -0400</pubDate></item><item><title>Bump's Visual Refresh for iOS</title><description>&lt;h3&gt;&lt;span style="border-collapse: collapse; font-family: arial, sans-serif; font-size: 13px; font-weight: normal;"&gt;
&lt;p&gt;&lt;span style="color: #424037; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: 21px; border-collapse: separate;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;This post was written by Shona from Bump&amp;#8217;s design team.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="p_embed p_image_embed"&gt;
&lt;a href="http://getfile6.posterous.com/getfile/files.posterous.com/temp-2011-06-27/qssfgrvwGGBzyAirpFfHakJDxjawFghuDpqBmekJpHJlzpnBpqAgzgGwdAhy/homescreen_compare.png.scaled1000.png"&gt;&lt;img alt="Homescreen_compare" height="373" src="http://getfile2.posterous.com/getfile/files.posterous.com/temp-2011-06-27/qssfgrvwGGBzyAirpFfHakJDxjawFghuDpqBmekJpHJlzpnBpqAgzgGwdAhy/homescreen_compare.png.scaled500.png" width="500"/&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Bump is simple. Right? You bump, and data is transferred from one phone to another. It can be anything from your contact info to photos to apps, but the premise is basic and totally functional. This was what I figured back when I started working on the visual redesign of the app.&lt;/p&gt;
&lt;p&gt;Three months later, my opinion has changed (kind of a lot). Bump is an incredibly complex, nuanced app that calls for a whole lot of visual interplay between screens, between elements on those screens, and across the whole application. It’s got hundreds of permutations and possibilities in what can be on the screen at any time. Fortunately I had the help of Abby, our UX designer here at Bump, when I undertook the work of giving Bump a visual “refresh.”&lt;/p&gt;
&lt;p&gt;Our choice was to make Bump more tactile. The app is based on the physical bumping of two phones, and there’s something really magical about highlighting a physical interaction in a world where you can talk with someone without ever seeing them, and show them photos without standing next to them. We love the fact that people get a kick out of making real contact when bumping. To carry that further, I decided to explore textures, shadows, and layering in the new design. These are things we see in real life and that make the app look touchable.&lt;/p&gt;
&lt;p&gt;Our homescreen background is paper-like; the buttons &amp;amp; graphics are tending toward a letter-pressed style; both of these are enormously tactile in appearance. Subtle dropshadows and glows give buttons, notes and bars the impression of popping up and out of the screen. This is all stuff we see everyday (just look at the pages of a book or the buttons on a TV). These details come from things we interact with and that we know how to use.&lt;/p&gt;
&lt;p&gt;At Bump we’re trying to capitalize on the intuitive understanding that people have of objects, buttons,  and icons, and use them in the app to help our users get where they want to go. In the end it’s all about making Bump easy, and a pleasure, to use.&lt;/p&gt;
&lt;p&gt;As with any large undertaking this project takes time. We’re only part-way finished with the redesign and we’re already looking ahead to a larger overhaul. But in the meantime I’m enjoying the new look we’ve injected into the app. It’s a huge step forward in making Bump even more a pleasure to use.&lt;/p&gt;
&lt;p&gt;&lt;span style="color: #424037; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: 21px; border-collapse: separate;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;Want to work with Shona and the rest of the Bump team? We are hiring: &lt;a href="http://bu.mp/jobs" style="color: #bc7134; text-decoration: none; padding: 0px; margin: 0px;"&gt;&lt;a href="http://bu.mp/jobs"&gt;http://bu.mp/jobs&lt;/a&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;
&lt;/span&gt;&lt;/h3&gt;</description><link>http://devblog.bu.mp/post/40786227691</link><guid>http://devblog.bu.mp/post/40786227691</guid><pubDate>Mon, 27 Jun 2011 15:24:00 -0400</pubDate></item><item><title>How we use Scala in Bump for Android</title><description>&lt;p&gt;&lt;span style="font-size: 12px; line-height: 21px; color: #424037;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;This post was written by Will from Bump&amp;#8217;s server team.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Since &lt;a href="http://devblog.bu.mp/ios-vs-android-from-the-trenches"&gt;Indy&amp;#8217;s post&lt;/a&gt; and &lt;a href="http://www.slideshare.net/michael.galpin/scala-on-android-experiences-at-bump-technologies"&gt;Michael and Indy&amp;#8217;s talk at Scala Days&lt;/a&gt;, many of you have been asking about how we used Scala for the Android version of Bump. I&amp;#8217;ll try to cover a little of the why (without getting to deep into the Scala v. Java battle) and then get into the how. But first, a little background.&lt;/p&gt;
&lt;p&gt;As with many startups, we&amp;#8217;re primarily limited by the number of developers we have working on projects and our Android team was no exception. After releasing 2.0 on iOS, Jamie and I (the server team at the time) had plenty of things we wanted to do to the server, but none of them seemed as pressing as bringing Android up to parity with iOS. Knowing the network stack better than most, we decided that Jamie and I would write the Service while Jake K. and Indy would switch over from iOS and write the Application layer. The final decision ended up being that the Service would be in Scala, whereas the Application would be in Java. So then, why did Jamie and I choose Scala?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why Scala?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;It has a lot of functional constructs we&amp;#8217;re used to and like. We use &lt;a href="http://devblog.bu.mp/haskell-at-bump"&gt;Haskell at Bump&lt;/a&gt; for various projects and we&amp;#8217;re both heavy users of the list comprehensions, first-class functions and other functional constructs that are available in Python. Scala let us express problems in a way we were used to.&lt;/li&gt;
&lt;li&gt;Scala works very well with existing Java frameworks. Android is, of course, one big Java framework and we were going to have to interface with it a lot. A number of people asked, given the above, why not use Clojure&amp;#8212;this is why.&lt;/li&gt;
&lt;li&gt;An Android Service can withstand higher latency. Scala runs a little slower than Java (I&amp;#8217;ve heard about 6x in benchmarks, but I&amp;#8217;d bet it&amp;#8217;s worse in Dalvik), but this was something we could tolerate. If an application takes 50ms extra to render a cell in a list, the user will most certainly notice. If, however, the Service takes 50ms more process something it had to fetch from the network, nobody cares&amp;#8212;it took 10x longer to do the network fetch anyway.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Why not Scala?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With all that out of the way, it&amp;#8217;s worth taking a minute to talk about some of the problems we ran into.&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Scala does have public member variables. To support some of the syntactic changes that Scala makes, it replaces public member variables with accessor functions. In Scala, when you do something like foo.bar, it implicitly calls the function bar() (that returns the value of the private member variable bar) on foo. Java, of course, doesn&amp;#8217;t do this. So, when you are using Scala classes in Java code, everything becomes a function and you have to explicitly refer to foo.bar() everywhere. An easy problem to deal with, but it requires the programmer to remember whether something they are using is a Scala class or a Java one.&lt;/li&gt;
&lt;li&gt;The above creates a more subtle problem with Android that I wanted to call out specifically&amp;#8212;Parcelables. Android&amp;#8217;s Parcelable interface depends on being able to access the public member variable CREATOR on a class that implements Parcelable. If you create the class in Scala, then, of course, CREATOR ends up being a private member variable with a matching accessor function. There&amp;#8217;s no easy way around this problem, but thankfully Stéphane Micheloud &lt;a href="https://lampsvn.epfl.ch/trac/scala/changeset/22628"&gt;committed a patch&lt;/a&gt; to the Scala trunk to solve this problem. This does mean if you&amp;#8217;re planning on using Parcelables, you&amp;#8217;re going to need to use a build of Scala that includes this patch.&lt;/li&gt;
&lt;li&gt;Scala doesn&amp;#8217;t have an equivalent concept to public static final variables in interfaces (and honestly, it&amp;#8217;s a bit of a mystery to me why they exist in Java as well). This problem can easily be solved by creating a Java wrapper class that maps values from the interface to member variables on the class. For example,&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;code&gt;import com.some.interface.SomeConsts;

class Consts {


      public static final CONST_A = SomeConsts.CONST_A;
      public static final CONST_B = SomeConsts.CONST_B;
      ...
}&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;To support anonymous functions and some of the other language constructs that Scala adds, it ends up creating a far larger number of classes than Java. Generally, this shouldn&amp;#8217;t be a problem, however, Android appears to have a limit on the number of classes that a single application can have. I don&amp;#8217;t have details on exactly what this limit is, but we did find that inheriting from the Scala classes pushed that number up a lot. At one point, we tried inheriting from the Map class and that pushed us over the edge. In general, inheritance can be rewritten as a standard class with the proposed parent class as a member variable, but it&amp;#8217;s certainly not as clean.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;How Scala?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before I get too deep into the specifics of how we did it, I want to point everyone to &lt;a href="http://lamp.epfl.ch/~michelou/"&gt;Stéphane Micheloud&lt;/a&gt; site on putting &lt;a href="http://lamp.epfl.ch/~michelou/android/"&gt;Scala on Android&lt;/a&gt;. Not only is this site a great resource, but Stéphane was immesurably helpful in getting us up and running.&lt;/p&gt;
&lt;p&gt;Our build process consists of three steps, the first compiled the Google Protobufs that we use to communicate between our client and the server, the second invoked the Scala compiler to build the Service and finally we went back to the Java compiler to build the Application level code. I&amp;#8217;ve attached the full versions of our build.xml and build-scala.xml (a modified version of the one on Stéphane&amp;#8217;s site), but I&amp;#8217;ll call out a few things here that might be of interest.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;property name="extensible.classpath" value="${scala-library.jar}" /&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re accessing any Scala objects in Java, you&amp;#8217;re going to need to let the Java compiler know how those objects work. Unfortunately, there&amp;#8217;s no mechanism for extending properties in ant, so when we started working on a new feature that involved Google Maps, we had to change this to:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;property name="extensible.classpath" value="${scala-library.jar};${path.to.maps.jar}" /&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;code&gt;&amp;lt;target name="-service-pre-compile"


        description="Compiled the protocol buffers"
        depends="-aidl, -resource-src"&amp;gt;
  &amp;lt;javac encoding="ascii" target="1.5" debug="true" extdirs=""
         includes="src/com/google/**,src/com/bump/proto/**"
         destdir="${out.classes.absolute.dir}"
         bootclasspathref="android.target.classpath"
         verbose="${verbose}"&amp;gt;
    &amp;lt;src path="." /&amp;gt;
    &amp;lt;classpath&amp;gt;
      &amp;lt;fileset dir="${jar.libs.absolute.dir}" includes="*.jar" /&amp;gt;
    &amp;lt;/classpath&amp;gt;
  &amp;lt;/javac&amp;gt;
&amp;lt;/target&amp;gt;&lt;/code&gt;
&lt;p&gt;This is our compile step for protocol buffers. It looks just like the version in the Android SDK, except we&amp;#8217;ve given it a new name and restricted the files it&amp;#8217;s compiling with the includes statement.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;target name="scala-compile" depends="-service-pre-compile"
    description="Compiles project's .scala files into .class files"
    if="myapp.containsScala" unless="do.not.compile"&amp;gt;
    &amp;lt;condition property="logging" value="verbose" else="none"&amp;gt;
        &amp;lt;istrue value="${verbose}" /&amp;gt;
    &amp;lt;/condition&amp;gt;
    &amp;lt;property prefix="scala"
        resource="compiler.properties"
        classpathref="scala.path" /&amp;gt;
    &amp;lt;echo
        message="Scala version ${scala.version.number} - &lt;a href="http://scala-lang.org"&gt;http://scala-lang.org&lt;/a&gt;"
        level="info" taskname="fsc" /&amp;gt;
    &amp;lt;fsc
        srcdir="." includes="gen/**,src/com/bump/core/**,src/com/bump/util/*.java,src/com/bump/*.java"
        destdir="${out.classes.dir}"
        bootclasspathref="android.target.classpath"
        deprecation="yes"
        logging="${logging}" addparams="${scalac.addparams}"&amp;gt;
        &amp;lt;classpath&amp;gt;
            &amp;lt;pathelement location="${scala-library.jar}" /&amp;gt;
            &amp;lt;pathelement location="${out.classes.dir}" /&amp;gt;
            &amp;lt;fileset dir="${jar.libs.absolute.dir}" includes="*.jar" /&amp;gt;
        &amp;lt;/classpath&amp;gt;
    &amp;lt;/fsc&amp;gt;
    &amp;lt;touch file="${out.dir}/classes.complete" verbose="no"/&amp;gt;
&amp;lt;/target&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The is the step to compile the scala code (from build-scala.xml). One thing we changed from Stéphane&amp;#8217;s version is we&amp;#8217;re using fsc in instead of scalac. fsc (Fast Scala Compiler) acts just like the regular Scala compiler, but it&amp;#8217;s faster. It does, however, do some caching to speed things up, so if you&amp;#8217;re trying to do a clean build, you need to tell fsc (fsc -reset).&lt;/p&gt;
&lt;p&gt;Jamie uses vim and I use emacs, and both of just like the command line too much to use Eclipse, so this is where I&amp;#8217;m going to have to stop. Since I know many of you use Eclipse, I&amp;#8217;ll call out Indy and Jake to talk about how they handled the Scala code in Eclipse.&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: 12px; line-height: 21px; color: #424037;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;Want to work with Will and the rest of the Bump team? We are hiring: &lt;a href="http://bu.mp/jobs" style="color: #bc7134; text-decoration: none; padding: 0px; margin: 0px;"&gt;&lt;a href="http://bu.mp/jobs"&gt;http://bu.mp/jobs&lt;/a&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786235557</link><guid>http://devblog.bu.mp/post/40786235557</guid><pubDate>Mon, 13 Jun 2011 17:06:00 -0400</pubDate></item><item><title>Introducing Stud</title><description>&lt;p&gt;&lt;span style="color: #424037; font-size: 12px; line-height: 21px;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;This post was written by Jamie from Bump&amp;#8217;s server team.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt;So a few weeks ago, when the zombie army &lt;a href="http://devblog.bu.mp/how-to-ddos-yourself"&gt;lurched its way toward our servers&lt;/a&gt;, a long-neglected scaling issue likewise rose from the dead.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt;Like all responsible companies, we strive to keep our users&amp;#8217; data protected; so, we tunnel our proprietary socket protocol in TLS. Unfortunately, our use of other-than-HTTP immediately removes the usual candidate for TLS/SSL termination&amp;#8212;nginx&amp;#8212;from the running.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt;So, when we were designing our backend systems last summer, we grabbed the only serious open source contender for adding TLS to an arbitrary socket: the venerable &lt;a href="http://www.stunnel.org/"&gt;stunnel project&lt;/a&gt;. Stunnel has three &amp;#8220;threading models&amp;#8221;: ucontext, threads, and processing.We decided to try each and see what worked best.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt;We had high hopes for ucontext, since the low memory overhead of setjmp/longjmp-based coroutines would work really well for our particular application.  As opposed to something like HTTP, which is typically comprised of many short-lived, active connections, Bump holds open low-bandwidth connections to a very high number of clients at once.  So minimizing the memory penalty of each connected client was important to us.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt;But the ucontext threading module of stunnel performed surprisingly poorly.  We could saturate one core with only ~1k mostly-idle concurrent connections&amp;#8212;and there was no graceful approach for utilizing more than one core without introducing another load balancing layer.  This may very well have been due to some of the flaws the folks at RethinkDB recently &lt;a href="http://blog.rethinkdb.com/making-coroutines-fast"&gt;documented on their blog&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt;&lt;a href="http://blog.rethinkdb.com/making-coroutines-fast"&gt;&lt;/a&gt;&lt;/span&gt;&lt;span style=""&gt;Next, we tried using the pthread-based threaded mode.  As programmers, we trust threads about as far as we can throw them&amp;#8212;but admit that written skillfully and very carefully, threaded programs can perform excellently. Unfortunately, when put under load, stunnel threw all kinds of nasty assertions and segfaults in threaded mode.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt;So prefork was looking pretty good at this point.  We happened to be using machine with a ridiculous amount of memory (north of 80GB), and copy-on-write semantics meant that each child process would only use around 2MB of resident memory.  Furthermore, under the concurrency estimates we had at that time (as well as 12-month projections), the OS scheduler would handle things quite nicely&amp;#8212;and to top it off, fork-based multiprocessing is an extremely robust way to run servers, as Apache, PostgreSQL, &lt;a href="http://unicorn.bogomips.org/"&gt;Unicorn&lt;/a&gt;, etc, have proven time and time again.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt;All in all, we were feeling pretty pleased with ourselves until those pesky zombies *octupled* our concurrent connections overnight.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt;(If you were wondering, by the way, where process scheduling breaks down&amp;#8212;at least, on a mostly-stock Linux kernel&amp;#8212;the magic number seems to be around 10-15k processes.  By 20k, you are basically doing no actual work&amp;#8212;only context switching.  And fork() can take upwards of 5 seconds.)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt;I suppose we *could* have just fired up lots of servers with lots of RAM and spent our way out of the problem.  But the whole situation was starting to get a little ridiculous.  So we decided to try our hand at a solution.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt;The result is &lt;a href="https://github.com/bumptech/stud"&gt;stud&lt;/a&gt;. Stud is the Scalable TLS Unwrapping Daemon (and yes, we worked very hard to make that acronym fit).  It takes the nginx model of using one process per CPU core and then doing asynchronous I/O within each process.  It has a low memory overhead per secure connection and it minimizes heap allocations to the extreme. It&amp;#8217;s easy to use and easy to configure.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt;Since deploying stud over a month ago, memory usage on our load balancing machines is down tenfold.  Load is down 80%, and TLS handshake times are back under 20ms consistently.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt;Here&amp;#8217;s the load on one of our TLS termination servers running stud, handling over 3,000 secure connections (including ~50 handshakes a second):&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;someserver:~$ netstat -na | grep ':2000' | grep ESTAB | wc -l
3337
someserver:~$ cat /proc/loadavg
0.67 0.66 0.61 3/415 18476
someserver:~$ cat /proc/cpuinfo | grep processor | wc -l 
16&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt;We decided to open source it in case it helps anyone else out there keep the zombies at bay&amp;#8212;it&amp;#8217;s a particularly natural partner for haproxy, which is our production deployment.  Feel free to drop me a line with any feedback, file bugs on github, or submit pull requests&amp;#8212;we&amp;#8217;d love improvements!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="color: #424037; font-size: 12px; line-height: 21px;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;Want to work with Jamie and the rest of the Bump team? We are hiring: &lt;a href="http://bu.mp/jobs" style="color: #bc7134; text-decoration: none; padding: 0px; margin: 0px;"&gt;&lt;a href="http://bu.mp/jobs"&gt;http://bu.mp/jobs&lt;/a&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786230183</link><guid>http://devblog.bu.mp/post/40786230183</guid><pubDate>Fri, 10 Jun 2011 13:51:00 -0400</pubDate></item><item><title>How to DDOS yourself</title><description>&lt;p&gt;&lt;span style="font-size: 12px; line-height: 21px; color: #424037;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;This post was written by Michael from Bump&amp;#8217;s Android team and is part of a series about lessons learned while developing Bump 2.0 for Android.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt; &lt;/span&gt;One of the key things that any website worth their salt does is collect log data and make the most of that data. This includes things like tracking what pages your users are accessing on your site, and also things like errors that happen or slow response times. The user behavior data can help you build a better product and of course monitoring errors alerts you to problems that need to be fixed. For mobile apps, this is not as easy to do since a lot is happening on a user’s smartphone instead of on a web server in your data center. Many mobile developers used 3rd party analytics services like Flurry, but since we already have a network stack at Bump, we do our own logging. One decision to make is when to send the logs to the server. We don’t want to be constantly using your data connection to send logs to Bump. We especially wouldn’t want to be doing this while you were using Bump. You shouldn’t have to wait for us to send a log file before you can send a picture to your mom.&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt; &lt;/span&gt;As part of our 2.0 release of our Android app, we thought we came up with a clever way to get these logs back to our servers without ever bothering our users. You see on Android there are many events on the phone that an application can listen for and thus respond to. In particular, the Android OS will fire such an event when you plug your phone in to charge (a broadcast Intent whose action is android.intent.action.ACTION_POWER_CONNECTED if you are playing at home). Most people plug in their phones at night when they are going to bed, and thus not using their phone. This seemed like a great time to send log files to the Bump servers.&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt; &lt;/span&gt;The plan was simple. The Bump app registered a BroadcastReceiver that listened for this power connected event. This caused the Bump background service to wake up and start an upload of log files. Once it finished, the service would go back to sleep. What could go wrong? &lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt; &lt;/span&gt;There was one obvious (at least in retrospect) thing that we took for granted. We assumed that this event would be fired exactly once when the phone was plugged in and then never again until the user’s phone was unplugged and plugged in again. This assumption turned out to not only be false, but nearly fatal for our servers.&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt; &lt;/span&gt;Shortly after Bump 2.0 for Android came out, we started noticing a disturbing trend in our server traffic. We would see large numbers of phone connect to our servers and then do nothing &amp;#8212; except for tie up connections to our servers. Of course we first noticed this one day while we were all hard at work here in our office in Mountain View. Further we noticed that most of these “zombies” were coming from Japan and South Korea. We thought that perhaps there was something odd about the phones being sold over there or maybe with the wireless networks.&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt; &lt;/span&gt;As the number of downloads of Bump 2.0 continued to climb, things got worse. We had first noticed the zombies from Japan because they showed up during the work day in California. There turned out to be many more zombies right here in the United States.They came out at night, every night, and went away in the morning. We didn’t notice them until they set off monitoring alarms in the middle of the night here. One night we had to block all connections coming from Verizon IP addresses in order to keep the zombies at bay.&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt; &lt;/span&gt;This pattern of zombie phones late at night suggested that our send logs to the server strategy was to blame. So we changed that code, and no longer listened for the power connected event at all. This immediately killed off the zombies. Still it left us scratching our heads about the cause of the zombies. So we wrote a little test app. This app would simply count the number of times the power connected event was fired on a device. Then we would plug in a device for awhile and see how many events the app had counted. &lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt; &lt;/span&gt;We started testing devices, and we began with Verizon phones since we had seen large numbers of zombies on Verizon’s network. Most phones behaved just as they should, firing the event right when the phone was plugged in and never again until you unplugged it and then plugged back in again. But one Verizon phone we tested did not: the Verizon Fascinate. Once plugged in to charge, this phone would fire the power connected event every ten seconds or so (there actually was quite a bit of variance.) With our old log uploading code, this would cause our background service to wake up every ten seconds, shake hands with our servers, and then sit idle. In other words, it would create a zombie.&lt;/p&gt;
&lt;p&gt;&lt;span style=""&gt; &lt;/span&gt;If you are familiar with Android phones, you will recognize that the Fascinate is Verizon’s version of the Samsung Galaxy S. The Galaxy S is perhaps  the most popular Android phone in the world. We tested several other Galaxy S phones, and none of them had the zombie gene like the Fascinate. The presence of zombies in Japan and South Korea suggests there are phones being sold there that have the zombie gene, perhaps some other flavor of the Galaxy S. We can’t say which one for sure. We’re just glad that we can once again sleep through the night without being woken up by zombies.&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: 12px; line-height: 21px; color: #424037;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;Want to work with Michael and the rest of the Bump team? We are hiring: &lt;a href="http://bu.mp/jobs" style="color: #bc7134; text-decoration: none; padding: 0px; margin: 0px;"&gt;&lt;a href="http://bu.mp/jobs"&gt;http://bu.mp/jobs&lt;/a&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786230770</link><guid>http://devblog.bu.mp/post/40786230770</guid><pubDate>Wed, 08 Jun 2011 11:27:00 -0400</pubDate></item><item><title>iOS vs. Android from the Trenches</title><description>&lt;p&gt;&lt;span style="font-size: 12px; line-height: 21px; color: #424037;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;This post was written by Indy from Bump&amp;#8217;s Android team and is the first part of a series about lessons learned while developing Bump 2.0 for Android.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: 12px; line-height: 21px; color: #424037;"&gt;&lt;/span&gt;After months of hard work, we shipped Bump 2.0 for Android at the end of April. It was a full rewrite of the client from the ground up to bring it onto Bump&amp;#8217;s 2.0 architecture. To make this happen a couple of us at Bump switched to working full time on Android from iOS, and experienced all the joys and pains that come from such an experience. We&amp;#8217;ve teased our former iOS teammates about how certain things are so amazing and easy to do in Android, but the truth is more nuanced. In this post I want to spend some time looking at the similarities and differences of the two platforms from both a technical perspective and a UX perspective. Though it is possible to separate these two, since we are talking about a handheld device, both these perspectives are often intertwined.&lt;/p&gt;
&lt;p&gt;For 2.0 we wanted to build an App that felt native to Android and not a shoddy copy of an iPhone app. We ourselves are guilty of this with the previous version of our Android app (Android doesn&amp;#8217;t have tabs on the bottom!). We went through several iterations of our initial specs for 2.0 to bring it closer to a native Android look and feel.&lt;/p&gt;
&lt;p&gt;Aside from the surface level UI differences, I found that Android&amp;#8217;s architecture is very forward looking in comparison to iOS. Every app gets a chance to deeply integrate with the operating system and other applications. There is a lot that the OS has to offer in this respect and so far we&amp;#8217;ve only scratched the surface of what we can do with this at Bump.&lt;/p&gt;
&lt;p&gt;One example of a future looking architecture decision is how different applications can flow back and forth between each other. There are two major parts of the system that make this possible: Intents and the hard back button.&lt;/p&gt;
&lt;p&gt;Intents are part of the notification system that is built right into the operating system. Any application can listen to and act upon intents that are broadcasted system wide. For example: when a user clicks on a link inside a chat in Bump, an intent to view the link is broadcasted by the system. The browser is registered to respond to it so the system slides the chat screen away and slides in the browser with the contents of the link. The user now has the power of the full Android browser to interact with the web page. When the user is done viewing this link hitting the back button slides the chat screen back in.&lt;/p&gt;
&lt;p&gt;This is a huge UX win! In iOS there is simply no way to make this sort of seamless interaction. Apps have to bake in a UIWebView and then give you an option to open the page in Safari if you wanted get all the browser features. Once there getting back to the previous app is a multi step process. Android is filled with many such integration points that help users flow seamlessly between tasks. As an app developer you can even add new integration points for other apps to interact with yours.&lt;/p&gt;
&lt;p&gt;When it comes to layouts, Android has to deal with many different screen sizes and resolutions. It provides many tools to deal with this variation. One such tool is declarative (in xml) layouts that &amp;#8220;flow&amp;#8221;. These layouts are very similar to how layouts flow on the web. Each object in the layout has its position either defined based on an edge of the screen or relative to other objects. This layout methodology allowed us to quickly iterate on the UI by simply moving bits of xml around. Also simple things like a line of prompt text that might become two in more verbose languages (*cough* German) don&amp;#8217;t break the UI. On screen elements simply shift to adapt to this change.&lt;/p&gt;
&lt;p&gt;There is, however, a flip-side to flow layouts. In iOS you can often do pixel perfect placement. In Android with it&amp;#8217;s multitudes of resolutions and screen sizes you simply don&amp;#8217;t have that luxury. Thus the same tricks for placing elements in iOS simply don&amp;#8217;t carry over. However, this is something every designer that has moved from print to the web has had to deal with, and it&amp;#8217;s not a new problem.&lt;/p&gt;
&lt;p&gt;Android also allows an app to run multiple OS level processes. We take advantage of this ability to do almost all of our CPU heavy and networking work in a separate background process. This is great because we don&amp;#8217;t have to worry about any of this work having much of an effect on UI performance. This is a constant struggle in iOS even if you manage your threads well.&lt;/p&gt;
&lt;p&gt;One thing that has been a disappointing with Android though, is that animations and responsiveness of the UI is generally slower. In the parts of our app that we animate, we often see missed frames. Honestly this sucks. There are definitely things that we can do to make this better but in the end this is because none of the graphics and animations are hardware accelerated pre Honeycomb. Unless you specifically write Open GL code (and now Renderscript) you won&amp;#8217;t get the same level of graphics performance that you see in normal iOS apps. Since currently only tablets run Honeycomb, we are stuck with generally not so stellar graphics performance on pretty much all current handsets.&lt;/p&gt;
&lt;p&gt;The list of differences between the two platforms is obviously enormous. There are quite a few purely technical differences, but discussing many of them can easily degrade into religious arguments (languages, dev tools, garbage collection vs. ref counted memory management). In most of these regards both platforms are fairly comparable. The major difference being that Android&amp;#8217;s Java code runs on a relatively young (dalvik) VM that hasn&amp;#8217;t figured out all of its optimizations and bugs yet. It&amp;#8217;s quickly catching up to its older VM cousins though.&lt;/p&gt;
&lt;p&gt;Building for Android was definitely quite a change from iOS, but both involve building for devices with very constrained resources. We learned a lot and had some very interesting experiences. In the coming weeks we&amp;#8217;ll share more of these on this blog, including something we&amp;#8217;ve been asked often about: using Scala in Android.&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: 12px; line-height: 21px; color: #424037;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;Want to work with Indy and the rest of the Bump team? We are hiring: &lt;a href="http://bu.mp/jobs" style="color: #bc7134; text-decoration: none; padding: 0px; margin: 0px;"&gt;&lt;a href="http://bu.mp/jobs"&gt;http://bu.mp/jobs&lt;/a&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786231711</link><guid>http://devblog.bu.mp/post/40786231711</guid><pubDate>Wed, 18 May 2011 15:09:00 -0400</pubDate></item><item><title>TL;DR.js</title><description>&lt;p&gt;Reading all the hacker news articles can take too long.  &lt;/p&gt;
&lt;p&gt;Sometimes an author will add a tl;dr (too long; didn&amp;#8217;t read) section at the bottom for people who just scrolled by the article without reading it.  For those authors who weren&amp;#8217;t so considerate, here is a script that will do it for you.  You install it by dragging it to your bookmark bar, then when you accidentally click on a really long article, don&amp;#8217;t worry, you don&amp;#8217;t have to read it.   Just click the link in your bookmark bar and a nice little overview will show up at the top of the page.  YMMV.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Install by dragging this link to your bookmark bar (in chrome click view-&amp;gt;always show bookmarks bar to see it): &lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;iframe marginheight="0" marginwidth="0" src="http://bu.mp/static/misc/tldrjs.html" frameborder="0" height="30" width="500"&gt;&lt;/iframe&gt;&lt;/p&gt;

&lt;p&gt;If you want to summarize a subset of the article, select it with your mouse then click the bookmarklet.&lt;/p&gt;
&lt;p&gt;It works by finding the most common words in the article, and then finding the sentences with the highest density of common words (excluding words like &amp;#8220;the&amp;#8221;, &amp;#8220;and&amp;#8221;, etc.)&lt;/p&gt;
&lt;p&gt;Here is the tldr of Daring Fireball:&lt;/p&gt;
&lt;p&gt;&lt;span style="font-family: Verdana, Bitstream Vera Sans, sans-serif; font-size: 11px; line-height: 19px;"&gt; &lt;/span&gt;&lt;/p&gt;
&lt;li&gt;Apple un-magic is interesting&lt;/li&gt;
&lt;li&gt;“Open” is to Android as “magic” is to iOS&lt;/li&gt;
&lt;li&gt;iOS aims for it Android doesn’t want it  ★&lt;/li&gt;
&lt;li&gt;Google hypocrisy is interesting; Apple secrecy, not so much&lt;/li&gt;
&lt;li&gt;Android feels like an independent Google subsidiary&lt;/li&gt;

&lt;p&gt;This is a quick hack so please fork on github:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/bumptech/tl-dr.js"&gt;tl;dr.js on GitHub&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;&lt;em&gt;Spend less time reading hacker news, join Bump: &lt;a href="http://bit.ly/iJwz9M"&gt;&lt;a href="http://bu.mp.jobs"&gt;http://bu.mp.jobs&lt;/a&gt;&lt;/a&gt;&lt;/em&gt;&lt;/div&gt;</description><link>http://devblog.bu.mp/post/40786232684</link><guid>http://devblog.bu.mp/post/40786232684</guid><pubDate>Wed, 11 May 2011 14:54:30 -0400</pubDate></item><item><title>So you want to do Android development at Bump...</title><description>&lt;p&gt;&lt;span style="font-size: 12px; line-height: 21px; color: #424037;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;This post was written by Michael from Bump&amp;#8217;s Android team.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;So you want to do Android development at Bump&amp;#8230; &lt;/p&gt;
&lt;p&gt;Well of course you do! However, Android is a hot technology, and there are a lot of companies trying to hire Android engineers these days. Here at Bump we have a little different approach to hiring for our Android team than other companies. Hereʼs an example of an Android job listing pulled from Dice.com and the Android developer position here at Bump:&lt;/p&gt;
&lt;p&gt;The Other Guys&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Hands on development experience with Android (2 plus years)&lt;/li&gt;
&lt;li&gt;Java programming (8 plus years)&lt;/li&gt;
&lt;li&gt;Expert knowledge of circuit boards, processors, electronic equipment and computer hardware and software&lt;/li&gt;
&lt;li&gt;Expert knowledge of Oracle, C#, .NET&lt;/li&gt;
&lt;li&gt;10+ years experience required&lt;/li&gt;
&lt;li&gt;Android SDK, Java, iOS, Agile, Java MBeans Extensions, JMS, javascript&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Bump Technologies&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Experience developing native Android apps or other mobile apps is strongly preferred&lt;/li&gt;
&lt;li&gt;Java; an interest in learning Scala (or experience)&lt;/li&gt;
&lt;li&gt;An eye for great design and user experience&lt;/li&gt;
&lt;li&gt;A desire to create one of the best apps in the Android Market&lt;/li&gt;
&lt;li&gt;Ability to communicate within a close-knit team&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;I found this listing to be pretty humorous. The Android SDK went 1.0 at the end of 2008. So to have 2+ years of Android experience means that any potential candidates for the above job would have had to have jumped on the Android bandwagon back when the T-Mobile G1 was the only phone in the world running Android. So this company is looking for an elite early adopter, who also happens to be an expert with circuit boards and Oracle (database?) Compare this to what we are looking for at Bump. You might argue that our standards are lower. Certainly we have less requirements, and our requirements are not as speciﬁc. However I would argue that our standards are actually much higher.&lt;/p&gt;
&lt;p&gt;Android is such a new technology that requiring tons of experience is quite limiting. Iʼd go as far as to say it is foolish. Good engineers can learn a new technology much easier than an experienced, but average engineer can suddenly take their game to the next level. Asking a talented engineer to learn a new technology is exactly the kind of risk that startups have to take, and it is deﬁnitely a given here at Bump. As an aside, I would conjecture that this hiring principle is a key reason why startups are able to innovate much faster than bigger, badder companies. Certainly at Bump weʼre not looking for another cog in the machine, weʼre looking for people that can raise our IQ and enhance our DNA.&lt;/p&gt;
&lt;p&gt;Ok enough with the propaganda, letʼs get a little more concrete about what it takes to be an Android engineer at Bump. It should be obvious by now that we are not requiring Android experience. The ﬁrst most important thing is that you are a great engineer. Of course everyone who applies for an engineering job in Silicon Valley is smart and gets things done, so that is not enough. At Bump our focus is on letting folks use their smartphones to interact with the physical world. So we routinely ﬁnd ourselves with very unique problems to solve &amp;#8212; so even if you have tons of experience, it may not give you much of an advantage in solving some of the problems we face. Thus we look for some knowledge of software engineering/computer science “theory”. If youʼve ever interviewed for a programming job in the Valley, you probably know the drill. Youʼll be given some problems to solve on a white board, and they will probably involve some essential algorithms, data structures, etc.&lt;/p&gt;
&lt;p&gt;Programming on a white board can provide some useful insights in to how a developer thinks and what kind of theoretical knowledge they bring to the table. However it is a far from perfect way to evaluate programmers. It really has little in common with how most programmers actually do their day-to-day job. So before you ever step into our ofﬁce and pick up a dry-erase marker, we want to see something real: real code or a real app that you are responsible for. Now I know what youʼre thinking. If youʼre being asked to send code in to a company, chances are you can come up with a clever enough search on a decent search engine to ﬁnd all or most of the answer. And then thereʼs always Stack Overﬂow, but I digress. The real coding problem is a good ﬁlter. It also gives us a lot of insight into what you think is important when you code. Is the code optimized for speed or memory? Does it have a procedural, object-oriented, or perhaps even a functional style to it? Do you have an eye for usability? Combine this with some white board pseudocode and we have a better shot at evaluating a candidate.&lt;/p&gt;
&lt;p&gt;Programming problems at home and on white boards provide an objective way to evaluate an engineer. Pure programming skills may be a necessary condition for working at Bump, but it is not sufﬁcient. There are a lot of softer things involved too. One of those is passion for technology. For an Android engineer that should mean passion for Android (if you walk in to an interview sporting an iPhone &amp;#8230; well Iʼll leave it at that.) So even if you do not have Android experience at your most recent job, we still expect that Android is at least a serious hobby of yours. Thatʼs why you should expect the at-home programming problem we give you to involve writing a working Android application. We want both code and an APK! We want people who want to develop for the Android platform, not people who just want to collect badges for their resume. So there you have it. Hopefully after reading the above youʼre now dying to see what kind of Android programs weʼll ask you to write. Thatʼs the kind of passion that weʼre looking for, and we think itʼs much more important than how many years of Android experience you have. If you think that describes you, then &lt;a href="http://bump.theresumator.com/apply/ZeOtJR/Android-Developer.html?source=BLOG"&gt;apply now&lt;/a&gt;.&lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786233199</link><guid>http://devblog.bu.mp/post/40786233199</guid><pubDate>Fri, 15 Apr 2011 18:10:00 -0400</pubDate></item><item><title>Safeguarding ourselves from ourselves</title><description>&lt;p&gt;&lt;span style="font-size: 12px; line-height: 21px; color: #424037;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;This post was written by Seth from Bump&amp;#8217;s iOS team.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Managing a large code base can be a challenging task, especially as a team grows and more people are contributing to different areas at the same time.  In iOS land, there are a couple gotchyas that seem to crop up from time to time and can really bite you.  Once bitten, twice shy.  Whenever we run into a problem, first we figure out what went wrong, next we educate the team about the root problem, and lastly we try to protect ourselves. Our frail human memory has a habit of forgetting little details that are important, and every time we add someone new to our team it&amp;#8217;s not practical to review every little thing we&amp;#8217;ve learned so far. We try to create safeguards that will protect ourselves from&amp;#8230; ourselves, tools that help us catch the mistakes that slip in now and again. &lt;/p&gt;
&lt;p&gt;One such tricky problem is UIViews and background threads.  Apple&amp;#8217;s UI code is not thread safe: you can&amp;#8217;t go adding and removing views from multiple threads at the same time without the risk of corrupting your views and possibly crashing.  In general we do a good job at not doing these terrible things when not on the main UI thread.  However, we&amp;#8217;ve occasionally had little bits of code that, either directly, or indirectly, cause some view code to be called in the background.  The end result is indeterminate race conditions and strange crashing from autorelease pools.  &lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s one tool we use to protect ourselves from this: a UIView category that ensures you do certain things like autorelease, and release on the main thread, things which can be subtle and hard to detect, yet potentially discrashterous. It throws an exception while debugging so that you can see which piece of code in your call stack is offending. Of course, we can only defend against mistakes we&amp;#8217;ve already made, but at least we won&amp;#8217;t make them again. And maybe it will help you too.&lt;/p&gt;
&lt;p&gt;Are there things that have bitten you once, that you&amp;#8217;ve coded against?&lt;/p&gt;
&lt;p&gt;&lt;span style="border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 17px;"&gt;&lt;div class="data"&gt;
    &lt;table class="lines highlight" cellspacing="0" cellpadding="0"&gt;&lt;tr&gt;&lt;td class="line_numbers"&gt;
          &lt;span rel="file-uiview-threading-m-L1" id="file-uiview-threading-m-L1"&gt;1&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L2" id="file-uiview-threading-m-L2"&gt;2&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L3" id="file-uiview-threading-m-L3"&gt;3&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L4" id="file-uiview-threading-m-L4"&gt;4&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L5" id="file-uiview-threading-m-L5"&gt;5&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L6" id="file-uiview-threading-m-L6"&gt;6&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L7" id="file-uiview-threading-m-L7"&gt;7&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L8" id="file-uiview-threading-m-L8"&gt;8&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L9" id="file-uiview-threading-m-L9"&gt;9&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L10" id="file-uiview-threading-m-L10"&gt;10&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L11" id="file-uiview-threading-m-L11"&gt;11&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L12" id="file-uiview-threading-m-L12"&gt;12&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L13" id="file-uiview-threading-m-L13"&gt;13&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L14" id="file-uiview-threading-m-L14"&gt;14&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L15" id="file-uiview-threading-m-L15"&gt;15&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L16" id="file-uiview-threading-m-L16"&gt;16&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L17" id="file-uiview-threading-m-L17"&gt;17&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L18" id="file-uiview-threading-m-L18"&gt;18&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L19" id="file-uiview-threading-m-L19"&gt;19&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L20" id="file-uiview-threading-m-L20"&gt;20&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L21" id="file-uiview-threading-m-L21"&gt;21&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L22" id="file-uiview-threading-m-L22"&gt;22&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L23" id="file-uiview-threading-m-L23"&gt;23&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L24" id="file-uiview-threading-m-L24"&gt;24&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L25" id="file-uiview-threading-m-L25"&gt;25&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L26" id="file-uiview-threading-m-L26"&gt;26&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L27" id="file-uiview-threading-m-L27"&gt;27&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L28" id="file-uiview-threading-m-L28"&gt;28&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L29" id="file-uiview-threading-m-L29"&gt;29&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L30" id="file-uiview-threading-m-L30"&gt;30&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L31" id="file-uiview-threading-m-L31"&gt;31&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L32" id="file-uiview-threading-m-L32"&gt;32&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L33" id="file-uiview-threading-m-L33"&gt;33&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L34" id="file-uiview-threading-m-L34"&gt;34&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L35" id="file-uiview-threading-m-L35"&gt;35&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L36" id="file-uiview-threading-m-L36"&gt;36&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L37" id="file-uiview-threading-m-L37"&gt;37&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L38" id="file-uiview-threading-m-L38"&gt;38&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L39" id="file-uiview-threading-m-L39"&gt;39&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L40" id="file-uiview-threading-m-L40"&gt;40&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L41" id="file-uiview-threading-m-L41"&gt;41&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L42" id="file-uiview-threading-m-L42"&gt;42&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L43" id="file-uiview-threading-m-L43"&gt;43&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L44" id="file-uiview-threading-m-L44"&gt;44&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L45" id="file-uiview-threading-m-L45"&gt;45&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L46" id="file-uiview-threading-m-L46"&gt;46&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L47" id="file-uiview-threading-m-L47"&gt;47&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L48" id="file-uiview-threading-m-L48"&gt;48&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L49" id="file-uiview-threading-m-L49"&gt;49&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L50" id="file-uiview-threading-m-L50"&gt;50&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L51" id="file-uiview-threading-m-L51"&gt;51&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L52" id="file-uiview-threading-m-L52"&gt;52&lt;/span&gt;
          &lt;span rel="file-uiview-threading-m-L53" id="file-uiview-threading-m-L53"&gt;53&lt;/span&gt;
        &lt;/td&gt;
        &lt;td class="line_data" width="100%"&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC1"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC2"&gt;&lt;span class="c1"&gt;//&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC3"&gt;&lt;span class="c1"&gt;//  UIView+Threading.m&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC4"&gt;&lt;span class="c1"&gt;//&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC5"&gt;&lt;span class="c1"&gt;//  Created by Seth Raphael on 4/12/11.&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC6"&gt;&lt;span class="c1"&gt;//  Copyright 2011 BumpTechnologies. All rights reserved.&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC7"&gt;&lt;span class="c1"&gt;//&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC8"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC9"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC10"&gt;&lt;span class="cp"&gt;#ifdef DEBUG&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC11"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC12"&gt;&lt;span class="k"&gt;@implementation&lt;/span&gt; &lt;span class="nc"&gt;UIView&lt;/span&gt; &lt;span class="nl"&gt;(UIView_Threading)&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC13"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC14"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;autorelease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC15"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC16"&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;NSThread&lt;/span&gt; &lt;span class="n"&gt;currentThread&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;isMainThread&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC17"&gt;        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NSException&lt;/span&gt; &lt;span class="nl"&gt;raise:&lt;/span&gt;&lt;span class="s"&gt;@&amp;#8221;UIView Background Exception&amp;#8221;&lt;/span&gt; &lt;span class="nl"&gt;format:&lt;/span&gt;&lt;span class="s"&gt;@&amp;#8221;Autoreleasing a UIView %@ on a background thread&amp;#8221;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC18"&gt;    &lt;span class="p"&gt;}&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC19"&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;super&lt;/span&gt; &lt;span class="n"&gt;autorelease&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC20"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC21"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC22"&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC23"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC24"&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;NSThread&lt;/span&gt; &lt;span class="n"&gt;currentThread&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;isMainThread&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC25"&gt;        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NSException&lt;/span&gt; &lt;span class="nl"&gt;raise:&lt;/span&gt;&lt;span class="s"&gt;@&amp;#8221;UIView Background Exception&amp;#8221;&lt;/span&gt; &lt;span class="nl"&gt;format:&lt;/span&gt;&lt;span class="s"&gt;@&amp;#8221;Releasing a UIView %@ on a background thread&amp;#8221;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC26"&gt;    &lt;span class="p"&gt;}&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC27"&gt;   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;super&lt;/span&gt; &lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC28"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC29"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC30"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC31"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC32"&gt;&lt;span class="k"&gt;@end&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC33"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC34"&gt;&lt;span class="k"&gt;@implementation&lt;/span&gt; &lt;span class="nc"&gt;UIViewController&lt;/span&gt; &lt;span class="nl"&gt;(UIViewController_Threading)&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC35"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC36"&gt;&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;autorelease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC37"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC38"&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;NSThread&lt;/span&gt; &lt;span class="n"&gt;currentThread&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;isMainThread&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC39"&gt;        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NSException&lt;/span&gt; &lt;span class="nl"&gt;raise:&lt;/span&gt;&lt;span class="s"&gt;@&amp;#8221;UIView Background Exception&amp;#8221;&lt;/span&gt; &lt;span class="nl"&gt;format:&lt;/span&gt;&lt;span class="s"&gt;@&amp;#8221;Autoreleasing a UIView %@ on a background thread&amp;#8221;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC40"&gt;    &lt;span class="p"&gt;}&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC41"&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;super&lt;/span&gt; &lt;span class="n"&gt;autorelease&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC42"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC43"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC44"&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC45"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC46"&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;NSThread&lt;/span&gt; &lt;span class="n"&gt;currentThread&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;isMainThread&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC47"&gt;        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NSException&lt;/span&gt; &lt;span class="nl"&gt;raise:&lt;/span&gt;&lt;span class="s"&gt;@&amp;#8221;UIView Background Exception&amp;#8221;&lt;/span&gt; &lt;span class="nl"&gt;format:&lt;/span&gt;&lt;span class="s"&gt;@&amp;#8221;Releasing a UIView %@ on a background thread&amp;#8221;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC48"&gt;    &lt;span class="p"&gt;}&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC49"&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;super&lt;/span&gt; &lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC50"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC51"&gt; &lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC52"&gt;&lt;span class="k"&gt;@end&lt;/span&gt;&lt;/div&gt;
          &lt;pre&gt;&lt;/pre&gt;&lt;div class="line" id="file-uiview-threading-m-LC53"&gt;&lt;span class="cp"&gt;#endif&lt;/span&gt;&lt;/div&gt;
        &lt;/td&gt;
      &lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: 12px; line-height: 21px; color: #424037;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;Want to work with Seth and the rest of the Bump team? We are hiring: &lt;a href="http://bu.mp/jobs" style="color: #bc7134; text-decoration: none; padding: 0px; margin: 0px;"&gt;&lt;a href="http://bu.mp/jobs"&gt;http://bu.mp/jobs&lt;/a&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786234029</link><guid>http://devblog.bu.mp/post/40786234029</guid><pubDate>Wed, 13 Apr 2011 16:47:00 -0400</pubDate></item><item><title>How we use Redis at Bump</title><description>&lt;div style="color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 13px; background-color: #ffffff; margin: 8px;"&gt;
&lt;p&gt;&lt;span style="font-size: 12px; line-height: 21px; color: #424037;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;This post was written by Will from Bump&amp;#8217;s server team.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ve been using Redis at Bump for a number of things since we launched our 2.0 platform last July. After reading &lt;a href="http://flazz.me/redis-the-ak-47-of-databases" target="_blank"&gt;Francesco&amp;#8217;s recent post&lt;/a&gt; about Redis I was inspired to enumerate the many different roles Redis plays here. I also stuck in a few best practices that we&amp;#8217;ve learned along the way at the end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Message Passing&lt;br/&gt;&lt;/strong&gt;We originally looked into using AMQP for communicating between multiple servers and processes, and were frustrated with the complexity of it&amp;#8212;we&amp;#8217;re not a bank nor do we want to deal with the overhead required for complex transactional messages. Enter Redis lists. The combination of lpush and brpop create simple queuing and message passing behavior. &lt;a href="http://bsonspec.org" target="_blank"&gt;BSON&lt;/a&gt; encoding the data we send over the wire provides a simple translation between python dictionaries and a reasonably efficient wire format.  (Note: I use queue and list here to represent the user-level functionality being provided, however, to Redis, they are all just lists.)&lt;/p&gt;
&lt;p&gt;Adding an rpc mechanism simply requires sending a header that defines a callback queue to listen on (this can be generated at a uuid4 or anything else suitable collision free) along with the original message. The sender calls lpush, followed by brpop on the callback queue and the receiver, whenever it&amp;#8217;s ready to reply, lpushes it&amp;#8217;s response onto the callback queue. Since there&amp;#8217;s nothing left in the callback queue, Redis takes care of cleaning it up for you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Logging&lt;br/&gt;&lt;/strong&gt;We run a number of different processes on a number of different servers to keep Bump up and running. Instead of trying to keep track of text logs spread across multiple machines we just push any log line we are interested in onto a single Redis queue. Then, we have one process pop from that queue and write those log lines to disk. If that process or the logging server goes down, no big deal, events just queue up in Redis until the logging service is back online.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Social Graphs&lt;/strong&gt;&lt;br/&gt;We recently released the ability to &lt;a href="http://blog.bu.mp/the-virtual-bump" target="_blank"&gt;make Bump friends without actually bumping&lt;/a&gt; and with that came the problem of constructing and storing a social graph of our users. Already knowing Redis well (and knowing it was fast), we turned to Redis sets. Want to know what friends I have in common with Jamie? We keep all of Jamie&amp;#8217;s friends and all of my friends in separate sets in Redis, so the friends we have in common is just a set intersection, a function Redis already provides on sets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Asset Caching&lt;br/&gt;&lt;/strong&gt;Like most companies these days, we&amp;#8217;ve gotten out of the storage business, leaving the heavy lifting to &lt;a href="http://aws.amazon.com/s3/" target="_blank"&gt;Amazon&lt;/a&gt;. Unfortunately, the latency to S3 wasn&amp;#8217;t as low as we wanted for our most active assets.  At this point I imagine you&amp;#8217;ve guessed the trend, but Redis has a solution for this too&amp;#8212;max memory and lru mode.  Redis 2.2 (just recently released) can be run in a mode where you specify the maximum amount of memory Redis can use and also specify the record eviction criteria.  When an asset gets set up through Bump we put in into the Redis cache and eagerly store it to S3 as well.  The fetch of an asset simply checks Redis, if it&amp;#8217;s not there, repopulates the cache from S3 and tries the fetch again.  LRU mode takes care of the eviction of items that haven&amp;#8217;t been used in a while.  Perfect.&lt;/p&gt;
&lt;p&gt;We have ended up using Redis for a host of other smaller things as we continue to grow. Although this wasn&amp;#8217;t an explicit decision, Redis provides enough basic data types and functionality to get most problems done and you&amp;#8217;d be hard pressed to find something that can do it faster.&lt;/p&gt;
&lt;p&gt;That said, we&amp;#8217;ve run into a few issues along the way.  None of these problems dampen my enthusiasm for Redis, they are worth being aware of, especially if you are planning on using Redis for latency-dependent operations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Persistence&lt;br/&gt;&lt;/strong&gt;This is something that every database has trouble with and Redis is no exception. Antirez is hard at work on a new disk-based back-end for Redis that looks like it has promise, but for current production deployments there are two options: periodic background saves and writing to an append only file (AOF). Since periodic background saves can result in significant data loss if the server crashes, that wasn&amp;#8217;t a great option, so we settled on using the append only file. This works without a hitch until you need to compact the AOF. Due to the behavior of fsync and the fact that Redis uses a single event loop, at some point in the process of compacting the AOF the main event loop can become blocked on disk I/O. Since we use Redis for time sensitive things like message passing, we can&amp;#8217;t afford anything that will hang the entire server up. Unfortunately, there&amp;#8217;s no silver bullet here&amp;#8212;you just can&amp;#8217;t persist an active production instance of Redis.  We can&amp;#8217;t live without persistence, so we just have the &lt;em&gt;slaves&lt;/em&gt; run in AOF persistence mode.  The momentary hiccup in the slave just leads to a minor backup of the replication process, not ideal, but certainly not a terrible solution to a hard problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Running with Mongo&lt;br/&gt;&lt;/strong&gt;Very early in our deployment we had Redis and Mongo deployed on the same machine.  The whole story here will have to wait for a post on Mongo, but the take away is definitely that Mongo should &lt;strong&gt;always&lt;/strong&gt; be run on a server by itself.  That said, it&amp;#8217;s worth taking a minute to think about the implications of the single-threaded model that Redis employs.  If, for example, malloc takes a few hundred ms to return (the problem we were seeing with instance shared with Mongo) or if something is doing heavy disk I/O and a writing a log line ends up being disk-bound, the entire server will stop responding.  Depending on your use case, this can be acceptable or not, but it&amp;#8217;s something to keep in mind.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re looking at a new problem and it involves a data type that Redis supports (and really, what problems can&amp;#8217;t be solved with lists, sets and hashes) I strongly recommend giving Redis a long look. It&amp;#8217;s become the Swiss Army knife here a Bump, except that it opens the bottle of wine faster than anything else, instead of leaving half the cork in there.&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: 12px; line-height: 21px; color: #424037;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;Want to work with Will and the rest of the Bump team? We are hiring: &lt;a href="http://bu.mp/jobs" style="color: #bc7134; text-decoration: none; padding: 0px; margin: 0px;"&gt;&lt;a href="http://bu.mp/jobs"&gt;http://bu.mp/jobs&lt;/a&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;</description><link>http://devblog.bu.mp/post/40786234853</link><guid>http://devblog.bu.mp/post/40786234853</guid><pubDate>Tue, 15 Feb 2011 13:14:00 -0500</pubDate></item><item><title>Haskell at Bump</title><description>&lt;p&gt;&lt;span style="color: #424037; font-size: 12px; line-height: 21px;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;This post was written by Jamie from Bump&amp;#8217;s server team.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;At Bump, we&amp;#8217;re always willing to try something &amp;#8220;off the beaten path&amp;#8221; to get an edge. For example, our backend systems are almost entirely non-blocking and coroutine based, written in Python using &lt;a href="https://github.com/jamwt/diesel" target="_blank"&gt;Diesel&lt;/a&gt;; we have an in-house analyzer written in Ruby that verifies retained properties are released in our iPhone code; and, when we recently launched our Bump Android 2.0 project, we elected to write large parts of the core code in Scala.&lt;/p&gt;
&lt;p&gt;Our use of &lt;a href="http://www.haskell.org" target="_blank"&gt;Haskell&lt;/a&gt;, then, fits right in with our &amp;#8220;try anything&amp;#8221; mantra.  Haskell is a lazy, pure (with explicit non-purity), statically typed functional programming language.  Its closest cousin is that other family of Hindley-Milner type-inferred languages, the ML-derived SML and OCaml.&lt;/p&gt;
&lt;p&gt;While Haskell has long enjoyed heavy use among the CS academic crowd, we at Bump believe it hits a sweet spot of safety, correctness, and speed, making it a great systems language.  With the advent of some very serious &lt;a href="http://snapframework.com/" target="_blank"&gt;web frameworks&lt;/a&gt; and &lt;a href="http://docs.yesodweb.com/blog/announcing-warp/" target="_blank"&gt;high performance servers&lt;/a&gt;, it appears we&amp;#8217;re not alone in this belief.&lt;/p&gt;
&lt;p&gt;Our first foray into Haskell was &lt;a href="https://github.com/jamwt/Angel" target="_blank"&gt;Angel&lt;/a&gt;, a daemon monitoring and management system ala daemontools or god.  After a very sucessful and stable 6+ months of Angel in production, we were encouraged to revisit Haskell in a future project.&lt;/p&gt;
&lt;p&gt;Enter our logging and analysis infrastructure.  At Bump, we use &lt;a href="http://redis.io" target="_blank"&gt;Redis&lt;/a&gt; extensively as a &amp;#8220;swiss army knife&amp;#8221; for data; we have over 700GB of RAM dedicated to Redis storage!  One of our heaviest uses of Redis is as a messaging/queue server for our centralized logging system.  Every single event generated by any backend or frontend flows through redis lists to a central recording/processing system.&lt;/p&gt;
&lt;p&gt;After &lt;a href="http://techcrunch.com/2010/12/25/santa-brings-bump-its-biggest-day-of-sharing-ever-swapping-20-photos-a-second/" target="_blank"&gt;our big christmas&lt;/a&gt;, our load has reached the point where, on peak hours, that event stream is ~1500 events per second.  Knowing that we had culled all the low-hanging optimization fruit out of the overtaxed Python-based daemon that had been consuming this event queue, we decided it was time to revisit this system altogether. It seemed as good a time as any to give Haskell another spin.&lt;/p&gt;
&lt;p&gt;First, &lt;a href="https://github.com/bumptech/redis-haskell" target="_blank"&gt;we made some modifications&lt;/a&gt; to the redis-haskell binding project.  While keeping the &lt;a href="https://github.com/bumptech/redis-haskell/blob/master/src/Database/Redis/Command.hs" target="_blank"&gt;command layer&lt;/a&gt; mostly the same, we swapped out the &lt;a href="https://github.com/bumptech/redis-haskell/blob/master/src/Database/Redis/Internal.hs" target="_blank"&gt;internals&lt;/a&gt; to use &lt;a href="http://hackage.haskell.org/package/attoparsec-0.8.3.0" target="_blank"&gt;attoparsec&lt;/a&gt; for protocol parsing and &lt;a href="http://hackage.haskell.org/package/binary-0.5.0.2" target="_blank"&gt;the binary package&lt;/a&gt; for protocol generation. After these modifications, operations with Redis were 10x faster than our pure Python equivalent.&lt;/p&gt;
&lt;p&gt;Once our work on the Redis bindings was done, rewriting the simple consume-and-log daemon in Haskell took about a day.  The resulting daemon is 4x faster than the Python equivalent, and has approximately the same lines of code.  Best of all, thanks to a very powerful type system and rigorous control on side effects and concurrency, we only discovered a single bug after compilation.&lt;/p&gt;
&lt;p&gt;But there&amp;#8217;s still quite a bit of tuning we can do in the future to make it go faster still.  First, one part of our process involves translating the event representation from &lt;a href="http://bsonspec.org" target="_blank"&gt;BSON&lt;/a&gt; to JSON.  Our naive use of various Haskell libraries for this task isn&amp;#8217;t very disciplined about avoiding conversions between data representations and string types (CompactString, Lazy/Strict ByteStrings, etc).  A custom, minimalist JSON generator tailored specifically to the BSON library&amp;#8217;s output could be an interesting enhancement.&lt;/p&gt;
&lt;p&gt;In addition, we&amp;#8217;re taking very little advantage of Haskell&amp;#8217;s very sophisticated parallelism capabilities.  We could explore an approach distributing our (de)serializaiton jobs across many cores, using &lt;a href="http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Concurrent-MVar.html" target="_blank"&gt;MVars&lt;/a&gt; or even &lt;a href="http://www.haskell.org/haskellwiki/Software_transactional_memory" target="_blank"&gt;full-blown STM&lt;/a&gt; to communicate between many forkIO microthreads and a single log writer doing the disk I/O.&lt;/p&gt;
&lt;p&gt;Technology changes so quickly, at Bump we believe it&amp;#8217;s best to have many arrows in the quiver, and just hire very smart, productive, generalist developers that can do amazing things with any of them. Thus far, Haskell has proven to be a very valuable addition to our arsenal.&lt;/p&gt;
&lt;p&gt;&lt;span style="color: #424037; font-size: 12px; line-height: 21px;"&gt;&lt;em style="padding: 0px; margin: 0px;"&gt;Want to work with Jamie and the rest of the Bump team? We are hiring: &lt;a href="http://bu.mp/jobs" style="color: #bc7134; text-decoration: none; padding: 0px; margin: 0px;"&gt;&lt;a href="http://bu.mp/jobs"&gt;http://bu.mp/jobs&lt;/a&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786229350</link><guid>http://devblog.bu.mp/post/40786229350</guid><pubDate>Mon, 24 Jan 2011 17:28:00 -0500</pubDate></item><item><title>Generators and Back Again</title><description>&lt;p&gt;&lt;em&gt;This post was written by Jamie from Bump&amp;#8217;s server team and is cross-posted from &lt;a href="http://blog.jamwt.com"&gt;his blog&lt;/a&gt;. The code snippets in this entry are all Python-esque pseudocode, unless otherwise noted.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I’ve long held an interest in asynchronous I/O frameworks for Python.&lt;/p&gt;
&lt;p&gt;I started out playing around with asyncore/asynchat circa 2001.  I spent some time in Twisted, and made some small &lt;a href="http://jamwt.com/pgasync/"&gt;contributions&lt;/a&gt; to that community.  Then, I started &lt;a href="http://www.jamwt.com/EasyAsync/EasyAsync.py"&gt;tinkering&lt;/a&gt; with a few micro-frameworks of my own.  At &lt;a href="http://yougov.com"&gt;my last job&lt;/a&gt;, I wrote a slightly-more-complete framework called “eventful” to build a number of tools we ran server side, like a key/value database system and a deployment system.&lt;/p&gt;
&lt;p&gt;Over the years, I’ve realized a lot of the evolution the various frameworks underwent was devoted to—somehow—achieve a more “natural” flow than callback style typically permits.&lt;/p&gt;
&lt;p&gt;Allow me to explain.&lt;/p&gt;
&lt;p&gt;Typically, your code is invoked by an asynchronous framework when some data is available to process:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;def handle_read(self, data):
    # do stuff with data&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Then, some data-dependent dispatching happens:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;def handle_read(self, data):
    if is_put_command(data):
        self.handle_put(data)
    else:
        self.handle_get(data)&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;And who knows, the framework might provide tools to facilitate dispatching at this level.&lt;/p&gt;
&lt;p&gt;Now, let’s concentrate on our &lt;code&gt;get&lt;/code&gt; event handler:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;def handle_get(self, data):
    resource = parse_get_stuff(data)
    return get_resource(resource)&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Note that in our fictional framework here, the handler returns the data to be written back onto the connected socket.  So far, so good.&lt;/p&gt;
&lt;p&gt;But now, let’s pretend that &lt;code&gt;get_resource(..)&lt;/code&gt; involves a call to a database or something.  Since we’re in an async I/O framework, everything is running in a single thread.  Our handler cannot block, or the main I/O loop will not be scheduled to handle events related to other sockets.  So, &lt;code&gt;get_resource&lt;/code&gt; itself must be asynchronous.  That means it needs the event loop to do I/O on its behalf—so, we need our handler to return some request that indicates more stuff needs to be done by the event loop, then the results of that operation need to be passed back into some continuation to finally arrive at the real “return value” of the &lt;code&gt;handle_get&lt;/code&gt; handler.&lt;/p&gt;
&lt;p&gt;Callbacks are the way this is classically achieved:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;def handle_get(self, data):
    resource = parse_get_stuff(data)
    io_request = get_resource(resource)
 
    def transform_database_data(db_result):
        return db_result['user_id']
    io_request.add_callback(transform_database_data)
 
    return io_request&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;But this kinda sucks for a few reasons:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
&lt;p&gt;The logic appears out of order.  The final transformation of the data appears in code before the “first stage” of the handler is actually finished&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Traditional exception handling isn’t possible.  You need to add an “error callback” handler to every &lt;code&gt;io_request&lt;/code&gt; in case an exception occurs in the operation the event loop does on your behalf&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You either need to pass through any data calculated at early stages of the callback chain or rely on closure scoping, which works but gets pretty ugly when your callback chain gets longer than a few links&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;But really, the most decisive reason this is ugly is that &lt;em&gt;people don’t usually code this way&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I think, lacking better metrics, a decent way to evaluate the elegance of a given approach in a particular problem domain is: “if the constraints of this particular domain were removed, would people still code it this way?”&lt;/p&gt;
&lt;p&gt;Ask yourself, would you ever write this function?&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;def print_in_uppercase(phrase):
    def print_it(up):
        print up
 
    op_request = do_for_me(phrase.upper)
    op_request.callback(print_it)
    return op_request&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2&gt;The Solution&lt;/h2&gt;
&lt;p&gt;Let’s be honest.  This is what we want:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;def handle_get(self, data):
    resource = parse_get_stuff(data)
    db_result = get_resource(resource)
    return db_result['user_id']&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The challenge is &lt;code&gt;get_resource&lt;/code&gt;, we need the event loop to take control of the thread again. But the event loop is “up the stack”—it called you!&lt;/p&gt;
&lt;p&gt;A first answer might be “well, let’s just call back to it!”.  In “normal” Python (and most other languages), however, we have at least two problems with that:&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;Every time we call over to the event loop, we’re making the stack deeper.  We’ll stack overflow eventually.&lt;/li&gt;
&lt;li&gt;There is no good way to “resume” our handler when the I/O is done.  Heck, the stack might have other frames on it related to other sockets—so we can’t just have the event loop “return” data back up to our handle_get frame.&lt;/li&gt;
&lt;/ol&gt;&lt;h2&gt;Generators to the Rescue?&lt;/h2&gt;
&lt;p&gt;Python async I/O developers&amp;#8217; collective ears perked up when generators were introduced in Python 2.2.  When a generator &lt;code&gt;yield&lt;/code&gt;s, it sort of freezes the stack frame and lets the caller do other work—including scheduling other generators.  Then, when .next() is called on that generator, the frame is resumed right where it left off.  This allows for cooperative multitasking patterns, sometimes called coroutines, like this (this is runnable code, not pseudocode):&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;def one_g():
    for x in xrange(3):
        print "one!"
        yield 
 
def two_g():
    while True:
        print "two!"
        yield
 
def scheduler(loops):
    for x in xrange(3):
        for l in loops:
            l.next()
scheduler([one_g(), two_g()])&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Output:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;one!
two!
one!
two!
one!
two!&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;All that was missing was the ability to pass something back &lt;em&gt;into&lt;/em&gt; a generator; then, you could have one generator affect the behavior of another.&lt;/p&gt;
&lt;p&gt;Fortunately, that was added in Python 2.5 when generators grew a &lt;code&gt;.send()&lt;/code&gt; method that took an argument that would be the return value of the last &lt;code&gt;yield&lt;/code&gt; statement.  So, now we can start to put something together that acheives our &lt;code&gt;handle_get&lt;/code&gt; goals:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;def handle_get(data):
    resource = parse_get_stuff(data)
    db_result = yield get_resource(resource) # returns control to the scheduler
    yield response(db_result['user_id'])
 
def do_db_work(request):
    # io stuff
 
def scheduler(loops):
    next_get = wait_for_get()
    getter = handle_get(next_get)
    val = getter.next()
    if val is get_resource:
        result = do_db_work(val)
        val = getter.send(result)
    assert val is response
    send_to_socket(val)&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The rough idea is, the framework does the heavy lifting to make generators look like near-seamless coroutines to application code.&lt;/p&gt;
&lt;h2&gt;Diesel is Born&lt;/h2&gt;
&lt;p&gt;In Summer 2009 I was building a web app with a couple of friends.  We were doing all sorts of Comet-y and event-y stuff, and I decided to gather up my decade of callback scars, my Python 2.5 generators, and take a stab at putting together something cool.&lt;/p&gt;
&lt;p&gt;So we started the &lt;a href="http://dieselweb.org"&gt;Diesel project&lt;/a&gt;.  Take a look at the docs to see lots of examples—but in a nutshell, it let you do very cool stuff, written in an intuitive, blocking style, with minimal code.&lt;/p&gt;
&lt;p&gt;Here’s a basic echo server, for example:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;def echo(remote_addr):
    their_message = yield until_eol()
    yield "you said: %s\r\n" % their_message.strip()&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Diesel managed huge bunches of these generators, and looked for specific tokens, like &lt;code&gt;until_eol&lt;/code&gt;, which gave it (ie., the event loop) instructions on what kind of I/O to conduct, or how long to wait to resume the loop, or what “event” to wait on.&lt;/p&gt;
&lt;p&gt;And it worked pretty well… but it wasn’t all wine and roses.&lt;/p&gt;
&lt;h2&gt;Degenerate Generators&lt;/h2&gt;
&lt;p&gt;As we’ve long known: the world is not flat.&lt;/p&gt;
&lt;p&gt;For programmers, the world is &lt;em&gt;nested&lt;/em&gt;.  And these nestings are the building blocks for generality, encapsulation, etc.  Functions and objects and methods allow us to adhere to the policy of “Don’t Repeat Yourself”.&lt;/p&gt;
&lt;p&gt;But these constructs are problematic for something like Diesel:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;def get_user(uname):
    do()
    several()
    io()
    things()
 
def handler(username):
    if username is not None:
        user = get_user(username)
    else:
        user = get_user('default')
 
    yield user.to_string()&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The fundamental problem is Diesel must be the “caller” of the generator—the parent frame—in order to process tokens destined for it.&lt;/p&gt;
&lt;p&gt;The call pattern we all know and love:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;Diesel calls handler
handler calls get_user
get_user returns to handler
handler returns to Diesel&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;…will not work!  If &lt;code&gt;get_user&lt;/code&gt; does any IO, Diesel needs to be the recipient of the tokens being &lt;code&gt;yield&lt;/code&gt;ed to the caller.  Once again, the issue is the event loop needs to be in control.&lt;/p&gt;
&lt;p&gt;This puts Diesel in the business of “faking the call stack”.  This convoluted mess is what’s required:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;Diesel calls handler
handler yields another generator (get_user) to diesel
diesel pushes get_user onto the stack and calls .next() on it
get_user does IO, yielding signals to Diesel
eventually, get_user yields a "return value"
Diesel pops get_user off the stack 
Diesel calls .send(..) on handler, passing in the return value from get_user
handler resumes with the result of get_user
eventually, handler yields a "return value"&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Oy!  Where do I begin?&lt;/p&gt;
&lt;p&gt;This code is ugly and hard to get right. It’s slow (compared to native function calls, which are relatively slow in Python already).  Exception handling being raised “up the stack” (of generators) is near impossible to do right and imposes un-pythonic things on the application code.  A funky token needs to be &lt;code&gt;yield&lt;/code&gt;ed that approximates the behavior of the keyword “return”—push something up to the caller in the generator stack and end the frame’s execution.  And it’s very easy to make mistakes in your application about when you’re yielding generators vs. calling regular functions, and hard to refactor one into the other.&lt;/p&gt;
&lt;h2&gt;The Greenlet Kool-Aid&lt;/h2&gt;
&lt;p&gt;We’ve been busy at &lt;a href="http://bu.mp"&gt;Bump&lt;/a&gt; writing new backend systems that power version 2.0 of our iPhone app.  We had 10k+ lines written on Diesel and generators, and things were mostly working… but we were fatigued of running into the aforementioned complications.  We wanted regular function calls, regular tracebacks, and regular exception handling.&lt;/p&gt;
&lt;p&gt;So I started investigating using the &lt;a href="http://pypi.python.org/pypi/greenlet"&gt;greenlet library&lt;/a&gt; as an alternative to generators.&lt;/p&gt;
&lt;p&gt;The greenlet library uses some assembly trickery to do true coroutines in Python.  This means you can “call over” into another user-space microthread without going deeper in the stack, and then resume the caller later on.&lt;/p&gt;
&lt;p&gt;Here’s an example from the greenlet website:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;from py.magic import greenlet
 
def test1():
    print 12
    gr2.switch()
    print 34
 
def test2():
    print 56
    gr1.switch()
    print 78
 
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;That &lt;code&gt;switch()&lt;/code&gt; call is the magic—jumping between arbitrary call stacks at will!&lt;/p&gt;
&lt;h2&gt;Diesel 2&lt;/h2&gt;
&lt;p&gt;One furious night of coding later, I had a branch of Diesel ported to use greenlet at its core instead of generators.  In the process, I removed hundreds of lines of code full of edge cases, and the result was a codebase with fewer bugs (even though it was younger) that was much faster to boot.&lt;/p&gt;
&lt;p&gt;We’ve been running millions of users on Diesel 2 at bump for the last few weeks since the launch of the Bump 2.0 app, and everything is going along swimmingly.&lt;/p&gt;
&lt;p&gt;Here’s our contrived application, Diesel 2 style (using MongoDB):&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;def get_user(uname):
    client = MongoClient()
    return client.myapp.users.find({'username' : uname}).one()
 
def handler(username):
    if username is not None:
        user = get_user(username)
    else:
        user = get_user('default')
 
    return user&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;I feel somewhat conflicted, because the generator approach, with &lt;code&gt;yield&lt;/code&gt;s aplenty, was the a key characteristic of Diesel when we launched the project; but I eventually had to concede that the decision to use the greenlet library instead of generators for the basis of Diesel was, practically, the right call.&lt;/p&gt;
&lt;p&gt;Try out Diesel 2: &lt;a href="http://github.com/jamwt/diesel"&gt;GitHub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Want to work with Jamie and the rest of the Bump team? We are hiring: &lt;a href="http://bu.mp/jobs"&gt;&lt;a href="http://bu.mp/jobs"&gt;http://bu.mp/jobs&lt;/a&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</description><link>http://devblog.bu.mp/post/40786236896</link><guid>http://devblog.bu.mp/post/40786236896</guid><pubDate>Mon, 09 Aug 2010 12:00:00 -0400</pubDate></item></channel></rss>
