<?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>bjk5</title><generator>Tumblr (3.0; @bjk5)</generator><link>http://bjk5.com/</link><item><title>App Engine Performance Essentials You'll Certainly Need, Part II</title><description>&lt;p&gt;It&amp;#8217;s kinda cheating to call this Part II of &lt;a href="http://bjk5.com/post/11766098283/app-engine-performance-hacks-youll-probably-never"&gt;App Engine Performace Hacks You&amp;#8217;ll Probably Never Need&lt;/a&gt;, but I recently stumbled across a single tip that anybody in App Engine land will want to know about.&lt;/p&gt;

&lt;h1&gt;Don&amp;#8217;t use &lt;code&gt;&lt;a href="https://developers.google.com/appengine/docs/python/datastore/queryclass#Query_fetch"&gt;fetch()&lt;/a&gt;&lt;/code&gt; for datastore access, it&amp;#8217;s &lt;em&gt;slower&lt;/em&gt; than it used to be&lt;br/&gt;&lt;br/&gt;&lt;/h1&gt;

&lt;p&gt;If you&amp;#8217;ve been on App Engine for a while, you&amp;#8217;re either surprised by that tip or more informed than I was earlier today. Until somewhat recently, it&amp;#8217;s been the case that running:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;for monkey in models.Monkey.all().fetch(500):
    monkey.swing_from_vine()

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&amp;#8230;would&amp;#8217;ve been much faster than:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;for monkey in models.Monkey.all():
    monkey.swing_from_vine()

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&amp;#8230;assuming that you have at least a couple hundred Monkeys (who doesn&amp;#8217;t?) and are willing to eat the memory required to hold all Monkeys at once (who wouldn&amp;#8217;t be?). That&amp;#8217;s because &lt;code&gt;all()&lt;/code&gt; returns a query iterator which chunks up its roundtrips to the datastore into a bunch of small trips, while &lt;code&gt;fetch()&lt;/code&gt; (it is hoped) only goes back&amp;#8217;n&amp;#8217;forth once.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/UFCm4gvze/screen_shot_2012-05-23_at_1.02.32_am.png"/&gt;&lt;br/&gt;&lt;em&gt;Most people who once wrote &lt;code&gt;fetch([some big number])&lt;/code&gt; were&lt;br/&gt;trying to avoid RPC performance waterfalls like this. Now it can cause them.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So if you&amp;#8217;re anything like us, your code is probably littered with &lt;code&gt;fetch()&lt;/code&gt; calls all over the place wherever you felt comfortable grabbing a large number of entities and were willing to make a deal w/ the App Engine memory gods to get it done as quickly as possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This no longer has &lt;em&gt;any&lt;/em&gt; performance benefit unless you use the new &lt;code&gt;batch_size&lt;/code&gt; parameter.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/appengine/docs/python/datastore/queryclass#Query_fetch"&gt;&lt;code&gt;fetch()&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://developers.google.com/appengine/docs/python/datastore/queryclass#Query_run"&gt;&lt;code&gt;run()&lt;/code&gt;&lt;/a&gt; now accept an optional &lt;code&gt;batch_size&lt;/code&gt; parameter, but &lt;code&gt;fetch()&lt;/code&gt;&amp;#8217;s is undocumented. You want something like: &lt;code&gt;fetch(1000, batch_size=1000)&lt;/code&gt; or any reasonable &lt;code&gt;batch_size&lt;/code&gt; for your use case. Without this parameter, &lt;code&gt;fetch()&lt;/code&gt; simply returns &lt;code&gt;list(run(...))&lt;/code&gt; using &lt;code&gt;run()&lt;/code&gt;&amp;#8217;s default parameters, which happen to set a small batch size.&lt;/p&gt;

&lt;p&gt;However, since most people were using &lt;code&gt;fetch()&lt;/code&gt; to get around the batch size issue and don&amp;#8217;t actually need all entities in memory at once, I recommend following the &lt;a href="https://developers.google.com/appengine/docs/python/datastore/queryclass#Query_fetch"&gt;recently updated docs&lt;/a&gt; and always using &lt;code&gt;run()&lt;/code&gt; with a reasonable limit and batch_size:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# A grossly simplified couple of lines from our student reporting code:
for problem in models.Problem.all().run(limit=10000, batch_size=1000):
    problem.add_to_student_report()

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&amp;#8230;which protects you from unnecessary round trips and still gives you control over the amount of memory you&amp;#8217;re willing to allocate at once. It feels like &lt;code&gt;fetch()&lt;/code&gt; is going the way of the dodo in App Engine land. You can see &lt;a href="http://code.google.com/p/googleappengine/source/diff?spec=svn224&amp;amp;r=224&amp;amp;format=side&amp;amp;path=/trunk/python/google/appengine/ext/db/__init__.py&amp;amp;old_path=/trunk/python/google/appengine/ext/db/__init__.py&amp;amp;old=209"&gt;similar hints dropped into the App Engine codebase&lt;/a&gt; right when their team made the &amp;#8216;ole switcheroo:&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/U2qm4gwdk/fetch.png"/&gt;&lt;br/&gt;&lt;em&gt;Critical docstring change right when the implementation switched.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you&amp;#8217;re working in App Engine land, you&amp;#8217;re going to find &lt;a href="https://groups.google.com/group/google-appengine-python/browse_thread/thread/52de7b3137f8e1cb"&gt;countless&lt;/a&gt; &lt;a href="http://stackoverflow.com/questions/264154/google-appengine-how-to-fetch-more-than-1000%0A%0A"&gt;examples&lt;/a&gt; &lt;a href="http://googleappengine.blogspot.com/2009/06/10-things-you-probably-didnt-know-about.html"&gt;all over the web&lt;/a&gt; of people advocating or just using &lt;code&gt;fetch([some big number])&lt;/code&gt;-ish code that directly contradicts the above advice. I&amp;#8217;m gonna go correct &lt;a href="http://stackoverflow.com/questions/4697542/are-query-fetch-and-iteration-effectively-the-same-in-app-engine"&gt;this Stack Overflow question&lt;/a&gt; as soon as I hit Publish. As of this change, all those old pieces of code suffer from the worst of both worlds: high memory requirements and small batch sizes causing lots of roundtrips.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve verified the perf impact on our production server, and just as expected, keeping your roundtrips low can really pay off. While it&amp;#8217;s possible we missed some big announcement somewhere, the fact that we just discovered this means there might be somebody else out there who can benefit.&lt;/p&gt;

&lt;p&gt;If you have any other requests for App Engine performance-related topics to cover, &lt;a href="mailto:kamens@gmail.com"&gt;I&amp;#8217;d love to hear them&lt;/a&gt;.&lt;/p&gt;</description><link>http://bjk5.com/post/23601113262</link><guid>http://bjk5.com/post/23601113262</guid><pubDate>Wed, 23 May 2012 02:05:00 -0700</pubDate></item><item><title>How intern mentorship works at Khan Academy</title><description>&lt;p&gt;Three of our twelve&lt;em&gt;(‽)&lt;/em&gt; summer interns have arrived. It&amp;#8217;s high time I share how we mentor interns before I&amp;#8217;m spending all my time swatting &lt;a href="http://www.amazon.com/Swimmer-Remote-Control-Inflatable-Flying/dp/B005FYEAJ8"&gt;sharks&lt;/a&gt; and &lt;a href="http://www.amazon.com/Syma-S107-S107G-Helicopter-Yellow/dp/B004A8ZRB0/ref=sr_1_2?s=toys-and-games&amp;amp;ie=UTF8&amp;amp;qid=1337304018&amp;amp;sr=1-2"&gt;helicopters&lt;/a&gt; out of the air. These tips also apply to new full-time hires, of course, but for now I&amp;#8217;ve got interns on the brain.&lt;/p&gt;

&lt;h1&gt;1. Make the mentorship relationship explicit&lt;/h1&gt;

&lt;p&gt;At some point in a new employee&amp;#8217;s first day they will hear some variation of the words, &amp;#8220;I&amp;#8217;m your official mentor. As we work through your first few projects together, you can interrupt me any time for any technical question, non-technical question, question about the rules of &lt;a href="http://boardgamegeek.com/boardgame/3955/bang"&gt;Bang!&lt;/a&gt;, or just because you want to order a specific keyboard. Don&amp;#8217;t think twice.&amp;#8221;&lt;/p&gt;

&lt;p&gt;We don&amp;#8217;t throw our interns into a room with 5 people and say &amp;#8220;You&amp;#8217;re surrounded by mentors! LEARN.&amp;#8221; If you&amp;#8217;re &lt;a href="http://www.joelonsoftware.com/articles/HighNotes.html"&gt;hiring right&lt;/a&gt;, they already know how to do that better than you. What they need is awareness of a specific mentor that will unflinchingly act as their outlet for any need, without frustration.&lt;/p&gt;

&lt;p&gt;Good hires will find the right balance between diving into their new codebase to find their own answers and asking you for help. Some may need a little bit of guidance. We&amp;#8217;d rather err on the side of interns asking too many questions (easily correctable) than them being scared or unsure of who to interrupt (unfortunate culture problem).&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/uIVm472f6/shark.png"/&gt;&lt;br/&gt;&lt;em&gt;I wish this shark was remote control.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;2. Code review everything, and have interns do code reviews&lt;/h1&gt;

&lt;p&gt;Gonna keep this short because I&amp;#8217;ve been over this before. &lt;a href="http://bjk5.com/post/3994859683/code-reviews-as-relationship-builders-a-few-tips"&gt;Code reviews form a huge part of our mentor/mentee relationship&lt;/a&gt;. Warning though! I&amp;#8217;ve been bitten in the past when a class of interns wasn&amp;#8217;t code reviewed consistently. If a few interns are getting great code reviews on every checkin and others&amp;#8230;not so much&amp;#8230;, then they&amp;#8217;re going to notice and draw weird conclusions. I&amp;#8217;ve been part of teams that have suffered from this in the past, and I publicly apologize. I&amp;#8217;m less worried about this now that we have &lt;a href="http://bjk5.com/post/18441794352/required-code-reviews"&gt;a simple review all the code policy&lt;/a&gt; at Khan.&lt;/p&gt;

&lt;h1&gt;3. Prep your product pre-arrival&lt;/h1&gt;

&lt;p&gt;The most successful intern projects I&amp;#8217;ve been part of began with &lt;em&gt;months&lt;/em&gt; (no exaggeration) of preparation. At least for Fog Creek and Khan, intern summers are the most suddenly dramatic infusion of horsepower we ever have to absorb. We don&amp;#8217;t want to waste a drop not knowing where we&amp;#8217;re going. You have 9 months every year to stumble around not knowing what you&amp;#8217;re doing&amp;#8230;just get it together for the summer.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/VVLm472u8/success.png"/&gt;&lt;br/&gt;&lt;em&gt;I&amp;#8217;ve been scientifically tracking every intern class and found this to be the most significant variable.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What do you prep? I&amp;#8217;ve seen a couple things work well:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;If you are planning on using the summer to launch a brand new product or large feature (I recommend this, it&amp;#8217;s a blast), have everything solidified from high-level goals to low-fidelity mockups to code scaffolding.&lt;/li&gt;

&lt;li&gt;If you have a less defined vision but generally want to improve a particular area, set aside a couple weeks of bite-sized projects long before anyone new sets foot inside.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Don&amp;#8217;t worry about overdefining things just yet. This is about making sure people start with a tangible goal to aim for while understanding how that goal fits into your team&amp;#8217;s deeper principles. Smart new hires will have absolutely no trouble stepping outside the bounds of your preparations, &lt;a href="http://bjk5.com/post/8826207372/khan-academy-internship-summer-11"&gt;taking ownership&lt;/a&gt;, and persuading you away from all your stupid assumptions. That&amp;#8217;s exactly what your culture should be encouraging.&lt;/p&gt;

&lt;h1&gt;4. Weekly 1-on-1&amp;#8217;s&lt;/h1&gt;

&lt;p&gt;Our mentors have weekly 1-on-1s with their interns to make sure they&amp;#8217;re learning what they hoped to learn and are working on the types of projects they&amp;#8217;re most passionate about. These days the top interns have tons of opportunity. It&amp;#8217;s a battle for the best, so we make sure Khan interns get the most out of their time. If you think it should be the other way around, you&amp;#8217;re probably already missing out on the best and it&amp;#8217;s highly likely you never started reading this blog in the first place.&lt;/p&gt;

&lt;p&gt;1-on-1&amp;#8217;s can be just a few minutes and may fall back to every other week when appropriate. Just enough to make sure our interns have a chance to self-direct.&lt;/p&gt;

&lt;h1&gt;5. Friday tech talks&lt;/h1&gt;

&lt;p&gt;&amp;#8220;Keep learning&amp;#8221; is on the short list of Khan Academy company values. &lt;a href="http://jamie-wong.com/"&gt;Jamie Wong&lt;/a&gt; started his internship this summer and dropped &lt;a href="https://vimeo.com/41595939"&gt;this tech talk about meteorjs&lt;/a&gt; in the first week. We&amp;#8217;ve had tech talks about fonts (typefaces? styles? ugh I can never remember the politically correct word, I&amp;#8217;m so sorry &lt;a href="http://generic.cx/"&gt;Marcos&lt;/a&gt;), game design, a/b testing, performance, and how Khan Academy is being used in towns without internet connectivity. We&amp;#8217;re inviting cool people like Steve Yegge to teach us about API-centric development. We want to learn more.&lt;/p&gt;

&lt;p&gt;In fact, if you like Khan Academy and want to give us a treat, we&amp;#8217;d love for you to come teach our team something. Email me - &lt;a href="mailto:kamens@gmail.com"&gt;kamens@gmail.com&lt;/a&gt; &amp;#8212; I promise a low-key atmosphere and maybe board games.&lt;/p&gt;</description><link>http://bjk5.com/post/23266999170</link><guid>http://bjk5.com/post/23266999170</guid><pubDate>Thu, 17 May 2012 19:00:00 -0700</pubDate></item><item><title>"Step one? FIX. Step two? IT."</title><description>&lt;blockquote&gt;&amp;#8220;Step three? FIXIT. Now repeat till it is FIXED.&amp;#8221;&lt;/blockquote&gt;

&lt;p&gt;Wise words from &lt;a href="http://www.youtube.com/watch?v=_laaxl1EKqQ"&gt;Kenan&lt;/a&gt;, patron saint of the first Khan Academy fixit.&lt;/p&gt;

&lt;p&gt;Fixit day is just one more in the long list of &lt;a href="http://bjk5.com/post/18441794352/required-code-reviews"&gt;solid dev lessons I&amp;#8217;ve been learning&lt;/a&gt; from the Googlers around here. Since I couldn&amp;#8217;t find a reputable source explaining the fixit culture (who reads the &lt;a href="http://www.nytimes.com/2007/10/21/jobs/21pre.html?_r=1"&gt;NY Times&lt;/a&gt;?), I figured it&amp;#8217;s my duty to share.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/gH5m2o24o/fixit.jpeg"/&gt;&lt;br/&gt;&lt;em&gt;&lt;a href="http://www.youtube.com/watch?v=_laaxl1EKqQ"&gt;Who&amp;#8217;s gonna fix it? They are. Because they broke it.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;What&amp;#8217;s fixit day?&lt;br/&gt;&lt;br/&gt;&lt;/h1&gt;

&lt;img src="http://static.tumblr.com/9hgswys/Yg5m2o2pt/screen_shot_2012-04-18_at_1.44.18_am.png" align="right" class="rightInset" style="margin-left:5px;"/&gt;&lt;blockquote&gt;&amp;#8220;The goal of a fixit is to address niggling concerns that bother you
time and again, but never enough to actually fix them.&amp;#8221;&lt;/blockquote&gt;

&lt;p&gt;That&amp;#8217;s straight from &lt;a href="http://allthingsd.com/20120209/googles-very-first-employee-craig-silverstein-technically-no-3-leaving/"&gt;somebody who has more experience with fixits&lt;/a&gt; than either of us. I prefer to view fixit day as that moment when you finally wake up in the middle of the night with enough consciousness to properly rearrange the blanket (or swipe away the breadcrumb, if you&amp;#8217;re gross like me) that&amp;#8217;s been &lt;em&gt;just barely&lt;/em&gt; interrupting your sleep for the past five hours, but never enough to break you out of your dream. Man that&amp;#8217;s a good feeling. I hate breadcrumbs in bed&amp;#8230;but I also really like cinnamon toast.&lt;/p&gt;

&lt;p&gt;Anyway, our first crack at the whole thing tackled two levels of fixits:&lt;/p&gt;

&lt;ol&gt;&lt;li&gt;
Two teams split up to handle upgrading us to the latest version of &lt;a href="http://documentcloud.github.com/backbone/"&gt;Backbone&lt;/a&gt; and refactoring our code to reduce our circular import problem, respectively. These were both nontrivial tasks that would&amp;#8217;ve been difficult for an individual to get done in the face of a rapidly changing codebase, so they were perfect fixit fodder.&lt;br/&gt;&lt;br/&gt;&lt;/li&gt;

&lt;li&gt;
The rest of us swept away just about any breadcrumb that needed sweeping. Error logs were cleaned up. 404 pages became prettier. Old, unused code was removed. Crashes were fixed. Little CSS bugs were stomped on.
&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;The &amp;#8220;fixedit!&amp;#8221; &lt;a href="http://trello.com"&gt;Trello&lt;/a&gt; column got quite full, fast. And while it&amp;#8217;s easy to &lt;a href="http://rachelbythebay.com/w/2012/02/17/fixit/"&gt;take potshots at fixit day&lt;/a&gt; by claiming that everybody should be fixing this stuff all the time, I was even happier with the team culture inspired by fixit day than with any individual change. Every single person on our team was having fun working on the same thing, and no fix was too &lt;strike&gt;small&lt;/strike&gt; &lt;strike&gt;annoying&lt;/strike&gt; UggggghhhhWhatIsThisBrowserDoing to be undeserving of absolutely anybody&amp;#8217;s attention*. Our first fixit day felt very healthy. It was a little chaotic at the end due to our refactoring ambitions, but they were good ambitions that paid off. The next fixit will be even better. I look forward to it.&lt;/p&gt;

&lt;p&gt;*&lt;a href="http://37signals.com/svn/posts/3163-making-shit-work-is-everyones-job"&gt;Making shit work is everyone&amp;#8217;s job&lt;/a&gt;, unless you&amp;#8217;re &lt;a href="http://bitquabit.com/post/coding-is-priority-number-five/"&gt;the shit umbrella for ever-&lt;/a&gt;&amp;#8230;wait&amp;#8230;nevermind. Too much cursing. This one&amp;#8217;s not gonna get past the censors on the official KA blog.&lt;/p&gt;</description><link>http://bjk5.com/post/21317611897</link><guid>http://bjk5.com/post/21317611897</guid><pubDate>Wed, 18 Apr 2012 01:51:58 -0700</pubDate></item><item><title>Teacher effectiveness ratings, programmers, and Khan Academy's data</title><description>&lt;p&gt;
Today I was doing whatever it is I do when I ran across this link from Joel:
&lt;/p&gt;

&lt;blockquote class="twitter-tweet tw-align-center"&gt;&lt;p&gt;NYC teacher &amp;#8220;effectiveness&amp;#8221; ratings are bogus, and the data prove it &lt;a href="http://t.co/AnCDYtY6" title="http://garyrubinstein.teachforus.org/2012/02/28/analyzing-released-nyc-value-added-data-part-2/"&gt;garyrubinstein.teachforus.org/2012/02/28/ana…&lt;/a&gt;&lt;/p&gt;— Joel Spolsky (@spolsky) &lt;a href="https://twitter.com/spolsky/status/175364445302820864" data-datetime="2012-03-01T23:38:36+00:00"&gt;March 1, 2012&lt;/a&gt;&lt;/blockquote&gt;
&lt;script src="http://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;&lt;p&gt;
&amp;#8230;and my brain started pattern matching. Replace &amp;#8220;NYC teacher&amp;#8221; with &amp;#8220;programmer&amp;#8221; in this tweet, and you&amp;#8217;d be in classic Joel on Software land. After all, one of Joel&amp;#8217;s self-stated missions is to make programmers&amp;#8217; lives better (you can see his efforts played out in both the principles of Fog Creek and Stack Overflow), and he&amp;#8217;s spent plenty of time trying to convince us of &lt;a href="http://www.joelonsoftware.com/news/20020715.html"&gt;the stupidity of using automated metrics to assess programmers&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
Before we go any further, here&amp;#8217;s the gist of the post about NY&amp;#8217;s teacher effectiveness ratings that were recently released to the public: they have major flaws. &lt;a href="http://garyrubinstein.teachforus.org/2012/02/28/analyzing-released-nyc-value-added-data-part-2"&gt;Read the post&lt;/a&gt; — but this chart says a lot:
&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/eKam092dc/effectiveness.png"/&gt;&lt;br/&gt;&lt;em&gt;Every point is a teacher that taught the &lt;strong&gt;same subject&lt;/strong&gt; to two different grades in the same year. Think of a middle school teacher handling both 6th and 7th grade math. The x-axis is their effectiveness rating for one of the grades, the y-axis is the other grade.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You don&amp;#8217;t have to stare at the graph long to see a surprising lack of correlation. If you&amp;#8217;re effective at teaching 7th grade math, shouldn&amp;#8217;t you be effective at 6th? Wait. Before you throw effectiveness ratings out the window, &lt;a href="http://garyrubinstein.teachforus.org/2012/02/28/analyzing-released-nyc-value-added-data-part-2/#comment-555465"&gt;read the comment further down the page&lt;/a&gt; that points out the increasing usefulness of the published data as you look across multiple years of teachers&amp;#8217; past. Ok, that makes sense. But still, judging teachers on test score summaries alone is madness. Perhaps they&amp;#8217;re useful feedback when given to teachers appropriately, with caveats, and all? Maybe the ratings need some tweaking?
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;None of this matters if the data is published to the public and uses a single, automated metric to reward or punish teachers.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
There&amp;#8217;s a good reason &lt;a href="http://www.nytimes.com/2012/02/23/opinion/for-teachers-shame-is-no-solution.html"&gt;Bill Gates tore apart the decision to publish this data&lt;/a&gt;. He knows that a single metric is bound to be not only flawed, but, if used as an incentive system, also destructive to both teachers &lt;em&gt;and&lt;/em&gt; any attempts to improve the metric. His nuanced argument for a system that combines data and highly trained teachers evaluating their peers sounds pretty similar to the belief that highly technical programmers should be the only ones managing other programmers:
&lt;/p&gt;

&lt;blockquote&gt;
But student test scores alone aren’t a sensitive enough measure to gauge effective teaching, nor are they diagnostic enough to identify areas of improvement. Teaching is multifaceted, complex work. A reliable evaluation system must incorporate other measures of effectiveness, like students’ feedback about their teachers and classroom observations by highly trained peer evaluators and principals.&lt;br/&gt;&lt;br/&gt;
— &lt;a href="http://www.nytimes.com/2012/02/23/opinion/for-teachers-shame-is-no-solution.html"&gt;For Teachers, Shame is Not the Solution&lt;/a&gt;
&lt;/blockquote&gt;

&lt;p&gt;
Again, replace &amp;#8220;teachers&amp;#8221; with &amp;#8220;software developers&amp;#8221; up there and you&amp;#8217;ll see Bill Gates is making the same crusade he made for developers — protection from the type of overly simplified management incentives that destroy your ability to focus on the tasks at hand when working in a complex, creative profession.
&lt;/p&gt;

&lt;p&gt;
I was lucky enough to step into professional programming at a time when an exploding number of forward-thinking companies were starting to treat and recruit programmers effectively. I was never promoted or demoted based on the number of bugs I created or lines of code I wrote. But it&amp;#8217;s clear that wasn&amp;#8217;t always the way things worked, and when I was in college I remember &lt;a href="http://joelonsoftware.com/articles/fog0000000070.html"&gt;reading Joel&lt;/a&gt; and &lt;a href="http://www.paulgraham.com/icad.html"&gt;Paul Graham&lt;/a&gt;, who both stood out as Defenders of The Programmer against destructive management.
&lt;/p&gt;

&lt;p&gt;
This is why &lt;strong&gt;we&amp;#8217;d never, ever use Khan Academy data to single-handedly &amp;#8220;rank&amp;#8221; teachers or anything else so ridiculous&lt;/strong&gt;. Khan Academy data (and there&amp;#8217;s a lot of it, we just passed 400 million practice problems done) is to be put in the hands of teachers, &lt;em&gt;for&lt;/em&gt; teachers, as a powerful tool that lets them dive deep into their students&amp;#8217; individual levels of mastery. We aim to empower teachers with the best tools available and believe that the only people assessing them should be highly trained teachers who understand the nuances of their craft and work with them to improve. Sound familiar to you, devs?
&lt;/p&gt;

&lt;p&gt;
I&amp;#8217;ve never been a teacher, but I do know that I&amp;#8217;ll never even consider working for a company that assesses my performance based on a single automated metric. I think I have Microsoft and Google and Joel and Paul Graham and co. to thank for the software world&amp;#8217;s culture of respect for both data and individuals. And now it&amp;#8217;s really cool to see Bill Gates and Joel taking a similar stand in defense of teachers.
&lt;/p&gt;

&lt;p&gt;
Ten bucks says none of the teachers in &lt;a href="http://www.joelonsoftware.com/items/2012/01/13.html"&gt;The Academy for Software Engineering&lt;/a&gt; suffer from a single metric incentive system.
&lt;/p&gt;</description><link>http://bjk5.com/post/18609999923</link><guid>http://bjk5.com/post/18609999923</guid><pubDate>Fri, 02 Mar 2012 08:49:52 -0800</pubDate></item><item><title>Required code reviews</title><description>&lt;p&gt;This is the story of the &lt;a href="http://www.khanacademy.org/about/the-team"&gt;growing Khan Academy team&lt;/a&gt; converting me into a passionate fan of requiring a code review for every single changeset.&lt;/p&gt;

&lt;p&gt;Those who have worked with me know that it&amp;#8217;s a surprising position for me to take. On the spectrum of &amp;#8220;Follows good development practices even if it slows down the product&amp;#8221; to &amp;#8220;Just ship the thing, code doesn&amp;#8217;t matter, only users matter,&amp;#8221; I tend to fall&amp;#8230;right about&amp;#8230;[furiously scribbling]&amp;#8230;here:&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/Eijm03fn7/devs2.png"/&gt;&lt;/p&gt;

&lt;p&gt;Even though I&amp;#8217;ve long been a fan of code reviews &lt;a href="http://bjk5.com/post/1468464500/why-are-code-reviews-socially-difficult"&gt;at both Fog Creek and Khan&lt;/a&gt;, I never would&amp;#8217;ve suggested &lt;em&gt;requiring&lt;/em&gt; them for every single changeset, no matter how small. At first glance it appears all &lt;strong&gt;P̝̂R̫͙̼̽ͪ̽̋Ö̝̹̿ͬ́̐̆̈CÈ̝̱S̮̜͙̩̠S̹͍̳̖͍̆̐Y̩̟̥̟̘̺̠ͭͫ̔&lt;/strong&gt;, this is web development, not rocket science, and Hey what if there&amp;#8217;s an emergency and Wait are you serious, you want me to review my single-line change to a trivial &lt;code&gt;#comment&lt;/code&gt;???&lt;/p&gt;

&lt;p&gt;Luckily for everyone, we&amp;#8217;ve been hiring smarter and smarter people at Khan who can save me from myself. (What&amp;#8217;s that theory about smart people and some lake? Lake Okeechobee, I think. With the crocodiles.) We told our team that we&amp;#8217;re requiring code reviews for all pushes a couple weeks ago. Spoiler alert: it&amp;#8217;s not that processy, and even a Just Ship It clown like me is already seeing immense value from the experiment.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/W9wm03e2u/croc.jpg"/&gt;&lt;br/&gt;&lt;em&gt;Croc! No, sorry, wait&amp;#8230;log!&amp;#8230;Or, no! Wait! Sorry&amp;#8230;Croc!&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;What&amp;#8217;s been so great about requiring reviews?&lt;/h1&gt;&lt;br/&gt;&lt;ol&gt;&lt;li&gt;For a team that &lt;a href="http://bjk5.com/post/3994859683/code-reviews-as-relationship-builders-a-few-tips"&gt;values code reviews so highly&lt;/a&gt;, we were missing a lot of them. Turns out there are quite a few excuses you&amp;#8217;ll tell yourself to explain why this changeset doesn&amp;#8217;t need a review. By explicitly setting the expectation, everything&amp;#8217;s much simpler. Just get it reviewed.&lt;br/&gt;&lt;br/&gt;&lt;/li&gt;

&lt;li&gt;Frequent, digestible reviews. By committing frequently and reviewing &lt;em&gt;everything&lt;/em&gt;, we don&amp;#8217;t let features build up to huge, threatening diffs that make your nose bleed like &lt;a href="http://www.rottentomatoes.com/m/chronicle/"&gt;the emo kids from Chronicle&lt;/a&gt;. Any change that makes reviews more enjoyable will amplify &lt;a href="https://sites.google.com/a/khanacademy.org/forge/for-developers/new-developers/getting-familiar-with-the-code/code-review-policy"&gt;all of the other well-understood benefits of code review that we&amp;#8217;ve listed in our public Khan onboarding docs&lt;/a&gt; so I don&amp;#8217;t have to make this sentence any longer by talking about them. Small reviews are just more fun.&lt;br/&gt;&lt;br/&gt;&lt;/li&gt;

&lt;li&gt;Those quick one-line reviews aren&amp;#8217;t actually a problem. They take 30 seconds to review, see #1. If you have a legitimate emergency, push it and get it reviewed later, ain&amp;#8217;t no thang. If I believed for a second that this decision would hurt our ability to Get Things Done, I&amp;#8217;d be fighting it tooth and nail.&lt;br/&gt;&lt;br/&gt;&lt;/li&gt;

&lt;li&gt;In two weeks of doing this, I feel I&amp;#8217;ve improved as a developer more than any other period in recent memory. All props to &lt;a href="http://generic.cx/"&gt;my&lt;/a&gt; &lt;a href="https://plus.google.com/110287455381476170305/posts"&gt;reviewers&lt;/a&gt;, of course, and it probably doesn&amp;#8217;t hurt that I&amp;#8217;m actually writing code for the first time in a while. But&amp;#8230;still.&lt;/li&gt;

&lt;/ol&gt;&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/e2xm03dus/reviews.png"/&gt;&lt;br/&gt;&lt;em&gt;All changesets reviewed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s not for every group. I&amp;#8217;m not convinced it would&amp;#8217;ve been right when Jason and I were hacking together alone. But requiring code reviews has already made for a better product and a healthier team, two things that I personally care about far more than a healthy codebase. That&amp;#8217;s just a nice side-effect.&lt;/p&gt;

&lt;hr&gt;&lt;br/&gt;&lt;p&gt;P.S. When working on &lt;a href="http://kilnhg.com"&gt;Kiln&lt;/a&gt;, I was adamantly opposed to building code review requirements directly into the source control product. I stand by that belief, and I&amp;#8217;m almost certain the Kiln team still agrees. Reviews should be required by your team&amp;#8217;s dynamics and strongly encouraged by your tooling, not the other way around.&lt;/p&gt;</description><link>http://bjk5.com/post/18441794352</link><guid>http://bjk5.com/post/18441794352</guid><pubDate>Tue, 28 Feb 2012 09:07:35 -0800</pubDate></item><item><title>Sharing the inspiring, personal stories of Khan Academy users</title><description>&lt;p&gt;
We have these emails hanging up all over our office, sent in from Khan Academy users with incredible, personal stories to tell. Every time I read a new one I&amp;#8217;m emotionally affected, which means my robot emotion chip is faulty.
&lt;/p&gt;

&lt;p&gt;
So when some curious soul (like a reporter) wanders in and asks me, &amp;#8220;How will you know if Khan Academy is really successful?&amp;#8221; I always answer their (totally valid) question with an explanation of our data, analytics, and fancy metrics &amp;#8212; but what I&amp;#8217;m really thinking is, &amp;#8220;&lt;em&gt;You haven&amp;#8217;t read these letters.&lt;/em&gt;&amp;#8221;
&lt;/p&gt;

&lt;p&gt;
Let&amp;#8217;s change that. &lt;a href="http://www.khanacademy.org/stories"&gt;These students&amp;#8217; and parents&amp;#8217; and teachers&amp;#8217; stories are now available for anyone to be inspired by.&lt;/a&gt; It is impossible to read them&amp;#8230;go ahead, I challenge you&amp;#8230;and not come away with the conclusion that a free educational resource like Khan Academy simply must exist.
&lt;/p&gt;

&lt;p class="center"&gt;&lt;a href="http://www.khanacademy.org/stories"&gt;&lt;img src="http://static.tumblr.com/9hgswys/oZWlyao2j/stories.png"/&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;
Call me a softie. It&amp;#8217;s not like I don&amp;#8217;t believe in data as the final arbiter of any learning tool&amp;#8217;s effectiveness. I do. But if our key data metric happened to be &amp;#8220;# of page-long, authentic stories sent in from users who have &lt;a href="http://www.khanacademy.org/stories/paesan"&gt;turned their lives around in the face of drug addiction&lt;/a&gt;, &lt;a href="http://www.khanacademy.org/stories/dan"&gt;unleashed their 2nd-grade son on the advanced math he&amp;#8217;s fully qualified to handle&lt;/a&gt;, or &lt;a href="http://www.khanacademy.org/stories/rayana"&gt;earned acceptance into a university despite being stuck in a country that does not value education&lt;/a&gt;,&amp;#8221; I don&amp;#8217;t think I&amp;#8217;d second guess seeing that number skyrocket.
&lt;/p&gt;

&lt;p&gt;
Hopefully these stories inspire others as much as everybody on our team. We spent time designing the page to celebrate the authors, their letters, and the fact that these are real lives, not product testimonials.
&lt;/p&gt;

&lt;p&gt;Does the page accomplish this? Feedback welcome, good and bad.&lt;/p&gt;</description><link>http://bjk5.com/post/16401068120</link><guid>http://bjk5.com/post/16401068120</guid><pubDate>Tue, 24 Jan 2012 00:50:07 -0800</pubDate></item><item><title>Khan Academy Internship, Fall '11</title><description>&lt;blockquote&gt;
I already can’t wait to drop some major challenges in the laps of our two incoming Fall interns to see what they can build.&lt;br/&gt;&lt;br/&gt;
- &lt;a href="http://bjk5.com/post/8826207372/khan-academy-internship-summer-11"&gt;Khan Academy Internship, Summer &amp;#8216;11&lt;/a&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="shadowless" src="http://static.tumblr.com/9hgswys/w9Ylxgcf0/green_checkmark_thick24.png"/&gt; Check!&lt;/p&gt;

&lt;p&gt;&lt;a href="http://david-hu.com"&gt;David Hu&lt;/a&gt; and &lt;a href="http://www.julianpulgarin.com"&gt;Julian Pulgarin&lt;/a&gt; stepped up to the plate this Fall during their &lt;strike&gt;coops&lt;/strike&gt;internships from University of Waterloo. We call &amp;#8216;em &lt;em&gt;internships&lt;/em&gt; because we&amp;#8217;re from Amurrrrica, you crazy Canadians.&lt;/p&gt;

&lt;p&gt;When hanging with friends and family recently, I found myself shocked by how willing my brain is to completely forget stories that were surely once described as unforgettable. I don&amp;#8217;t have any desire to forget what we&amp;#8217;re doing at Khan Academy, and that&amp;#8217;s kinda sorta why &lt;a href="https://sites.google.com/a/khanacademy.org/forge/for-developers"&gt;being as open as possible is one of our core dev principles&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://bjk5.com/post/8826207372/khan-academy-internship-summer-11"&gt;The Summer &amp;#8216;11 story&lt;/a&gt; is already a nice piece of shared history that helps me answer every intern candidate who asks, &amp;#8220;What kind of project do interns work on at Khan Academy?&amp;#8221;. Here&amp;#8217;s my version of the Fall story.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/f9plxgd7f/bison_bull_photo.jpg"/&gt;&lt;br/&gt;&lt;em&gt;If tales about &lt;a href="http://www.amazon.com/Ride-ebook/dp/B006QXE2OA"&gt;battling a bison for the right to cross a road&lt;/a&gt; can get up and walk out of my head,&lt;br/&gt; then&amp;#8230;well&amp;#8230;better keep blogging.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;David&lt;/h1&gt;

&lt;p&gt;It doesn&amp;#8217;t get much more open than David&amp;#8217;s post about &lt;a href="http://david-hu.com/2011/11/02/how-khan-academy-is-using-machine-learning-to-assess-student-mastery.html"&gt;how we use machine learning to assess student mastery&lt;/a&gt;. If I tried to summarize it for you, you&amp;#8217;d see my managerial hair start spiking up and up and up toward the ceiling, Pinocchio-style. I won&amp;#8217;t insult the work by talking about the statistics. Instead, I&amp;#8217;ll just say that we now have a much better understanding of how competent each Khan student is in each math subject. Thanks, David.&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s not all he did. From a dashboard to emphasize the importance of our exercises to a much smoother way of asking students to review work they&amp;#8217;ve done in the past, he covers it all in &lt;a href="http://david-hu.com/2012/01/05/khan-academy-internship-post-mortem.html"&gt;this Vi Hart-inspired internship post-mortem&lt;/a&gt;.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/vv4lxgdtk/dashboard.png"/&gt;&lt;br/&gt;&lt;em&gt;Keeping an eye on our students&amp;#8217; activity via David&amp;#8217;s dashboard&lt;/em&gt;&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/2nWlxgdw8/teach-all-the-things.jpg"/&gt;&lt;br/&gt;&lt;em&gt;Forgetful Ben from the future is grateful for &lt;a href="http://david-hu.com/2012/01/05/khan-academy-internship-post-mortem.html"&gt;this video&lt;/a&gt;. And he&amp;#8217;s also super-jacked and smart.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;Julian&lt;/h1&gt;

&lt;p&gt;If anybody reading this has ever beaten Julian Pulgarin in chess, please rub his nose in it. Julian wiped the floor with me so many times that he would beg me to play him while he was blindfolded. My ego can&amp;#8217;t handle that sort of hit, so I usually just deleted some data from production and pretended to be disappointed at each newfound emergency&amp;#8217;s particularly poor timing.&lt;/p&gt;

&lt;p&gt;When he wasn&amp;#8217;t humoring me, Julian made major contributions across the board.&lt;/p&gt;

&lt;p&gt;He started by building a number of new exercises for students to learn from, including an experimental crack at a new way of teaching fraction intuition. While working on this, he realized that it was painful to test our open source contributor&amp;#8217;s GitHub pull requests, so he disappeared for a few days and came back with &lt;a href="https://github.com/jpulgarin/sandcastle"&gt;Sandcastle&lt;/a&gt;. Sandcastle automatically tags every pull request with a link that lets our developers test out the requests&amp;#8217; new exercise content in one click.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/gpKlxgedd/sandcastle.png"/&gt;&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s a shining example of the reason we hire smart people and set them free to get things done. The first time Julian told me about his Sandcastle idea, I didn&amp;#8217;t even really understand the direction. Now it&amp;#8217;s indispensable.&lt;/p&gt;

&lt;p&gt;Julian also gave our first KA Friday Tech Talk about how to do gradual feature rollouts for various segments of a large userbase. He ended up bringing this full-circle at the end of his internship by building Gandalf, our tool for doing the following:&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/irllxgemx/gandalf.png"/&gt;&lt;br/&gt;&lt;em&gt;Gandalf lets us selectively roll out features to all sorts of different subsections of our userbase.&lt;/em&gt;&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/O84lxgeqn/pass.jpg"/&gt;&lt;br/&gt;&lt;em&gt;&amp;#8220;YOU SHA &amp;#8212; ok, you guys, Hey!, you guys over there, you can pass &amp;#8212; BUT OTHER THAN THEM YOU SHALL NOT PASS.&amp;#8221;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Julian even &amp;#8220;accidentally&amp;#8221; left his chess set in Mountain View for us to mail back to him, which I&amp;#8217;m pretty sure was his way of dropping the mic and walking off stage. &amp;#8220;You clean up.&amp;#8221;&lt;/p&gt;

&lt;p&gt;In conclusion, University of Waterloo is legit. I skipped over plenty of work done by both David and Julian, and it still makes for an impressive &lt;strike&gt;Fall&lt;/strike&gt; &lt;strike&gt;Winter&lt;/strike&gt; there are seasons in Mountain View? As argued in the previous internship&amp;#8217;s summary, any team that&amp;#8217;s not dedicating tons of resources to both recruiting and mentoring interns is plain old missing out. We&amp;#8217;re loving every minute of working with our interns.&lt;/p&gt;

&lt;h1&gt;BONUS!&lt;/h1&gt;

&lt;p&gt;Much like the phoenix or a &lt;a href="http://twitter.com/dino_joel"&gt;tyrannosaurus flying a fighter jet&lt;/a&gt;, Summer &amp;#8216;11 intern Joel Burget has risen from out of nowhere and dropped &lt;a href="http://joelburget.com/video-progress-indicators/"&gt;entertaining stories&lt;/a&gt; about &lt;a href="http://joelburget.com/khan-summer/"&gt;his summer&amp;#8217;s work&lt;/a&gt;. If you read them, are impressed, and want to hire Joel&amp;#8230;you can forget it. He&amp;#8217;s now full-time Joel.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you wanna tag in next, &lt;a href="http://www.khanacademy.org/r/jobs"&gt;the Summer &amp;#8216;12 internship class still has openings&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</description><link>http://bjk5.com/post/15500332273</link><guid>http://bjk5.com/post/15500332273</guid><pubDate>Sat, 07 Jan 2012 23:49:00 -0800</pubDate></item><item><title>.end() makes jQuery DOM traversal beautiful</title><description>&lt;p&gt;
This is my new favorite jQuery trick. I just learned it this year and have mentioned it in enough code reviews to decide it&amp;#8217;s worth sharing.
&lt;/p&gt;

&lt;p&gt;
When manipulating the DOM with jQuery, you often see code that looks something like:
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$("#container").show();
$("#container .error").hide();
$("#container .zoo").css("background-color", "white");
$("#container .zoo .monkeys").empty();
$("#container .zoo .title").text("The zoo is empty");
$("#container .zoo input").val("");
$("#container .zoo").animate({height: 250});

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&amp;#8230;or, if somebody gets concerned about performance, they might try to reduce DOM lookups:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var container = $("#container");
container.show();
container.find(".error").hide();
container.find(".zoo").css("background-color", "white");
...

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&amp;#8230;and so on. Odds are, when you&amp;#8217;re manipulating a single element like &lt;code&gt;container&lt;/code&gt;, you&amp;#8217;ll probably be doing something to nearby elements in the next few lines of code.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/Icglwtqya/emma.png"/&gt;&lt;br/&gt;&lt;em&gt;Readers of this blog, meet Emma. Emma, meet the three readers of this blog.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="http://api.jquery.com/end/"&gt;&lt;code&gt;.end()&lt;/code&gt;&lt;/a&gt;, newlines, indentation, and chaining. When you have one jQuery chain going and modify it with, say, &lt;code&gt;.find()&lt;/code&gt;, &lt;em&gt;you&amp;#8217;re actually pushing the new chained set of elements onto a stack&lt;/em&gt;. &lt;code&gt;.end()&lt;/code&gt; pops the current jQuery chain off the stack, which lets you do stuff like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$("#container")
    .show()
    .find(".error")
        .hide()
        .end()
    .find(".zoo")
        .css("background-color", "white")
        .find(".monkeys")
            .empty()
            .end()
        .find(".title")
            .text("The zoo is empty")
            .end()
        .find("input")
            .val("")
            .end()
        .animate({height: 250});

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;#8217;s easy to read, because the indentation is significant and matches up with DOM nesting levels. It gets rid of unnecessary DOM lookups. But most importantly for me, it feels natural to indent in and out as I write the code, using small additional selectors to step deeper into the DOM and .end() to find my way back out.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve been destroying my old, ugly &lt;code&gt;var&lt;/code&gt;&amp;#8217;s left and right with this trick. I hope it helps somebody else.&lt;/p&gt;</description><link>http://bjk5.com/post/14819494947</link><guid>http://bjk5.com/post/14819494947</guid><pubDate>Mon, 26 Dec 2011 10:52:46 -0800</pubDate></item><item><title>Laughing at Others' Code</title><description>&lt;p&gt;
Those who have worked with me will know that I&amp;#8217;m an expert on this topic because my code gets laughed at all the time.
&lt;/p&gt;

&lt;p&gt;
I&amp;#8217;ve seen Good laughing and Bad laughing. Good is what I imagine happens when Robert De Niro sits next to Al Pacino as they&amp;#8217;re watching Al&amp;#8217;s cameo in &lt;a href="http://www.rottentomatoes.com/m/jack_and_jill_2011/"&gt;some trainwreck of an Adam Sandler movie&lt;/a&gt;, and Bob turns to Al smiling and says, &amp;#8220;This is awful.&amp;#8221; It&amp;#8217;s when you stare at some code and think, &amp;#8220;Good grief. I can just &lt;em&gt;imagine&lt;/em&gt; whatever took priority over making this code more reasonable.&amp;#8221; There&amp;#8217;s a knowing wink and a friendly jab between the laughed-at ghost-coder and the laugher:
&lt;/p&gt;

&lt;blockquote&gt;
Hah! I almost feel bad that you wound up solving it this way. I&amp;#8217;ve been there before. You must be exhausted. Why don&amp;#8217;t you sit down, I&amp;#8217;ll take it from here.
&lt;/blockquote&gt;

&lt;p&gt;
Good laughter contains respect for the fact that &lt;em&gt;this code exists at all and is being worked on by more than one programmer&lt;/em&gt;, which is more than you can say for what I&amp;#8217;d bet is a whole boatload of perfectly refactored, unused files littering hard drives around the world right now.
&lt;/p&gt;

&lt;p&gt;
That&amp;#8217;s the type of laugher that&amp;#8217;s erupting at Khan Academy these days, and it&amp;#8217;s no coinkydink that now is right about when a team of top-notch coders are getting their first gazes into some of my previous &lt;strike&gt;creations&lt;/strike&gt;abysses. I can say with certainty that in these cases the knowing winks and playful jabs are well-deserved.
&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/Zyglw97i8/laughing-dog-article.jpg"/&gt;&lt;br/&gt;&lt;em&gt;The rare (and best) third type of laughter.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;
A quick story before we get to the Bad laughter. Did you know that when Sal was a one-man show, the entire Khan Academy application was one big main.py file? At least the server-side stuff. All the request handlers, URL mappings, datastore models, data migrations, and even some HTML generation in one big 1000+ line file.
&lt;/p&gt;

&lt;p&gt;
How funny is that! And it stayed that way for months! I mean, &lt;u&gt;please&lt;/u&gt;. Who the heck wants to work on a codebase that&amp;#8217;s one big file? If you haven&amp;#8217;t detected the dripping sarcasm yet, recalibrate your sarcasm detector and start this paragraph again.
&lt;/p&gt;

&lt;p&gt;
It&amp;#8217;s easy to see how judging Sal by that one big file while he was busy making 2400+ free educational videos would be like judging a geek for wearing a t-shirt while she was just trying to look presentable enough to get to her computer to start writing code. Guess what? Sal&amp;#8217;s code is still around, and it&amp;#8217;s responsible for helping teach literally millions of students. Yet, as time goes on, it gets more and more likely that one day somebody will laugh at an out-of-place line with the type of judgment that can only come from being out-of-touch with what really mattered back then&amp;#8230;and the fact that that line helped change many students&amp;#8217; lives.
&lt;/p&gt;

&lt;p class="center"&gt;&lt;a href="http://twitter.com/#!/patio11/status/145188512109576193"&gt;&lt;img src="http://static.tumblr.com/9hgswys/nqjlw8n87/screen_shot_2011-12-15_at_1.19.07_am.png"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;em&gt;You&amp;#8217;ve gotta bend this brilliant tweet a bit to apply it to non-profit education,&lt;br/&gt;but you&amp;#8217;ll notice &amp;#8220;good code&amp;#8221; and &amp;#8220;bad code&amp;#8221; aren&amp;#8217;t on the list.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;
Bad laughter doesn&amp;#8217;t need much explanation, it just lacks respect. It happens too much in our industry, and I&amp;#8217;m not sure why. I&amp;#8217;m proud to say that it&amp;#8217;s not a problem at Khan at all, but we haven&amp;#8217;t always been 100% immune. We weren&amp;#8217;t always 100% immune at Fog Creek.  I&amp;#8217;ve been guilty of this laughter myself, and I&amp;#8217;d bet money it exists elsewhere. It&amp;#8217;s most common among coders who feel like they need to prove themselves, and it can be combatted by a team that emphasizes shipping and the healthy laughter that comes from reminiscing about the last crappy &lt;a href="http://bjk5.com/post/2954631955/messy-solutions-work-just-as-well"&gt;hack you were responsible for when you decided to Just Ship It&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s (just one of) ours:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;PLAYLIST_STRUCTURE = [
    {
        "name": "Math",
        "items":
            [
                {
                    "name": "Arithmetic",
                    "playlist": "Arithmetic"
                },
                {
                    "name": "Developmental Math",
                    "items": [
                    ...

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;#8217;s our current Khan playlist structure, defined in code. When Sal adds or renames a playlist, we have to change the code. Laugh it up.&lt;/p&gt;

&lt;p&gt;This will actually go away soon in favor of something much nicer, and I&amp;#8217;m not arguing for crappy code. I&amp;#8217;m putting this example here because it got us this far, without many problems, and who knows where we&amp;#8217;d be if Sal had spent the first iteration of &lt;a href="http://www.khanacademy.org"&gt;khanacademy.org&lt;/a&gt; trying to decide on the perfect playlist data structure.&lt;/p&gt;

&lt;p class="center"&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/PaGTQMAIMhY&amp;amp;hl=en&amp;amp;fs=1"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;embed src="http://www.youtube.com/v/PaGTQMAIMhY&amp;amp;hl=en&amp;amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br/&gt;&lt;em&gt;&amp;#8230;and a more rambling attempt to get a similar point across to a group of UIUC students by playing &lt;a href="http://www.khanacademy.org/video/thank-you-khan-academy"&gt;this powerful Thank You, Khan Academy video&lt;/a&gt; before revealing main.py.&lt;/em&gt;&lt;/p&gt;</description><link>http://bjk5.com/post/14265572563</link><guid>http://bjk5.com/post/14265572563</guid><pubDate>Thu, 15 Dec 2011 08:39:00 -0800</pubDate></item><item><title>After giving logged out users access to pretty much everything*</title><description>&lt;p&gt;We had some heated debates a while ago about &lt;a href="http://bjk5.com/post/3716277312/should-khan-academy-follow-stack-overflows"&gt;what would happen if we opened up all of Khan Academy&amp;#8217;s content for logged out users&lt;/a&gt;. Sal&amp;#8217;s videos have always been open in this way, of course, but all the interactive exercises and statistical tracking and badges and stuff required an account.&lt;/p&gt;

&lt;p&gt;It felt like the right move when we reconfirmed our belief that educational content should be as open and available as possible. We were also persuaded by &lt;a href="http://www.avc.com/a_vc/2011/06/dont-forget-your-logged-out-users.html"&gt;Fred Wilson&amp;#8217;s belief&lt;/a&gt; that giving logged out users more power is an effective way to empower your community. But we worried that registrations would drop, because by handing our 250+ exercises to logged out users, we&amp;#8217;d be drastically shrinking the carrot on the other side of the &amp;#8220;please login!&amp;#8221; boundary.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://bjk5.com/post/8826207372/khan-academy-internship-summer-11"&gt;We decided to go for it this summer&lt;/a&gt;. Figured I&amp;#8217;d share some results.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/KvFlw19kj/flossi-golden-retriever1.jpg"/&gt;&lt;br/&gt;&lt;em&gt;A dog&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;4+ months after the change, we know a little more. Jace looked at the data and found:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Registration rate &lt;strong&gt;hasn&amp;#8217;t&lt;/strong&gt; changed. Bit of a surprise for both sides of the debate.&lt;/li&gt;
&lt;li&gt;Percentage of our visitors who try an exercise problem increased by (relative) 10-15%.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;So more visitors are trying exercises, but they&amp;#8217;re not converting into more registered users&amp;#8230;yet. We could have fun making up all sorts of explanations. Maybe we need to show off the badges and points unregistered users are accumulating a little bit more, maybe we&amp;#8217;re not asking visitors to login forcefully enough, maybe doing math exercises makes people tired, maybe we don&amp;#8217;t have enough pictures of golden retrievers on the login page.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/Q9Llw199d/exusers.png"/&gt;&lt;br/&gt;&lt;em&gt;Percentage of all visitors who use our exercises&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Far more important than any random explanation is the fact that we&amp;#8217;re now getting X% more data about how users learn (or don&amp;#8217;t learn) thanks to these new exercise visitors. That data is powering some of the &lt;a href="http://david-hu.com/2011/11/02/how-khan-academy-is-using-machine-learning-to-assess-student-mastery.html"&gt;best work coming out of Khan Academy so far&lt;/a&gt;, so feeding more logged out users into our exercises is, as Jace puts it, a big win on data collection.&lt;/p&gt;

&lt;p&gt;Plus, we&amp;#8217;re confident that we could iterate and A/B test our way to higher registration rates for our new exercise users. It&amp;#8217;s not our priority (for this week, at least). We&amp;#8217;re busy cooking up important changes to the core learning experience.&lt;/p&gt;

&lt;p&gt;*They don&amp;#8217;t have access to &lt;em&gt;everything&lt;/em&gt;. The ability to coach and communicate with other users is still restricted to users who have logged in.&lt;/p&gt;</description><link>http://bjk5.com/post/14059107433</link><guid>http://bjk5.com/post/14059107433</guid><pubDate>Sun, 11 Dec 2011 01:48:25 -0800</pubDate></item><item><title>How to make "consecutive days of Khan Academy activity" badges</title><description>&lt;p&gt;&lt;ol&gt;&lt;li&gt;Think how cool it would be if users were rewarded after learning for X consecutive days.&lt;/li&gt;
&lt;li&gt;Think about implementation for a second and then go, &amp;#8220;Sweet! This&amp;#8217;ll be trivial Let&amp;#8217;s knock it out Here we go I&amp;#8217;ve got things to do!&amp;#8221;
&lt;br/&gt;&lt;br/&gt;&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/mdxlvge1g/2.png"/&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Write a line of code or two.&lt;/li&gt;
&lt;li&gt;Get sucker-punched by &lt;a href="http://bjk5.com/post/2877789021/to-all-the-big-boys-solving-the-internets-identity"&gt;the gruesome specter of timezones&lt;/a&gt; when realizing that a student doing work at 8am on Thursday and 9pm on Friday should probably still earn their badge even though over 24 hours of non-work elapsed.
&lt;br/&gt;&lt;br/&gt;&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/Zt2lvge07/1.png"/&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Think &amp;#8220;How does Stack Exchange do this?&amp;#8221; and discover that while they suffer from the timezone bug, &lt;a href="http://meta.stackoverflow.com/questions/55483/proposed-consecutive-days-badge-tracking-change"&gt;passionate Stack Exchange users have &lt;em&gt;written actual code&lt;/em&gt; to do the trick&lt;/a&gt; without asking users for timezone information.&lt;/li&gt;
&lt;li&gt;Follow those passionate users&amp;#8217; suggestions, knock it out, and enjoy a few weeks later when the most dedicated users start earning badges for 30 days of consecutive learning.
&lt;br/&gt;&lt;br/&gt;&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/mg6lvge1q/3.png"/&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;/p&gt;</description><link>http://bjk5.com/post/13529957109</link><guid>http://bjk5.com/post/13529957109</guid><pubDate>Tue, 29 Nov 2011 19:17:04 -0800</pubDate></item><item><title>A/B testing still works. [Sarcastic *PHEW*].</title><description>&lt;p&gt;After releasing &lt;a href="http://bjk5.com/post/10171483254/a-bingo-split-testing-now-on-app-engine-built-for-khan"&gt;GAE/Bingo&lt;/a&gt;, we received a number of worried correspondences from various very worried correspondents. It seems that GAE/Bingo, along with practically every other A/B testing framework out there, &lt;a href="http://www.evanmiller.org/how-not-to-run-an-ab-test.html"&gt;violates some purist principles of how to do significance testing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The crux of the argument, reworded so simply that I&amp;#8217;m pretty sure all statisticians (I admittedly know nothing about stats) would string me up:&lt;/p&gt;

&lt;blockquote&gt;If you repeatedly check the results of an experiment, sometimes you&amp;#8217;ll see statistically significant results that aren&amp;#8217;t actually significant.&lt;br/&gt;&lt;br/&gt;
So if you&amp;#8217;re constantly checking your A/B dashboard and making decisions based on what it tells you, you&amp;#8217;re often screwing up.&lt;/blockquote&gt;

&lt;p&gt;It&amp;#8217;s a mathematically sound argument, as explained to me by my much smarter teammates. And it must be absolutely devastating for all the programmers who went out and bought the &lt;a href="http://store.razerzone.com/store/razerusa/en_US/pd/productID.231103000/parentCategoryID.35208800/categoryId.36716300"&gt;Razer Mamba Elite Wireless Gaming Mouse&lt;/a&gt; just to increase their click speed so they could mash the refresh button on their A/B dashboards as fast as possible.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s the thing. I know of absolutely nobody who runs an A/B test like a crazed puppy who keeps sprinting loops around your legs hoping that&amp;#8230;..ohboyohboyohboyohboy&amp;#8230;..after the next 360° you&amp;#8217;ll have lowered the puppy treat to the floor.&lt;/p&gt;

&lt;p&gt;That doesn&amp;#8217;t mean the argument isn&amp;#8217;t valid. If you &lt;em&gt;do&lt;/em&gt; check your dashboard every 5 seconds like a crazed puppy and immediately end experiments at the first sign of stat sig, &lt;a href="http://www.evanmiller.org/how-not-to-run-an-ab-test.html"&gt;then you probably should read the article&lt;/a&gt; and&amp;#8230;..ummmmm&amp;#8230;..find better uses for your time.&lt;/p&gt;

&lt;p&gt;Luckily for us, one of my much smarter teammates with much more experience analyzing numbers&amp;#8217;n&amp;#8217;stuff landed an early modification to GAE/Bingo that should pacify all worried correspondents:&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/sTuluoxp8/ab.png"/&gt;&lt;br/&gt;&lt;em&gt;A historical graph of one of our A/B tests and each alternative&amp;#8217;s performance. On our dashboard it&amp;#8217;s interactive, weeeeeeeee.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;By showing this graph everywhere our dashboard shows A/B results and waiting for the results to stabilize, we can be confident that we&amp;#8217;re not making a snap judgment in the zone of idiotic decisions.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/nxgluprjk/idiotic.png"/&gt;&lt;br/&gt;&lt;em&gt;&amp;#8220;&lt;a href="http://www.dangerzone.me/"&gt;Danga zone&lt;/a&gt;&amp;#8221;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ok, good. We&amp;#8217;re safe. But what about everybody else? Did &lt;a href="http://blog.fogcreek.com/our-marketing-is-up-fog-creek-and-what-we-did-about-it/"&gt;Fog Creek&lt;/a&gt; and &lt;a href="http://37signals.com/svn/posts/2991-behind-the-scenes-ab-testing-part-3-final"&gt;37signals&lt;/a&gt; and everybody including Google immediately start hemorrhaging money due to their reliance on faulty A/B tests which this truth came to light???&lt;/p&gt;

&lt;p&gt;My guess is no, because A) they aren&amp;#8217;t making snap judgments at the first sign of stat sig and B) with significant traffic, many of our A/B test experiments don&amp;#8217;t even &lt;em&gt;have&lt;/em&gt; a zone of idiotic decisions. Lots of &amp;#8216;em look something like this:&lt;/p&gt;

&lt;p class="center"&gt;&lt;nobr&gt;&lt;img src="http://static.tumblr.com/9hgswys/qnPluoyqr/1.png"/&gt; &lt;img src="http://static.tumblr.com/9hgswys/Lf2luoyyr/22.png"/&gt;&lt;/nobr&gt;&lt;br/&gt;&lt;img src="http://static.tumblr.com/9hgswys/q6Rluoys1/3.png"/&gt;&lt;/p&gt;

&lt;p&gt;&amp;#8230;and it&amp;#8217;s pretty clear in which cases a difference has been made.&lt;/p&gt;</description><link>http://bjk5.com/post/12829339471</link><guid>http://bjk5.com/post/12829339471</guid><pubDate>Mon, 14 Nov 2011 23:51:00 -0800</pubDate></item><item><title>App Engine Performance Hacks You'll Probably Never Need, Part I </title><description>&lt;p&gt;&lt;a href="http://bjk5.com/post/10171483254/a-bingo-split-testing-now-on-app-engine-built-for-khan"&gt;Building GAE/Bingo&lt;/a&gt; required reaching into the bag of performance tricks a couple times. We needed long-term persistence of the data behind many A/B experiments, with stats accumulating at 500 reqs/sec, without slowing down pageloads.&lt;/p&gt;

&lt;p&gt;Some of the wabbits we pulled out of the hat are pretty cool. Some are probably really stupid &lt;a href="http://bjk5.com/post/2954631955/messy-solutions-work-just-as-well"&gt;but get the job done&lt;/a&gt;. I&amp;#8217;ll throw a couple your way and let you choose which is which.&lt;/p&gt;

&lt;h1&gt;Access a select few from a list of entities on every single request &amp;#8212; and you don&amp;#8217;t know which until the request is done&lt;/h1&gt;&lt;br/&gt;&lt;p&gt;GAE/Bingo makes it easy to run A/B experiments in one line of code: &lt;code&gt;ab_test("monkeys")&lt;/code&gt;. This means during any given request, an individual user might interact with a number of different experiments depending on various code paths. Without knowing ahead of time which &lt;code&gt;ab_test("monkeys") or ab_test("gorillas") or ab_test("chimpanzees")&lt;/code&gt;&amp;#8217;s are going to run, we need to minimize the number of roundtrips spent talking to memcache or the datastore.&lt;/p&gt;

&lt;a href="http://www.offrench.net/photos/gallery-3_photo-406.php"&gt;&lt;img src="http://static.tumblr.com/9hgswys/uq6ltgjdm/boat.jpg" align="right" class="rightInset"/&gt;&lt;/a&gt;

    &lt;p&gt;At first it makes sense to put a collection of all &lt;code&gt;Experiment&lt;/code&gt; models in a single memcache slot. This is kinda helpful because at the beginning of the request you can:&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;experiments = memcache.get("experiments")

&lt;/code&gt;&lt;/pre&gt;

    &lt;p&gt;&amp;#8230;and then each time you need to work with an experiment you can:&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;experiment = experiments[experiment_name]

&lt;/code&gt;&lt;/pre&gt;

    &lt;p&gt;You&amp;#8217;ve only got one memcache call regardless of how many experiments you&amp;#8217;ll be interacting with on each request.&lt;/p&gt;

    &lt;p&gt;There&amp;#8217;s a big problem. Getting a bunch of objects out of memcache also involves deserializing all of those objects, not just transferring them over the wire. And at least until the &lt;a href="https://sites.google.com/site/gaepython27testing/"&gt;2.7 release&lt;/a&gt; ships, deserializing objects innnn ppuuurreeee Pyyyyttthhhooonnnnn iiiiiiiiiisssssssssssssss rrrreaaaaaaaaaaaaalllllllllllllyyyyyyyyyyyyy ssssssssssssssssssslllllllllllllllllllllloooooooooooooooooooowwwwwwwwwwwwwwwwwwwwww. If you&amp;#8217;re running, like, 50 live A/B experiments and your user needs to interact with, like, three of them when requesting &lt;code&gt;/profile&lt;/code&gt;, you&amp;#8217;ve got, like, 47 experiment-deserializations worth of performance waste.&lt;/p&gt;

    &lt;p&gt;Here&amp;#8217;s where we pulled out the same trick we first used when building a &lt;a href="http://bjk5.com/post/2562662487/badges-on-app-engine-implementing-a-real-time-badge"&gt;fast real-time badging system for Khan Academy&lt;/a&gt;. Since you&amp;#8217;ll almost never be interacting with all of the experiments in an individual request, you really really Really don&amp;#8217;t want to spend time deserializing them. So what happens if you serialize the objects once (in this case using protocol buffers) &lt;em&gt;before&lt;/em&gt; putting them in the memcache collection?&lt;/p&gt;

    &lt;p&gt;Things are a little bit slower when creating the collection:&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;memcache.set(
    "experiments",
    {
        "monkey": db.model_to_protobuf(experiment_monkey).Encode(),
        "gorilla": db.model_to_protobuf(experiment_gorilla).Encode(),
        ...
    }
)

&lt;/code&gt;&lt;/pre&gt;

    &lt;p&gt;Getting the collection from memcache is MUCH faster:&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;experiments = memcache.get("experiments")

&lt;/code&gt;&lt;/pre&gt;

    &lt;p&gt;&amp;#8230;because instead of deserializing 50 experiment models, you&amp;#8217;re unpacking 50 pre-serialized protocol buffers. Fast. Many much fast.&lt;/p&gt;

    &lt;p&gt;Now, when you need an actual experiment model, you just:&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;experiment = db.model_from_protobuf(entity_pb.EntityProto(experiments[experiment_name]))

&lt;/code&gt;&lt;/pre&gt;

    &lt;p&gt;&amp;#8230;and only pay the deserialization penalty when you actually need to use the object.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/wKVltginu/screen_shot_2011-10-22_at_12.42.34_am.png"/&gt;&lt;br/&gt;&lt;em&gt;This screenshot from my recent Khan Academy Friday tech talk should make everything totally clear. Especially without any context, I&amp;#8217;m pretty sure seeing a picture of a gnome riding a platypus while carrying a monkey explains everything.&lt;/em&gt;&lt;/p&gt;

    &lt;p&gt;Bottom line: we make one single memcache call coupled with the minimum amount of experiment deserialization necessary, regardless of how many A/B experiments are running or which experiments are used by each request. There are &lt;a href="http://kovshenin.com/archives/pickle-vs-json-which-is-faster/"&gt;lots of arguments over the fastest way to (de)serialize objects in App Engine&lt;/a&gt; &amp;#8212; the fastest is to avoid the issue as much as possible.&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;Where we use this:&lt;/em&gt;&lt;/p&gt;

    &lt;p&gt;&lt;a href="http://bjk5.com/post/10171483254/a-bingo-split-testing-now-on-app-engine-built-for-khan"&gt;Split testing experiments&lt;/a&gt; and our &lt;a href="http://bjk5.com/post/2562662487/badges-on-app-engine-implementing-a-real-time-badge"&gt;real-time badge framework&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;put_async without waiting for the put to finish &amp;#8212; someone&amp;#8217;s gonna yell at me&lt;/h1&gt;&lt;br/&gt;&lt;p&gt;I&amp;#8217;ll get in trouble for this or maybe even ruin the fun for everyone. This involves starting an asynchronous datastore put via &lt;code&gt;db.put_async&lt;/code&gt; and then walking away with your hands in your pockets acting like nothing happened.&lt;/p&gt;
    
    &lt;p&gt;There are &lt;a href="http://stackoverflow.com/questions/7244081/appengine-put-async-doesnt-work-at-least-in-the-development-server/7250613#7250613"&gt;very clear instructions by the talented App Engine team&lt;/a&gt; that you should find some time to wait for the &lt;code&gt;get_result()&lt;/code&gt; of any call to &lt;code&gt;db.put_async(monkey)&lt;/code&gt;. It&amp;#8217;s also very clear that if you don&amp;#8217;t wait for put_async to finish, App Engine is going to wait for you. In other words, you can&amp;#8217;t magically send off a bunch of put_async&amp;#8217;s and then send your response to the user without waiting for the put to complete.&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;db.put_async(experiment_monkey)
return render_template("mwuuahaha_im_not_doing_anything_else.html")

&lt;/code&gt;&lt;/pre&gt;

    &lt;p&gt;You can, however, send off a &lt;code&gt;put_async&lt;/code&gt; and then do everything else your request could possibly think of doing (including rendering templates and such) without waiting for the response. App Engine will make sure the response finishes, but if you just kick off the &lt;code&gt;put_async&lt;/code&gt; and then walk away and handle the rest of your request, you can maximize concurrency of your request&amp;#8217;s work w/ the asynchronous put.&lt;/p&gt;

    &lt;p&gt;There are *lots* of other ways to get a very similar effect. All of them are probably more kosher. I won&amp;#8217;t list them here. This just happens to be a neat little trick that you can trigger with one line of code without worrying about any other boilerplate.&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;Where we use this:&lt;/em&gt;&lt;/p&gt;

    &lt;p&gt;&lt;a href="https://khanacademy.kilnhg.com/Repo/Website/Group/stable/Files"&gt;Find the spots yourself&lt;/a&gt; and make fun of me. I have a strong feeling this&amp;#8217;ll be replaced in the future.&lt;/p&gt;

&lt;h1&gt;Long-term persistence without waiting on the datastore&lt;/h1&gt;&lt;br/&gt;&lt;p&gt;This one doesn&amp;#8217;t belong in a &amp;#8220;you&amp;#8217;ll probably never need&amp;#8221; post. It&amp;#8217;s extremely common and handy: throw data in memcache (fast) and then run a background task or cron job that persists the data from memcache to the datastore (slow).&lt;/p&gt;

    &lt;p&gt;
&lt;a href="http://www.flickr.com/photos/livenature/444275529/"&gt;&lt;img align="left" class="leftInset" src="http://static.tumblr.com/9hgswys/ugcltgj78/boat.jpg"/&gt;&lt;/a&gt;
We actually get a little trickier because we need to persist lots of data that&amp;#8217;s coming in quite often: each and every user&amp;#8217;s participation and conversions in each and every A/B test. These events could be triggered multiple times per request for each user. It&amp;#8217;s not quite clear how we&amp;#8217;d put this data in memcache and what scheme would be running in the background to send it all to the datastore.&lt;/p&gt;

    &lt;p&gt;We opted for a bucketing system. Every time a user participates or converts in an A/B test, we randomly choose one of 50 memcache buckets and throw their user id in the bucket. When any of those buckets begins to overflow, we fire off a deferred task queue task to poke through the overflowing bucket, pull each user&amp;#8217;s data out of memcache, and whisk it into the datastore.&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;bucket = random.randint(0, 50)
key = "_gae_bingo_identity_bucket:%s" % bucket

list_identities = memcache.get(key) or []
list_identities.append(ident)

if len(list_identities) &amp;gt; 50:
    deferred.defer(persist_gae_bingo_identity_records, list_identities)

&lt;/code&gt;&lt;/pre&gt;

    &lt;p&gt;&lt;em&gt;Where we use this:&lt;/em&gt;&lt;/p&gt;

    &lt;p&gt;&lt;a href="http://github.com/kamens/gae_bingo"&gt;GAE/Bingo&lt;/a&gt; and, in simpler fashions, pretty much all over the place.&lt;/p&gt;

&lt;h1&gt;More wabbits where those came from&lt;/h1&gt;&lt;br/&gt;&lt;p&gt;If any of these hacks help someone else out, &lt;a href="http://twitter.com/kamens"&gt;please let me know ASAP&lt;/a&gt; so I can win the bet against myself.&lt;/p&gt;

&lt;p&gt;Regardless, expect more of these posts in the future. Tricks like these have been critical to keeping Khan Academy fast while adding &lt;a href="http://github.com/kamens/gae_mini_profiler"&gt;new&lt;/a&gt; &lt;a href="http://github.com/kamens/gae_bingo"&gt;tools&lt;/a&gt;.&lt;/p&gt;</description><link>http://bjk5.com/post/11766098283</link><guid>http://bjk5.com/post/11766098283</guid><pubDate>Sat, 22 Oct 2011 01:08:43 -0700</pubDate></item><item><title>A/Bingo split testing now on App Engine, built for Khan Academy</title><description>&lt;p&gt;Continuing my trend of straight-up &lt;a href="http://bjk5.com/post/6944602865/google-app-engine-mini-profiler"&gt;copying the work of the smartest people I know&lt;/a&gt;, I recently decided to tackle &lt;a href="http://www.khanacademy.org"&gt;Khan Academy&lt;/a&gt;&amp;#8217;s A/B testing problem (we didn&amp;#8217;t have any A/B testing) by bringing &lt;a href="http://www.kalzumeus.com/"&gt;Patrick McKenzie&lt;/a&gt;&amp;#8217;s &lt;a href="http://www.bingocardcreator.com/abingo"&gt;A/Bingo&lt;/a&gt; into App Engine land.&lt;/p&gt;

&lt;p&gt;So here you go: &lt;a href="https://github.com/kamens/gae_bingo"&gt;GAE/Bingo is released and should get anyone on App Engine up and A/B testing in minutes&lt;/a&gt;. It&amp;#8217;s currently in production on Khan Academy and performing well with hundreds of requests per second.&lt;/p&gt;

&lt;h1&gt;Cool! But what&amp;#8217;s A/Bingo?&lt;/h1&gt;&lt;br/&gt;&lt;p&gt;
&lt;a href="http://www.bingocardcreator.com/abingo"&gt;A/Bingo&lt;/a&gt; is an &lt;a href="http://en.wikipedia.org/wiki/A/B_testing"&gt;A/B testing&lt;/a&gt; framework for Ruby on Rails. It&amp;#8217;s specifically designed to make the creation of split test experiments as quick and painless as possible.
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;GAE/Bingo&lt;/em&gt; is a re-imagining of &lt;a href="http://www.bingocardcreator.com/abingo/design"&gt;this framework&amp;#8217;s core design principles&lt;/a&gt; inside of Google App Engine. GAE/Bingo was specifically built for use at Khan Academy, which means:
&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;GAE/Bingo is highly optimized for App Engine. Drop it right into any Python App Engine app and you&amp;#8217;ll be all set. It&amp;#8217;s running in production for us with minimal impact on page load times.&lt;/li&gt;
&lt;li&gt;GAE/Bingo works hard to persist experiment data for long periods of time without sacrificing performance.
&lt;ul&gt;&lt;li&gt;Unlike most A/B experiments out there, we may keep an eye on the educational results of an experiment for months and months after a student started down their A/B path.
&lt;/li&gt;
&lt;li&gt;Heck, we may even need to correlate our A/B student splits with offline data, like end-of-the-year test scores.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;h1&gt;Why do this?&lt;/h1&gt;&lt;br/&gt;&lt;p&gt;
We&amp;#8217;ve got a million and one ideas to try out at Khan Academy. What tweak to our game mechanics will best motivate students to challenge themselves? What message makes it most likely for a student to sit back and watch a video when they really need to take time, slow down, and re-learn a core concept?
&lt;/p&gt;

&lt;p&gt;
An A/B testing framework gives us the tools necessary to start answering these questions with experiments and hard(er) data. With ~1.5MM practice exercises answered per school day by Khan Academy students, we have a treasure trove of student activity from which to learn.
&lt;/p&gt;

&lt;p&gt;
We also wanted to spread the love. Patrick helped out the Rails community by open sourcing &lt;a href="http://www.bingocardcreator.com/abingo"&gt;A/Bingo&lt;/a&gt;, and we wanted to do the same for App Engine. I also couldn&amp;#8217;t find any Python split testing framework that satisfied our needs and stayed true to the &lt;a href="http://www.bingocardcreator.com/abingo/design"&gt;design principles of A/Bingo&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;Plus, why not take advantage of the fact that App Engine&amp;#8217;s vertical stack empowers framework creators to go pretty far when it comes to creating a drop-in, It Just Works experience? We hope GAE/Bingo accomplishes this and helps out some others in the community.
&lt;/p&gt;

&lt;h1&gt;How&amp;#8217;s it work?&lt;/h1&gt;&lt;br/&gt;&lt;p&gt;Start an A/B test in one line:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Returns "chimpanzee" to half your users and "zorilla" to the other half
animal = ab_test("cute_logo_animal", ["chimpanzee", "zorilla"])&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;&lt;p&gt;&amp;#8230;and when something good happens, score a conversion in one line:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;bingo("cute_logo_animal")&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;&lt;p&gt;
These two lines will automatically take care of experiment creation, user tracking, consistent A/B results for each individual user, and statistical analysis. &lt;a href="https://github.com/kamens/gae_bingo#readme"&gt;You can do a lot more, of course, when it comes to specifying alternatives and tracking conversions &amp;#8212; check out the docs.&lt;/a&gt; There are some pretty simple (optional) hooks that make it very easy to get consistent A/B results even when your users transition from anonymous to logged-in.
&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/Yrplrh6l1/screen_shot_2011-09-13_at_12.09.52_pm.png"/&gt;&lt;br/&gt;&lt;em&gt;Trivial example: an A/B test proving that messaging a student with &amp;#8220;You&amp;#8217;re ready to move on!&amp;#8221; is statistically more likely to encourage a student to move into to new content than &amp;#8220;Nice work!&amp;#8221;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once at least one user causes the above lines of code to execute, you&amp;#8217;ll get statistical analysis and be able to control your experiment from the dashboard.&lt;/p&gt;

&lt;h1&gt;Can I use it? Can I tweak it?&lt;/h1&gt;&lt;br/&gt;&lt;p&gt;Please do. &lt;a href="http://twitter.com/kamens"&gt;Let me know how it goes via Twitter&lt;/a&gt; or &lt;a href="mailto:ben@khanacademy.org"&gt;email&lt;/a&gt;. Patch up all the inevitable bugs and fill in &lt;a href="https://github.com/kamens/gae_bingo#non-features"&gt;all the major holes left by our desire to ship v1&lt;/a&gt;. We&amp;#8217;ll be continuing to improve the framework, and all help is welcome.&lt;/p&gt;

&lt;p&gt;Enormous thanks goes out to Patrick McKenzie for his framework&amp;#8217;s inspiration and the encouragement to follow his lead. I&amp;#8217;ll be blogging more in the future about how we&amp;#8217;re using GAE/Bingo and how we keep track of hundreds of requests per second w/ persistent storage and minimal impact on page load times.&lt;/p&gt;</description><link>http://bjk5.com/post/10171483254</link><guid>http://bjk5.com/post/10171483254</guid><pubDate>Tue, 13 Sep 2011 12:32:41 -0700</pubDate></item><item><title>Khan Academy Internship, Summer '11</title><description>&lt;p&gt;&lt;em&gt;Want to be handed a major portion of Khan Academy ownership, ridiculously high expectations, and a bunch of mentorship from our full-time devs? &lt;a href="http://www.khanacademy.org/jobs"&gt;Sign up now.&lt;/a&gt; We believe anybody can help the world get a great education, and we accept interns year-round.&lt;/em&gt;&lt;/p&gt;

&lt;hr&gt;&lt;br/&gt;&lt;p&gt;I can&amp;#8217;t remember a time in my history of small company software development that hasn&amp;#8217;t felt like sitting in a rickety donkey kong cart with jet afterburners attached and blazing, and everybody inside is just trying to keep the staples (why did they use &lt;em&gt;staples?&lt;/em&gt;) to hold long enough for us to make it around the next bend in the tracks.&lt;/p&gt;

&lt;p&gt;That being said, at least in my limited donkey kong cart experience, summer internship seasons always stand out in my mind as new high watermarks for shipping speed and dev intensity.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/7d2lpt36s/sincos.png"/&gt;&lt;br/&gt;&lt;em&gt;Just like Sal&amp;#8217;s videos, our practice exercises are at the very heart of Khan Academy.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This summer&amp;#8217;s class of Khan Academy interns has been no different. Our interns come in with promises of being handed ownership and control over major, user-facing features, and in return we demand excellence; it&amp;#8217;s pretty similar, actually, to Khan Academy&amp;#8217;s educational belief of &lt;a href="http://www.ted.com/talks/salman_khan_let_s_use_video_to_reinvent_education.html"&gt;encouraging experimentation but expecting mastery&lt;/a&gt;. They were shipping features on day one.&lt;/p&gt;

&lt;p&gt;Any dev team out there not acknowledging the fact that high school and college students are capable of showing up on your doorstep and almost immediately redefining major portions of your product for the better is either failing to recruit well or is plain old missing out. Big time.&lt;/p&gt;

&lt;p&gt;If that&amp;#8217;s you, I hope to change your mind with this post.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Each of the following improvements to Khan Academy was contributed either largely or entirely by our interns this summer. Four of &amp;#8216;em are in college, one just graduated high school, and one hasn&amp;#8217;t even started applying to colleges yet.&lt;/em&gt;&lt;/p&gt;

&lt;br/&gt;&lt;h1&gt;An entirely new collection of practice exercises built on &lt;a href="http://ejohn.org/blog/khan-exercise-rewrite/"&gt;an entirely new exercise framework&lt;/a&gt;.&lt;/h1&gt;&lt;br/&gt;&lt;p&gt;This is a &lt;em&gt;major&lt;/em&gt; body of work.&lt;/p&gt;

&lt;p&gt;We learned about all types of weaknesses in our old exercises after last year&amp;#8217;s pilots, and we&amp;#8217;ve tackled them head on by improving our hints, removing multiple choice answers, focusing on the user&amp;#8217;s exercise experience, and building new ways of asking old questions.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/zuDlpt3gg/choice.png"/&gt;&lt;br/&gt;&lt;em&gt;Almost all multiple choice questions are gone.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We&amp;#8217;ve focused on &lt;a href="http://github.com/khan/khan-exercises"&gt;helping our developers and our community create new exercises quickly&lt;/a&gt;. We&amp;#8217;ve written better documentation, shipped simpler dev tools, and built solid bug reporting workflows to maintain a healthy stream of new, quality exercises. Our interns are responsible for not only porting all existing exercises to our new tools but also developing brand new frameworks to help exercises draw graphs, randomize questions, generate procedural hints, and more.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/Qyzlpt3i1/mult.png"/&gt;&lt;br/&gt;&lt;em&gt;The Summer 11 interns&amp;#8217; recently launched new exercises have already served up over 5,000,000 math problems to Khan Academy students.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We know that at the end of the day, the only thing that matters is whether or not Khan Academy students are really learning, and a large quantity of quality interactive exercise content is core to that mission. KA wouldn&amp;#8217;t be what it is today without the large quantity of quality videos Sal has created. As a development team and community, we should consider ourselves challenged to match his videos with quality exercises. The team&amp;#8217;s efforts this summer have given us the tools necessary to take a crack at this considerable challenge.&lt;/p&gt;

&lt;p&gt;In fact, exercises are so important to us that we&amp;#8217;re now hiring &lt;a href="http://www.khanacademy.org/jobs"&gt;full-time exercise developers&lt;/a&gt; to come push these tools to their limits and redefine what it means to learn online. If you want to join some very passionate devs, either &lt;a href="http://www.khanacademy.org/jobs"&gt;apply now&lt;/a&gt; or join our &lt;a href="https://github.com/khan/khan-exercises"&gt;open source exercise community&lt;/a&gt;.&lt;/p&gt;

&lt;br/&gt;&lt;h1&gt;Full access for unregistered users&lt;/h1&gt;&lt;br/&gt;&lt;p&gt;Followers of this blog (also: leprechauns, unicorns) may remember a post in which I struggled to decide &lt;a href="http://bjk5.com/post/3716277312/should-khan-academy-follow-stack-overflows"&gt;if Khan Academy should follow Stack Overflow&amp;#8217;s registration model&lt;/a&gt; by allowing non-logged-in users to participate in all of our content and automatically transferring their work to a permanent account after they log in.&lt;/p&gt;

&lt;p&gt;The more we thought about it and read &lt;a href="http://www.avc.com/a_vc/2011/06/dont-forget-your-logged-out-users.html"&gt;posts about unregistered users like Fred Wilson&amp;#8217;s&lt;/a&gt;, the more we realized that making access to our educational content as easy as possible was the right thing to do.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/odSlpt3r5/login.png"/&gt;&lt;br/&gt;&lt;em&gt;We track users&amp;#8217; progress and encourage them to log in, but we never get in anyone&amp;#8217;s way when they&amp;#8217;re trying to learn.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Two interns completely owned the design and implementation of this feature. If you go to Khan Academy now, you can start earning points and badges for watching videos and working on exercises without ever logging in. We encourage users to login at various milestones in their progress, but we never stop them from continuing to use the site or force them to close a popup.&lt;/p&gt;

&lt;p&gt;If you log in, you keep all your progress. This has significantly reduced our bounce rate by getting rid of painful login walls, and we&amp;#8217;re continuing to watch other statistics to see the effects of this change.&lt;/p&gt;

&lt;br/&gt;&lt;h1&gt;Video progress tracking&lt;/h1&gt;&lt;br/&gt;&lt;p&gt;I can&amp;#8217;t count of the number of times I&amp;#8217;ve heard users ask us to display individual video progress next to each one of the 2,500+ video links on our homepage. I&amp;#8217;m not gonna get into the various technical challenges here (maybe a different blog post), but this is nontrivial for a brain like mine.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/jiylpt3ud/videoprogress.png"/&gt;&lt;/p&gt;

&lt;p&gt;Luckily, we hire interns that are way smarter than me and are able to solve such problems. These days, whenever you watch a piece of a Khan Academy video, skip around it, pause it, play it, or whatever, we keep track of extremely precise video progress statistics and display useful progress indicators next to every video link.&lt;/p&gt;

&lt;br/&gt;&lt;h1&gt;Twitter and Facebook sharing&lt;/h1&gt;&lt;br/&gt;&lt;p&gt;One of the earliest features launched during Summer &amp;#8216;11 was the ability to share videos, exercises, and badges on Facebook and Twitter.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/kjrlpt3xq/facebook.png"/&gt;&lt;br/&gt;&lt;em&gt;Facebook sharing has slowly gone up (even during the natural academic lull of summer), and we hope this trend will continue.&lt;/em&gt;&lt;/p&gt;

&lt;br/&gt;&lt;h1&gt;All that and more, powered by interns&lt;/h1&gt;&lt;br/&gt;&lt;p&gt;&amp;#8230;and those are just the bigger changes. Our interns continue to claw for &lt;a href="http://www.joelonsoftware.com/items/2007/06/07.html"&gt;inch after inch after inch&lt;/a&gt; of improvements like nicer internal statistics, faster deploy scripts, performance tweaks, and better user account management.&lt;/p&gt;

&lt;p&gt;Summer&amp;#8217;s not over yet. &lt;a href="http://omarrizwan.com/"&gt;Omar Rizwan&lt;/a&gt;, &lt;a href="http://twitter.com/#!/rubergly"&gt;Jeff Ruberg&lt;/a&gt;, &lt;a href="http://twitter.com/#!/joelburget"&gt;Joel Burget&lt;/a&gt;, &lt;a href="https://plus.google.com/100044714483635073835/"&gt;Igor Terzic&lt;/a&gt;, &lt;a href="http://twitter.com/#!/ParkerKuivila"&gt;Parker Kuivila&lt;/a&gt;, and &lt;a href="https://plus.google.com/101013822660106280579/posts"&gt;Ben Alpert&lt;/a&gt; continue to set the current bar for Khan Academy internship classes. As an organization, we aim to beat this mark in the future. But those six are pushing hard to make it a tough task, and khanacademy.org is improving for the better, quickly.&lt;/p&gt;

&lt;p&gt;Don&amp;#8217;t doubt the inexperienced. Get your team&amp;#8217;s &lt;a href="http://www.amazon.com/Smart-Gets-Things-Done-Technical/dp/1590598385"&gt;recruiting&lt;/a&gt;, mentorship, and &lt;a href="http://bjk5.com/post/3994859683/code-reviews-as-relationship-builders-a-few-tips"&gt;code reviews&lt;/a&gt; right (easier said than done), and a summer internship can be one of the best things that&amp;#8217;s ever happened to your product. I already can&amp;#8217;t wait to drop some major challenges in the laps of our two incoming Fall interns to see what they can build.&lt;/p&gt;

&lt;br/&gt;&lt;h1&gt;Join us&lt;/h1&gt;&lt;br/&gt;&lt;p&gt;Want to be handed a major portion of Khan Academy ownership, ridiculously high expectations, and a bunch of mentorship from our full-time devs? &lt;a href="http://www.khanacademy.org/jobs"&gt;Sign up now.&lt;/a&gt; We believe anybody can help the world get a great education, and we accept interns year-round.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/BF7lpt4ay/badge.png"/&gt;&lt;br/&gt;&lt;em&gt;Big shoes to fill.&lt;/em&gt;&lt;/p&gt;</description><link>http://bjk5.com/post/8826207372</link><guid>http://bjk5.com/post/8826207372</guid><pubDate>Fri, 12 Aug 2011 09:47:00 -0700</pubDate></item><item><title>Fast and slow queues on App Engine</title><description>&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt; &amp;#8212; If you&amp;#8217;re using task queues on App Engine and your task execution speeds vary greatly, you can get yourself into serious performance trouble. We addressed this by explicitly separating fast and slow tasks, and &lt;a href="https://github.com/kamens/gae_fast_slow_queue"&gt;we released a little utility to help you do the same&lt;/a&gt;.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/fAblokjgq/screen_shot_2011-07-18_at_11.58.53_pm.png"/&gt;&lt;br/&gt;&lt;em&gt;Only one user has ever earned this badge&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Quick story: even though &lt;a href="http://bjk5.com/post/2562662487/badges-on-app-engine-implementing-a-real-time-badge"&gt;we put in a lot of work making sure Khan Academy users are awarded badges in real-time&lt;/a&gt;, we also run background badging processes to make sure we didn&amp;#8217;t miss any. This process uses &lt;a href="http://code.google.com/p/appengine-mapreduce/"&gt;GAE&amp;#8217;s mapreduce framework&lt;/a&gt; to map over all users and make sure their badges are up-to-date, and it looks something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Called once for every user
def badge_background_check(user):
    if user.has_recent_activity():
        user.update_badges()

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;has_recent_activity&lt;/code&gt; is really fast, and &lt;code&gt;update_badges&lt;/code&gt; can be really slow. This doesn&amp;#8217;t play nice with App Engine&amp;#8217;s request scheduler, and here&amp;#8217;s why.&lt;/p&gt;

&lt;p&gt;When you start firing off a bunch of tasks to a specific task queue, App Engine keeps a running average of how long tasks in that particular queue are taking. If they&amp;#8217;re really fast (&amp;lt; 1000ms is what we&amp;#8217;ve heard&amp;#8230;), you can think of the task queue being painted with a shiny yellow smiley face. If they&amp;#8217;re slow, the queue gets a sad red frowny face stamped on its forehead.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/ZdPlokl1e/untitled.png"/&gt;&lt;br/&gt;&lt;em&gt;Don&amp;#8217;t judge just because the sad one sounds like Eeyore. Neither of these situations cause problems.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you&amp;#8217;ve got a shiny yellow smiley face, App Engine&amp;#8217;s scheduler will try to get your tasks done quickly by queuing up your fast tasks in the same lines that your users&amp;#8217; requests wait in. As long as these tasks stay fast, your app will scale when more instances are needed, your users should never notice that they&amp;#8217;re standing in the same line as the fast tasks, and all is good.&lt;/p&gt;

&lt;p&gt;Thing is, it&amp;#8217;s even ok to have a frowny face. App Engine will use a different, slower scheduler to hand out your work without interrupting user facing requests. You&amp;#8217;ll never wait in the same line as a user request, and you can take all the time in the world (as long as the world only lasts for the next 10 minutes) without worrying about someone emailing and complaining that your site&amp;#8217;s gotten really slow lately.&lt;/p&gt;

&lt;p&gt;The misery starts when you have a queue that&amp;#8217;s mostly fast but hits sporadically slow tasks. Now your queue is all shiny and yellow and smiley and sharing the same checkout lines as user facing requests, but every once in a while a grumpy red frowny face stands in line, takes &lt;em&gt;five full minutes&lt;/em&gt; at the cash register asking about the store&amp;#8217;s raincheck coupon policy, and ruins everybody&amp;#8217;s day. Your queue&amp;#8217;s sporadic behavior is now directly hurting your users&amp;#8217; perceived performance.&lt;/p&gt;

&lt;p&gt;This has caused us some very serious perf hiccups. 90% of our users don&amp;#8217;t need to run update_badges on any given day, so the average task speed is very fast. When we hit a slow task, instance request queues can grind to a halt. At our worst, we&amp;#8217;ve seen user facing requests sit waiting in the request queue for 9000ms (that&amp;#8217;s approximately one full eternity) before our code even gets a chance to run.*&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/tFelokllr/mud.jpg"/&gt;&lt;br/&gt;&lt;em&gt;I was going to put an animated gif of a yellow smiley face that suddenly flashes a red frowny face here, but then I remembered that I&amp;#8217;d have to kill myself for having an animated gif.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/kamens/gae_fast_slow_queue"&gt;gae_fast_slow_queue utility helps work around this as quickly as possible&lt;/a&gt; by making it easy to run a bunch of fast tasks while identifying slow tasks and splitting them off into a separate queue:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@fast_slow_queue.handler(lambda user: user.has_recent_activity())
def badge_background_check(user):
    user.update_badges()

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, when badge_background_check gets queued up, it&amp;#8217;ll always only run the fast lambda function to keep the main queue yellow and smiley. If real work needs to be done, it fires off a different task in a different queue, and this one is guaranteed by our utility to take at least 1000ms so it stays red and frowny forever. GAE&amp;#8217;s scheduler will steer these clear of user facing requests, and you don&amp;#8217;t have to worry about your task impacting users&amp;#8217; perceived perf.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;* We noticed this after deploying &lt;a href="http://bjk5.com/post/6944602865/google-app-engine-mini-profiler"&gt;gae_mini_profiler&lt;/a&gt; and browsing around the site &amp;#8212; every once in a while a developer got frustrated waiting forever for a page to load, then the profiler would come back and add insult to injury by screaming, &amp;#8220;Woohoo this page only took 150ms!&amp;#8221; You can confirm issues like these by looking for high pending_ms values in your logs.&lt;/em&gt;&lt;/p&gt;</description><link>http://bjk5.com/post/7796556212</link><guid>http://bjk5.com/post/7796556212</guid><pubDate>Tue, 19 Jul 2011 00:59:00 -0700</pubDate></item><item><title>App Engine Mini Profiler and Temporary Redirects</title><description>&lt;p&gt;We just made a small change to &lt;a href="https://github.com/kamens/gae_mini_profiler"&gt;Google App Engine Mini Profiler&lt;/a&gt; to deal with the fact that spitting out profiling stats on every rendered page still misses all the pages that aren&amp;#8217;t rendered: the POST side of temporary redirects.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s super common to submit a POST and redirect to a GET. When using a profiler that spits out performance data about the currently rendered page, you lose all of that profiling data about the POST request, even though the user still had to wait for the request to finish.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/jHPlo01kh/redirect-corner.png"/&gt;&lt;br/&gt;&lt;em&gt;Not no more&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Sticking with the belief that making the path from developers to profiling data as short as possible will produce a faster site, we now automatically expose these redirects and all of their performance stats. App Engine Mini Profiler handles this with ajax requests as well (you&amp;#8217;ll see two profiler entries in the corner when sending an ajax POST and getting redirected to a GET full of JSON data), and in the unfortunate event that you&amp;#8217;re bouncing the user around a long chain of redirects (more than one and you should feel guilty), it&amp;#8217;ll keep track of all &amp;#8216;em.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/LmQlo01ll/redirect-details.png"/&gt;&lt;br/&gt;&lt;em&gt;Exposing the redirect&amp;#8217;s data&lt;/em&gt;&lt;/p&gt;</description><link>http://bjk5.com/post/7373318608</link><guid>http://bjk5.com/post/7373318608</guid><pubDate>Thu, 07 Jul 2011 22:23:00 -0700</pubDate></item><item><title>Google App Engine Mini Profiler</title><description>&lt;blockquote&gt;Patrick Bateman: &lt;em&gt;(Looking at the business card) &amp;#8220;Look at that subtle off-white coloring. The tasteful thickness of it. Oh my god&amp;#8230;&amp;#8221;&lt;/em&gt;&lt;/blockquote&gt;

&lt;p&gt;I finally understood the full extent of Bateman&amp;#8217;s jealousy recently when reading about the &lt;a href="http://code.google.com/p/mvc-mini-profiler/"&gt;MVC Mini Profiler&lt;/a&gt; created by the Stack Exchange team. My eyes scanned all the features, and I started to lose my mind:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&amp;#8220;&amp;#8230;live, instant feedback on the performance characteristics of the pages we are visiting – in production,&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;&amp;#8230;ubiquitous,&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;&amp;#8230;only visible to developers and has no noticeable impact on the site’s performance,&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;&amp;#8230;drill-down on and share profile sessions,&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;&amp;#8230;ajax calls are displayed as they happen,&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;&amp;#8230;duplicate query detection,&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;&amp;#8230;drop in module for any MVC project,&amp;#8221;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&amp;#8230;my god, it even had a watermark.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://gae-mini-profiler.appspot.com/images/gae-mini-profiler/corner.png"/&gt;&lt;br/&gt;&lt;em&gt;&lt;a href="http://www.codinghorror.com/blog/2011/06/performance-is-a-feature.html"&gt;As Jeff said&lt;/a&gt;, simply showing a render time for all pages can be critical&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It really hit home for me when reading &lt;a href="http://samsaffron.com/archive/2011/06/09/+Profiling+your+website+like+a+true+Ninja"&gt;Sam Saffron&amp;#8217;s post&lt;/a&gt;: &amp;#8220;No web frameworks seem to provide a comprehensive approach to page profiling out of the box.&amp;#8221; It&amp;#8217;s true. This level of ubiquitous profiling baked right into all major web frameworks would really change the game. I decided I couldn&amp;#8217;t live without something like mvc-mini-profiler any longer, so we just released &lt;a href="https://github.com/kamens/gae_mini_profiler"&gt;gae_mini_profiler&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kamens/gae_mini_profiler"&gt;gae_mini_profiler&lt;/a&gt; is a drop-in, ubiquitous, production profiling tool for Google App Engine &lt;em&gt;heavily&lt;/em&gt; inspired by &lt;a href="http://code.google.com/p/mvc-mini-profiler/"&gt;MVC Mini Profiler&lt;/a&gt;. Since App Engine and MVC have so many fundamental differences, the tools aren&amp;#8217;t identical, and it&amp;#8217;s not really a port as much as a ridiculously kindred spirit. If you want, you can play around with &lt;a href="http://gae-mini-profiler.appspot.com/"&gt;a gae_mini_profiler-enabled demo of GAE&amp;#8217;s example chess app&lt;/a&gt; &amp;#8212; in this demo case, the profiler is enabled for all users.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://gae-mini-profiler.appspot.com/images/gae-mini-profiler/ajax-profile.png"/&gt;&lt;br/&gt;&lt;em&gt;Taking a glance at one of our slower pages in production&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m confident that always having all of this data right in front of our developers as we browse around the live Khan Academy site will improve performance. I&amp;#8217;ve already noticed a few problems I didn&amp;#8217;t previously know about in just the first few hours after deploying.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://gae-mini-profiler.appspot.com/images/gae-mini-profiler/ajax-corner.png"/&gt;&lt;br/&gt;&lt;em&gt;AJAX calls stack up as they come in, ready for examination&lt;/em&gt;&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/ljtlne32e/small.png"/&gt;&lt;br/&gt;&lt;em&gt;You can dive deep on the details of each request&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All props go to &lt;a href="http://twitter.com/#!/jarrod_dixon"&gt;Jarrod&lt;/a&gt;, &lt;a href="http://samsaffron.com/archive/2011/06/09/+Profiling+your+website+like+a+true+Ninja"&gt;Sam&lt;/a&gt;, and probably the rest of the Stack Exchange team for blazing the path with &lt;a href="http://code.google.com/p/mvc-mini-profiler/"&gt;mvc-mini-profiler&lt;/a&gt; and inspiring this tool. I borrowed ideas ranging from basic UI to dupe query detection to jQuery.tmpl usage to ajax request stacking to lots of other stuff I can&amp;#8217;t remember. The sizable differences in the tools really spawn from the type of data I get from &lt;a href="http://code.google.com/appengine/docs/python/tools/appstats.html"&gt;Appstats&lt;/a&gt; and &lt;a href="http://docs.python.org/library/profile.html"&gt;cProfile&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The project is obviously young, but any App Engine app should be able to drop it in quite quickly with minimal configuration. Instructions are at &lt;a href="https://github.com/kamens/gae_mini_profiler"&gt;the repo&lt;/a&gt;, and I hope others find it useful.&lt;/p&gt;

&lt;blockquote&gt;&lt;a href="http://www.imdb.com/title/tt0144084/quotes?qt=qt0453383"&gt;&amp;#8220;&amp;#8230;relief washes over me in an awesome wave.&amp;#8221;&lt;/a&gt;&lt;/blockquote&gt;</description><link>http://bjk5.com/post/6944602865</link><guid>http://bjk5.com/post/6944602865</guid><pubDate>Sun, 26 Jun 2011 11:39:00 -0700</pubDate></item><item><title>Connecting the students</title><description>&lt;p&gt;We&amp;#8217;re thinking about how to connect our community of students, and there&amp;#8217;s a lot we don&amp;#8217;t know. Here&amp;#8217;s the little we do:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Students have watched Sal&amp;#8217;s videos over 60,000,000 times and have answered 75,000,000 practice problems.&lt;/li&gt;
&lt;li&gt;This is a massive amount of learning, but much of it has been done by students who are relatively disconnected from their peers.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Nothing&lt;/em&gt; indicates true mastery of a subject like the ability to teach it to others.&lt;/li&gt;
&lt;li&gt;The small (relative to our total userbase) number of students using Khan Academy alongside their peers in a school setting engage the software in &lt;a href="http://lasdandkhanacademy.edublogs.org/2011/04/01/learning-about-learning/"&gt;incredible ways&lt;/a&gt;. They work together in groups, challenge each other, and cheer for their friends when they earn badges. Working with others, especially a fearless teacher or coach, amplifies Khan Academy&amp;#8217;s effect significantly.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;We want to build these amplifiers directly into Khan Academy. No matter which direction we brainstorm, the possibilities for connecting our users don&amp;#8217;t seem to stop. A small subset of what we&amp;#8217;ve considered:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Any struggling student could ask for immediate help from a qualified peer or pre-approved teacher, who could immediately see the student&amp;#8217;s past work and mistakes.&lt;/li&gt;
&lt;li&gt;Any teacher, coach, or student (the lines &lt;em&gt;should&lt;/em&gt; be blurred) could add their own content in the form of both videos and exercises to supplement the KA library according to their own needs while taking advantage of our platform, dashboard, and analytics.&lt;/li&gt;
&lt;li&gt;Users could participate in message board-like communities about all types of KA-related content.&lt;/li&gt;
&lt;li&gt;Students could team up to work through KA content together while facing all kinds of cooperative challenges.&lt;/li&gt;
&lt;li&gt;&amp;#8230;doesn&amp;#8217;t stop there.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;While we don&amp;#8217;t claim to have the answers, you&amp;#8217;ll see more and more experiments coming from our core belief that teaching others is a great way to learn. We&amp;#8217;ve already dabbled (can&amp;#8217;t emphasize that enough&amp;#8230;&lt;sup&gt;dabbled&lt;/sup&gt;) with this goal in the question and answer section beneath each of our videos:&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/8H9lmz6ks/earth.png"/&gt;&lt;br/&gt;&lt;em&gt;Students teaching students&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It seems likely that Sal&amp;#8217;s videos each have a few common misunderstandings or logical jumps that trick the majority of viewers, and this feature is designed to let the community fill in the most important gaps.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/aRSlmz6n1/typo.png"/&gt;&lt;br/&gt;&lt;em&gt;Even little questions like these are important&lt;/em&gt;&lt;br/&gt;&lt;br/&gt;&lt;img src="http://static.tumblr.com/9hgswys/s03lmz6nm/anti.png"/&gt;&lt;br/&gt;&lt;em&gt;Simple voting mechanics (with one or two doodads from &lt;a href="http://stackoverflow.com"&gt;the best voting implementation out there&lt;/a&gt;) hopefully surface the most common questions&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This small experiment has already taught us some important lessons. I see no reason to stop the lazy list writing style I started above:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;There&amp;#8217;s a big difference between fostering a community that&amp;#8217;s focused on creating and refining artifacts (think StackOverflow and Wikipedia) and a community that encourages any and all mentoring between students. In a community that creates artifacts, duplicate content is the enemy and efficiently finding others&amp;#8217; answers is the holy grail. For us, there&amp;#8217;s something very important about a kid raising her hand, asking why subtracting a negative number moves you to the right on the number line, and working towards the answer with another human being (or human being-like coach). It doesn&amp;#8217;t matter how many people have asked the question previously.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://kamvar.org/"&gt;Sep Kamvar&lt;/a&gt; gave us some great advice along those lines the other day when he reminded us that the most efficient system (think about the ability to instantly find all others&amp;#8217; questions and answers) is not necessarily the best solution when encouraging interaction. I&amp;#8217;ll put myself in the hot seat and admit that as a developer, that takes some getting used to.&lt;/li&gt;
&lt;li&gt;Our content is frequented by different age groups, which creates different community dynamics for each subject.&lt;/li&gt;
&lt;li&gt;As expected, even this small feature generates a wide range of content quality. Not all participation is helpful, and our system isn&amp;#8217;t perfect.&lt;/li&gt;
&lt;li&gt;It&amp;#8217;s true that each video comes with some common curiosities, and a few members of our community are fantastic at responding to them.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;We&amp;#8217;ll be experimenting more, and we&amp;#8217;re always listening. The direction of educational communities online feels wide open, and every day we have to pick our path. Share your opinions, they matter a lot.&lt;/p&gt;</description><link>http://bjk5.com/post/6649413224</link><guid>http://bjk5.com/post/6649413224</guid><pubDate>Sat, 18 Jun 2011 00:46:00 -0700</pubDate></item><item><title>Opening up the Khan Academy API</title><description>&lt;p&gt;As soon as I joined KA, I began receiving emails from people asking to integrate with Sal&amp;#8217;s content in various ways: in mobile apps, in search engine results, in other educational sites. So we threw together &lt;a href="https://sites.google.com/a/khanacademy.org/forge/for-developers/technical/api"&gt;the quickest, ugliest API we could get away with&lt;/a&gt; at the time in order to give other developers access to our playlist and video library.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s now a few months later, and that hack of an API no longer cuts it. It lacks authentication, user-specific data, API versioning, and other basics. We need these basics for the official mobile apps we&amp;#8217;re developing, and the development community needs them to make apps that do more than link to our videos. Which is why we just released what we&amp;#8217;re calling &lt;a href="https://github.com/Khan/khan-api/wiki/Khan-Academy-API"&gt;API version 1.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The new API gives developers access to not just playlists and videos, but also &lt;a href="https://github.com/Khan/khan-api/wiki/Khan-Academy-API-Methods"&gt;exercises, badges, users, and logs of historical data&lt;/a&gt; about each and every problem or video students have watched. I&amp;#8217;m sure we missed a lot of stuff, so developers: just let us know when you need access to something else.&lt;/p&gt;

&lt;p class="center"&gt;&lt;img src="http://static.tumblr.com/9hgswys/1vvlmbwql/w_e_1.png"/&gt;&lt;br/&gt;&lt;em&gt;Using the API to check out my performance in &lt;a href="http://www.khanacademy.org/exercises?exid=writing_expressions_1"&gt;our Writing Expressions 1 exercise&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We&amp;#8217;re slotted to be one of the featured APIs in next weekend&amp;#8217;s &lt;a href="http://hack4knowledge.eventbrite.com/"&gt;hack4knowledge&lt;/a&gt; &amp;#8212; I&amp;#8217;m crossing my fingers we see some cool educational hacks using our data.&lt;/p&gt;</description><link>http://bjk5.com/post/6219080921</link><guid>http://bjk5.com/post/6219080921</guid><pubDate>Sun, 05 Jun 2011 11:06:00 -0700</pubDate></item></channel></rss>

