Nov 25, 2008

WOA isn't for the masses

Nick Gall's note on Web Oriented Architecture--basically SOA constrained to RESTful princicples--got me thinking about the futility of end-user programmable services.

Given the difficulty even highly trained engineers have in creating good interfaces, only a select few will be able to take a list of arbitrary services and make anything like the "slightly less general interfaces" mentioned in the note. Of course, that makes it worth it, because even a tiny percentage of the web's population is still significant and can benefit all. We just shouldn't expect the nirvana where ever user is a programmer and creates a wonderful mashup of services.

I suspect instances of "serendipity" and "unexpected reuse" will exist at the services level, but will be far and few between. As far as I can tell, I'm right so far...

Oct 28, 2008

Relative Times in PHP

While working on a side project I found myself in need of a function to produce relative times and dates--e.g. "3 minutes ago" instead of "October 28, 2008 12:18 AM". You'd think this should be easy to find in the age of Google, but I was quite disappointed. It turns out that there are some simple functions out there, but none that adequately take into account the new PHP 5 DateTime object (which avoids UNIX timestamps and therefore allows years prior to 1970 and after 2038), and is performant. So here's my solution for posterity:

/* Warning: this is a quick and dirty solution. I'm sure there
are some bugs or better ways of doing it. Hoever, feel free
to use it however you like. */

function is_leap_year($year) {
return ((($year % 100 == 0) && ($year % 400 == 0)) || ($year % 4 == 0));
}

/* for relative dates */
$month_lengths = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
$units = array("year", "month", "day", "hour", "minute", "second");
$unit_comp_max = array(12, 30, 24, 60, 60);

function relative_time($datetime){
global $month_lengths;
global $units;
global $unit_component_max;

$a = date_parse($datetime);
$b = date_parse(date("r"));

for ($i=0; $i $val = 0;
$unit = $units[$i];
$val = $b[$unit] - $a[$unit];
if ($val > 0) {
if ($a[$units[$i+1]] >= $b[$units[$i+1]]) {
$val = $val - 1;
if ($unit == "month") {
$b['day'] = $b['day'] +$month_lengths[$a['month']];
if ($a['month'] == 2 && is_leap_year($a['year'])) {
$b['day'] = $b['day'] + 1;
}
} else {
$b[$units[$i+1]] = $b[$units[$i+1]] + $unit_comp_max[$i];
}
}
if ($val > 0) {
return $val . " " . $unit . (($val>1)? "s ago":" ago");
}
}
}

$val = $b['second'] - $a['second'];
if ($val > 0) {
return $val . " " . (($val>1)? "seconds ago":"second ago");
}

return "only moments ago";
}
Please let me know if you have a better solution, but this seems to work for me at the moment.

Aug 29, 2008

RIAs DNA runs against the web

Good post from DeWitt Clinton on the oppositional nature of RIA to the Web. I agree with him and other RIA skeptics that a "richer" web is seductive but ultimately counterproductive. While DeWitt's argument of the inevitable force of the Web is compelling, Tim Bray's comments on Web vs heavyweight application usability is even more so. For the vast majority of applications simplicity and consistency should trump unique interfaces.

Aug 25, 2008

Kongregate sucks/rocks



Ok, this is a pretty geeky image to post, but I had to capture the moment when I saw it. I've been somewhat addicted to Kongregate the last couple of months, as it suits my needs to play games, is free, and allows quick play of 15 minutes or so that I have spare in the evenings. Like an RPG it totally appeals to the collector part of my brain, encouraging me to play just a little more to acquire the badge and points, even through bad games.

I used to have a completionist OCD, where I had to finish any book I opened, and game I played, or any movie I began watching regardless of how terrible it was. Maybe this was due to thriftiness in my family genes--i.e. I payed good money for it, I had better use it to its fullest. Whatever the cause I've been able to fight it back in recent years, and proudly have a stack of unfinished books and games (unfortunately this trait never seemed to translate to useful projects, so that stack remains sadly untouched).

Web games are perfect in the sense that they are low cost entry and can be left at any time if they suck. Kongregate plays on my weakness, though. One the one hand, I can't complain, because Kongregate rocks at giving me that fix, provides a damn good service (for free!), and most of the games are pretty good. On the other hand, it preys on that weakness in the same sense that many RPG/MMORPGs do, with the dreaded treadmill--forcing you to perform mundane tasks to level up, grinding away at mediocre games for way too long.

This isn't Kongregate's fault, but it is a chance to rant at those RPGs. I've long believed that a much better strategy for a truly broad audience would be to forgo the accretion strategy and come up with an engaging concept that would allow anyone to join in for a few minutes of play without having to worry about spending a ton of time levelling up or getting killed by those who have disproportionately more time or money.

Some online games have done better in this regard. Puzzle Pirates, for example, although that's largely derivative causal games mashed together, with little social interaction in the core gamely. There's a ton of room for improvement. I predict the first game to do this right will blow World of Warcraft's numbers out of the water. I'm waiting, people, get on it! (I know I won't--it's one of those unfinished projects on my pile...)

UPDATE: Another potentially negative aspect of grinding: gold farming. Bruce: "Possibly there is evidence here that game design need looking at."

Aug 5, 2008

Vision and Action

There's a Japanese proverb I love: vision without action is a daydream; action without vision is a nightmare. I've come to believe that too many visions induce a B-grade suspense thriller that has a lot of action but ultimately leaves you feeling empty.

Aug 1, 2008

Offline code reviews are more effecient

I've been listening to the stackoverflow podcast by Jeff Atwood and Joel Spolsky. Like Joel's blog/columns I find him alternately insightful and infuriatingly naive.

Anyway, the recent stackoverflow podcast #15 contains segment on code reviews in which both Jeff and Joel agree that interactive face-to-face code reviews are more effective than offline reviews in which reviewers read the code and send comments to the author. I have extensive experience with both and I strongly disagree.

This is actually studied and there is good, researched hard data that shows offline code reviews are just about as good as group- or meeting-based code reviews. Meetings find 4% more defects on average, which is statistically significant, but take anywhere between 50-1200% longer to get there. This indicates diminishing returns to say the least, hence they are less efficient. A good summary of these findings can be found in the free book Best Kept Secrets of Peer Code Review, specifically the "Brand New Information" chapter (note: you can ignore the sales pitch chapters at the end if you like--no disclaimer necessary: I don't own stock in the company or use their products).

Given Joel's earlier podcast rant about people on the internet blogging things based on anecdotes without research and data, I find this kind of ironic. Yet it is understandable: meeting-based code reviews do feel a lot better emotionally than offline reviews; there is less oppportunity for misunderstanding and most people do enjoy the social interaction. As good engineers, though, we should recognize that what feels good isn't always the best for us, and do the right thing.

To be fair, Jeff and Joel are really lauding the learning factor of information and tip-swapping that occurs during discussions, which has nothing to do with the code defect rate or efficiency. However, further reading of the literature shows that group-based code review tends to find few new defects, and those they do find tend to be surface-level in nature.

The book theorizes--and this is borne out by my own experience and those of my trusted coworkers--that really understanding code and algortihms at a sufficient level of depth takes time and concentration that is nigh impossible to achieve in a social setting.

I don't want to completely discount the learning aspect. If you have less experienced developers then it does help to train them in code reviews. However, you should do this consciously with the understanding of the productivity hit your more senior employees are taking. Of course, there's nothing stopping you from doing offline reviews and then reviewing results with junior developers.

What I've seen work is having primarily offline reviews with comments sent back to the author (and tracked in a system), and then having face-to-face (or voice-to-voice) meetings to clarify if necessary. This gets the benefits of concentrated brain cycles from the reviewer while maintaining human contact and communication where needed. In addition, some percentage of code can be targeted for meeting-style reviews to maintain the benefits Jeff and Joel care about in terms of learning. Along with good code review guidelines and coding convention guidelines this process can scale to larger (50+) teams with many smaller code reviews a day. It is also very effective for geographically distributed teams.

Jul 31, 2008

Bad Engineering Idea of the Week

I'm struggling to remember to post new stuff here, or maybe I'm struggling to find something new to say. Either way, I'm going to try a different strategy: post about software engineering things from my job--lessons learned, handy tips, interesting bugs, hard problems, etc.

Today's tidbit is a bad idea for fixing a bug. Our architecture has a primary server and a secondary server for backup purposes, both of which must be kept in sync to guarantee correct backup behavior. One new feature attempts to provide better error detection and feedback, a key part of which is determining whether the backup process is running.

For a little more context, the primary server already will not allow clients to connect until it handshakes with the backup process and verifies a synchronized starting point. There is a simple socket connection and protocol to determine if the backup process is listening and do the handshake. If the backup process is not available, the primary server polls the socket occasionally and waits forever.

The objective of the new feature is to watch the startup of the primary server and send status to a separate application that monitors the status of all servers and clients in the network. How would you solve this problem?

Well, one of our engineers decided to modify the startup batch script to log in to the secondary server, get a task list and see if the backup process was running. If it's not, it fails immediately and stops the startup process. Why is this a bad idea? Let me count the ways...

  • It introduces a new interface between the two servers that didn't exist before, which adds complexity to the model.
  • It introduces technology not used elsewhere in the product, namely logging in to other servers and using non-portable command line tools.
  • It adds its own failure mode for incorrect login/passwords on the secondary server.
  • It couples the two servers in the startup sequence, as opposed to letting both start independently.
  • It requires starting over completely to recover from the identified failure mode.
  • It relies on the primary server configuration knowing the name of the backup process on a different machine.
  • The condition it detects is different from the information you want. It detects if a process is running or not, as opposed to detecting if the backup process is accepting connections and is ready to handshake (the process might be running, but more subtly broken, which this will not detect).
I'm sure there are more, but you get the idea. So what is the better solution? How about using the existing socket connection information instead of adding a redundant channel? Provide the status to the administration tool and wait for the backup to start up. An admin can easily diagnose the situation and get the backup process running if needed. You could add an optional timeout if the backup hasn't started in 20 minutes or so, but that's not really necessary.

There are a couple of key lessons/principles at work here. One is loose coupling, which is almost always a win, generally without introducing much complexity. The other is reuse: don't add new stuff unless you really need it.