<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss version="2.0"><channel><title>Developer Blog Posts</title><link>http://www.review-board.org/news/</link><description>Latest Review Board developer blog posts</description><language>en-us</language><lastBuildDate>Sun, 11 Jul 2010 02:44:46 -0700</lastBuildDate><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/ReviewBoard" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="reviewboard" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><title>Look down. Now back up again. The Defects are now Issues.
</title><link>http://mikeconley.ca/blog/2010/07/10/look-down-now-back-up-again-the-defects-are-now-issues/</link><description>&lt;p&gt;From my software development experience, there are a few different words for the generic notion of a &amp;#8220;problem&amp;#8221;.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;bug&lt;/strong&gt; or a &lt;strong&gt;defect&lt;/strong&gt;, for example, is defined as the following from &lt;a href="http://en.wikipedia.org/wiki/Software_bug"&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;A &lt;strong&gt;software bug&lt;/strong&gt; is the common term used to describe an error flaw,  mistake, failure,  or fault in a computer program or system that produces an incorrect or unexpected result, or  causes it to behave in unintended ways. Most bugs arise from mistakes  and errors made by people in either a program&amp;#8217;s source  code or its design, and a few are caused by compilers producing incorrect code.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;An &lt;strong&gt;issue&lt;/strong&gt; goes a level higher &amp;#8211; a bug is an issue, but an issue might not be a bug.  &lt;a href="http://en.wikipedia.org/wiki/Issue_%28computers%29#Issue"&gt;Wikipedia says&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;In computing, the term &lt;strong&gt;issue&lt;/strong&gt; is a unit of work to accomplish an  improvement in a system. An issue could be a bug, a requested feature,  task, missing documentation, and so forth. The word &amp;#8220;issue&amp;#8221;  is popularly misused in lieu of &amp;#8220;problem.&amp;#8221;  This usage is probably related.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Where am I going with all of this?&lt;/p&gt;
&lt;p&gt;Well, remember when I said &lt;a href="http://mikeconley.ca/blog/2010/07/10/filing-defects-in-review-board/"&gt;I was going to add defect reporting/tracking capabilities&lt;/a&gt; to &lt;a href="http://www.reviewboard.org"&gt;Review Board&lt;/a&gt;?  I asked for some feedback on &lt;a href="http://mikeconley.ca/blog/2010/07/10/filing-defects-in-review-board/"&gt;my UI mockups&lt;/a&gt; on the developer mailing list, and &lt;a href="http://groups.google.com/group/reviewboard-dev/browse_thread/thread/48705cfb39296991"&gt;an interesting conversation on terminology erupted&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Anyhow, the long and the short of it is &amp;#8211; we&amp;#8217;re going to be calling &amp;#8220;problems still existing within a review request revision&amp;#8221; &lt;strong&gt;issues&lt;/strong&gt;.  And this is distinct from the sort of thing that might show up in an issue tracker.&lt;/p&gt;
&lt;p&gt;Maybe down the line, we&amp;#8217;ll have a way for administrators to set their own word for it.  From the thread, it sounds like everybody and their brother has their own favourite terminology.  &amp;#8221;Issue&amp;#8221; will have to do for now.&lt;/p&gt;
&lt;p&gt;Thanks again to everyone on the list who contributed to the conversation.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=N2myp6h7wX0:vpqA9Ybz_zw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=N2myp6h7wX0:vpqA9Ybz_zw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=N2myp6h7wX0:vpqA9Ybz_zw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=N2myp6h7wX0:vpqA9Ybz_zw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=N2myp6h7wX0:vpqA9Ybz_zw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=N2myp6h7wX0:vpqA9Ybz_zw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=N2myp6h7wX0:vpqA9Ybz_zw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">mikeconley</dc:creator><pubDate>Sun, 11 Jul 2010 02:44:46 -0700</pubDate><guid>http://mikeconley.ca/blog/2010/07/10/look-down-now-back-up-again-the-defects-are-now-issues/</guid></item><item><title>Filing Defects in Review Board
</title><link>http://mikeconley.ca/blog/2010/07/10/filing-defects-in-review-board/</link><description>&lt;p&gt;In my last post, I talked about &lt;a href="http://mikeconley.ca/blog/2010/07/05/review-board-statistics-extensions-karma-stopwatch-and-fixit/"&gt;an extension for Review Board&lt;/a&gt; that would allow users to register “defects”, “TODOs” or “problems” with code that&amp;#8217;s up for review.&lt;/p&gt;
&lt;p&gt;After chatting with the lead RB devs for a bit, we&amp;#8217;ve decided to scrap the extension.&lt;/p&gt;
&lt;p&gt;[audible gasp, booing, hissing]&lt;/p&gt;
&lt;p&gt;Instead, we&amp;#8217;re just going to put it in the core of Review Board.&lt;/p&gt;
&lt;p&gt;[thundering applause]&lt;/p&gt;
&lt;h3&gt;Defects&lt;/h3&gt;
&lt;p&gt;Why is this useful?  I&amp;#8217;ve got a few reasons for you:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It&amp;#8217;ll be easier for reviewees to keep track of things left to fix, and similarly, it&amp;#8217;ll be harder for reviewees to accidentally skip over fixing a defect that a reviewer has found&lt;/li&gt;
&lt;li&gt;My statistics extension will be able to calculate useful things like &lt;strong&gt;defect detection rate&lt;/strong&gt;, and &lt;strong&gt;defect density&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Maybe it&amp;#8217;s just me, but checking things off as &amp;#8220;fixed&amp;#8221; or &amp;#8220;completed&amp;#8221; is &lt;em&gt;really&lt;/em&gt; satisfying&lt;/li&gt;
&lt;li&gt;Who knows, down the line, I might code up an extension that lets you &lt;a href="http://mikeconley.ca/blog/2010/03/09/turning-peer-code-review-into-a-game/"&gt;turn finding/closing defects into a game&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;However, since we&amp;#8217;re adding this to the core of &lt;a href="http://www.reviewboard.org"&gt;Review Board&lt;/a&gt;, we have to keep it simple.  One of Review Board&amp;#8217;s biggest strengths is in its total lack of clutter.  No bells.  No whistles.  Just the things you need to get the job done.  Let the extensions bring the bells and whistles.&lt;/p&gt;
&lt;p&gt;So that means creating a bare-bones defect-tracking mechanism and UI, and leaving it open for extension.  Because who knows, maybe &lt;a href="http://groups.google.com/group/reviewboard/browse_thread/thread/e224b4afce4a8cfc/d3501fd3018fae93"&gt;there&lt;/a&gt; &lt;a href="http://groups.google.com/group/reviewboard/browse_thread/thread/2b4dc38ad73b82b2/9d410350f1c769ae"&gt;are&lt;/a&gt; &lt;a href="http://groups.google.com/group/reviewboard/browse_thread/thread/eb6d98fad2c1b3c5/bbf2592fcc70b53c"&gt;some&lt;/a&gt; &lt;a href="http://groups.google.com/group/reviewboard/browse_thread/thread/8dfbea6d40a9f160/a4319afa5b1404b1"&gt;people&lt;/a&gt; out there who want to customize what &lt;em&gt;kind &lt;/em&gt;of defects they&amp;#8217;re filing.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve come up with a design that I think is pretty simple and clean.  And it doesn&amp;#8217;t rock the boat &amp;#8211; if you&amp;#8217;re not interested in filing defects, your Review Board experience stays the same.&lt;/p&gt;
&lt;h4&gt;Filing a Defect&lt;/h4&gt;
&lt;p&gt;I propose adding a simple checkbox to the comment dialog to indicate that this comment files a defect, like so:&lt;/p&gt;
&lt;div class="wp-caption alignnone" id="attachment_1560" style="width: 310px;"&gt;&lt;a href="http://mikeconley.ca/blog/wp-content/uploads/2010/07/comment_checkbox_shot.png"&gt;&lt;img alt="Comment Defect Checkbox Screenshot" class="size-medium wp-image-1560 " height="119" src="http://mikeconley.ca/blog/wp-content/uploads/2010/07/comment_checkbox_shot-300x119.png" title="Comment Defect Checkbox Screenshot" width="300" /&gt;&lt;/a&gt;&lt;p class="wp-caption-text"&gt;No bells.  No whistles.  Just a simple little checkbox.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;While I&amp;#8217;m in there, I&amp;#8217;ll try to toss in some hooks so that extension developers can add more fields &amp;#8211; for example, the classification or the priority of the defect.  By default, however, it&amp;#8217;s just a bare-bones little checkbox.&lt;/p&gt;
&lt;p&gt;So far, so good.  You&amp;#8217;ve filed a defect.  Maybe this is how it&amp;#8217;ll look like in the in-line comment viewer:&lt;/p&gt;
&lt;div class="wp-caption alignnone" id="attachment_1569" style="width: 310px;"&gt;&lt;a href="http://mikeconley.ca/blog/wp-content/uploads/2010/07/comments_interface_shot_report_inline.png"&gt;&lt;img alt="The inline comment viewer is showing that a defect report has been filed." class="size-medium wp-image-1569 " height="128" src="http://mikeconley.ca/blog/wp-content/uploads/2010/07/comments_interface_shot_report_inline-300x128.png" title="comments_interface_shot_report_inline" width="300" /&gt;&lt;/a&gt;&lt;p class="wp-caption-text"&gt;A defect has been reported!&lt;/p&gt;&lt;/div&gt;
&lt;h4&gt;Two Choices&lt;/h4&gt;
&lt;p&gt;A reviewer can file defects reports, and the &lt;strong&gt;reviewee&lt;/strong&gt; is able to act on them.&lt;/p&gt;
&lt;p&gt;Lets say I&amp;#8217;m the reviewee.  I&amp;#8217;ve just gotten a review, and I&amp;#8217;ve got my editor / IDE with my patch waiting in the background.  I see a few defect reports have been filed.  For the ones I completely agree with, I fix them in my editor, and then go back to Review Board and mark them as &lt;strong&gt;Fixed&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="wp-caption alignnone" id="attachment_1567" style="width: 310px;"&gt;&lt;a href="http://mikeconley.ca/blog/wp-content/uploads/2010/07/comments_interface_shot_fixed_inline.png"&gt;&lt;img alt="The defect report has been marked as being fixed." class="size-medium wp-image-1567" height="128" src="http://mikeconley.ca/blog/wp-content/uploads/2010/07/comments_interface_shot_fixed_inline-300x128.png" title="comments_interface_shot_fixed_inline" width="300" /&gt;&lt;/a&gt;&lt;p class="wp-caption-text"&gt;All fixed!&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;It&amp;#8217;s also possible that I might not agree with one or more of the defect reports.  In this case, I&amp;#8217;ll reply to the comment to argue my case.  I might also mark the defect report as &lt;strong&gt;Pass&lt;/strong&gt;, which means, &amp;#8220;I&amp;#8217;ve seen it, but I think I&amp;#8217;ll pass on that&amp;#8221;.&lt;/p&gt;
&lt;div class="wp-caption alignnone" id="attachment_1568" style="width: 310px;"&gt;&lt;a href="http://mikeconley.ca/blog/wp-content/uploads/2010/07/comments_interface_shot_passed_inline.png"&gt;&lt;img alt="The defect report has been marked as &amp;quot;pass&amp;quot;." class="size-medium wp-image-1568" height="128" src="http://mikeconley.ca/blog/wp-content/uploads/2010/07/comments_interface_shot_passed_inline-300x128.png" title="comments_interface_shot_passed_inline" width="300" /&gt;&lt;/a&gt;&lt;p class="wp-caption-text"&gt;I think I'll pass on that, thanks.&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;These comments and defect reports are also visible in the review request details page:&lt;/p&gt;
&lt;div class="wp-caption alignnone" id="attachment_1564" style="width: 310px;"&gt;&lt;a href="http://mikeconley.ca/blog/wp-content/uploads/2010/07/comments_interface_shot_report.png"&gt;&lt;img alt="A defect report has been filed, and we're in the review request detail page." class="size-medium wp-image-1564" height="86" src="http://mikeconley.ca/blog/wp-content/uploads/2010/07/comments_interface_shot_report-300x86.png" title="comments_interface_shot_report" width="300" /&gt;&lt;/a&gt;&lt;p class="wp-caption-text"&gt;A defect has been filed.&lt;/p&gt;&lt;/div&gt;
&lt;div class="wp-caption alignnone" id="attachment_1565" style="width: 310px;"&gt;&lt;a href="http://mikeconley.ca/blog/wp-content/uploads/2010/07/comments_interface_shot_fixed.png"&gt;&lt;img alt="The defect is marked as fixed, and we're in the review request detail page." class="size-medium wp-image-1565" height="86" src="http://mikeconley.ca/blog/wp-content/uploads/2010/07/comments_interface_shot_fixed-300x86.png" title="comments_interface_shot_fixed" width="300" /&gt;&lt;/a&gt;&lt;p class="wp-caption-text"&gt;All fixed up.&lt;/p&gt;&lt;/div&gt;
&lt;div class="wp-caption alignnone" id="attachment_1566" style="width: 310px;"&gt;&lt;a href="http://mikeconley.ca/blog/wp-content/uploads/2010/07/comments_interface_shot_passed.png"&gt;&lt;img alt="We're passing on the defect report, and we're in the review request detail page." class="size-medium wp-image-1566" height="86" src="http://mikeconley.ca/blog/wp-content/uploads/2010/07/comments_interface_shot_passed-300x86.png" title="comments_interface_shot_passed" width="300" /&gt;&lt;/a&gt;&lt;p class="wp-caption-text"&gt;It's all good - just pass this defect report.&lt;/p&gt;&lt;/div&gt;
&lt;h3&gt;Thoughts?&lt;/h3&gt;
&lt;p&gt;What do you think?  Am I on the right track?  Am I missing a case?  Does &amp;#8220;pass&amp;#8221; make sense?  Will this be useful?  I&amp;#8217;d love to hear your thoughts.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=h34c_6vmkeU:8eo_Z0ZtBCA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=h34c_6vmkeU:8eo_Z0ZtBCA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=h34c_6vmkeU:8eo_Z0ZtBCA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=h34c_6vmkeU:8eo_Z0ZtBCA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=h34c_6vmkeU:8eo_Z0ZtBCA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=h34c_6vmkeU:8eo_Z0ZtBCA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=h34c_6vmkeU:8eo_Z0ZtBCA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">mikeconley</dc:creator><pubDate>Sat, 10 Jul 2010 20:08:50 -0700</pubDate><guid>http://mikeconley.ca/blog/2010/07/10/filing-defects-in-review-board/</guid></item><item><title>Review Board Statistics Extensions: Karma, Stopwatch, and FixIt
</title><link>http://mikeconley.ca/blog/2010/07/05/review-board-statistics-extensions-karma-stopwatch-and-fixit/</link><description>&lt;p&gt;I just spent the long weekend in Ottawa and Qu﻿﻿é﻿﻿﻿bec City with my parents and my girlfriend Em.&lt;/p&gt;
&lt;p&gt;During the long drive back to Toronto from Qu﻿﻿é﻿﻿﻿bec City, I had plenty of time to think about &lt;a href="http://mikeconley.ca/blog/category/technology/computer-science/gsoc-computer-science/"&gt;my GSoC project&lt;/a&gt;, and where I want to go with it once &lt;a href="http://code.google.com/soc/"&gt;GSoC&lt;/a&gt; is done.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s what I came up with.&lt;/p&gt;
&lt;h3&gt;Detach Reviewing Time from Statistics&lt;/h3&gt;
&lt;p&gt;I think it&amp;#8217;s a safe assumption that my reviewing-time extension isn&amp;#8217;t going to be the only one to generate useful statistical data.&lt;/p&gt;
&lt;p&gt;So why not give extension developers an easy mechanism to display statistical data for their extension?&lt;/p&gt;
&lt;p&gt;First, I&amp;#8217;m going to extract the reviewing-time recording portion of the extension. Then, RB-Stats (or whatever I end up calling it), will introduce it&amp;#8217;s &lt;em&gt;own &lt;/em&gt;set of hooks for other extensions to register with.  This way, if users want some stats, there will be one place to go to get them.  And if an extension developer wants to make some statistics available, a lot of the hard work will already be done for them.&lt;/p&gt;
&lt;p&gt;And if an extension has the capability of combining its data with another extensions data to create a new statistic, we&amp;#8217;ll let RB-Stats manage all of that business.&lt;/p&gt;
&lt;h3&gt;Stopwatch&lt;/h3&gt;
&lt;p&gt;The reviewing-time feature of RB-Stats will become an extension on its own, and register its data with RB-Stats.  Once RB-Stats and Stopwatch are done, we should be feature equivalent with &lt;a href="http://mikeconley.ca/blog/2010/06/24/review-board-statistics-extension-demo-time/"&gt;my demo&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Review Karma&lt;/h3&gt;
&lt;p&gt;I kind of breezed past this in &lt;a href="http://mikeconley.ca/blog/2010/06/24/review-board-statistics-extension-demo-time/"&gt;my demo&lt;/a&gt;, but I&amp;#8217;m interested in displaying &amp;#8220;review karma&amp;#8221;.  Review karma is the reviews/review-requests ratio.&lt;/p&gt;
&lt;p&gt;But I&amp;#8217;m not sure karma is the right word.  It suggests that a low ratio (many review requests, few reviews) is a bad thing.  I&amp;#8217;m not so sure that&amp;#8217;s true.&lt;/p&gt;
&lt;p&gt;Still, I wonder what the impact will be to display review karma?  Not just in the RB-Stats statistics view, but next to user names?  Will there be an impact on review activity when we display this &amp;#8220;reputation&amp;#8221; value?&lt;/p&gt;
&lt;h3&gt;FixIt&lt;/h3&gt;
&lt;p&gt;This is a big one.&lt;/p&gt;
&lt;p&gt;Most code review tools allow reviewers to register &amp;#8220;defects&amp;#8221;, &amp;#8220;todos&amp;#8221; or &amp;#8220;problems&amp;#8221; with the code up for review.  This makes it easier for reviewees to keep track of things to fix, and things that have already been taken care of.  It&amp;#8217;s also useful in that it helps generate interesting statistics like defect density and defect detection rate (assuming Stopwatch is installed and enabled).&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m going to tackle this extension as soon as RB-Stats, Stopwatch and Karma are done.  At this point, I&amp;#8217;m quite confident that the current extension framework can more or less handle this.&lt;/p&gt;
&lt;p&gt;Got any more ideas for me?  Or maybe an extension wish-list?  Let  me know.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=P3zHcH9q0Kc:NsITZ1-1fRs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=P3zHcH9q0Kc:NsITZ1-1fRs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=P3zHcH9q0Kc:NsITZ1-1fRs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=P3zHcH9q0Kc:NsITZ1-1fRs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=P3zHcH9q0Kc:NsITZ1-1fRs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=P3zHcH9q0Kc:NsITZ1-1fRs:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=P3zHcH9q0Kc:NsITZ1-1fRs:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">mikeconley</dc:creator><pubDate>Mon, 05 Jul 2010 19:22:13 -0700</pubDate><guid>http://mikeconley.ca/blog/2010/07/05/review-board-statistics-extensions-karma-stopwatch-and-fixit/</guid></item><item><title>Review Board Statistics Extension – Demo Time
</title><link>http://mikeconley.ca/blog/2010/06/24/review-board-statistics-extension-demo-time/</link><description>&lt;p&gt;If I&amp;#8217;ve learned anything from &lt;a href="http://www.third-bit.com/"&gt;my supervisor&lt;/a&gt;, it&amp;#8217;s to demo.  Demo often. Step out of the lab and introduce what you&amp;#8217;ve been working on to the world. Hit the pavement and &lt;em&gt;show&lt;/em&gt;, rather than tell.&lt;/p&gt;
&lt;p&gt;So here&amp;#8217;s a video of me demoing my statistics extension for &lt;a href="http://www.reviewboard.org"&gt;Review Board&lt;/a&gt;.  It&amp;#8217;s still in the early phases, but a lot of the groundwork has been taken care of.&lt;/p&gt;
&lt;p&gt;And sorry for the video quality.  Desktop capture on Ubuntu turned out to be surprisingly difficult for my laptop, and that&amp;#8217;s the best I could do.&lt;/p&gt;
&lt;p&gt;So, without further ado, here&amp;#8217;s my demo (&lt;a href="http://www.youtube.com/watch?v=ZY4IqP26PnY"&gt;click here if you can&amp;#8217;t see it&lt;/a&gt;):&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Not bad!  And I haven&amp;#8217;t even reached the midterm of &lt;a href="http://code.google.com/soc/"&gt;GSoC&lt;/a&gt; yet.  Still plenty of time to enhance, document, test, and polish.&lt;/p&gt;
&lt;p&gt;If you have any questions or comments, I&amp;#8217;d love to hear them.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=n-ayE1Y7-_c:t_NCpK9Sq_g:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=n-ayE1Y7-_c:t_NCpK9Sq_g:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=n-ayE1Y7-_c:t_NCpK9Sq_g:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=n-ayE1Y7-_c:t_NCpK9Sq_g:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=n-ayE1Y7-_c:t_NCpK9Sq_g:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=n-ayE1Y7-_c:t_NCpK9Sq_g:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=n-ayE1Y7-_c:t_NCpK9Sq_g:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">mikeconley</dc:creator><pubDate>Thu, 24 Jun 2010 20:22:54 -0700</pubDate><guid>http://mikeconley.ca/blog/2010/06/24/review-board-statistics-extension-demo-time/</guid></item><item><title>GSoC Update:  My Review Board Statistics Extension
</title><link>http://mikeconley.ca/blog/2010/06/21/gsoc-update-my-review-board-statistics-extension/</link><description>&lt;h3&gt;The Primary Goal&lt;/h3&gt;
&lt;p&gt;From the very beginning, my GSoC project has been mainly focused towards one primary goal:  I want to build an extension for &lt;a href="http://www.reviewboard.org"&gt;Review Board&lt;/a&gt; that will allow me to collect information about how long reviewers actually spend reviewing code.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s easier said than done.  When I started, the Review Board extension framework wasn&amp;#8217;t really in a state to allow such an extension to exist.&lt;/p&gt;
&lt;p&gt;So I&amp;#8217;ve been tooling around in the Review Board code for the past 2 months, preparing the framework, and getting it ready to handle my extension.&lt;/p&gt;
&lt;p&gt;And last night, it started to work.  I can now give rough estimates on how long a reviewer has spent reviewing code.&lt;/p&gt;
&lt;h3&gt;How It Works&lt;/h3&gt;
&lt;p&gt;My extension adds a new table to the database which stores &amp;#8220;reviewing sessions&amp;#8221;.  Each reviewing session is associated to a particular review request and user, and also has a field to store the number of seconds that a user has spent in review.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve created a TemplateHook that allows me to inject Javascript into key areas of Review Board (in particular, the diff viewer, and the screenshot viewer).  The Javascript does the following:  every 10 seconds, we check to see if the mouse has moved on the body of the HTML document.  If it has, we send an &amp;#8220;activity&amp;#8221; notification to the server.&lt;/p&gt;
&lt;p&gt;The server receives this activity notification through &lt;a href="http://www.reviewboard.org/docs/manual/dev/webapi/#webapiguide"&gt;the Web API&lt;/a&gt;, and checks to see if the time lapsed since the last session update was greater than 10 seconds.  If it is, we increment the working session by 10 seconds and return a 200 HTTP code.  If it isn&amp;#8217;t, we don&amp;#8217;t change anything and return a 304 HTTP code.&lt;/p&gt;
&lt;p&gt;Next, my extension waits for a user to publish a review.  When it notices that a review is being published, it finds the working session for that user and review request, and then attaches it to the published review.  If the user then starts looking at the diff or screenshots again, a new working session is created.&lt;/p&gt;
&lt;p&gt;The result?  A pretty decent estimate of how long a user has spent reviewing the code.  No time gets recorded if the user gets up and has a sandwich.  No time gets recorded if the user is on another tab reading &lt;a href="http://www.reddit.com"&gt;Reddit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://mikeconley.ca/blog/wp-content/uploads/2010/06/Reviewing-Time.png"&gt;&lt;img alt="An image showing how reviewing time is displayed to the user" class="alignnone size-medium wp-image-1518" height="124" src="http://mikeconley.ca/blog/wp-content/uploads/2010/06/Reviewing-Time-300x124.png" title="Reviewing Time" width="300" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Not bad.  For a first draft, anyhow.&lt;/p&gt;
&lt;p&gt;I think I&amp;#8217;m going to try to chart the data somehow, so that users can track their inspection rates.  I&amp;#8217;ll let you know how that goes.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=7ykVzkLeS9E:tnTDCy9zmmw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=7ykVzkLeS9E:tnTDCy9zmmw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=7ykVzkLeS9E:tnTDCy9zmmw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=7ykVzkLeS9E:tnTDCy9zmmw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=7ykVzkLeS9E:tnTDCy9zmmw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=7ykVzkLeS9E:tnTDCy9zmmw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=7ykVzkLeS9E:tnTDCy9zmmw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">mikeconley</dc:creator><pubDate>Mon, 21 Jun 2010 18:19:22 -0700</pubDate><guid>http://mikeconley.ca/blog/2010/06/21/gsoc-update-my-review-board-statistics-extension/</guid></item><item><title>Review Board Tests:  SCMTool Segmentation Fault
</title><link>http://mikeconley.ca/blog/2010/06/02/review-board-tests-scmtool-segmentation-fault/</link><description>&lt;p&gt;I can&amp;#8217;t honestly say I&amp;#8217;ve been doing much test-driven development on Review Board.  Django is a really cool web-framework, but I miss all of the nice testing tools from the Rails ecosystem.&lt;/p&gt;
&lt;p&gt;Anyhow, today, I decided to run the tests, and BAM &amp;#8211; Segmentation Fault:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Testing Perforce binary diff parsing &amp;#8230; SKIP: perforce/p4python is not installed&lt;br /&gt;
Testing PerforceTool.get_changeset &amp;#8230; SKIP: perforce/p4python is not installed&lt;br /&gt;
Testing Perforce empty and normal diff parsing &amp;#8230; SKIP: perforce/p4python is not installed&lt;br /&gt;
Testing Perforce empty diff parsing &amp;#8230; SKIP: perforce/p4python is not installed&lt;br /&gt;
Testing PerforceTool.get_file &amp;#8230; SKIP: perforce/p4python is not installed&lt;br /&gt;
Testing parsing SVN diff with binary file &amp;#8230; ok&lt;br /&gt;
Testing SVNTool.get_file &amp;#8230; &lt;strong&gt;Segmentation Fault&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Yikes.  Getting a segfault in Python is unusual, and a little jarring.  However, it did let me narrow down the problem a bit:  it must have to do with the pysvn bindings that Review Board uses to talk to Subversion, because those are written in C++ (which can certainly segfault).&lt;/p&gt;
&lt;p&gt;The machine I was using had Ubuntu Hardy on it, and the Hardy packages have pysvn 1.5.2-1.  Taking a look at &lt;a href="http://pysvn.tigris.org/"&gt;the pysvn homepage&lt;/a&gt;, the most recent version is actually 1.7.2.&lt;/p&gt;
&lt;p&gt;So, I uninstalled pysvn, &lt;a href="http://pysvn.tigris.org/project_downloads.html"&gt;downloaded the source&lt;/a&gt; for 1.7.2, compiled it, and installed it manually.&lt;/p&gt;
&lt;p&gt;Segfault gone.  Tests pass.  Awesome sauce.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=-iWlzFaN1bM:FD8La9TS4KY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=-iWlzFaN1bM:FD8La9TS4KY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=-iWlzFaN1bM:FD8La9TS4KY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=-iWlzFaN1bM:FD8La9TS4KY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=-iWlzFaN1bM:FD8La9TS4KY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=-iWlzFaN1bM:FD8La9TS4KY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=-iWlzFaN1bM:FD8La9TS4KY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">mikeconley</dc:creator><pubDate>Wed, 02 Jun 2010 20:24:28 -0700</pubDate><guid>http://mikeconley.ca/blog/2010/06/02/review-board-tests-scmtool-segmentation-fault/</guid></item><item><title>Python Eggs:  Sunny Side Up, and Other Goodies (or How I Learned to Stop Worrying and Start Coding)
</title><link>http://mikeconley.ca/blog/2010/05/12/python-eggs-sunny-side-up-and-other-goodies/</link><description>&lt;h3&gt;Cooking with Eggs&lt;/h3&gt;
&lt;p&gt;Every now and then, the computer gods smile and give me a freebie.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve been worrying my mind out over a few problems / obstacles for &lt;a href="http://mikeconley.ca/blog/2010/04/27/my-gsoc-project-review-board-extensions/"&gt;my Review Board extensions GSoC project&lt;/a&gt;.  In particular, I&amp;#8217;ve been worrying about dealing with extension dependencies, conflicts, and installation.&lt;/p&gt;
&lt;p&gt;I racked my brain.  I came up with scenarios.  I drew lots of big scary diagrams on a wipe board.&lt;/p&gt;
&lt;p&gt;And then light dawned.&lt;/p&gt;
&lt;h3&gt;Batteries Come Included&lt;/h3&gt;
&lt;p&gt;Enter &lt;a href="http://peak.telecommunity.com/DevCenter/setuptools"&gt;Setuptools&lt;/a&gt; and &lt;a href="http://peak.telecommunity.com/DevCenter/PythonEggs"&gt;Python Eggs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All of those things I was worried about having to build and account for?  When using Python Eggs, It&amp;#8217;s all built in&lt;em&gt;.&lt;/em&gt; Dependencies?  Taken care of. Conflicts?  Don&amp;#8217;t worry about it.  Installation?  That&amp;#8217;s what Setuptools and Python Eggs were built for!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://peak.telecommunity.com/DevCenter/setuptools#extensible-applications-and-frameworks"&gt;In fact, it even looks like Setuptools was designed with extensible applications in mind.&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Wait, really?  How?&lt;/h3&gt;
&lt;p&gt;Here&amp;#8217;s the setup.py file for &lt;a href="http://github.com/chipx86/rb-extension-pack/tree/master/rbreports/"&gt;the rb-reports extension in the rb-extensions-pack on Github:&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;from setuptools import setup, find_packages

PACKAGE="RB-Reports"
VERSION="0.1"

setup(
    name=PACKAGE,
    version=VERSION,
    description="""Reports extension for Review Board""",
    author="Christian Hammond",
    packages=["rbreports"],
    entry_points={
        'reviewboard.extensions':
        '%s = rbreports.extension:ReportsExtension' % PACKAGE,
    },
    package_data={
        'rbreports': [
            'htdocs/css/*.css',
            'htdocs/js/*.js',
            'templates/rbreports/*.html',
            'templates/rbreports/*.txt',
        ],
    }
)
&lt;/pre&gt;
&lt;p&gt;Pay particular attention to the &amp;#8220;entry_points&amp;#8221; parameter.  What this is doing, is registering rbreports.extension:ReportsExtension to the entry point &amp;#8220;reviewboard.extensions&amp;#8221;.&lt;/p&gt;
&lt;p&gt;&amp;#8220;Hold up!&amp;#8221;, I hear you asking. &amp;#8220;What&amp;#8217;s an entry point?&amp;#8221;&lt;/p&gt;
&lt;h3&gt;Entry Points&lt;/h3&gt;
&lt;p&gt;An entry point is a unique identifier associated with an application that can accept extensions.&lt;/p&gt;
&lt;p&gt;The unique identifier for Review Board extensions is &amp;#8220;reviewboard.extensions&amp;#8221;.&lt;/p&gt;
&lt;p&gt;This is the first handshake, more or less, between Review Board and any extensions:  in order for Review Board to &amp;#8220;see&amp;#8221; the extension, the extension must register an entry point at &amp;#8220;reviewboard.extensions&amp;#8221;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://reinout.vanrees.org/weblog/2010/01/06/zest-releaser-entry-points.html"&gt;This blog post shows how extensions can be found and loaded up.&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Other Goodies&lt;/h3&gt;
&lt;h4&gt;INSTALLED_APPS and Django&lt;/h4&gt;
&lt;p&gt;I remember also being worried about how to create tables in Django for extension models.  I thought &amp;#8220;holy smokes, I&amp;#8217;m going to have to either shoehorn some raw SQL into the extension manager, or maybe even trust the extension developers to write the CREATE TABLE queries themselves!&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Luckily, there&amp;#8217;s a better alternative.&lt;/p&gt;
&lt;p&gt;Django knows about its applications through a dictionary called &lt;a href="http://docs.djangoproject.com/en/dev/ref/settings/#installed-apps"&gt;INSTALLED_APPS.&lt;/a&gt; When you add a new model to a Django project, you simply add the model app to the INSTALLED_APPS dictionary, and run &amp;#8220;manage.py syncdb&amp;#8221;.  Django does the magic, bingo-bango, and boom &amp;#8211; tables created.&lt;/p&gt;
&lt;p&gt;So if a new extension has some tables it needs created, I simply insert the app name of the extension into INSTALLED_APPS when the extension is installed, and &lt;a href="http://groups.google.com/group/django-users/browse_thread/thread/34b501d2d1f88496?pli=1"&gt;call syncdb programmatically&lt;/a&gt;.  Tables created:  no sweat.&lt;/p&gt;
&lt;h4&gt;django-evolution&lt;/h4&gt;
&lt;p&gt;Creating tables is easy.  But what if an extension gets updated, and the table needs to be modified?  Sounds like we&amp;#8217;ve got a mess on our hands.&lt;/p&gt;
&lt;p&gt;And don&amp;#8217;t expect Django to save you.  When you modify a model in Django, they expect you to into that DB and alter that table by hand:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;[syncdb] creates the tables if they don’t yet exist. Note that syncdb does &lt;em&gt;not&lt;/em&gt; sync changes in models or deletions of models; if you make a change to a model or delete a model, and you want to update the database, syncdb will not handle that.&lt;br /&gt;
From &lt;a href="http://www.djangobook.com/"&gt;The Django Book&lt;/a&gt; &amp;#8211; &lt;a href="http://www.djangobook.com/en/2.0/chapter05/"&gt;Chapter 5: Models&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Thankfully, there&amp;#8217;s a mechanism that&amp;#8217;s already built into Review Board that makes this trouble go away:  &lt;a href="http://code.google.com/p/django-evolution/"&gt;django-evolution&lt;/a&gt;.  Django-evolution, when used properly, will automatically detect changes in application models, and alter the database tables accordingly.  This is how Review Board does upgrades.&lt;/p&gt;
&lt;p&gt;And to top that off, RB co-founder &lt;a href="http://www.chipx86.com/blog/"&gt;Christian Hammond&lt;/a&gt; just became the django-evolution maintainer.&lt;/p&gt;
&lt;p&gt;Wow.  Everything is falling neatly into place.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=ED3RnkNnQBg:YrAKVYz2TEI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=ED3RnkNnQBg:YrAKVYz2TEI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=ED3RnkNnQBg:YrAKVYz2TEI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=ED3RnkNnQBg:YrAKVYz2TEI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=ED3RnkNnQBg:YrAKVYz2TEI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=ED3RnkNnQBg:YrAKVYz2TEI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=ED3RnkNnQBg:YrAKVYz2TEI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">mikeconley</dc:creator><pubDate>Wed, 12 May 2010 20:20:28 -0700</pubDate><guid>http://mikeconley.ca/blog/2010/05/12/python-eggs-sunny-side-up-and-other-goodies/</guid></item><item><title>Python Metaclasses in Review Board
</title><link>http://mikeconley.ca/blog/2010/05/04/python-metaclasses-in-review-board/</link><description>&lt;p&gt;So, after &lt;a href="http://mikeconley.ca/blog/2010/04/30/code-spelunking-review-board-extensions-2/"&gt;diving into the Review Board extension code&lt;/a&gt;, I hit a little snag.&lt;/p&gt;
&lt;p&gt;It turns out I never learned about Python metaclasses.  And the extension code in Djblets / Review Board uses them.  In &lt;a href="http://www.mikeconley.ca/images/rb_ext/Map.html"&gt;the map I made of the Review Board extension code&lt;/a&gt;, I represented my confusion with an image of some kind of quantum-divide-by-zero implosion.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll get to the &lt;em&gt;why&lt;/em&gt; for metaclasses in a second.  First, I&amp;#8217;ll demonstrate &lt;em&gt;how&lt;/em&gt; it&amp;#8217;s currently being used in the code.&lt;/p&gt;
&lt;h3&gt;The Way Things Are&lt;/h3&gt;
&lt;p&gt;This snippit is from the Djblets library, in the extensions folder, in base.py:&lt;/p&gt;
&lt;pre&gt;...

&lt;a href="#extension_hook" name="extension_hook"&gt;class ExtensionHook(object):&lt;/a&gt;
    def __init__(self, extension):
        self.extension = extension
        self.extension.hooks.add(self)
        self.__class__.add_hook(self)

    def shutdown(self):
        self.__class__.remove_hook(self)

&lt;a href="#extension_hook_point" name="extension_hook_point"&gt;class ExtensionHookPoint(type):&lt;/a&gt;
    def __init__(cls, name, bases, attrs):
        super(ExtensionHookPoint, cls).__init__(name, bases, attrs)

        if not hasattr(cls, "hooks"):
            cls.hooks = []

    def add_hook(cls, hook):
        cls.hooks.append(hook)

    def remove_hook(cls, hook):
        cls.hooks.remove(hook)

...&lt;/pre&gt;
&lt;p&gt;And here are those classes being used in the Review Board extension directory, where it defines its hooks:&lt;/p&gt;
&lt;pre&gt;...

&lt;a href="#dashboard_hook" name="dashboard_hook"&gt;class DashboardHook(ExtensionHook):&lt;/a&gt;
    __metaclass__ = ExtensionHookPoint

    def get_entries(self):
        raise NotImplemented

&lt;a href="#navigation_bar_hook" name="navigation_bar_hook"&gt;class NavigationBarHook(ExtensionHook):&lt;/a&gt;
    """
    A hook for adding entries to the main navigation bar.
    """
    __metaclass__ = ExtensionHookPoint

    def get_entry(self):
        """
        Returns the entry to add to the navigation bar.

        This should be a dict with the following keys:

            * `label`: The label to display
            * `url`:   The URL to point to.
        """
        raise NotImplemented
...&lt;/pre&gt;
&lt;p&gt;The idea here is that, if someone wanted to write an extension, they could add a hook to the navigation bar by subclassing the hooks, like so:&lt;/p&gt;
&lt;p&gt;(from &lt;a href="http://github.com/chipx86/rb-extension-pack/blob/master/rbreports/rbreports/extension.py"&gt;the rbreports prototype extension&lt;/a&gt;)&lt;/p&gt;
&lt;pre&gt;...

class ReportsDashboardHook(DashboardHook):
    def get_entries(self):
        return [{
            'label': 'Reports',
            'url': settings.SITE_ROOT + 'reports/',
        }]

class ReportsExtension(Extension):
    is_configurable = True

    def __init__(self):
        Extension.__init__(self)

        self.url_hook = URLHook(self, patterns('',
            (r'^reports/', include('rbreports.urls'))))

        self.dashboard_hook = ReportsDashboardHook(self)
...&lt;/pre&gt;
&lt;p&gt;So you can see the __metaclass__ thing up there in the &lt;a href="#dashboard_hook"&gt;DashboardHook&lt;/a&gt;.  &lt;a href="#dashboard_hook"&gt;DashboardHook&lt;/a&gt; subclasses &lt;a href="#extension_hook"&gt;ExtensionHook&lt;/a&gt;, and has &lt;a href="#extension_hook_point"&gt;ExtensionHookPoint&lt;/a&gt; as a metaclass.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Why?&lt;/em&gt; And what is a metaclass anyways?  Why is this useful at all?&lt;/p&gt;
&lt;p&gt;Well, luckily, I think I&amp;#8217;ve figured it out.&lt;/p&gt;
&lt;h3&gt;Behold &amp;#8211; Metaclasses&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;Metaclasses are deeper magic than 99% of users should ever worry about.         If you wonder whether you need them, you don&amp;#8217;t (the people who actually need them         know with certainty that they need them, and don&amp;#8217;t need an explanation about why).&lt;br /&gt;
&amp;#8211; Python Guru Tim Peters&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;There are &lt;a href="http://onlamp.com/pub/a/python/2003/04/17/metaclasses.html"&gt;plenty&lt;/a&gt; &lt;a href="http://www.voidspace.org.uk/python/articles/metaclasses.shtml"&gt;of resources&lt;/a&gt; &lt;a href="http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python"&gt;available&lt;/a&gt; &lt;a href="http://www.vrplumber.com/programming/metaclasses.pdf"&gt;regarding&lt;/a&gt; &lt;a href="http://stackoverflow.com/questions/392160/what-are-your-concrete-use-cases-for-metaclasses-in-python"&gt;Python&amp;#8217;s&lt;/a&gt; metaclasses.  And I ended up reading a ton of them trying to figure out just what the hell metaclasses actually do.&lt;/p&gt;
&lt;p&gt;As it turns out, &lt;a href="http://en.wikipedia.org/wiki/Metaclasses"&gt;the best explanation I got was from Wikipedia&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;In object-oriented programming, a metaclass is a class whose instances are classes. Just as an ordinary class defines the behavior of certain objects, a metaclass defines the behavior of certain classes and their instances.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Metaclasses#Python_example"&gt;In particular, check out their example on Cars&lt;/a&gt;.  That, for me,  more or less set the record straight on how metaclasses are used.&lt;/p&gt;
&lt;p&gt;But why does Review Board use them when defining those hooks, like &lt;a href="#dashboard_hook"&gt;DashboardHook&lt;/a&gt;?&lt;/p&gt;
&lt;h3&gt;Why?&lt;/h3&gt;
&lt;p&gt;Forget the metaclasses for just a second.&lt;/p&gt;
&lt;p&gt;Something is missing from that code that I posted up.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll pose it as a question:  How exactly is Review Board supposed to &lt;em&gt;know&lt;/em&gt; about ReportsDashboardHook?  Like&amp;#8230;if we&amp;#8217;re rendering the Dashboard, and want to fire off calls to all of our DashboardHooks&amp;#8230;how do we do it?  How can we find all of the active extension subclasses for DashboardHook?&lt;/p&gt;
&lt;p&gt;One way you could do it, is to dive into the extensions directories, and use regular expressions to find defined classes.  That sounds like a lot of work, brittle, and prone to error.  What else?&lt;/p&gt;
&lt;p&gt;Next, you could go back to those extension files, &amp;#8220;eval&amp;#8221; them (&lt;em&gt;shudder&lt;/em&gt;), and extract the globals(), looking for &lt;a href="#extension_hook"&gt;ExtensionHook&lt;/a&gt; subclasses.  That also sounds like lots of work, brittle, and prone to error.&lt;/p&gt;
&lt;p&gt;You could go for &lt;a href="http://docs.python.org/library/stdtypes.html#class.__subclasses__"&gt;class.__subclasses__&lt;/a&gt;&amp;#8230;but this gives you every subclass, and we just want the hooks that are for active extensions.  We could filter out all of the ones that aren&amp;#8217;t activated, but we&amp;#8217;d have to do that for every hook, and that blows.&lt;/p&gt;
&lt;p&gt;Next, we could have developers add their hooks to a registry after defining them.  So, we could have:&lt;/p&gt;
&lt;pre&gt;class ReportsDashboardHook(ExtensionHook):
  # ...
  # code goes here
  # ...

dashboard_hook_list.append(ReportsDashboardHook)&lt;/pre&gt;
&lt;p&gt;And then when an extension is shut down, we just remove it from the global hook list.  That doesn&amp;#8217;t look so bad, does it?  The only problem, is now we have to trust that extension developers will know to add those hooks to the global_hook_list?  It&amp;#8217;s another step, another thing to forget, and another point of failure.&lt;/p&gt;
&lt;p&gt;And it seems silly &amp;#8211; I mean, why go through all this effort?  Review Board has already seen these hooks&amp;#8230;why should it be so hard to just access the list activated hooks easily?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And there it is.&lt;/strong&gt; &lt;em&gt;That&amp;#8217;s&lt;/em&gt; why I think we&amp;#8217;re using metaclasses.&lt;/p&gt;
&lt;p&gt;If you go back to &lt;a href="#extension_hook"&gt;ExtensionHook&lt;/a&gt; and &lt;a href="#extension_hook_point"&gt;ExtensionHookPoint&lt;/a&gt;, you&amp;#8217;ll notice that ExtensionHookPoint has a list as an instance variable called hooks.  That&amp;#8217;s the global hook list for that class of hook (&lt;a href="#dashboard_hook"&gt;DashboardHook&lt;/a&gt;).  And then &lt;a href="#extension_hook"&gt;ExtensionHook&lt;/a&gt;, in its constructor, automatically adds itself to the Extension&amp;#8217;s internal list of hooks, as well as the global hook list, with the add_hook method.  Shutting down the hook removes that hook from the global hook list.&lt;/p&gt;
&lt;p&gt;So now, all we need to do to add our implemented hook to the list of hooks, is to simply subclass &lt;a href="#dashboard_hook"&gt;DashboardHook&lt;/a&gt;, or &lt;a href="#navigation_bar_hook"&gt;NavigationBarHook&lt;/a&gt;, or &lt;a href="http://www.mikeconley.ca/images/rb_ext/Map.html"&gt;any of those Review Board hooks&lt;/a&gt;.  No need to add the hook to the global list manually &amp;#8211; Djblets / Review Board will take care of it.  So now, we can get all of the DashboardHook subclasses for activated hooks, easily and consistently, with no extra work for the extension developer.  Same with the NavigationBarHook subclasses.&lt;/p&gt;
&lt;p&gt;Smooth as glass.  Nice.&lt;/p&gt;
&lt;p&gt;Anyhow, that&amp;#8217;s my understanding of it.  If I&amp;#8217;m totally off, I&amp;#8217;ll let you know when I find out.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=eDViMtH8V1k:GbI31yUrhYY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=eDViMtH8V1k:GbI31yUrhYY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=eDViMtH8V1k:GbI31yUrhYY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=eDViMtH8V1k:GbI31yUrhYY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=eDViMtH8V1k:GbI31yUrhYY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=eDViMtH8V1k:GbI31yUrhYY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=eDViMtH8V1k:GbI31yUrhYY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">mikeconley</dc:creator><pubDate>Wed, 05 May 2010 01:31:43 -0700</pubDate><guid>http://mikeconley.ca/blog/2010/05/04/python-metaclasses-in-review-board/</guid></item><item><title>Looking Back on Review Board
</title><link>http://www.chipx86.com/blog/2010/05/04/looking-back-on-review-board/</link><description>&lt;p&gt;Just over 3.5 years ago, David Trowbridge and I spent some time discussing the annoyances of the typical patch submission and code review processes in the open source projects we participated in and at companies, and decided to play with some ideas for improving this. At the time, we knew very little about what we intended to do. We had a name for it pretty early on, but that was about all we had. We didn&amp;#8217;t even know whether we&amp;#8217;d get past an early prototyping stage. But here it is, over 3 years later, and we have the leading open source code review tool with an active support and development community, hundreds of companies using it, and exciting new innovations for aiding in the code review process.&lt;/p&gt;
&lt;p&gt;I was thinking a few days ago about how far we&amp;#8217;ve come and some of the decisions we made along the way. I went digging through our commit history in order to relive some of the past of our little project. Since so few people were even aware of Review Board&amp;#8217;s existence at the time, I thought I&amp;#8217;d share some of our history with you. Particularly the interesting and funny bits.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&amp;#8220;Add the reviewboard.&amp;#8221;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Commit #1. The very first thing we put in our Subversion tree on September 27, 2006. I don&amp;#8217;t even remember what was in this change now. We transitioned to Git last year and this commit is now just plain empty. Maybe it was jut the directory structure? Who can say.&lt;/p&gt;
&lt;p&gt;Early on, we didn&amp;#8217;t refer to &amp;#8220;Review Board&amp;#8221; as a proper name. It was generally &amp;#8220;the reviewboard&amp;#8221; or something similar. The codebase was young. We didn&amp;#8217;t actually do code review on the project at this point (and it shows!). The first few months are littered with odd or nonsensical commit messages, small breakages, and bad decisions.&lt;/p&gt;
&lt;p&gt;A few of my favorite commit messages are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;#8220;I suck. Make submitting of reviews.&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;Don&amp;#8217;t stuff the list of files in the bug list. It&amp;#8217;s impolite.&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;Avoid failing out with Christian&amp;#8217;s wacko form&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;Gum.&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;Holy apple pancakes. It worked!&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;I suck&amp;#8230; The array was empty&amp;#8230; The tests never had a chance to fail. :(&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;&amp;#8216;This is a summary&amp;#8217; sucks. Now we use fortune for the summary, description, and testing done. &amp;#8216;You&amp;#8217;re ugly and your mother dresses you funny.&amp;#8217;&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;Unbreak things before ChipX86 notices&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;I&amp;#8217;m just&amp;#8230; garhgh&amp;#8221;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nowadays, our commit messages look nothing like that, but that&amp;#8217;s the fun of a new project. You get to go commit-crazy while you try to figure out what you&amp;#8217;re building.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Dashboard, quips and fortunes&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;The UI of old looked quite different than the UI of today.&lt;/p&gt;
&lt;p&gt;We had a dashboard from the very beginning (before the review request pages, even) but it wasn&amp;#8217;t anything like the dashboard we had today. It was a simple page with a table containing all outgoing review requests and a table containing incoming review requests. But it also had one more thing: quips.&lt;/p&gt;
&lt;p&gt;The beginning of quips functionality was being built. Quips are just little random quotes that are inserted in the UI. I think the plan was to put quips on certain pages, making Review Board a little more fun. We were using them in the dashboard for empty lists, with variations all saying something about the dashboard being empty. Quips are a neat feature that just never survived the early days of development.&lt;/p&gt;
&lt;p&gt;Fortunes are similar. On Linux/Unix systems, there&amp;#8217;s a little program called &amp;#8220;fortune&amp;#8221; that just displays a random quote. Since we at first had to test review request functionality without actually having a repository backend of any sort, and we didn&amp;#8217;t want to input all the information each time, we just used fortune to generate the summary, description and testing done text. This made for some really funny review requests early on, but this is of course something that had no reason to survive initial development.&lt;/p&gt;
&lt;p&gt;Sometimes we would create a bunch of review requests just to see what kind of quotes we&amp;#8217;d get. :)&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Multiple repositories? Almost didn&amp;#8217;t happen.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;One of the really critical parts of Review Board today is the ability to talk to a variety of different types of repositories in one instance. But, it turns out, this almost didn&amp;#8217;t happen.&lt;/p&gt;
&lt;p&gt;The initial goals were not that ambitious. Review Board talked to one repository per instance. Everything was basically hard-coded with one repository in mind. That type of repository, as well as its information, was customizable. You just couldn&amp;#8217;t have more than one. At the time, this wasn&amp;#8217;t a problem, but it didn&amp;#8217;t take long until we had a need to talk to two repositories.&lt;/p&gt;
&lt;p&gt;We discussed this and at first decided that if we needed to talk to two repositories, we could just set up two instances. It would have been a lot of work to update it for multiple repositories, after all. And really, this was a small project. Who would really need more than a couple repositories? This started to nag at me, though, and so I spent a couple nights rewriting all of the code as an experiment. It ended up working pretty nicely, and we were able to ditch the multi-instance model.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;The importance of rewards&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s always nice to have a little reward for milestones. Developers sometimes compete over cool bug numbers, revisions, etc. Initially, we were going to use quips to add some fun to the site, but we ended up settling on our current trophy system.&lt;/p&gt;
&lt;p&gt;One of our first Review Board instances started to approach review request #1000, which was a huge milestone for us. I decided to commemorate the event by staying up and quickly hacking in a hidden feature for showing a trophy for review request #1000. The way we implemented it, you&amp;#8217;d see the first ever trophy at 1,000, and from there you&amp;#8217;d see it at every milestone number (1,000, 2,000, 3,000, 10,000, etc.). I didn&amp;#8217;t want to stop there, though, so I added support for a second type of trophy, one that has confused people with its appearance to this day. Mission complete.&lt;/p&gt;
&lt;p&gt;Of course, when we updated the server and someone finally hit 1000, it triggered a bug in the new trophy code and broke his review request. Oh well, I tried.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Diff viewers are hard&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;If I could pick one point during the whole history of Review Board where I was ready to completely give up, it would be during the creation of our diff viewer. All three diff viewers.&lt;/p&gt;
&lt;p&gt;See, the first diff viewer was a complete and total hack. We generated a side-by-side diff using the diff tools and just parsed the output, basically generating a table of that. It was ugly, though, and limiting. It also caused problems where text on a row would either be truncated or would break the parser. I spent a long time working on this before I totally gave up and went on to try a new approach.&lt;/p&gt;
&lt;p&gt;My second approach was closer to what we have today, but also limiting and very, very buggy. We were using Python&amp;#8217;s built-in diff generation module, which implements a basic diff algorithm. It gave us insert and delete information, but not replace information. We had to hack that in ourselves, and it was really a hack. Try taking a bunch of inserts and deletes and find out which of those are really changed lines. No, really, try it. It&amp;#8217;s harder than you think, and it&amp;#8217;ll often be wrong.&lt;/p&gt;
&lt;p&gt;Still, we stuck with this for a long time. It was slow, buggy, and didn&amp;#8217;t generate the sort of output people expected from diff tools. Most people see diffs from GNU Diff, which implements the Meyers Diff Algorithm (with a few additions and tweaks). These Meyers diffs are much nicer to view than what Python gave us. Another problem we hit was that we didn&amp;#8217;t have real line number information, so we had to output fake line numbers. They weren&amp;#8217;t really line numbers so much as row numbers in the table. Ugh. Even getting this far was really hard and frustrating, and the result still wasn&amp;#8217;t good.&lt;/p&gt;
&lt;p&gt;Attempt #3. I decided to build our own diff parser and generator from scratch. What a project. I knew nothing about diff generation and hardly knew where to start. I spent probably a good month or so just trying to work on this new diff code, and was so close to giving up so many times. It ended up being completely worth it, though, as we ended up with a very nice, extensible diff parser.&lt;/p&gt;
&lt;p&gt;Without that third attempt, we&amp;#8217;d be in the stone age. Review Board would not be as nice to use. We wouldn&amp;#8217;t have inter-line diffs (where we highlight what changed in a replace line), syntax highlighting, move detection (coming in 1.5), or function/class headers (where we show which function/class the part of the diff is in &amp;#8212; also coming in 1.5).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;What else&amp;#8230;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Well, there&amp;#8217;s a lot more I could talk about. Our initial attempts at JavaScript code for the UI, our trials and challenges with database migration, or our early problems storing diffs with different encodings in databases. This is getting long, though, so I&amp;#8217;ll cover these in another post on lessons learned.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=-bsNUPXMJII:zyYZy9angkQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=-bsNUPXMJII:zyYZy9angkQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=-bsNUPXMJII:zyYZy9angkQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=-bsNUPXMJII:zyYZy9angkQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=-bsNUPXMJII:zyYZy9angkQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=-bsNUPXMJII:zyYZy9angkQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=-bsNUPXMJII:zyYZy9angkQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><author>chipx86@chipx86.com (chipx86)</author><pubDate>Tue, 04 May 2010 09:53:00 -0700</pubDate><guid>http://www.chipx86.com/blog/2010/05/04/looking-back-on-review-board/</guid></item><item><title>The Review Board Extension Life-Cycle
</title><link>http://mikeconley.ca/blog/2010/05/02/reviewboard-extension-lifecycle/</link><description>&lt;p&gt;According to &lt;a href="http://socghop.appspot.com/document/show/gsoc_program/google/gsoc2010/timeline"&gt;the timeline&lt;/a&gt;, I&amp;#8217;m still in the community-bonding period for GSoC.  Coding for &lt;a href="http://mikeconley.ca/blog/2010/04/27/my-gsoc-project-review-board-extensions/"&gt;my project&lt;/a&gt; is supposed to start sometime towards the end of May.&lt;/p&gt;
&lt;p&gt;So I&amp;#8217;m using the time to do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Close as many small, easy tickets as I can for the  upcoming Review Board release.  I&amp;#8217;ve already posted some patches for review.  More forthcoming.&lt;/li&gt;
&lt;li&gt;Get to know the tools I&amp;#8217;ll be using.  Review Board is hosted on Github, and I&amp;#8217;m relatively new to the whole DVCS thing.  I&amp;#8217;ve been figuring out &lt;a href="http://progit.org"&gt;how to use Git&lt;/a&gt;, how to post patches, merging, branching, etc.&lt;/li&gt;
&lt;li&gt;Get to know the area I&amp;#8217;ll be working in.  I&amp;#8217;ve been figuring out how Django apps organize themselves.  I&amp;#8217;ve also drawn up &lt;a href="http://mikeconley.ca/blog/2010/04/30/code-spelunking-review-board-extensions-2/"&gt;a map of the current state of the extension framework&lt;/a&gt; to help me visualize it.&lt;/li&gt;
&lt;li&gt;Get to know the other developers working on Review Board.  I&amp;#8217;ve been hanging out in the #reviewboard-soc FreeNode IRC channel.  Very nice, and helpful people to work with.&lt;/li&gt;
&lt;li&gt;Develop a plan of attack for my project&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And this last point is the one I want to talk about.&lt;/p&gt;
&lt;h3&gt;The Review Board Extension Life-Cycle&lt;/h3&gt;
&lt;p&gt;An extension isn&amp;#8217;t just some isolated piece of code that gets crammed into an application.  When you&amp;#8217;ve got multiple extensions already installed and running, installing and activating a new extension is like introducing a new animal into an ecosystem.  You have to make sure that your new animal plays nice with the others, and that, in the morning, there won&amp;#8217;t be a pile of rotting corpses where your application used to be.&lt;/p&gt;
&lt;p&gt;I may have gotten carried away with my metaphor.&lt;/p&gt;
&lt;p&gt;So let&amp;#8217;s look at what I&amp;#8217;m envisioning as the life-cycle for a Review Board extension.  I&amp;#8217;ll start right from the top.&lt;/p&gt;
&lt;h4&gt;Getting the Extension&lt;/h4&gt;
&lt;p&gt;Ideally, this will work as nicely as WordPress&amp;#8217;s implementation:  a Review Board administrator is given a catalog of extensions to choose from within the Administrator interface, and one click later, the desired extensions are downloaded and ready to be installed.&lt;/p&gt;
&lt;p&gt;For all you system administrators out there, that last idea might make your toes curl.  A Review Board administrator is not necessarily a system administrator, and the system administrator knows what he/she likes on their machine.  An application that can go and download other applications can be dangerous.  We have to ensure that the application that we&amp;#8217;re downloading is the one we&amp;#8217;re &lt;em&gt;trying &lt;/em&gt;to download.  The last thing we need is some man-in-the-middle to do something cute and bork the code review machine.  And we want to ensure that the extension functions as advertised.  No hidden features.  No self-destruct mechanisms.  No back doors.&lt;/p&gt;
&lt;p&gt;Do I have a plan for this part?  Well&amp;#8230;.no, not really.  I don&amp;#8217;t imagine I&amp;#8217;ll get that far &amp;#8211; I consider it a little out of my scope.  So, for my project, I think it&amp;#8217;ll satisfy if the system admin (or Review Board admin) can manually download the extension, decompress it, and place it where Review Board can work with it.  That other stuff can come later (and I&amp;#8217;ll try to design so that it can come later &lt;em&gt;easily&lt;/em&gt;).&lt;/p&gt;
&lt;h4&gt;Installing the Extension&lt;/h4&gt;
&lt;p&gt;Ok, so at this point, we&amp;#8217;ve got our extension downloaded in a place where Review Board can see it.&lt;/p&gt;
&lt;p&gt;So now what?&lt;/p&gt;
&lt;p&gt;Now we need to &lt;em&gt;install&lt;/em&gt; the extension.  To me, that means letting the extension put its roots into the RB install by creating database tables, preparing initial data, and generally doing everything to make conditions suitable for the extension to function.&lt;/p&gt;
&lt;p&gt;When an extension install begins, I imagine it will consider the following questions (in no particular order):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Do I (the extension) depend on other extensions to function?  If so, are those extensions present?  If not, let the user know so that they can go get them.&lt;/li&gt;
&lt;li&gt;Are there some extensions already installed that will conflict with me, or make me behave badly?  If so, let the user know so that they can either remove that conflict, or find an alternative extension.&lt;/li&gt;
&lt;li&gt;Is the user entirely aware of what I can do?  Make sure that my capabilities, limitations, and behavioural quirks are known to the user.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once those 3 questions are answered, and everything is looking good for the install, the extension will create the database tables it needs (if any) in order to function.  If anything goes wrong during this process, the database changes will be rolled back, and the user will get a full read out about what went wrong.&lt;/p&gt;
&lt;p&gt;If nothing goes wrong, the extension will be installed.  The user might then be asked to set some initial operating parameters for the extension.&lt;/p&gt;
&lt;p&gt;Ok great &amp;#8211; the extension is installed.  Now what?&lt;/p&gt;
&lt;h4&gt;Activating the Extension&lt;/h4&gt;
&lt;p&gt;For something that sounds so dramatic, the explanation about what happens is pretty short:  Review Board simply becomes aware that the extension is activated, and passes data through the necessary hooks in order for the extension to function properly.  Upon activation, the extension should do a quick double-check to ensure that all prerequisites for the extension have been met.  This is because we can&amp;#8217;t trust users to activate an extension immediately after downloading them.&lt;/p&gt;
&lt;h4&gt;The Extension Runs&lt;/h4&gt;
&lt;p&gt;While it&amp;#8217;s activated, the extension will probably react to various events that happen on Review Board.  Tables will be updated.  View methods will be run.  Templates will be rendered.&lt;/p&gt;
&lt;p&gt;If anything, ever, goes horribly wrong with an extension, the following will happen:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A log entry will be written, dumping the error, and information about what the user was trying to do&lt;/li&gt;
&lt;li&gt;An error message will be displayed to the user, trying to tell them what exactly happened&lt;/li&gt;
&lt;li&gt;The extension (and its dependents) will be deactivated.  They will no longer react to events on Review Board.  Their tables will still be there, the settings will still, but the extension will be, in essence, asleep.  Dormant.  Non-reactive.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The administrator could try to reactivate the extension at this point.  They might try to contact the extension developer for support.&lt;/p&gt;
&lt;h4&gt;The Extension is Un-installed&lt;/h4&gt;
&lt;p&gt;If the user wants to rid themselves of an extension, they must first deactivate it.  This will put it (and its dependents) in the dormant state.  It just switches them off, nothing else.&lt;/p&gt;
&lt;p&gt;Deactivated extensions can then be un-installed.  If the user chooses to un-install the extension, the extension database tables and settings will be wiped out.&lt;/p&gt;
&lt;p&gt;The extension itself won&amp;#8217;t be deleted though &amp;#8211; at least, not within the scope of my project.  The extension files will need to be removed from Review Board manually.&lt;/p&gt;
&lt;p&gt;At this point, any dependents that this uninstalled extension had will no longer be able to be activated.&lt;/p&gt;
&lt;p&gt;Anyhow, that&amp;#8217;s how I envision the life-cycle.  It&amp;#8217;s my first go at it, so I&amp;#8217;d love to hear some feedback if you have any.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=83ziWRET4Ow:xsD6sgFMKkk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=83ziWRET4Ow:xsD6sgFMKkk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=83ziWRET4Ow:xsD6sgFMKkk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=83ziWRET4Ow:xsD6sgFMKkk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=83ziWRET4Ow:xsD6sgFMKkk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=83ziWRET4Ow:xsD6sgFMKkk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=83ziWRET4Ow:xsD6sgFMKkk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">mikeconley</dc:creator><pubDate>Mon, 03 May 2010 02:55:07 -0700</pubDate><guid>http://mikeconley.ca/blog/2010/05/02/reviewboard-extension-lifecycle/</guid></item><item><title>Code Spelunking: Review Board Extensions
</title><link>http://mikeconley.ca/blog/2010/04/30/code-spelunking-review-board-extensions-2/</link><description>&lt;p&gt;So this summer, &lt;a href="http://mikeconley.ca/blog/2010/04/27/my-gsoc-project-review-board-extensions/"&gt;I&amp;#8217;m working on Review Board for the Google Summer of Code.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Until my GSoC acceptance, my romps into the code had been relatively shallow.  But with my proposal being given the green light, I&amp;#8217;ve started doing more extensive explorations.&lt;/p&gt;
&lt;p&gt;Review Board is built using &lt;a href="http://www.djangoproject.com/"&gt;the Django web framework&lt;/a&gt;.  I haven&amp;#8217;t worked with Django before, but I have quite a bit of experience with Rails, so that should be an asset.  Using a web framework means having (relatively) predictable source code layout, and Review Board is no exception.&lt;/p&gt;
&lt;h4&gt;Djblets&lt;/h4&gt;
&lt;p&gt;At one point or another, the Review Board developers realized that a lot of their code wasn&amp;#8217;t Review Board specific, and could be abstracted out into an external library.&lt;/p&gt;
&lt;p&gt;That library is called &lt;a href="http://github.com/djblets/djblets"&gt;Djblets&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Among other things, Djblets adds a DataGrid component for easy record sorting and pagination.  There are improvements to Django&amp;#8217;s Authentication system.  Functions for easily displaying a user&amp;#8217;s &lt;a href="http://en.gravatar.com/"&gt;Gravatar&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And, low and behold, there is a branch of Djblets that provides classes and functions for giving a Django application an extension framework.  The classes are abstract enough so that, in your Django application, you can specify different types and behaviours for your Hooks.&lt;/p&gt;
&lt;h4&gt;Djblets -&amp;gt; Review Board&lt;/h4&gt;
&lt;p&gt;The Review Board extension branch takes these Djblets extension classes, and extends them into DashboardHooks, NavigationBarHooks, ReviewRequestDetailHooks&amp;#8230;lots of different hooks.&lt;/p&gt;
&lt;p&gt;So, Djblets creates the foundation abstractions.  Review Board makes these abstractions a little more specific.  And then an extension writer needs to instantiate and use these classes to design their extensions.  It sounds complicated, I know.&lt;/p&gt;
&lt;h4&gt;So Let&amp;#8217;s Map It Out&lt;/h4&gt;
&lt;p&gt;When I start learning a new code base, I do a lot of drawing.  To me, getting to now a code base is like getting to know a city, and that means walking around it, and mapping it out.&lt;/p&gt;
&lt;p&gt;So I&amp;#8217;ve taken the liberty of mapping out the extension classes that I&amp;#8217;ve found, and how they relate to one another.  Note that at the bottom of my map, a simple extension (RB Reports) is using some of those classes to hook itself into Review Board.  You can find this, and other extensions,&lt;a href="http://github.com/chipx86/rb-extension-pack"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class="wp-caption alignnone" id="attachment_1222" style="width: 310px;"&gt;&lt;a href="http://www.mikeconley.ca/images/rb_ext/Map.html"&gt;&lt;img alt="My map of the extension framework" class="size-medium wp-image-1222" height="238" src="http://mikeconley.ca/blog/wp-content/uploads/2010/04/Map-300x238.png" title="Extensions Map" width="300" /&gt;&lt;/a&gt;&lt;p class="wp-caption-text"&gt;Click here to check out my map of the current state of the extension framework&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;Now, before someone in the department starts complaining about my misuse of UML:  I&amp;#8217;m not a UML guy.  I just wanted an easy piece of diagramming software, and the one that I found (&lt;a href="http://www.gnome.org/projects/dia/"&gt;Dia&lt;/a&gt;), did UML.  I just wanted something to draw boxes and lines. So please don&amp;#8217;t freak out if you think I&amp;#8217;m using the wrong symbols.&lt;/p&gt;
&lt;p&gt;One symbol you might be wondering about is the blue quantum-flux-capacitor-implosion.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll save that for a future post.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=aAuTZB0_nlo:dxBa5lcRSOM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=aAuTZB0_nlo:dxBa5lcRSOM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=aAuTZB0_nlo:dxBa5lcRSOM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=aAuTZB0_nlo:dxBa5lcRSOM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=aAuTZB0_nlo:dxBa5lcRSOM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=aAuTZB0_nlo:dxBa5lcRSOM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=aAuTZB0_nlo:dxBa5lcRSOM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">mikeconley</dc:creator><pubDate>Sat, 01 May 2010 00:25:04 -0700</pubDate><guid>http://mikeconley.ca/blog/2010/04/30/code-spelunking-review-board-extensions-2/</guid></item><item><title>My GSoC Project:  Review Board Extensions
</title><link>http://mikeconley.ca/blog/2010/04/27/my-gsoc-project-review-board-extensions/</link><description>&lt;p&gt;If you didn&amp;#8217;t already know, &lt;a href="http://www.reviewboard.org"&gt;Review Board&lt;/a&gt; is an open-source web-based code review tool.  &lt;a href="http://www.markusproject.org"&gt;The MarkUs Team&lt;/a&gt; has been using Review Board for &lt;a href="http://mikeconley.ca/blog/2010/02/02/pre-commit-code-review-in-markus-development/"&gt;pre-commit code review&lt;/a&gt; for about a year now.  This has given the team a number of advantages:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;For a team that usually has a 4 month turnover, this allows us to quickly get new team members up to speed with how to contribute to MarkUs.  We review every change that they propose, and give them tips/guidance on how to make it fit in well with the application.  They learn, and the applications code stays healthy.&lt;/li&gt;
&lt;li&gt;We catch defects before they enter the code base.  Simple as that.&lt;/li&gt;
&lt;li&gt;We get a good sense of what other people are working on, and what is going on in the code.  Review Board has become a central conversation and learning hub for the developers on the MarkUs team.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, the long and the short of it:  &lt;em&gt;I like Review Board.  Review Board helps us write better code.  I want to make Review Board better.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So what am I proposing?&lt;/p&gt;
&lt;h3&gt;How to Avoid A Bloated Software Monster&lt;/h3&gt;
&lt;p&gt;You can never make some people happy.&lt;/p&gt;
&lt;p&gt;No matter how decent your software is, someone will eventually come up to you and say:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Wow!  Your software would be perfect if only it had feature XYZ!  Sadly, because you don&amp;#8217;t have feature XYZ, I can&amp;#8217;t use it.  Please implement, k thx!&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;And so you either have to politely say &amp;#8220;no&amp;#8221;, and lose that user, or say &amp;#8220;yes&amp;#8221;, and add feature XYZ to the application.  And for users out there who don&amp;#8217;t need, or don&amp;#8217;t care about feature XYZ, that new feature just becomes a distraction and adds no value.  Make this happen a bunch of times, and you&amp;#8217;ve got yourself a bloated mutha for a piece of software.&lt;/p&gt;
&lt;p&gt;And we don&amp;#8217;t want a bloated piece of software.  But we &lt;em&gt;do &lt;/em&gt;want to make our users happy, and provide feature XYZ for them if they want it.&lt;/p&gt;
&lt;p&gt;So what&amp;#8217;s the solution?  &lt;strong&gt;We provide an extension framework&lt;/strong&gt; (which is also sometimes called a plug-in architecture).&lt;/p&gt;
&lt;p&gt;An extension framework allows developers to easily expand a piece of software to do new things.  So, if a user wants feature XYZ, we (or someone else) just creates and make available an extension that implements the feature.  The user installs the extension, activates it, and bam &amp;#8211; our user is happy as a clam with their new feature.&lt;/p&gt;
&lt;p&gt;And if we make it super-easy to develop them, third-party developers can write new, wonderful, interesting extensions to do things that&amp;#8230;well, we wouldn&amp;#8217;t have considered in the first place. It&amp;#8217;s a new place for innovation.  What&amp;#8217;s that old cliché?&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;If you build it [the plug-in framework], they will come [the third-party developers who write awesome things]&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;And the developers do come.  Just look at &lt;a href="https://addons.mozilla.org/en-US/firefox/"&gt;Firefox add-ons&lt;/a&gt; or &lt;a href="http://wordpress.org/extend/plugins/"&gt;WordPress plugins&lt;/a&gt;.  Entire &lt;em&gt;ecosystems&lt;/em&gt; of extensions, doing things that the original developers would probably have never dreamed of doing on their own.  Hell, &lt;em&gt;I&amp;#8217;ve &lt;/em&gt;even written &lt;a href="../category/technology/firefox-extensions/alertcheck-firefox-extensions-technology/"&gt;a Firefox add-on.&lt;/a&gt; And users love customizing their Firefox / WordPress with those extensions.  It &lt;em&gt;adds value&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So we get wins all over the place:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our user gets their feature&lt;/li&gt;
&lt;li&gt;The software gets more attractive because it&amp;#8217;s flexible and customizable&lt;/li&gt;
&lt;li&gt;The original software developers get to focus on the core piece of software, and let the third-party developers focus on the fringe features&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And this is where I think I can help Review Board.&lt;/p&gt;
&lt;p&gt;(Before I go on, if you&amp;#8217;re interested, &lt;a href="http://www.fogcreek.com/fogbugz/blog/post/the-fogbugz-plugin-architecture.aspx"&gt;here&amp;#8217;s another article on the how and the why of plug-in architectures&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;Review Board Extensions&lt;/h3&gt;
&lt;p&gt;So if you look at the &lt;a href="http://code.google.com/p/reviewboard/w/list"&gt;Review Board Wiki&lt;/a&gt;, or glance at the &lt;a href="http://www.reviewboard.org/mailing-lists/"&gt;mailing lists&lt;/a&gt; you see numerous requests from users for new features, for example:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;It would be nice if the review board had a &amp;#8220;next comment&amp;#8221; button that is always available to click, or had a collapse/expand button. This would make it easier to see other people&amp;#8217;s comments in cases like this.&lt;/p&gt;
&lt;p&gt;&amp;#8230;&lt;/p&gt;
&lt;p&gt;It will be nice to have post-commit support. Instead of every post-commit review being a separate URL, if we could setup default rules for post-commit reviews to update an existing review providing the diff-between-diff features, it would be very useful.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;The Review Board developers could smell the threat of bloated feature-creep from a mile away.  So, &lt;a href="http://github.com/chipx86/reviewboard/tree/extensions"&gt;in a separate branch&lt;/a&gt;, they began working on integrating an extension framework into Review Board.&lt;/p&gt;
&lt;p&gt;The extension branch, however, has been gathering dust, while the developers focus on more critical patches and releases.&lt;/p&gt;
&lt;p&gt;My GSoC proposal is to finish off a draft of the extension framework, document it, and build a very simple extension for it.  My simple extension will allow me to record basic statistics about Review Board reviewers &amp;#8211; for example, how long they spend on a particular review, their inspection rate, etc.&lt;/p&gt;
&lt;p&gt;Having been a project lead &lt;a href="http://www.markusproject.org"&gt;MarkUs&lt;/a&gt; for so long, it&amp;#8217;s going to be a good experience to be back on &amp;#8220;the bottom&amp;#8221; &amp;#8211; to be the new developer who doesn&amp;#8217;t entirely have a sense of the application code yet.  It&amp;#8217;s going to be good to go code spelunking again.  I&amp;#8217;ve done some preliminary explorations, and it&amp;#8217;s reminding me of my first experiences with MarkUs.  Like &lt;a href="http://www.youtube.com/watch?v=7N7i7_ts_eg"&gt;a submarine using its sonar&lt;/a&gt;, I&amp;#8217;m slowly getting a sense of the code terrain.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll let you know what my first few sweeps find.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=cYuIs-CKyTw:xzh8mt2C3dk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=cYuIs-CKyTw:xzh8mt2C3dk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=cYuIs-CKyTw:xzh8mt2C3dk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=cYuIs-CKyTw:xzh8mt2C3dk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=cYuIs-CKyTw:xzh8mt2C3dk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=cYuIs-CKyTw:xzh8mt2C3dk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=cYuIs-CKyTw:xzh8mt2C3dk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">mikeconley</dc:creator><pubDate>Tue, 27 Apr 2010 19:54:24 -0700</pubDate><guid>http://mikeconley.ca/blog/2010/04/27/my-gsoc-project-review-board-extensions/</guid></item><item><title>Ping!
</title><link>http://mikeconley.ca/blog/2010/04/27/ping/</link><description>&lt;p&gt;I&amp;#8217;ve &lt;a href="http://mikeconley.ca/blog/2010/01/19/markus-squad-hows-refactor-my-code-belated-happy-holidays-im-not-dead/"&gt;done it&lt;/a&gt; &lt;a href="http://mikeconley.ca/blog/2009/08/20/still-alive/"&gt;again&lt;/a&gt;:  I&amp;#8217;ve let dust gather on my blog.&lt;/p&gt;
&lt;p&gt;Quick update:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I&amp;#8217;ve finished my courses for this semester, and have gone into &lt;a href="http://mikeconley.ca/blog/2010/03/29/does-peer-grading-make-students-better-programmers/"&gt;full-blown research mode&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;My research proposal is going through ethics review, in order to make sure that I&amp;#8217;m not going to blow things up (or hurt anybody if I do)&lt;/li&gt;
&lt;li&gt;While my paperwork is reviewed, I&amp;#8217;m refining my procedure and apparatus.  Better and better.&lt;/li&gt;
&lt;li&gt;I&amp;#8217;ve been accepted into &lt;a href="http://socghop.appspot.com"&gt;Google Summer of Code&lt;/a&gt; this year &amp;#8211; I&amp;#8217;ll be working on &lt;a href="http://www.reviewboard.org"&gt;Review Board&lt;/a&gt;.  Details about my project will be the subject of an upcoming post, which I will toss up shortly.&lt;/li&gt;
&lt;li&gt;I may or may not be co-directing a radio play.  I&amp;#8217;ll let you know.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.markusproject.org"&gt;The MarkUs team&lt;/a&gt; is about to release version 0.7, and a fresh batch of Summer students will soon be here at UofT to work on it!&lt;/li&gt;
&lt;li&gt;I have &lt;em&gt;not &lt;/em&gt;forgotten about the &lt;a href="http://www.uc.utoronto.ca/content/view/340/2083/"&gt;UCDP&lt;/a&gt; &lt;a href="http://mikeconley.ca/blog/category/personal/poland/"&gt;trip to Poland&lt;/a&gt;.  I still have to tell you what we saw and did at Auschwitz.  Cripes &amp;#8211; it&amp;#8217;s almost a year since I returned, and I&amp;#8217;m only half-way through the whole story.  And there&amp;#8217;s a ton more to tell.  Coming soon.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Stay tuned.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=Y21VMNxYIeU:lPHzVBT0r5Y:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=Y21VMNxYIeU:lPHzVBT0r5Y:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=Y21VMNxYIeU:lPHzVBT0r5Y:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=Y21VMNxYIeU:lPHzVBT0r5Y:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=Y21VMNxYIeU:lPHzVBT0r5Y:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=Y21VMNxYIeU:lPHzVBT0r5Y:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=Y21VMNxYIeU:lPHzVBT0r5Y:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">mikeconley</dc:creator><pubDate>Tue, 27 Apr 2010 18:03:05 -0700</pubDate><guid>http://mikeconley.ca/blog/2010/04/27/ping/</guid></item><item><title>Review Board 1.0 Released!
</title><link>http://www.chipx86.com/blog/2009/06/20/review-board-10-released/</link><description>&lt;p&gt;&lt;a href="http://www.review-board.org/"&gt;&lt;img alt="Review Board 1.0" class="alignleft size-full wp-image-319" height="123" src="http://www.chipx86.com/blog/wp-content/uploads/2009/06/rb10.png" title="Review Board 1.0" width="130" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Tonight, we hit a milestone in the &lt;a href="http://www.review-board.org/"&gt;Review Board&lt;/a&gt; project that we&amp;#8217;ve been working toward for over two years. We finally pushed out our 1.0 release. A lot of blood, sweat and tears went into this release (okay, so not literally, but it was A LOT OF WORK!). The last few months in particular have been challenging, as we&amp;#8217;ve had to solve some tricky bugs and scalability problems, but the end result is pretty great.&lt;/p&gt;
&lt;p&gt;Just a short while ago, we &lt;a href="http://www.review-board.org/news/2009/06/20/review-board-10-released/"&gt;announced&lt;/a&gt; the release and put up an &lt;a href="http://www.review-board.org/docs/releasenotes/dev/reviewboard/1.0/"&gt;overview&lt;/a&gt; of the entire release and product. We&amp;#8217;ve already had some nice congratulatory e-mails and tweets, which is really nice :)&lt;/p&gt;
&lt;p&gt;Some stats for this release:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2 years, 9 months, 25 days have passed since our first commit.&lt;/li&gt;
&lt;li&gt;120 contributors have contributed to Review Board so far (in terms of code contributions).&lt;/li&gt;
&lt;li&gt;2,019 commits were made.&lt;/li&gt;
&lt;li&gt;899 review requests have been posted to our project&amp;#8217;s actual &lt;a href="http://reviews.review-board.org/"&gt;Review Board server&lt;/a&gt;. 1,650 users are registered on there.&lt;/li&gt;
&lt;li&gt;Our &lt;a href="http://demo.review-board.org/"&gt;demo server&lt;/a&gt;, in comparison, has 2,082 review requests filed and 10,154 users.&lt;/li&gt;
&lt;li&gt;938 bugs were filed. 812 were fixed.&lt;/li&gt;
&lt;li&gt;232 feature requests were filed. 101 were implemented. Most remaining ones are scheduled for releases.&lt;/li&gt;
&lt;li&gt;An estimated 200+ companies are now using Review Board. 26 have let us &lt;a href="http://www.review-board.org/users/"&gt;list them publicly&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The largest known Review Board install has over 83,000 filed review requests and over 2,000 users, doing upwards of 10GB of traffic per day.&lt;/li&gt;
&lt;li&gt;5 presentations on Review Board are known to have been given, 3 by us, 2 by others.&lt;/li&gt;
&lt;li&gt;552 users have joined our main mailing list, and 3,674 e-mails have been sent.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that Review Board 1.0 is out, we can get started on some awesome new features we&amp;#8217;ve had planned. I have a little notebook full of ideas for our 1.1 and 1.5 releases (which may become 1.5 and 2.0, respectively, as this list grows). Some of the new features are actually ready to be committed within the next couple of days, so those of you using nightlies will start to see them soon.&lt;/p&gt;
&lt;p&gt;We were accepted into this year&amp;#8217;s &lt;a href="http://review-board.org/summer-of-code/"&gt;Summer of Code&lt;/a&gt;, and have three students working on exciting projects for us, so hopefully we&amp;#8217;ll start to see these trickle into the upcoming nightlies as well. Among these projects include diff viewer improvements (moved region detection, better whitespace-only change detection), IDE integration with Eclipse, and improved notification hooks and e-mail support.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;re also working on providing support for third-party extensions, which will allow developers to extend Review Board in new, exciting ways without having to modify Review Board itself. This is especially handy for companies who wish to integrate better with their sandboxes, bug trackers or unit testing services. This will likely land in 1.5 (2.0?) at the earliest, as it&amp;#8217;s a large change, but the code for this mostly works today. It&amp;#8217;s just a matter of getting the codebase ready and figuring out what APIs we want to stabilize and expose.&lt;/p&gt;
&lt;p&gt;As I mentioned in the &lt;a href="http://www.review-board.org/news/2009/06/20/review-board-10-released/"&gt;release announcement&lt;/a&gt;, we&amp;#8217;re planning a release party, tentatively on July 11th, 2009, in the Bay Area (somewhere around Palo Alto, CA). If any Review Board users want to join us, please &lt;a href="http://tinyurl.com/rb1-release-party"&gt;RSVP!&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=vySeBU86Ujg:uJHUZuLTCYc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=vySeBU86Ujg:uJHUZuLTCYc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=vySeBU86Ujg:uJHUZuLTCYc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=vySeBU86Ujg:uJHUZuLTCYc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=vySeBU86Ujg:uJHUZuLTCYc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=vySeBU86Ujg:uJHUZuLTCYc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=vySeBU86Ujg:uJHUZuLTCYc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><author>chipx86@chipx86.com (chipx86)</author><pubDate>Sun, 21 Jun 2009 07:47:36 -0700</pubDate><guid>http://www.chipx86.com/blog/2009/06/20/review-board-10-released/</guid></item><item><title>Review Board: Summer of Code, Roadmap and Future Plans
</title><link>http://www.chipx86.com/blog/2009/04/02/review-board-summer-of-code-roadmap-and-future-plans/</link><description>&lt;p&gt;&lt;b&gt;Summer of Code&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;This year, we (the &lt;a href="http://www.review-board.org/"&gt;Review Board&lt;/a&gt; project) was given the opportunity to participate in Google&amp;#8217;s Summer of Code. We&amp;#8217;ve received some great student proposals so far, and I think we&amp;#8217;ll see exciting work done on Review Board this summer.&lt;/p&gt;
&lt;p&gt;The deadline for Summer of Code is coming up fast (April 3rd, 19:00 UTC). If you&amp;#8217;re interested in working on Review Board and haven&amp;#8217;t yet applied, it&amp;#8217;s not too late, but you&amp;#8217;ll want to hurry. Skim through our &lt;a href="http://www.review-board.org/wiki/Summer_of_Code_Ideas"&gt;ideas&lt;/a&gt; page and, if you find something interesting or have a great idea not listed here, then &lt;a href="http://socghop.appspot.com/"&gt;apply&lt;/a&gt; and tell us your plans. I can say we&amp;#8217;ve received several proposals so far for the installer and admin UI, so unless you feel strongly about either of those, you&amp;#8217;ll increase your chances with other proposals.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;re also offering &lt;a href="http://www.review-board.org/summer-of-code/hosting/"&gt;free Review Board hosting&lt;/a&gt; for open source projects participating in Summer of Code. If you&amp;#8217;re a mentoring organization and would like to give Review Board a try for reviewing and managing student code, go ahead and contact us and we&amp;#8217;ll get you set up.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Roadmap&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;We&amp;#8217;re finally nearing 1.0. We recently put out our 1.0 beta 2 release and are now in a feature freeze. We&amp;#8217;re working to get some bug, performance and usability fixes in for beta 3, which I&amp;#8217;m shooting for in a few weeks. Then we&amp;#8217;ll branch for 1.0, put out a Release Candidate or two, and then finally release 1.0!&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s a lot of really cool features planned after 1.0, namely &lt;b&gt;extensions&lt;/b&gt; and &lt;b&gt;policy customization&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Extensions&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Our bug tracker is filled with feature requests for all kinds of things, ranging from bug tracker integration, instant messaging, a method for offering bribes for code reviews, and so on. We clearly can&amp;#8217;t put all the requested features in the codebase, so we&amp;#8217;ve decided instead to add support for third-party extensions. Coming soon, developers will be able to write extensions to Review Board in the form of Python modules to extend or alter the functionality of Review Board. The extension framework will allow them to do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Access the database using the existing Review Board database models.&lt;/li&gt;
&lt;li&gt;Add new database models for storing data.&lt;/li&gt;
&lt;li&gt;Listen for signals (new review request published, review request submitted, etc.) and act on them.&lt;/li&gt;
&lt;li&gt;Add custom URLs.&lt;/li&gt;
&lt;li&gt;Replace existing URLs, for advanced capabilities such as replacing the diff viewer.&lt;/li&gt;
&lt;li&gt;Add new API handlers.&lt;/li&gt;
&lt;li&gt;Add &amp;#8220;action&amp;#8221; links to existing review requests and reviews.&lt;/li&gt;
&lt;li&gt;Add columns and sidebar entries to the dashboard.&lt;/li&gt;
&lt;li&gt;Add pages to the administration UI.&lt;/li&gt;
&lt;li&gt;Communicate with other extensions.&lt;/li&gt;
&lt;li&gt;Provide a settings page, which stores data in Review Board-provided models (we even auto-generate the settings page for the extension by default).&lt;/li&gt;
&lt;li&gt;And more!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A lot of this already exists in a private development branch, and it will be one of our primary focuses as soon as 1.0 goes out.&lt;/p&gt;
&lt;p&gt;In time, we&amp;#8217;ll add a new section to the Review Board website where developers can list their extensions for download and for sale. Administrators will be able to browse and search for extensions directly from the administration UI and install them without having to even open a terminal (in most cases).&lt;/p&gt;
&lt;p&gt;We&amp;#8217;re hoping this will solve a lot of in-house integration issues. For example, many companies have custom sandbox architectures, bug trackers, and statistics software which they&amp;#8217;ll now be able to tie in with Review Board.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Policy Customization&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ve found that a lot of companies have very specific ways they want to handle policy and access restrictions. For example, many companies want to limit who can see certain parts of a repository (and therefore certain diffs), or want to allow anybody to create review groups, or want to disallow people from joining review groups. Some also want to dictate what constitutes approval for submitting a change.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;re looking into the various requests and attempting to come up with a policy model that is flexible enough to handle these needs. One of the ideas is to provide some basic level of access control on a per-repository, per-path, and per-group basis. We&amp;#8217;d then piggy-back on the extension framework to allow for more specific policy control. The advantage is that developers could write their own policy rules that interface with some part of their company&amp;#8217;s infrastructure.&lt;/p&gt;
&lt;p&gt;If people have any input on this, we&amp;#8217;d love to hear it.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=QRspFP8F_60:KQd3NmatfKY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=QRspFP8F_60:KQd3NmatfKY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=QRspFP8F_60:KQd3NmatfKY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=QRspFP8F_60:KQd3NmatfKY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=QRspFP8F_60:KQd3NmatfKY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=QRspFP8F_60:KQd3NmatfKY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=QRspFP8F_60:KQd3NmatfKY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><author>chipx86@chipx86.com (chipx86)</author><pubDate>Thu, 02 Apr 2009 21:53:39 -0700</pubDate><guid>http://www.chipx86.com/blog/2009/04/02/review-board-summer-of-code-roadmap-and-future-plans/</guid></item><item><title>Improving browser performance in Review Board
</title><link>http://www.chipx86.com/blog/2009/01/27/improving-browser-performance-in-review-board/</link><description>&lt;p&gt;This past Sunday, I landed a set of changes into &lt;a href="http://www.review-board.org/"&gt;Review Board&lt;/a&gt; that provide improved performance, such as aggressive browser-side caching of media and pages. It&amp;#8217;s just a start, but has already significantly reduced page load times in all of my tests, in some case by several seconds. We implemented these methods for Review Board, but they&amp;#8217;re methods that can be applied to any &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt; project out there.&lt;/p&gt;
&lt;p&gt;There are several key things that Review Board now does to improve performance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tells browsers to cache all media for one year.&lt;/li&gt;
&lt;li&gt;Only sends page data if new data is available.&lt;/li&gt;
&lt;li&gt;Compresses all media files to reduce transfer time.&lt;/li&gt;
&lt;li&gt;Parallelizes media downloads.&lt;/li&gt;
&lt;li&gt;Loads CSS files as early as possible.&lt;/li&gt;
&lt;li&gt;Loads JavaScript files as late as possible.&lt;/li&gt;
&lt;li&gt;Progressively loads expensive data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A lot of the performance improvements come straight from Yahoo!&amp;#8217;s &lt;a href="http://developer.yahoo.com/performance/rules.html"&gt;Best Practices for Speeding Up Your Site&lt;/a&gt;. We&amp;#8217;re not doing everything there &lt;i&gt;yet&lt;/i&gt;, but we&amp;#8217;re working toward it. That&amp;#8217;s a great resource, by the way, and I recommend that everyone who has even made a website before go and read it.&lt;/p&gt;
&lt;p&gt;So what do the above techniques buy us, and how are we doing them? Let me go into more details&amp;#8230;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Caching all media for a year&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;The average site has one or more CSS files, JavaScript files, and several images. This translates to a lot of requests to the server, which may leave the site feeling slow. On top of this, a browser only makes a few requests to a server at a time, in order to avoid swamping the server, which will further hinder load times. This happens every time a user visits a page on your site.&lt;/p&gt;
&lt;p&gt;Aggressive caching makes a huge difference and can greatly reduce load times for users. Review Board now tells the browser to cache media files for a year. Once a user downloads a JavaScript or CSS file, they won&amp;#8217;t have to download it again, meaning that in general the only requests the browser needs to make is for the page requests and AJAX requests.&lt;/p&gt;
&lt;p&gt;The big pitfall with long-term caching is that the cached resources can go stale. For example, if a new version of an image was uploaded, the browser wouldn&amp;#8217;t even know about it, since it was told it should keep its old version for a year before checking again.&lt;/p&gt;
&lt;p&gt;We solve this by introducing &amp;#8220;media serials,&amp;#8221; timestamps that are appended to all media paths. Instead of caching &lt;tt&gt;/js/myscript.js&lt;/tt&gt;, the browser would cache &lt;tt&gt;/js/myscript.js?1273618736&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;These media serials are computed on the first page request by our &lt;tt&gt;djblets.util.context_processors.ajaxSerial&lt;/tt&gt; context processor. This quickly scans all media files known to the program, finding out the latest modification timestamp. It then provides a &lt;tt&gt;{{MEDIA_SERIAL}}&lt;/tt&gt; variable for templates to append to media URLs as part of the query string.&lt;/p&gt;
&lt;p&gt;The benefit to this method is that we can cache media files for a year and not worry about users having stale cached resources the next time we upgrade a copy of Review Board. The filenames requested will be different, browsers will see that the new file is not in the cache, and make a request, caching the new file for a year.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Only send page data if new data is available&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Aggressive caching of media files is great and saves a lot of time, but it doesn&amp;#8217;t help for dynamically generated content. For this, we need a new strategy.&lt;/p&gt;
&lt;p&gt;When a browser makes a request, it can send a &lt;tt&gt;If-Modified-Since&lt;/tt&gt; header to the server containing the &lt;tt&gt;Last-Modified&lt;/tt&gt; value it received the last time it downloaded that page. This is a very valuable header, and there&amp;#8217;s some things we can do with it to save both the server and the browser a lot of trouble.&lt;/p&gt;
&lt;p&gt;If the browser sends &lt;tt&gt;If-Modified-Since&lt;/tt&gt;, and we know that no new data has been generated since the timestamp provided, we can send an &lt;tt&gt;HttpResponseNotModified&lt;/tt&gt; (HTTP response code 304). This will tell the browser it already has the newest version of the page. The sooner we do this, the better, as it means we don&amp;#8217;t have to waste time building templates or doing any expensive database queries.&lt;/p&gt;
&lt;p&gt;Djblets, once again, provides some functions to help out here: &lt;tt&gt;djblets.util.http.set_last_modified&lt;/tt&gt; and &lt;tt&gt;djblets.util.http.get_modified_since&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;The general usage pattern is that we first build a timestamp representing the latest version of the page. This could be the timestamp for a particular object that the page represents. We then check if we can bail early by calling:&lt;/p&gt;

&lt;div class="wp_syntax"&gt;&lt;div class="code"&gt;&lt;pre class="python python" style="font-family: monospace;"&gt;&lt;span style="color: #ff7700; font-weight: bold;"&gt;if&lt;/span&gt; get_modified_since&lt;span style="color: black;"&gt;&amp;#40;&lt;/span&gt;request, timestamp&lt;span style="color: black;"&gt;&amp;#41;&lt;/span&gt;:
    &lt;span style="color: #ff7700; font-weight: bold;"&gt;return&lt;/span&gt; HttpResponseNotModified&lt;span style="color: black;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: black;"&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Further down, after building the page, we must set the &lt;tt&gt;Last-Modified&lt;/tt&gt; timestamp, using the same timestamp as above, like so:&lt;/p&gt;

&lt;div class="wp_syntax"&gt;&lt;div class="code"&gt;&lt;pre class="python python" style="font-family: monospace;"&gt;set_last_modified&lt;span style="color: black;"&gt;&amp;#40;&lt;/span&gt;response, timestamp&lt;span style="color: black;"&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We&amp;#8217;re using this in only a few places right now, such as the review request details page, but it drastically improves load times. If the review request hasn&amp;#8217;t changed and nobody&amp;#8217;s commented on it since the browser last loaded the page, a reload of the page will be almost instant.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Compress all media files&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Our Apache and lighttpd config files now enable compression by default. By compressing these files, we can turn a relatively large JavaScript file (such as the jquery and jquery-ui files) into a very small file before sending it over to the browser. This reduces transfer times at the expense of compression/decompression time (which is small enough to not worry for deployments of this size, and can be offset by caching of compressed files server-side).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Parallelize media downloads&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s important to not mix loads of media files of different types. The browser parallelizes media downloads of the same type, in page load order, but if you load one CSS file, one JavaScript file, another CSS file, and then another JavaScript file, the browser will only attempt one load at a time. If you load all the CSS files before all JavaScript files, it will parallelize the CSS file download and then the JavaScript downloads. By enforcing the separation of loads, we can achieve faster page download/render times.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Load CSS files as soon as possible&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Loading CSS files before the browser starts to display the page can make the page appear to load smoother. The browser will already know &lt;i&gt;how&lt;/i&gt; things should look and will lay the page out accordingly, instead of laying the page out once and then updating that once the CSS files have loaded.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Load JavaScript files as late as possible&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;JavaScript loads block the browser, as the browser must parse and interpet the JavaScript before it can continue. Sometimes it&amp;#8217;s necessary to load a JavaScript file early, but in many cases the files can be loaded late. When possible, we load JavaScript files at the very end of the document body so that they won&amp;#8217;t even begin downloading until the page has rendered. This provides noticeable performance for script-heavy pages.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Progressively load expensive data&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;There are types of data that are just too expensive to load along with the rest of the page. For a long time, Review Board would parse and render fragments of a diff for display in the review request page, but that meant that before the page could load, Review Board would need to do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Query the list of all comments.&lt;/li&gt;
&lt;li&gt;Fetch every file commented on.&lt;/li&gt;
&lt;li&gt;Apply the stored patch to each file.&lt;/li&gt;
&lt;li&gt;Diff between the original and patched files.&lt;/li&gt;
&lt;li&gt;Render the portion of the diff commented on into the page.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This became very time-consuming, and if a server was down, the page wasn&amp;#8217;t available until everything timed out. The solution to this was to lazily load each of these diff fragments in order.&lt;/p&gt;
&lt;p&gt;We now display a placeholder table for each diff fragment in roughly the same size of the rendered fragment (to avoid excessive page scrolling on loads). The table contains a spinner showing that something is happening, and, one-by-one (to avoid dogpiling) we load each diff fragment.&lt;/p&gt;
&lt;p&gt;The code to render the diff fragment, by the way, takes advantage of the &lt;tt&gt;If-Modified-Since&lt;/tt&gt; header and is also cached for a year. We use an &lt;tt&gt;AJAX_SERIAL&lt;/tt&gt; (same principal as the &lt;tt&gt;MEDIA_SERIAL&lt;/tt&gt; above) to allow for changes in new deployments.&lt;/p&gt;
&lt;p&gt;With these caching mechanisms in place, the review request page now loads in roughly a second in many cases (or less once cached), with diff fragments coming in lazily (and then almost immediately on future loads).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;More to come&amp;#8230;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;This was a great first step, but there&amp;#8217;s more we can do. Before we hit our 1.0 release, we&amp;#8217;re going to batch together all our CSS files and JavaScript files into a couple of combined files and then &amp;#8220;minify&amp;#8221; them (basically compressing them in such a way to allow for smaller files and faster load times of the interpreted data).&lt;/p&gt;
&lt;p&gt;Again, these are techniques we&amp;#8217;re now making use of in Review Board, but they&amp;#8217;re not in any way specific to Review Board. Anyone out there developing websites or web applications should seriously look into ways to improve performance. I hope this was a good starting point, but seriously, do read Yahoo!&amp;#8217;s article as well.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/ReviewBoard?a=jXQMBtcQ"&gt;&lt;img src="http://feeds.feedburner.com/~f/ReviewBoard?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ReviewBoard?a=qP6AaYra"&gt;&lt;img src="http://feeds.feedburner.com/~f/ReviewBoard?i=qP6AaYra" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ReviewBoard?a=XM9Q8Wck"&gt;&lt;img src="http://feeds.feedburner.com/~f/ReviewBoard?i=XM9Q8Wck" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ReviewBoard?a=cuPnkDWl"&gt;&lt;img src="http://feeds.feedburner.com/~f/ReviewBoard?i=cuPnkDWl" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><author>chipx86@chipx86.com (chipx86)</author><pubDate>Tue, 27 Jan 2009 12:14:29 -0700</pubDate><guid>http://www.chipx86.com/blog/2009/01/27/improving-browser-performance-in-review-board/</guid></item><item><title>Infect your application with Parasite!
</title><link>http://feedproxy.google.com/%7Er/chipx86/chiplog/%7E3/E2ntREFWw8k/</link><description>&lt;p&gt;&lt;img alt="Parasite" class="alignright size-full wp-image-294" height="137" src="http://www.chipx86.com/blog/wp-content/uploads/2009/01/parasite.png" title="Parasite" width="131" /&gt;&lt;/p&gt;
&lt;p&gt;Ever find yourself stuck debugging an application because the UI is just doing something weird that you can&amp;#8217;t track down? Maybe a widget isn&amp;#8217;t appearing correctly, or you just need more information about the overall structure and logging statements aren&amp;#8217;t doing you much good. Debugging complex UIs can be a pain.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ve had some real challenges at &lt;a href="http://www.vmware.com/"&gt;VMware&lt;/a&gt;, due to the complexity of our applications. It was enough to drive me mad one day, so rather than write more logging statements, I wrote &lt;a href="http://chipx86.github.com/gtkparasite"&gt;Parasite&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Parasite is a debugging tool that David Trowbridge and I have been working on to give developers an interactive view of their entire application&amp;#8217;s UI. It provides a number of really useful features, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;See the entire widget hierarchy of your UI.&lt;/li&gt;
&lt;li&gt;Watch properties update live.&lt;/li&gt;
&lt;li&gt;Modify existing properties on a widget.&lt;/li&gt;
&lt;li&gt;View all registered GtkActions.&lt;/li&gt;
&lt;li&gt;Toggle GTK+&amp;#8217;s debugging of graphic updates.&lt;/li&gt;
&lt;li&gt;Inject custom code while the application is running.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Yes, you can inject new code into an application. With Python. Parasite runs in-process as a GTK+ module, so it has access to some internals of your application. We provide a Python shell equipped with PyGTK support for creating and modifying your UI on-the-fly, regardless of the language it was written in. Handy when you want to test out new concepts for a UI without writing new C code.&lt;/p&gt;
&lt;p&gt;David has a nice &lt;a href="http://chipx86.github.com/gtkparasite/video/parasite-intro.avi"&gt;screencast&lt;/a&gt; available showing some of what Parasite can do.&lt;/p&gt;
&lt;p&gt;For more information on Parasite, including screenshots, a mailing list, and where to get the source code, see the &lt;a href="http://chipx86.github.com/gtkparasite"&gt;Parasite homepage&lt;/a&gt;.&lt;/p&gt;
&lt;img height="1" src="http://feeds2.feedburner.com/~r/chipx86/chiplog/~4/E2ntREFWw8k" width="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=UlC5-cbhGpQ:ODyunSRcbFI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=UlC5-cbhGpQ:ODyunSRcbFI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=UlC5-cbhGpQ:ODyunSRcbFI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=UlC5-cbhGpQ:ODyunSRcbFI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=UlC5-cbhGpQ:ODyunSRcbFI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=UlC5-cbhGpQ:ODyunSRcbFI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=UlC5-cbhGpQ:ODyunSRcbFI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><author>chipx86@chipx86.com (chipx86)</author><pubDate>Tue, 20 Jan 2009 02:52:47 -0700</pubDate><guid>http://feedproxy.google.com/~r/chipx86/chiplog/~3/E2ntREFWw8k/</guid></item><item><title>Review Board 1.0 alpha 1 released
</title><link>http://www.chipx86.com/blog/2009/01/19/review-board-10-alpha-1-released/</link><description>&lt;p&gt;Roughly two years ago, David Trowbridge and I began development of &lt;a href="http://www.review-board.org/"&gt;Review Board&lt;/a&gt; for use in our open source projects and our team at &lt;a href="http://www.vmware.com/"&gt;VMware&lt;/a&gt;. During that time, we&amp;#8217;ve turned Review Board into a powerful code review tool that works with a variety of version control systems. Most of VMware has moved over to it, as have an estimated 50-100 companies world-wide. We&amp;#8217;ve had over 100 contributors to the project, people providing volunteer support on the mailing list, and people have developed third party tools for integrating with Review Board.&lt;/p&gt;
&lt;p&gt;After all this time in development, with this many people contributing, we decided it&amp;#8217;s probably time to get a release out there. Sure, we could have done this a long time ago, but there&amp;#8217;s a number of large things we were hoping to get in (a recently-committed UI rewrite, for instance). Now that we have most of the major features we want for our 1.0 release, we decided it was time for an alpha.&lt;/p&gt;
&lt;p&gt;Over the coming months, we&amp;#8217;ll be working on stabilizing the codebase, fixing a few large remaining usability quirks, enhancing performance, and writing some proper documentation (which is coming along nicely).&lt;/p&gt;
&lt;p&gt;We&amp;#8217;re eager to get a quality product out there and to begin development on the next release. There&amp;#8217;s a lot of neat things planned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support for writing extensions to Review Board.&lt;/li&gt;
&lt;li&gt;A fully-featured API covering every operation you&amp;#8217;ll need to perform.&lt;/li&gt;
&lt;li&gt;Some degree of policy support (specifying which users/groups can see which parts of a repository, for instance).&lt;/li&gt;
&lt;li&gt;Reviews with statuses other than &amp;#8220;Ship It&amp;#8221;. This will probably be customizable to some degree.&lt;/li&gt;
&lt;li&gt;Possibly some theme customization to allow Review Board to blend in better with corporate sites, Trac installs, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Along with this, I plan to roll out a new website for the project that will have a browseable list of third party extensions, apps, Greasemonkey scripts, and more.&lt;/p&gt;
&lt;p&gt;We have more information on our release on our &lt;a href="http://www.review-board.org/news/2009/01/19/review-board-10-alpha-1-released/"&gt;release announcement&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/ReviewBoard?a=JIs796ro"&gt;&lt;img src="http://feeds.feedburner.com/~f/ReviewBoard?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ReviewBoard?a=UB5Sl4wk"&gt;&lt;img src="http://feeds.feedburner.com/~f/ReviewBoard?i=UB5Sl4wk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ReviewBoard?a=QZWaOFbk"&gt;&lt;img src="http://feeds.feedburner.com/~f/ReviewBoard?i=QZWaOFbk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ReviewBoard?a=HqRNYLFS"&gt;&lt;img src="http://feeds.feedburner.com/~f/ReviewBoard?i=HqRNYLFS" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><author>chipx86@chipx86.com (chipx86)</author><pubDate>Mon, 19 Jan 2009 23:20:13 -0700</pubDate><guid>http://www.chipx86.com/blog/2009/01/19/review-board-10-alpha-1-released/</guid></item><item><title>Armed robbery in progress
</title><link>http://feedproxy.google.com/%7Er/chipx86/chiplog/%7E3/EhLFIEPn0qI/</link><description>&lt;p&gt;Our Christmas this year was very nice, with lots of good presents, time spent with family, delicious food, and an opportunity to foil an armed robbery. Yes, an armed robbery. How do I continually get myself into these situations?&lt;/p&gt;
&lt;p&gt;While heading back home from my stepdad&amp;#8217;s parents&amp;#8217; house, I spotted a guy standing in a small field at a street corner near my parents&amp;#8217; house, holding what looked to be a gun. The guy was probably late teens/early adult, Caucasian, and dressed in all black. His actions looked instantly suspicious. He was pointing the gun to the ground and made some motion as if he was checking the ammo or something. He seemed pretty lost in his own world, apparently not even realizing he seemed very suspicious.&lt;/p&gt;
&lt;p&gt;My Mom was driving, and decided to slowly drive away from home instead of toward it, and then turn around, giving us time to watch and see what was happening. We knew there was a gas station across the street and wanted to see if he was going to head in there. If so, there was a good chance we&amp;#8217;d be witnessing a robbery.&lt;/p&gt;
&lt;p&gt;Sure enough, he started walking across the street to the TowerMart, a gas station/convenience store. We parked the car and my Mom grabbed my phone and called 911 while my brothers and I carefully watched from behind a building, making sure we weren&amp;#8217;t noticed. We saw the guy walking back and forth at the side of the building, looking &lt;i&gt;very&lt;/i&gt; nervous. He was wearing long sleeves with his left hand exposed and his right hand (which was holding the gun) completely covered. As my Mom talked to the police, we continued to watch, and the guy eventually psyched himself into going into the store. He put the gun in his pocket and went in.&lt;/p&gt;
&lt;p&gt;The store was pretty crowded, and we weren&amp;#8217;t sure what to expect. Would people be running out screaming? Would people be locked in? Would we hear gun fire? Or would he just leave?&lt;/p&gt;
&lt;p&gt;We never saw him actually leave, but we could only see the one side of the building. A couple minutes later, six police cars drove up, two right beside us. Two cop cars pulled up alongside us. One of them hopped out, grabbed a big ol&amp;#8217; semi-automatic, and approached the building, pointing the gun, ready to fire. Three other cops did the same, surrounding the building. A couple other cops went in and got people out of there, with another couple cops asking those people if they had seen anyone matching the description we gave, or saw other suspicious activity.&lt;/p&gt;
&lt;p&gt;They spent some time going through the TowerMart and eventually came back out once they were sure he wasn&amp;#8217;t hiding in there. It seems at some point, he had left the building. We weren&amp;#8217;t able to see when. However, he was definitely in there. Practically everyone they talked to noticed him, as he was nervously walking in circles around the building, completely covered. He had either grown nervous with the number of people in there, or heard the sirens come. Either way, he got out of there before doing anything.&lt;/p&gt;
&lt;p&gt;As most of the cops started to exit the building, the one who had pulled up closest to us walked up and asked what we saw. Then he said, &amp;#8220;Oh, I talked to you before.&amp;#8221; We all thought that was strange, since he hadn&amp;#8217;t actually talked to us, but then he pointed out that he remembered us from &lt;a href="http://www.chipx86.com/blog/?p=257"&gt;the assault&lt;/a&gt; back in May. Good memory.&lt;/p&gt;
&lt;p&gt;We walked with him to the field and pointed out roughly where we saw him standing. He found the footprints and was calling out the detectives to take pictures or whatever. We chit-chatted briefly before returning home. He told us we very well may have saved the store and a lot of people from experiencing a robbery on Christmas Day. I just hope the guy didn&amp;#8217;t make another attempt elsewhere.&lt;/p&gt;
&lt;p&gt;We found out that an hour or two later, the police were still all over that place. About an hour ago, they apparently had arrested someone not too far from here. Whether related or not, I don&amp;#8217;t know. Given that they had video footage of the guy, testimonies and descriptions from a bunch of people in the store, and his footprints, it&amp;#8217;s probably only a matter of time.&lt;/p&gt;
&lt;p&gt;The rest of Christmas proceeded without police intervention. Merry Christmas!&lt;/p&gt;
&lt;img height="1" src="http://feeds2.feedburner.com/~r/chipx86/chiplog/~4/EhLFIEPn0qI" width="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=xPwgkZxjcYM:AcpNBEwpNfE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=xPwgkZxjcYM:AcpNBEwpNfE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=xPwgkZxjcYM:AcpNBEwpNfE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=xPwgkZxjcYM:AcpNBEwpNfE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=xPwgkZxjcYM:AcpNBEwpNfE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=xPwgkZxjcYM:AcpNBEwpNfE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=xPwgkZxjcYM:AcpNBEwpNfE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><author>chipx86@chipx86.com (chipx86)</author><pubDate>Fri, 26 Dec 2008 06:04:46 -0700</pubDate><guid>http://feedproxy.google.com/~r/chipx86/chiplog/~3/EhLFIEPn0qI/</guid></item><item><title>Ubuntu and Desktop Notifications
</title><link>http://feedproxy.google.com/%7Er/chipx86/chiplog/%7E3/bijFJKrT-cs/</link><description>&lt;p&gt;This past Monday, Mark Shuttleworth &lt;a href="http://www.markshuttleworth.com/archives/253"&gt;wrote about&lt;/a&gt; their plans for an overhaul of desktop notifications (the little popup bubbles telling you someone IM&amp;#8217;d you or there&amp;#8217;s updates available). Many people have asked me about this, some concerned, and wanted to know what I thought. Being the maintainer of libnotify, notification-daemon and the &lt;a href="http://www.galago-project.org/specs/notification/"&gt;Desktop Notifications specification&lt;/a&gt;, some people were concerned that this work would supersede my own.&lt;/p&gt;
&lt;p&gt;The reality is, this isn&amp;#8217;t a replacement of my project. This is a new joint effort between Ubuntu, KDE, and myself. What&amp;#8217;s been written in Mark&amp;#8217;s post may not end up being the end result. We&amp;#8217;re still deciding how this will progress, and Ubuntu wants to experiment a bit. &lt;a href="http://aseigo.blogspot.com/2008/12/notifications.html"&gt;Aaron Seigo&amp;#8217;s post&lt;/a&gt; on the subject sums up a lot of my thoughts on this, and I recommend reading it, though I&amp;#8217;ll go further and discuss where this all started and how it&amp;#8217;ll affect the project.&lt;/p&gt;
&lt;p&gt;First of all, libnotify/notification-daemon isn&amp;#8217;t going anywhere. It&amp;#8217;s not being replaced, nor is an alternate spec being drafted. Ubuntu&amp;#8217;s User Experience team has some new things they want to try, and that&amp;#8217;s fine. The plan is to see how this stuff goes in their codebase, with the intention of migrating code back upstream.&lt;/p&gt;
&lt;p&gt;A couple of weeks ago, during the Ubuntu Summit, I was invited to speak with some of the developers and User Experience guys from Ubuntu about their plans. They showed me the mockup that&amp;#8217;s on Mark&amp;#8217;s blog and told me about their plans. They have things they want to do that could definitely improve the experience. Some things are pretty controversial, such as the removal of actions on notifications. We sat down, discussed and debated various aspects of the proposals for a while, and I believe reached a general course of action for the project. The highlights include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Actions will be removed for applications packaged in Ubuntu. The developers will try to replace them with something that they feel makes more sense, with the hope of pushing these changes upstream.&lt;/li&gt;
&lt;li&gt;The released notification-daemon will, I believe, support actions, since many non-packaged applications do use them. They will, however, appear as old-style notifications and not appear in the new window stack demoed in Mark&amp;#8217;s blog post.&lt;/li&gt;
&lt;li&gt;We&amp;#8217;ll be drafting new additions to the notification spec in order to address the needs of KDE and Mozilla.&lt;/li&gt;
&lt;li&gt;The work will be done by their developers in either a fork or a whole new notification-daemon implementation, allowing them a greater ability to experiment. These changes (or parts of them) will make their way upstream. It will be spec-compatible so users won&amp;#8217;t have to worry too much about losing features (aside from actions, perhaps).&lt;/li&gt;
&lt;li&gt;In the end, it&amp;#8217;ll likely be that the Ubuntu theme specifically works this new way, and that other themes will work differently (they may support actions more directly, for example).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now I should point out that I don&amp;#8217;t believe actions are a bad thing. There&amp;#8217;s many use cases where actions are very much warranted, and it seems Aaron agrees. While the Ubuntu team has discussed the possibility of deprecating this in the spec, I believe the end result will be that actions will live on. I&amp;#8217;m also pretty adamant that upstream notification-daemon will still support actions and some other features. Ubuntu can choose what experience to give their packaged applications, but that may differ a bit from what we decide upstream.&lt;/p&gt;
&lt;p&gt;Time will tell how this all turns out. I personally think it&amp;#8217;s great that there&amp;#8217;s some momentum on this project. I know I haven&amp;#8217;t had much time to work on it as of late, between &lt;a href="http://www.vmware.com/"&gt;VMware&lt;/a&gt; and &lt;a href="http://www.review-board.org/"&gt;Review Board&lt;/a&gt;, which is why getting some new people on board with fresh thoughts will probably be a good thing.&lt;/p&gt;
&lt;p&gt;On a related note, I&amp;#8217;d like to welcome Andrew Walton to the project. He&amp;#8217;s going to be working as a co-maintainer and helping out when I&amp;#8217;m busy (which will be a lot of the time for a while).&lt;/p&gt;
&lt;p&gt;Over the next month or two, the project should start to pick up. We&amp;#8217;re beginning to look at ways to improve the spec and at what work needs to be done in the near future for the project. These discussions will take place on &lt;a href="http://lists.freedesktop.org/mailman/listinfo/xdg"&gt;xdg-list&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And with that, I wish everyone a Merry Christmas (or just a very good December 25th for those who don&amp;#8217;t celebrate Christmas)!&lt;/p&gt;
&lt;img height="1" src="http://feeds2.feedburner.com/~r/chipx86/chiplog/~4/bijFJKrT-cs" width="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=6bTp7yHB9RM:t_MvAwQZWSg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=6bTp7yHB9RM:t_MvAwQZWSg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=6bTp7yHB9RM:t_MvAwQZWSg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=6bTp7yHB9RM:t_MvAwQZWSg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=6bTp7yHB9RM:t_MvAwQZWSg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ReviewBoard?a=6bTp7yHB9RM:t_MvAwQZWSg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ReviewBoard?i=6bTp7yHB9RM:t_MvAwQZWSg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description><author>chipx86@chipx86.com (chipx86)</author><pubDate>Thu, 25 Dec 2008 07:09:12 -0700</pubDate><guid>http://feedproxy.google.com/~r/chipx86/chiplog/~3/bijFJKrT-cs/</guid></item></channel></rss>
