Year in Review

  1. The end of 2008 marks the end of my first year as Digg’s Lead Architect. In that time we’ve rewritten the majority of the site using frameworks that I built. We’re currently rewriting the underlying data access layer to be horizontally partitioned, elastic, services oriented and multi-homed.
  2. In early January, Digg Images launched and, with it, the result of months of work resulting in a completely rewritten submission framework for Digg. This project resulted in me writing and releasing Net_Gearman. I consider this project to be some of my best work at Digg.
  3. In early January I snuck off to Vail for one last snowboarding trip before back surgery. It was on this trip that I finally became comfortable with Western black diamonds, including an awkward drop off of an 8+ foot precipice into 3+ feet of fluffy powder.
  4. On January 23rd, 2008 I went in for back surgery. Two hours after surgery I was up and walking around without a hint of sciatica or back pain. I can’t thank Dr. Fred Naraghi enough for what I view as a second chance at life.
  5. 2008 will be known as the Year of the Conferences for me. I spoke at Future of Web Apps in Miamion a panel at SXSW on scaling websitesMySQL Conference on Services Oriented Architecture, Web 2.0 Expo in New York City, Future of Web Apps in London with Blaine Cook, Future of Web Design on the friction between developers and designers, and Q-Con in San Francisco on Digg’s architecture.
  6. The summer brought another bout of triathlon training. Along with my friend Mark Lewandowski, I trained for my first Olympic distance triathlon, which I ended up finishing in 2 hours, 50 minutes and change. As part of our training Mark and I also did a 72 mile bike race around Lake Tahoe. The race included 3,900 feet of vertical gain over 72 miles and is, without a doubt, the most challenging endurance race of my life. I finished the race in 4 hours, 15 minutes and change.
  7. In June I was elected to the PEAR Group, which is the governing board of my favorite PHP project.
  8. In early September I launched PleaseDressMe with my friends AJ and Gary Vaynerchuk. The site continues to gain traction in the tshirt arena and is, to date, my most successful side project.
  9. In October Aubrey, Kevin and I went on a whirlwind tour of Europe that included Oktoberfest in Munich, London, and Amsterdam.
  10. November brought big news at Digg with the hire of my friend and release manager for PHP6, Andrei Zmievski, as Digg’s first Open Source Fellow.
  11. November also brought about me finally diving into Python and Django for a side project. I’ve built an API for iPhone games that my friend Garren and I plan on releasing soon. More on this to come.
  12. December brought another trip to Thailand with my good friend Chris Lea. We’d originally planned to do Thailand, Cambodia and either Laos or Vietnam, however the islands of Koh Phangan and Koh Samui had other ideas. I type this sitting on Haad Lamai on Koh Samui. So far it’s been an epic trip with highlights including New Year’s Eve on Haad Rin Nok and a trip back to Haad Rin Nok tomorrow for another Full Moon Party.

This year I’m going to follow the year in cities theme that so many other blogs follow because I feel I really have done a ridiculous amount of travel this year.

  • San Francisco, CA
  • Miami, FL
  • Austin, TX
  • San Diego, CA
  • Seattle, WA
  • Vail, CO
  • East Jordan, MI
  • New York, NY
  • Munich, Germany
  • London, United Kingdom
  • Amsterdam, Netherlands
  • Los Angeles, CA
  • Bangkok, Thailand
  • Haad Leela, Koh Phangan, Thailand
  • Haad Lamai, Koh Samui, Thailand

I’m going to start a new theme here today. Below is my year in open source software. This is a list of projects I’ve released publicly and/or have contributed to. I’m not sure how many lines of code this is, but this is, by far, my most prolific year in FOSS contributions.

Framework 0.4.0

Thanks to Southwest delaying my 1.5 hour flight to Portland by 2 hours I’ve finally gotten time to package up the latest release of Framework. I jumped ahead to 0.4.0 from the 0.2.x series due to the fact that 0.4.0 isn’t really 100% backwards compatible and because I felt it was a major enough release to skip ahead a number. Lots of bug fixes, features, etc.

The biggest enhancements are that I switched to a pure exception model for error handling. I even went so far to switch the default PEAR_Error handler to throw Framework_Exception’s. Also, as asked by a ton of people I’ve created the ability to change your DB abstraction layers or not use one at all.

New iPhone version of Digg

Like many other interesting projects the Digg iPhone project started with a conversation over a few beers and a challenge: code it in 48 hours and Kevin would give me a free iPhone. Being the unabashed Apple fanboy I am and, also, being a self-respecting coder I set out to create Digg for the iPhone.  After spending a short time white boarding the application, Daniel mocked up the design and I set off to code it.

Technically speaking, it’s no revolutionary application and I didn’t spend the entire 48 hours working on the application. I did, of course, find time to go see Transformers (awesome) over the weekend. The JavaScript was borrowed from Joe Hewitt and adapted a bit using jQuery. The application iteself is based on our API using the Services_Digg PEAR package I maintain. I’ve been talking with the jQuery team about some limitation in the animations and plan on packaging up a more robust iPhone JavaScript library based on jQuery sometime in the near future (hopefully).

Yesterday Kevin announced the iPhone application and Daniel Burka, our designer at Digg, has covered the details about designing for the iPhone. So far the response to the application has been positive. It was fun and I’m glad everyone is enjoying it. I know I did while riding the bus to work today.

And to answer everyone’s questions. I got an 8GB version last night, the keyboard is interesting, it’s breathtakingly gorgeous and I’ll write YAiPR (Yet Another iPhone Review) soon.

Technical Background of Digg's new Comment System

UPDATE: As you might have noticed, we’re having some technical issues rolling out the new comments. Please bare with us as we work out the kinks.

UPDATE: We reworked a few things and the comments are now live again.

Today Digg launched it’s redesign of the comment system, which was programmed by yours truly. Daniel has written up a detailed overview of the design decisions so if you’re interested in the design aspects you’ll definitely want to check that out.

There were a few fairly complex technical changes to the comment systems, which I’ll outline and then go into a little detail about.

  • We’ve been talking about moving towards a services oriented architecture on and off since I started in February. Steve had coded the API and the decision was made that the new comments system would use Digg’s public API.
  • Comment threads would be loaded dynamically using AJAX and JSON.
  • All commenting, editing, etc. would happen via AJAX.

The API ended up making the PHP code behind the scenes relatively painless. Each page loads using two small calls; one to figure out how many comments are on a story and another to fetch the first 50 or so comments (we use a fuzzy limit so it’ll just load all of them if there’s, say, 55 comments on a story). Both our local proxy and the comments code use the Services_Digg package we released via PEAR when the API launched. In fact, the entire permalink page is built using the API now, which is pretty neat.

By far the most complex portion of the comments system was how dynamic it was going to be. Threads would be zipping in and out, we’d be creating 90% of the HTML dynamically in the DOM from JSON, posting and editing over AJAX, etc. It was during design that Micah and I also plotted to remove script.aculo.us and replace it with the smaller jQuery library. The entire comment system is, in fact, a series of jQuery plugins.

Probably the coolest, technically speaking, portion of the new comments is the manner in which most of the page is created. No longer do we create static HTML in PHP and send you a huge HTML page. Instead we give you the basics and, via AJAX/JSON, we make requests to the API and dynamically create the DOM using the FlyDOM jQuery plugin. The FlyDOM JSON templates are a stroke of genius if you’re looking at loading JSON dynamically into the DOM. The advantage of this is that initial page loads are much snappier and you can load the threads you wish to read on demand.

I really picked up the whole dynamically created DOM ball and ran with if. If you notice, on the initial page load there aren’t any forms anywhere in the DOM. Those, also, are created dynamically on request. An interesting side effect to this is that there’s about 4x as much JavaScript code on the new comments than there is PHP.

The major technical and design changes of comments should lead to faster load times, less bandwidth being eaten up and, hopefully, a better user experience. I hope you enjoy them and, as always, welcome comments and input.

As Kevin would say, “Digg on!”

Introducing correlate.us

As some of you know I’ve been working on a little side project and I’d like to officially announce that correlate.us is open for business. Whatever that means.

I’ve been kicking this idea around for quite some time. The basic idea is that you authenticate your various Web 2.0 accounts and then correlate.us goes out and aggregates that data, groups it by tags and makes it generally more browseable for everyone involved.

The best part about it is that you can add friends. Once you’ve added a few friends you can view your friends’ activity online in an aggregated view as well. Don’t forget to add correlate.us to your facebook profile.

Intelligent image thumbnails

A recent project I’ve been working on required 4:3 thumbnails of all images no matter the original image’s orientation. This required me to do a little math and cropping before actually making the thumbnail. I use the package Image_Transform to figure out which orientation the image is and then crop it appropriately.


$o = Image_Transform::factory('IM');
if (PEAR::isError($o)) {
    return $o;
}


$result = $o->load($ds1);
if (PEAR::isError($result)) {
    return $result;
}


$w = $o->getImageWidth();
$h = $o->getImageHeight();

if ($h > $w) {
    $newWidth = $w;
    $newHeight = ($newWidth * .75);
    $newY = ($h * .15);
    $newX = 0;
} else {
    $newWidth = ($w / 2);
    $newHeight = ($newWidth * .75);
    $newY = ($h / 2) - ($newHeight / 2);
    $newX = ($x / 2) + ($newWidth / 2);
}

$o->crop($newWidth, $newHeight, $newX, $newY);
$o->save($ds2);

The first check checks to see if the image is in landscape or portrait (in portrait the height will be greater than the width). With portrait’s I use the width, multiple that by 0.75 to get my 4:3 ratio and finish by going 15% down from the top of the portrait (assuming that you’re focusing your portrait in the upper portion of the image). With landscape images I simply go outwards from the center of the image (again, assuming you’re focusing your landscape in the center of the image).

Writing phpt files for PEAR and profit

I’ve been programming PHP now for, oh, almost a decade and I’ve been a contributor to PEAR for about four years now. It took me this long to finally get to the point that I think writing unit tests, in some form, is a good idea. I jumped on the OOP bandwagon about 6 years ago and drank the MVC koolaid about 4 years ago. As of a few weeks ago, I’ve jumped on the phpt bandwagon. I’m not going to cover the basics, because they’re well covered in a few different places around the web, but I am going to cover some of the nuances I’ve learned in the last few weeks.First off, you can run phpt files using the PEAR command line utility. I’ve been creating a tests directory and putting all of my phpt files in there. I normally name them 000-class-method.phpt and then increment the sequence number at the front for each test by 5 so I can do a decent job of predicting how tests run. Once you have a few tests you can run your tests in two different manners from the command line:

  1. pear run-tests
  2. pear run-tests 000-class-method.phpt

When you run your tests you’ll get results of which tests passed, which failed, if any of them were skipped and the reason why they were skipped, and files for debugging. If 000-class-method.phpt fails, there are a few files that will be of interest to you:

  • 000-class-method.php is the actual PHP file ran, which is found in the --FILE-- portion of your phpt file.
  • 000-class-method.outis what was actually output by the PHP file ran from the --FILE-- portion of your phpt file.
  • 000-class-method.exp is what the test expected the output of 000-class-method.php to be, which is found in the --EXPECT-- portion of your phpt file.

You pretty much have everything you need to debug why a test failed. I normally diff the exp and out files and then debug the test (or my code, which is usually the case) using the php file.

Another great thing about phpt files is that you can use a cgi PHP binary to debug actual GET requests (phpt supports spoofing $_GET, $_POST and $_COOKIE using the cgi binary). This lets you create tests like the following:

--TEST--
Test a GET request
--GET--
foo=bar&baz=foo
--FILE--
<?php
echo $_GET['bar'] . "\n";
echo $_GET['baz'] . "\n";

?>
--EXPECT--
bar
foo

This test should pass without incident. The only catch is that you need to specify your cgi binary path using the --cgi argument when you run the tests (e.g. pear run-tests --cgi=/path/to/php-cgi).

Overall, I’m pretty happy with my newfound testing experiences. My only complaint is that phpt files don’t support spoofing of $_SESSION natively. A small complaint to be sure.

Adding authentication to PEAR channels

A client of mine is taking the proactive approach of packaging all of their software using PEAR and distributing it via a custom PEAR channel. I can’t recommend this enough for people that are distributing their PHP code to a number of clients/users.

The problem is that, by default, PEAR channels are consumable by anyone with an internet connection. I sent an email to Greg asking him if there was a way to restrict this and how to go about doing it. As it turns out it’s not only available, but detailed in the free excerpt from his new book The PEAR Installer Manifesto.

There are a number of ways to restrict access. The more complicated approach involves coding a script that handles the authentication and then restricts packages on a per client basis. This is a great way to say client X can install packages A, C and F, while client Y can only install packages B and D.

The route I ended up taking involved simply setting up HTTP-Auth using and .htaccess and .htpasswd file. Once you have that set up and working you can log in with the following commands.

$ pear -d "pear.mychannel.com" login

Follow the instructions by entering your username and password and you should see a confirmation that you’re logged in. After that you’re allowed to download and install.