Sunday, November 1, 2009

Macports voodoo distortion field


Today I was building the opensprints-core gem. The Rakefile depends on Jeweler which depends on the Git ruby gem. No problem. I got all that flotsam and jetsam installed and wouldn't you know my version of git was too old. Shaving yaks is dangerous work. I broke out into a cold sweat because I knew git was installed via macports and macports works by rube-goldberg-inter-dimensional-voodoo-distortion-field, 800 rolls of duct tape and a buttplug. Let's just say I've had some bad experiences with it. On top of that I haven't tried updating anything ports related for a year or two. So let's upgrade.

sudo port selfupdate
sudo port upgrade outdated

Sure enough, I start upgrading and BOOM. Some obscure library fails to build.

---> Building cyrus-sasl2
Error: Target org.macports.build returned: shell command " cd "/opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.org_release_ports_security_cyrus-sasl2/work/cyrus-sasl-2.1.23" && /usr/bin/make -j1 all " returned error 2
Command output: /usr/bin/make all-recursive
Making all in include
make[2]: Nothing to be done for `all'.
Making all in sasldb
ar cru .libs/libsasldb.a db_ndbm.o allockey.o
Making all in plugins
make[2]: Nothing to be done for `all'.
Making all in lib
make[2]: Nothing to be done for `all'.
Making all in utils
/bin/sh ../libtool --mode=link /usr/bin/gcc-4.0 -Wall -W -O2 -arch i386 -L/opt/local/lib -Wl,-rpath,/opt/local/lib -L/opt/local/lib -o pluginviewer pluginviewer.o ../lib/libsasl2.la -lresolv -lresolv -lpam
/usr/bin/gcc-4.0 -Wall -W -O2 -arch i386 -L/opt/local/lib -Wl,-rpath,/opt/local/lib -L/opt/local/lib -o .libs/pluginviewer pluginviewer.o -L../lib/.libs -lsasl2 -ldl -lresolv -lresolv -lpam -lresolv -lresolv -lpam
Undefined symbols:
"_auxprop_plugin_info", referenced from:
_main in pluginviewer.o
_main in pluginviewer.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make[2]: *** [pluginviewer] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2
Luckily the Google knew how to fix it.
{{{
sudo port deactivate cyrus-sasl2
sudo port clean cyrus-sasl2
sudo port upgrade cyrus-sasl2
}}}
Then I hit the wall

---> Building MPlayer
Error: Target org.macports.build returned: shell command " cd "/opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.org_release_ports_multimedia_MPlayer/work/MPlayer-1.0rc2" && /usr/bin/make -j1 all " returned error 2
Command output: /usr/bin/gcc-4.0 -I../libavcodec -I../libavformat -Wdisabled-optimization -Wno-pointer-sign -Wdeclaration-after-statement -I. -I.. -I../libavutil -Wall -Wno-switch -Wpointer-arith -Wredundant-decls -O4 -march=i386 -mtune=i386 -pipe -ffast-math -fomit-frame-pointer -mdynamic-no-pic -falign-loops=16 -DSYS_DARWIN -shared-libgcc -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DHAVE_CONFIG_H -I/opt/local/include/lzo -I/opt/local/include -I/usr/local/include -c -o ao_mpegpes.o ao_mpegpes.c
/usr/bin/gcc-4.0 -I../libavcodec -I../libavformat -Wdisabled-optimization -Wno-pointer-sign -Wdeclaration-after-statement -I. -I.. -I../libavutil -Wall -Wno-switch -Wpointer-arith -Wredundant-decls -O4 -march=i386 -mtune=i386 -pipe -ffast-math -fomit-frame-pointer -mdynamic-no-pic -falign-loops=16 -DSYS_DARWIN -shared-libgcc -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DHAVE_CONFIG_H -I/opt/local/include/lzo -I/opt/local/include -I/usr/local/include -c -o ao_null.o ao_null.c
/usr/bin/gcc-4.0 -I../libavcodec -I../libavformat -Wdisabled-optimization -Wno-pointer-sign -Wdeclaration-after-statement -I. -I.. -I../libavutil -Wall -Wno-switch -Wpointer-arith -Wredundant-decls -O4 -march=i386 -mtune=i386 -pipe -ffast-math -fomit-frame-pointer -mdynamic-no-pic -falign-loops=16 -DSYS_DARWIN -shared-libgcc -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DHAVE_CONFIG_H -I/opt/local/include/lzo -I/opt/local/include -I/usr/local/include -c -o ao_pcm.o ao_pcm.c
/usr/bin/gcc-4.0 -I../libavcodec -I../libavformat -Wdisabled-optimization -Wno-pointer-sign -Wdeclaration-after-statement -I. -I.. -I../libavutil -Wall -Wno-switch -Wpointer-arith -Wredundant-decls -O4 -march=i386 -mtune=i386 -pipe -ffast-math -fomit-frame-pointer -mdynamic-no-pic -falign-loops=16 -DSYS_DARWIN -shared-libgcc -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DHAVE_CONFIG_H -I/opt/local/include/lzo -I/opt/local/include -I/usr/local/include -c -o ao_openal.o ao_openal.c
ar r libao2.a audio_out.o ao_mpegpes.o ao_null.o ao_pcm.o ao_openal.o
ar: creating archive libao2.a
ranlib libao2.a
/usr/bin/make -C input
/usr/bin/gcc-4.0 -I../libavcodec -I../libavformat -Wdisabled-optimization -Wno-pointer-sign -Wdeclaration-after-statement -I. -I.. -I../libavutil -Wall -Wno-switch -Wpointer-arith -Wredundant-decls -O4 -march=i386 -mtune=i386 -pipe -ffast-math -fomit-frame-pointer -mdynamic-no-pic -falign-loops=16 -DSYS_DARWIN -shared-libgcc -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DHAVE_CONFIG_H -I/opt/local/include/lzo -I/opt/local/include -I/usr/local/include -c -o input.o input.c
/usr/bin/gcc-4.0 -I../libavcodec -I../libavformat -Wdisabled-optimization -Wno-pointer-sign -Wdeclaration-after-statement -I. -I.. -I../libavutil -Wall -Wno-switch -Wpointer-arith -Wredundant-decls -O4 -march=i386 -mtune=i386 -pipe -ffast-math -fomit-frame-pointer -mdynamic-no-pic -falign-loops=16 -DSYS_DARWIN -shared-libgcc -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DHAVE_CONFIG_H -I/opt/local/include/lzo -I/opt/local/include -I/usr/local/include -c -o ar.o ar.c
In file included from /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/MachineExceptions.h:29,
from /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/DriverServices.h:32,
from /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/CarbonCore.h:125,
from /System/Library/Frameworks/CoreServices.framework/Frameworks/AE.framework/Headers/AE.h:20,
from /System/Library/Frameworks/CoreServices.framework/Headers/CoreServices.h:21,
from /System/Library/Frameworks/Carbon.framework/Headers/Carbon.h:20,
from ar.c:27:
/usr/lib/gcc/i686-apple-darwin9/4.0.1/include/xmmintrin.h:35:3: error: #error "SSE instruction set not enabled"
In file included from /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/DriverServices.h:32,
from /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/CarbonCore.h:125,
from /System/Library/Frameworks/CoreServices.framework/Frameworks/AE.framework/Headers/AE.h:20,
from /System/Library/Frameworks/CoreServices.framework/Headers/CoreServices.h:21,
from /System/Library/Frameworks/Carbon.framework/Headers/Carbon.h:20,
from ar.c:27:
/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/MachineExceptions.h:216: error: syntax error before '__m128'
/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/MachineExceptions.h:218: error: syntax error before 'sd'
/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/MachineExceptions.h:220: error: syntax error before '}' token
/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/MachineExceptions.h:264: error: array type has incomplete element type
make[1]: *** [ar.o] Error 1
make: *** [input/libinput.a] Error 2

Error: Unable to upgrade port: 1

The good news is git got upgraded. Mplayer and who knows what else is not. Oh well, while I am being a hater I might as well mention that the real suckiness is the fact that Leopard doesn't have a package manager. And that IS the dumbest thing about OSX.

Monday, September 28, 2009

ShellSink adds inline tagging

If you don't know about shellsink you can find more info here. Release 0.2.2 adds a new feature. You can add tags to a command at the same time as you execute it. This is achieved by using inline comments. Here is an example:
cat /proc/cpuinfo #sysadmin:diagnostic
That command will show up in your shellsink history with the tags sysadmin and diagnostic. This nifty idea was given to me by Jesse Hallett at my shellsink presentation at the open source bridge conference in portland this summer. Thanks Jesse.

Wednesday, September 16, 2009

A JS Bach's Crab Canon on a Mobius Strip

If you don't know what a crab canon is see here. video link

Sunday, September 13, 2009

Ruby is a Bloodsport


8th Light's 2009 ruby sparring tournament was posted at the end of August, but I just heard about it last week. I followed the simple instructions for getting started and was quickly rewarded with a very cool limelight app that drives the code you write. The coolest part of the app is that it analyzes your player and assigns a score. The score is based on efficiency, lines of code, test coverage, various metrics and of course how well your player does at hangman. I was immediately sucked in to the fun and challenge of the problem and I have created and refined my own player and submitted it for entry in the tournament. I thought I would share a few of the things I learned that might help others improve the scores of their own hangman players.
  1. "Simplicity Score" depends on lines of code, including comments, so delete all comments from the code to maximize your simplicity score.
  2. "Flog Score" is an easy one to maximize. Run flog separately on your code. Anything with a flog score above 9 will cost you points. Refactor bigger methods to smaller ones to keep their flog score below the limit.
  3. "Time Score" can be tricky to maximize. One approach is to create a performance test to help drive out the bottlenecks in your code. The hangman uses a list of 10,000 words so any time you iterate over that complete list you kick holes in performance.
Those were the 3 biggest things that helped me get my player score up there. It was definitely lots of fun and a good way to sharpen skills. I'm looking forward to seeing how the tournament plays out. Drop me a line if you wanna talk shop on this. Hope you decide to join in. And a big thank you to the folks at 8th light for making this happen.

Sunday, September 6, 2009

LambdaJ: the wild man's closure


A couple weeks back I was talking about using anonymous inner classes to lend a more functional style to your Java. A common response to this was "hey champ, just use Scala" or "hey tough guy, have you tried Clojure?" Thanks. In the immortal words of the Dude, "Obviously you're not a golfer." That aside, I wouldn't have anything useful to say about closures in Java but for a posting on tss that linked to me. As luck would have it that post also had a link to something REALLY interesting: Mario Fusco's lambdaJ. What is lambdaJ? Only one of the most interesting and creative uses of Java syntax I've seen since Szczepan Faber's Mockito came out a couple years ago.

LambdaJ is a library that very artfully plasters over some of the uglier bits of Java, like the collections framework and the lack of closures. I'm not going to waste prose trying to describe it. I'll just cut to the chase with some code:


//example of lambdaJ closure
Closure println = closure(); { of(System.out).println(var(String.class)); }
println.each("one", "two", "three");

//example of lambdaJ forEach
List personInFamily = asList(new Person("Domenico"), new Person("Mario"), new Person("Irma"));
forEach(personInFamily).setLastName("Fusco");

//example of lambdaJ sort
List sortedByAgePersons = sort(persons, on(Person.class).getAge());

The Catch
If you haven't seen that before, I bet you are excited. I was too the first time I saw it and I nearly ran out and refactored all the code I was working on to use lambdaJ. Then I decided to slow down and do some benchmarks. That is where I hit a snag. It turns out that all this magic comes with a price. Most iterative operations are an order of magnitude slower than java's for loops. Here is some benchmarking code.

import static ch.lambdaj.Lambda.forEach;
import static ch.lambdaj.Lambda.forEach;
import static ch.lambdaj.Lambda.on;
import static ch.lambdaj.Lambda.sum;
import static org.junit.Assert.assertTrue;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class LambdaJBenchmark {
public class Sequence{

private List<BigDecimal> sequence;

public Sequence(int size){
sequence = new ArrayList<BigDecimal>();
for(int i = 0; i<size; i++){
sequence.add(new BigDecimal(i));
}
}

public int iterativeSum(){
BigDecimal sum = new BigDecimal(0);
for(BigDecimal value : sequence){
sum = sum.add(value);
}
return sum.intValue();
}

public void iterateEntireSequence(){
for(BigDecimal value : sequence){
value.intValue();
}
}

public int lambdaJSum(){
return sum(sequence, on(BigDecimal.class).intValue());
}

public void forEachEntireSequence(){
forEach(sequence).intValue();
}

}

@Test
public void lambdaJIsSlowerThanForForTenThousandItems() {
long startTime = System.currentTimeMillis();
new Sequence(10000).lambdaJSum();
long endTime = System.currentTimeMillis();
long lambdaJRunningTime = endTime - startTime;

startTime = System.currentTimeMillis();
new Sequence(10000).iterativeSum();
endTime = System.currentTimeMillis();
long javaRunningTime = endTime - startTime;

System.out.println("Summing 10000 numbers. LambdaJ run time: " + lambdaJRunningTime + " and Java: " + javaRunningTime);
}

@Test
public void lambdaJIsSlowerThanForForOneItems() {
long startTime = System.currentTimeMillis();
new Sequence(1).lambdaJSum();
long endTime = System.currentTimeMillis();
long lambdaJRunningTime = endTime - startTime;

startTime = System.currentTimeMillis();
new Sequence(1).iterativeSum();
endTime = System.currentTimeMillis();
long javaRunningTime = endTime - startTime;

System.out.println("Summing 1 number. LambdaJ run time: " + lambdaJRunningTime + " and Java: " + javaRunningTime);
}

@Test
public void lambdaJNestedLoopsAreMoreOrLessAsFastAsFlatLoopOfSameSize() {
List<Sequence> sequences = new ArrayList<Sequence>();
for(int i = 0; i<100; i++){
sequences.add(new Sequence(100));
}

//Seems that "warming up" lambdaJ makes a big difference.
//Without this line the second test is an order of mag. faster.
new Sequence(10).lambdaJSum();

long startTime = System.currentTimeMillis();
new Sequence(10000).lambdaJSum();
long endTime = System.currentTimeMillis();
long flatRunTime = endTime - startTime;

startTime = System.currentTimeMillis();
forEach(sequences).lambdaJSum();
endTime = System.currentTimeMillis();
long nestedRunTime = endTime - startTime;

assertTrue("Summing 100 numbers 100 times. Run time: " + nestedRunTime + " but summing 10000 numbers took: " + flatRunTime, (nestedRunTime < (flatRunTime + 15)) && (nestedRunTime > (flatRunTime - 15)));
}
}
Here is sample output:
Summing 10000 numbers.  LambdaJ run time: 259 and Java: 19


All those tests show you how much slower things are with lambdaJ. I haven't really looked into the lambdaJ code, but I imagine reflection is what is slowing this down... still, for some applications perhaps the trade-off between speed and readability is worth it. Another thing to bear in mind is that lambdaJ is a pretty new project. They might still be optimizing this stuff. Looking at the LambdaDemoTestMain class (in the lambdaJ source) it is clear that Mario and company are thinking about this performance stuff. They have a more exhaustive set of speed comparisons like the ones I created.

More Catches
Bear in mind that I'm new to lambdaJ and might be missing a few tricks here. But here are some gotchas that have tripped me up. That closure trick is really clever, but when you try to use it I think you will find the behavior of lambdaJ closures to surprising. If you try something like this:

Sequence sequenceOfOne = new Sequence(1);
Closure foo = closure(); { sequenceOfOne = new Sequence(2); }

You realize you can't really do assignment because you need to use of() to bind sequenceOfOne to the active closure. Another surprise to me was that you can't have a closure with a return value. See this example:

private Integer plusTen(int lambdaJSum) {
return lambdaJSum + 10;
}

Closure sequenceSumPlusTen = closure();{ of(this).plusTen(var(Sequence.class).lambdaJSum()); }
Integer sequenceOfOnePlusTen = (Integer)sequenceSumPlusTen.apply(new Sequence(1));


I expected sequenceOfOnePlusTen to be 11, but sequenceOfOnePlusTen gets set to null. And no, you can't just inline a return statement in there. I hope I don't seem to be picking on lambdaJ. I think it is great. I would love to be able to use the sort methods and forEach methods in my codebase. But while we are talking about gotchas, here are some more: Using forEach on a null or zero sized collection requires using a different forEach method that has a slightly different syntax. And using lambdaJ on classes that are final will cause problems because lambdaJ can't proxy those classes. I suppose Strings must play hell with lambdaJ for that reason. And trying this code out, sure enough, I get a class cast exception.


List<String> strings = new ArrayList<String>();
strings.add("foo");
forEach(strings).toUpperCase();


Other interesting behavior I noticed was that the first lambdaJ operation you do is much slower than subsequent ones. See my benchmarking tests from before. The last test case will fail horribly if you comment out the lambdaJ "warm up code". I haven't dug through the lambdaJ code enough to understand why.

Conclusion
In the end you see how lambdaJ is a fantastic project full of great ideas. It offers you a taste of how things could be different if Java implemented closures. However it is just papering over this ugliness in Java. And because of the amount of proxy, thread local and reflection magic they had to use to do it, you should be prepared for some surprises when things don't work as you would expect. Regardless, my hat is off to the lambdaJ team. This is a great project that deserves to get more attention. I hope the project matures, inspires more DSL style code and whets the Java communities appetite for real closures and a better collections framework.

Saturday, August 8, 2009

Anonymous Inner Classes: A Poor Man's Closure?


Yesterday I had a discussion with a colleague about whether Java has closures or not. We both could immediately agree that, formally speaking, Java does not have them, but the part of the discussion that went on and on was about passing anonymous inner classes vs. passing around an anonymous function. I argued that the anonymous inner classes were a very poor substitute because a class has so much extra baggage, both conceptually and behaviorally. Classes understand and do all sorts of things that you don't care about when you are simply trying to pass along a little ol' function. Stuff like: inheritance, encapsulation, polymorphism. Worst of all, classes require lots of messy syntax. My colleague made an important point though: What else is a Java developer gonna do? When you are working in Java and you need something like a closure you've got no choice but to go for the anonymous inner class, the poor man's closure.

Google's Collection Framework is the best example I know of Java programmers making do with their poor man's closures. Here is a quick bit of sample code I created that demonstrates applying a function to every element of a list (Sorry you can't see my generics. I can't seem to escape properly for html):


import com.google.common.collect.Lists;
import com.google.common.base.Function;
import java.util.ArrayList;
import java.util.List;
public class PoorMansClosure{
public static void main(String[] args){
//Demonstrate something similar to the map function on a collection in ruby
ArrayList strings = Lists.newArrayList("feeling", "bad");
Function upcase = new Function(){
public String apply(String from){
return from.toUpperCase();
}
};
List upperCaseStrings = Lists.transform(strings, upcase);
for(String val : upperCaseStrings){
System.out.println(val);
}
}
}

Martin Fowler has a nice article about how closures naturally compliment collections. Here is a quick bit of ruby to demonstrate that.

class Closure
def demonstrate
strings = ["feeling", "good"]
upper_case_strings = strings.map{|elem| elem.upcase }
p upper_case_strings
end
end
Closure.new.demonstrate


In this example the closure frees us from the burden of specifying the names and signatures for both class and method and we simply give the function that maps to upper case without the noise. There have been rumblings in the Java world for some time that Java might someday support closures. Here's hoping that Java 7 will. If that does happen it will be interesting to see what they do to the collection framework. The existance of Google's collection framework is proof that the standard Java framework has major drawbacks. I think a major rewrite will be in order.

Thursday, July 30, 2009

Hooray, Wes Anderson! Hooray, Roald Dahl!

Roald Dahl + Wes Anderson = The next movie I go to at the cinema. Dig the preview here.

Sunday, July 19, 2009

Angry Drunken Programmers


One aspect of my talk at OSCON next week is showing how to distribute a custom version of an application via Launchpad PPAs. For my demonstration I chose the game "Angry, Drunken Dwarves" and re-skinned it to be "Angry, Drunken Programmers". You can play the following characters:


  • Alan Kay - Description: Alan has been torn to shreds by Lions that were soaked in psychedelic drugs and gasoline. He still stabs them in the head with authority. He is a computer scientist, known for his mustache, his early pioneering work on object-oriented programming and windowing graphical user interface design.
  • Linus Torvalds - Description: Linus is best known for having initiated the development of the Linux kernel. He has done other stuff, but what else do you need to know other than his his wife is a six-time Finnish national karate champion and she will snap your neck like a pencil.
  • Other characters include: Larry Wall, Richard Stallman, Donald Knuth, Martin Fowler.
While I hope this adds a bit of silliness to my talk, I do think it demonstrates a legitimate use for PPAs. Most of the time if you are making improvements to an open source project it is best to push those improvements back to the community, but there are scenarios when your changes are not generally desirable. The debian build system is very robust and supports being able to make changes to upstream projects without affecting the upstream codebase. Ubuntu makes very heavy use of this and so can you. Come hear my talk and let Angry Drunken Programmers teach us about this!

In the meantime if you run Ubuntu and want to play Angry, Drunken Programmers you can install it via my PPA, here (see the instructions link on the page). Or you can get the source here.

Go Native with Launchpad


Next week I am giving a talk on Launchpad's Personal Package Archives (PPA) feature at OSCON. PPAs allow you to upload Ubuntu source packages to be built and published as an apt repository by Launchpad. Publishing your software as a PPA means that your software will be a "native" installation for the millions of Ubuntu users out there. Aside from attracting that large community there are many other reasons why having a simple and reliable install/uninstall/upgrade path for software is important:
  • less support effort.
  • doesn't scare people away.
  • gives confidence in your software.
The challenge with PPAs is creating the initial Ubuntu source package. I will show some of the basics of this in my talk as well as how you can create and distribute custom versions of software with your PPA.

Sunday, July 12, 2009

I should have gone to Art and Code this year.

ART && CODE Symposium: Hackety Hack, why the lucky stiff from STUDIO for Creative Inquiry on Vimeo.

This is a talk by a certain lucky fellow at the CMU Art and Code Jamboree. Looks like fun.

Cleaning up after the great JavaScript Framework Explosion of 2006


For the past 3 years every web application I have worked on has used a JavaScript (JS) framework. Usually it is one of these guys:
All of these guys are really good guys to know; especially if you find yourself in a dark alley being threatened by a mob of project managers wielding GWT manuals. These guys will save your bacon. I would go so far as to say that in this era of Ajaxified interfaces you really can't do without knowing one of these guys. You would be totally lost. Nowhere. If you don't know one of these guys then I pity you just like I pity the descendants of the lost tribe that never discovered fire and thus do all their cooking with friction. Nothing is more pitiful or unappetizing than a hamburger and fries that were cooked by rubbing them against a rock for 8 hours.

These libraries extend the JS language, make data exchange with the server more flexible, give you enhanced widgets and let you create effects on the page. Great! But should we really be doing all these things in JS? It seems like widgets and effects are more in line with what HTML and CSS are responsible for, not JS.

I hadn't really thought about this until today when I was reading about some of the new stuff in CSS3 (my favorites are the new selectors, transitions and animations). This is pretty exciting stuff that will really clean up alot of ugly things you end up doing in your JS code. For example, the Wolfire blog has a great, nontrivial sample of the sort of custom widgets that you can achieve with CSS3 animations and transitions. (see the animated gif, but please, do yourself a favor and go to the wolfire link above so you get the full context). This is a custom widget that is just pure CSS. You only use JS for activating state changes and sending data. You know, JS for behavior, CSS for appearance. Perfect.

It looks like CSS3 is going to put in order all the things that were dislodged by the "Great JavaScript Framework Explosion" of 2006. Of course I still want my JS frameworks, but let them help me with event handling, data transfer and writing concise, testable, maintainable JS code. Leave the appearance of my page for CSS to describe.

Wednesday, June 17, 2009

Meta Programming with a Barf Bag


Day one of the Open Source Bridge conference was action packed. I'll probably have to write a few posts, but I'm going to start things out with notes on my favorite talk of the day "Spindle, Mutilate and Metaprogram: How far can you push it before there be dragons?" by Markus Roberts and Matt Youell. Yes the picture is them wearing colanders on their heads.

This talk was 2 hours long so it is hard to cover it in all its glory. The crux is that programmers are generally very inhibited by the orthodoxy of each particular language community to the detriment of the code they are writing. Done properly, applying the magic of meta programming simplifies problems and makes code more understandable. Markus especially seemed to wipe his boots on some of the taboos. They mentioned ActiveRecord and jQuery as examples of effective meta magic.

The talk began with a gameshow where 3 volunteers were shown code snippets and the first person who could identify what language it was got a point. The first program looked like C but was in fact Ruby. Another looked like assembly language but was Perl, they even threw some Cobol in there, but it turns out it really was Cobol. :) Each time after they revealed what the real programming language was they showed the code that allowed them to mimic the other languages. It was really a cool way to start a presentation about meta programming.

At one point they showed some C that had been made to look like another language (I don't remember which). Somebody from the audience pointed out a memory leak. Markus responded by pointing out a table in the back where they had barf bags laid out and recommended he get one because there was going to be some spectacularly intolerable displays of metaprogramming. There was lots to learn about how you can shape your own destiny in a programming language if you are willing to amp up your level of meta skulduggery. Tomorrow when I see Markus and Matt again I'll ask about their slide deck, because it would be fun to share some of their code examples.

Wednesday, June 3, 2009

To ORM or Not to ORM.


Sara Taraporella recently added this very interesting post to her blog. In this post she argues for a separation between domain models and ORM models. There is a pretty lively discussion in the comments that I found useful.

For me it is situational and so for the most part I think being somewhere between these extremes is nice. Something that keeps me from having to do lots and lots of transformations but also keeps me from having to touch too many files when something changes. Active Record is the poster child for combining ORM with the domain, and in the situation where you have complete control to define and change your DB it is great, though I think it comes at the cost of testability. In the comments Clinton Begin describes a situation where other applications need to consume the same DB and require changes. In this case or in the case of a legacy DB you might find yourself gravitating towards the opposite end of the spectrum, which is what Sara is advocating. Complete separation of these concerns.

I recently attended a talk by Drew Olson at the Chicago ruby user group about Data Mapper (among other things). Data Mapper is definitely a step away from the the purity of active record. With active record your DB schema describes your domain model and so you stay DRY. Data mapper says you need an explicit mapping. This buys you flexibility at the cost of being explicit and potentially redundant in describing the relationship between the domain and the database.

I see Active Record as one extreme and Sara's perspective as the opposite. Datamapper is a step towards the middle, and with the changes in Rails 3 the door will be open for people to use data mapper instead of active record. So it appears that Rails is mellowing in its old age, going for a less extreme worldview. Or maybe the world has moved towards rails' view of the world. In the end a little of both are a good thing, I think.

Monday, May 18, 2009

JMX is my favorite rapper!

JMX rules! Some of his best songs: Where the Enterprise at, Xml Gon Give it to 'Ya, Ruff Ryders MBean Anthem, Can't Stop Being Greedy.

The biggie commerce (big e-commerce) project I've been working on is now dev complete and we are working on some production readiness tasks. My job today was instrumenting the most important pages of the application with JMX so we can get statistics on requests/sec, responses/sec, and successes and failures on a per page basis. Word.

I'm new to JMX and it took me some time to get it working in Jetty and Tomcat with Spring. Here are a few of the snags I ran into and what I was doing wrong.

  1. Getting Jetty's MBean server to start when we are using the builtin jetty Ant task. There isn't lots of documentation out there about getting Jetty and JMX working when you are starting Jetty via the builtin Ant task. Here is what I did. I added the jettyXml attribute to the jetty tag like this:
    <jetty ... jettyXml="web/target/main/webapp/WEB-INF/jetty.xml"> ... </jetty>
    My jetty.xml file contains the following:
    <Configure id="Server" class="org.mortbay.jetty.Server">

    <Call id="MBeanServer"
    class="java.lang.management.ManagementFactory"
    name="getPlatformMBeanServer"/>

    <Get id="Container" name="container">
    <Call name="addEventListener">
    <Arg>
    <New class="org.mortbay.management.MBeanContainer">
    <Arg>
    <Ref id="MBeanServer"/>
    </Arg>
    <Call name="start"/>
    </New>
    </Arg>
    </Call>
    </Get>

    </Configure>

    The jetty.xml tells Jetty to start an MBean Server and adding the jettyXml attribute will let Jetty know where to find the jetty.xml file. It seems obvious, but I had to really scour the web to figure that one out. The tricky 'ah-ha' bit is the fact that you can define your jmx stuff in jetty.xml rather than in jetty-jmx.xml, because of course the jetty ant task doesn't have an attribute for jetty-jmx

  2. Spring was silently ignoring my JMX annotations, thus none of my MBeans were being exposed. This took me hours to figure out. Here is the explanation I found buried in the spring JMX docs.
    Do not use interface-based AOP proxies in combination with autodetection of JMX annotations in your bean classes. Interface-based proxies 'hide' the target class, which also hides the JMX managed resource annotations. Hence, use target-class proxies in that case: through setting the 'proxy-target-class' flag on , , etc. Otherwise, your JMX beans might be silently ignored at startup...
    The nub of it is I don't get to use spring's fancy 'ManagedResource' annotations to define and name my MBeans. Instead I have to describe each one in XML. Not a huge deal, but unfortunate. Stupid AOP stuff!
  3. Jconsole, which is the default tool Java gives you for connecting to JMX enabled systems, doesn't work in Ubuntu. Man oh man. If I could have the time back that I wasted before I realized that. You just get a blank window when you connect to your server with Jconsole in Ubuntu. I think the compiz desktop effects are probably the culprit here. Lame.
I spent most of the day dealing with my configuration woes, so I didn't get to work on the interesting part yet which is instrumenting the controllers. I'll post about that if it turns out to be interesting. This post is mostly a "what not to do" post. Hope it helps someone.

Monday, May 11, 2009

Building your resume


And when I say "building your resume" I literally mean creating a build system for a resume with config files, LaTeX and Rake. Why in the name of Knuth would I do such a thing?
  1. Because it is AWESOME!?!
  2. Version control! So how old will I be when my resume reaches 1.0?
  3. Hosting on GitHub means my resume has an RSS feed!
  4. LaTeX's Inline comments make for fun Easter eggs and color commentary.
  5. A really keen potential employer could 'watch' my resume via GitHub. Heck they could even fork my resume and add things they would like to see me learn.
  6. I could add a Rake task to publish my resume somewhere or to email it directly or even to tweet me whenever someone builds my resume.
  7. Rake task for spellcheck.
  8. I could have build parameters for adding or hiding certain sections of my resume... for example swapping out the objective at compile time.
  9. They say "blogs are the new resumes" but I say, "GitHub is the new resume!"

Sunday, May 3, 2009

Evolution of a Programmer


In a recent discussion about the Intentional language workbench on the Software Craftsmanship mailing list Dave Hoover made the following comment:
If programmers from 30 years ago looked at my typical day today, I bet they would think I was more of an analyst than a programmer. The high level code that I get to work with typically keeps me very close to the domain language of my customer... the problems I'm generally solving aren't related to computer science and optimizing milliseconds, they're translating my customer's desires into executable software.
I thought this was interesting and I agree with Dave. To some extent I wish this was even more true than it already is. Writing software and solving problems 'close to the metal' can be interesting and rewarding, but being able to bring my ideas and my customer's ideas to life quickly and elegantly is really what it is all about for me.

Saturday, May 2, 2009

Filtering What Goes Into Your Shell History


I wrote a post here that has a few techniques for filtering what goes into the shell history. It is unwise to store sensitive or dangerous commands in your history. An example of a sensitive command would be one with an inline password. Executing such a command would store your password in cleartext in your history file. An example of a dangerous command is 'rm -rf' If you were to accidentially execute this by using ctrl-r or ! or !? then you could potentially lose important data or destroy your system. Bash offers configurations that let you ignore commands, including the ability to ignore any command that is prepended with a space. It is handy, especially for anyone who makes good use of their shell's history features. Btw, I know a couple folks out there who use zsh. For you guys, know that zsh offers a subset of the bash functionality (HIST_IGNORE_SPACE) so you should check it out.

Monday, April 20, 2009

I'm speaking at the open source bridge conference


The hits keep coming and my summer schedule is filling up! I didn't want to miss out on the Open Source awesomeness happening in Portland this year, so I made sure to submit a proposal to the Open Source Bridge. I was lucky enough to get accepted. Huzzah! My talk will be about Shellsink. Here is an abstract. Drop me a line if you are going to be there!

OSCON 2009, Angry Drunken Dwarves, and Crazy Diagrams.


I'm pretty excited to be presenting at OSCON again this year. In keeping with my tradition of bringing the most slipshod weird diagrams to the open source community, I promise to have crazy diagrams in this talk, even if it is absolutely unwarranted. Oh, and speaking of my talk. it is on using Launchpad's PPA system for distributing open source projects. Sound boring? Don't be too sure. I plan to show you how it is directly applicable to your life and the lives of many an angry drunken dwarf. An abstract of my talk is here.

By the way, if you are interested in attending OSCON you can use this code to get a 15% discount on the registration fee: OS09PGM.

Sunday, April 19, 2009

Buying from apple? Sometimes it pays to wait.


When you buy a new Apple product you are getting a shiny new toy from the makers of the shiniest toys around. It would be a big disappointment to buy a new gadget only to have a new model come out the next day. Not only is the newer model going to be cooler, but the older model will suddenly be worth less. How do you figure out when it is safe to buy an Apple gizmo? The Apple obsessed have created a website using historical data about Apple product lifecycles in order to make a recommendation about when to buy. Check it out.

Sunday, April 12, 2009

Notes From a Large Agile Project: A Developer's Perspective.


16 ThoughtWorks developers, 8 pairs, 5 months. We are re-implementing a large, well-known* e-commerce site with lots of complex legacy systems integration. The timeframe from start to finish is 5 months. In the beginning I had no idea if that was realistic. After a month I thought it was a tad optimistic. Now, with one month to go I am convinced that we are going to make the deadline!

Here are some of the things that I think are making this project successful:

1. Shared vision and values among developers. Projects suffer when developers have to do battle over values, tools, or techniques with clients, project managers or other developers. Our development team is 100% ThoughtWorkers, and though we do have heated arguments (frequently these are simply violent agreements), we agree upon and enjoy many of the following values and techniques: pair programming, simplicity, embracing change and test driven development.

2. Strong support and responsiveness by the client for integration tasks. Interacting with legacy systems at large companies can be challenging. Often times such systems have been on life support for so long that nobody really understands how they work. In cases like that it is critical to make sure you have full access to the system, code, and available experts. We have been fortunate to have direct access to the code and experts, and it has been key to our success.

3. Love of Simplicity. Throughout the project most battles and arguments fought amongst ourselves and with other stakeholders have been about simplicity and figuring out how to do the simplest thing that can possibly work. While we may have lost a few 'architectural battles' along the way. I think that in general our daily focus on simplicity has kept velocity (and spirits) high.

Here are some things that have hurt us:

1. Managers who equate working long hours with hard work. With as much agile and XP experience as we have at ThoughtWorks I can't believe that this still comes up. Honestly, forcing long hours over a long period of time and restricting vacation doesn't make the project go faster. Poppycock!

2. Processes that inhibit code improvement. This is another thing that I wish I didn't have to mention. Creating a 'workflow' around bug fixes so that developers aren't notified when bugs are found is horrendously wasteful. If you've read any books on lean techniques you have to realize that creating and storing inventories is very bad mojo. Creating and storing inventories of bugs? Poppycock!

3. Java. You know, web frameworks for Java have come a long way, but there is one big problem: they still use Java. Big IT needs to get out of the 90's! Rails is a much better framework than anything the Java community has produced. It is mature and has a thriving developer ecosystem. Heck, it even runs on the JVM. For more opinions on this, check out the first question of this interview of Neal Ford and Paul Gross.

*I know it would be more interesting if I could talk about who our client is... but the deepest, darkest sort of nondisclosure magic has bound my lips and my pen so that I cannot use certain names.

Friday, April 10, 2009

Ola Bini on the Ioke Language


For those of you in Chicago Wednesday, June 10, 2009 I am going to be at Ola's talk about his new language Ioke. It should be exciting. Admittedly I haven't dug into Ioke yet. My plate is full with learning Scala, but every new language I learn teaches me something about the languages I already know. I expect Ioke will not be an exception to this rule. Doors Open @6pm Talk @6:30. Stop by and say hi.

Location:
ThoughtWorks, 200 E Randolph St. 25th Floor


Abstract:
Ioke is a new language, an experiment to see how expressive a language can be. It's a language for the JVM influenced by Io, Self, Smalltalk, Lisp and Ruby. It supports a prototype based object oriented system, is homoiconic, supports high level methods and macros and makes it easy to build DSLs and new abstractions from scratch. The presentation will first talk about the motivation for a new language, then talk about some of the more interesting features of Ioke, including the object system, the macro system and java integration features.

RSVP Here:
http://connect.thoughtworks.com/olabini/


Ola's Bio:
Ola Bini is a core JRuby developer and is the author of the book ‘Practical JRuby on Rails'. His technical experience ranges from Java, Ruby and LISP to several open source projects. He likes implementing languages, writing regular expression engines, YAML parsers and other similar things that exist at the border of computer science. Check out Ola's Blog. http://olabini.com/blog/

Saturday, April 4, 2009

Pycon 2009 videos of interest


Here are a few presentations I got alot out of at Pycon. This one by Ian Bicking, Topics of Interest, was good for me because I'm new to the Python community and It really covers alot of ground and gives you one person's perspective on a bit of python history. I also like the parts where Ian dives into some non technical topics of interest like women in computing (17:00) and postmodern programming(21:50). Plus the IRC comments at the bottom are at times hilarious.
http://pycon.blip.tv/file/1932161/

The second presentation by Jack Diederich, Class Decorators Radically Simple, is one that I found useful as in my one Python project I did I never used class decorators and it was good to get some ideas about how and when to use those. Check it out.
http://pycon.blip.tv/file/1949345/

Monday, March 30, 2009

Searching my favorite ruby blogs


I've been making custom google search engines for things I find useful. Tonight I was doing some research on ruby metaprogramming and I decided to create a search of some of the better ruby blogs. Let me know if I am missing any in the search. In the meantime, I hope this comes in handy. Check it out!

Sunday, March 29, 2009

Artful Food Blog Search


So people have been using the artful food blog search (see previous post), but google gives their custom search engines such terrible default URL's I had to create a homepage for it. Turns out blogspot is good for that stuff when you get rid of the blog part. Just add JQuery.

Check it out.

http://flavorsearch.blogspot.com/

Pycon 2009


PyCon is wrapping up and I just thought I'd mention a few things of interest that I saw.

Adam Christian gave a presentation on windmill which is a functional test tool like selenium, written in python. It looks pretty good, but I didn't really see how it differentiated itself from selenium.

Adrian Holovaty gave a talk called "Behind the scenes of EveryBlock.com" If you don't know about everyblock you should check it out. His talk was mostly about technical challenges they faced and how they addressed them. I won't go into detail, but want to say this is a very cool project and I think it offers a glimpse into the kind of useful things that would be possible if government could find a way to share their public records online.

Michael Foord gave a great lightning talk called "Metaclasses in 5 minutes" Plus he has an awesome "Knuth is my homeboy" shirt (see picture). Be like mike and get one here.

Guido Van Rossum gave a keynote. Two things about that: First, he is trying to "fade away" from being in charge of the python community. Second, python is very similar to lisp. If someone could explain to me what he meant by python and lisp being close, I would be grateful.

Joe Gregorio gave a talk on "The (lack of) design patterns in python". It was good and really applies to most any dynamic language. Read the slide deck to see that popular design pattern names are less likely to be talked about on the python mailing list than say, "the pope" or "sausage". Also some great quotes in there about why dynamic languages with metaprogramming basically have all these common patterns built in.

Jack Diederich Gave a very detailed talk on class decorators in Python, and how they make your code more readable than metaprogramming. Good info about this python language feature can be found here.

Finally, Gregor Lingl a high school teacher from vienna who wrote the turtle module from python 2.6 and 3.x spoke about "Seven ways to use Python's new turtle module" He showed off this beautiful demonstration that animated the path of the earth and moon going around the sun. Check out slides 15 and 16 of his talk. Also see slide 28 for a screenshot of his nice animation of building a penrose kite. He wrote a book on this "Python für Kids" Too bad it is in German. Logo rules!

Tuesday, March 24, 2009

Crunchbang Linux

This could be a long post if I agonized over all the little things that make me want to chuck OSX for Linux, but I'm not going there. I'll just say that I think Gnu/Linux and the tremendous set of open source software that inhabits it is the best environment for a productive developer. Sure a linux VM is nice (I use them for packaging and testing shellsink for linux), but somehow running a VM of linux just doesn't cut it for me.

Soooo, I have gone and dual booted my MacBook Pro. What distro did I pick? Well I like the convenience and hardware support of Ubuntu, but can't stand the bloat of gnome, and even xfce seems slow to me these days. I wanted something lightweight, but easy. And lo and behold look what I have found: a new linux distro called #! Crunchbang Linux. Quoth the Crunchbangers:
CrunchBang Linux is an Ubuntu based distribution featuring the lightweight Openbox window manager and GTK+ applications. The distribution has been built and customised from a minimal Ubuntu install. The distribution has been designed to offer a good balance of speed and functionality.
I installed it on my mac (after installing refit.) After getting the proprietary nvidia drivers going, all the hardware worked right out of the box (minus the keyboard backlight and light sensors). All I had to do was configure the multitouch and I immediately felt comfortable. It is truly wonderful little distro. No it isn't perfect, and I'm not sure if I'll ever get rid of OSX on my laptop, but I am considering it. Here is a list of things that could be improved (this is probably mostly stuff ubuntu, debian and the upstream packages would have to work out, not crunchbang).
  • Short battery life (1 hour vs 3 hours in OSX) due to the wired ethernet driver.
  • Decreased Wifi reception (about half the range of the OSX drivers) due to wireless driver.
  • Occansional issues with mouse locking up after a suspend (but only since I enabled multitouch).
That is it. Everything is completely usable, but for obvious reasons the crunchbang software isn't as highly tuned to my system as OSX is. I suspect with some research and effort I could mitigate some of these things, for example using ndiswrapper I might be able to use the proprietary wifi driver which supports the hardware better and gets a better signal from it. I never use the wired ethernet so I could probably remove that module from the kernel to improve battery life. If this were a perfect world I could get the best of both worlds, an OS with a philosophy like crunchbang but with the polish of a commercial product. Sigh. Ah well, it is getting better all the time.

Monday, March 23, 2009

ThoughtWorks and Clojure


I'm happy to say that Chicago now has a Clojure user group! Props to Cosmin Stejerean for making this happen. I'm also happy to say that the first meeting will be in ThoughtWorks office April 15th. I'm going to be there and I'm bringing along my absolutely-zero-Clojure-experience. Confession: I haven't played with any lisp dialects since college.

ThoughtWorks has been heavily invested in JVM based languages for some time starting with JRuby. Hosting the Chicago Scala and Clojure groups is for me more evidince of that commitment. Lets face it, all of us would like to see less Java code in the world, but we don't need to dump Java becuase it turns out that it is still useful. People see JVM based languages like JRuby, Scala and Clojure as a way forward for big enterprise shops who have invested heavily in Java. If this comes to pass than by some strange twist the JVM will have just been a really, really well engineered trojan horse for getting more beautiful languages like JRuby and friends into the enterprise.

On a different note, let me mention how happy I am that somebody finally named a Java project without dropping the 'J' bomb at the beginning of the name. Emphasizing the 'J' by putting it in an unusual context should be the new hip way to name your Java project. With that in mind I'm going to keep the trend going by announcing a new JVM based language that I just invented on the spot! Hear-Ye, Hear-Ye. I formally announce a language designed for search and manipulation of text and structured data. I will call it Seijure becuase nothing goes together better than Search and Seijure. Hark! What's that I hear? It is a phone call from Google about using it to re-write their aging search engine.

Sunday, March 22, 2009

Google Custom Search Engines


Today I was looking a good veggie fried rice recipe. The usual delimma I face when searching the web for a recipe is that I never get the result I want. Inevitably google returns some crappy commercial site like foodtv.com or about.com or something becuase loads of people link to them. Unfortuantely, when it comes to recipes the stuff they serve up is uninspired.

What I really want is a veggie fried rice recipe from one of those artsy little food blogs like "everybody likes sandwiches" or "eggs on sunday". But how to find the artsy food blog links among all the commercial noise on google? Technology will have a solution, right? Yes. The solution is a Google Custom Search Engine. Give google a list of urls and it will let you search them exclusively.

Here is my custom food blog search:

It covers about 150 artsy little food blogs. Where did I get the URL's? I wrote a simple little ruby script to scrape urls out of HTML. While I was at it I made another search engine I thought would be useful. It is a search of every blog listed on blogs.thoughtworks.com. Here is the widget if you are interested:

Incidentially, here is the fried rice recipe that I ended up with. You gotta love the not eating out in new york blog.

Thursday, March 19, 2009

How to break the back button with javascript and how to fix it.


Firefox has a known bug where it can fail to restore the state of a form when you hit the back button or reload the page. Here is a situation in which I encountered this and how I got around it.

We have a project that has some fancy jQuery "flyouts" (think jQuery's datepicker meets a select box) that replace standard select boxes, but we want the page to degrade gracefully if javascript is disabled, and that means when you disable javascript you should be able to see select boxes. The way to do this is to hide the select boxes on page load with jQuery and then to add the text boxes with flyout functionality to the form. It works great until you submit the form and hit the back button. Firefox only partially repopulates the previously selected form values. With javascript disabled everything works fine. What is the problem? Turns out firefox has problems repopulating forms when form elements have been added or moved with javascript. This is because form elements are repopulated based on their position in the dom, not based on the name of the elements. Bummer. But, if you know what causes the bug it becomes easy to work around. The solution is to simply not move or replace anything on the form. Most of the time you can replicate this behavior by showing and hiding elements. So for our case it was simple enough to put the textboxes for the flyouts on the page in a "hidden" state. Then if javascript is enabled they will become unhidden on page load at the same time the select boxes are hidden. Now firefox has no problem repopulating the form on reload or with the back button, and in the case of no javascript we still degrade gracefully.

I posted this because it took us a couple days to realize this was a limitation of firefox and not something we were doing wrong. Hopefully this will help someone else. Incidentially Safari doesn't have this problem, so clearly there is room for improvement in the way firefox repopulates forms. Probably something based on both form element name AND position, instead of a purely positional approach.

Sunday, March 15, 2009

Hackety Hack is Backety Back


Oh my, sorry about the title. I couldn't help myself. If you follow _why's blog: hackety.org then you heard _why was demonstrating his new version of hackety hack, based on shoes, at the art and code conference at CMU. Unfortunately I couldn't make it to the conference, but I was itching to try the new hackety. Though the main hackety site isn't helpful our old friend google is. A search for "hackety hack" will deliver the download page as the second result. Yea! I'm hackety hacking at this very moment!

Friday, March 13, 2009

Pair programming with multiple mouse pointers and keyboard foci


I've been practicing XP for 3 years now, but I remember having some doubts about it when I first started. It just didn't seem natural for two people to sit at the same computer all day. Right away I realized that my concerns were unfounded and, in fact, I found myself to be a more focused, productive, and happy programmer while pair programming. The one thing that has always bothered me was that computers are just not designed to have multiple participants. Usually there is one monitor, one mouse and one keyboard. Sure, you can supplement a second monitor, mouse and keyboard, but it is a bit like having two strings attached to the same kite or two handles on the same shovel. No matter how many input devices you connect you are forced to share control of a single pointer. Obviously our tools aren't up to the challenge of real time, in person collaboration!

There is, perhaps, a solution to this problem. MPX is a fork of the X server that allows for multiple mouse pointers and multiple keyboard foci! (up to 18 of them) See this video.

One obvious drawback to MPX in a pair programming context is that it could be considered a distraction for the pair. One person could pull open a web browser or otherwise lose focus. Also there could be contention for control of what is happening on the screen. But honestly, both of these problems exist without MPX, and it is a matter of etiquette and professionalism, not a matter of tools and technology.

I look foward to playing around with MPX, and pair programming, seeing what works and what doesn't. I expect that IDEs and editors could find interesting ways to capitalize on this new way of working. What sort of benefits and drawbacks do you think MPX would have for pair programming? What kinds of editor and IDE enhancements would you like to see?

Most likely we are still a long way from this technology becoming a part of our favorite linux distrobutions, but it is fun to imagine the possibilities. I think it would make our tools more suited to collaboration.

Monday, March 9, 2009

The RPG, distilled


This weekend I came across a flash based RPG by Sophie Houlden called 'The Linear RPG'. It really is a boiled down version of what many RPG's are. Essentially you make your character travel around and increase statistics like HP and experience, except in this RPG you are moving on a line so you can only go forward and back, but like other RPG's there is a gradient of moving from easy to hard, so you can't just go directly to the end, you have to back track and spend time in easier places 'training' before you can proceed to the hard places. Sophie did a nice job doing some 3d bending of the line to make the game more visually stimulating and having the story scroll by as text behind your character's position is a nice touch. It is a game that you can play through and complete in 5 minutes or less. And it is free and in browser. Enjoy a great idea that was well executed for a few moments. Play
'The Linear RPG'

Tuesday, March 3, 2009

Googling for Ruby Quiz finds an outdated site


Ruby Quiz is an awesomely fun programming challenge that comes out on the ruby-talk mailing list every week. There has even been a book of them published by the prag guys a couple years ago. Anyway, I can't stay up with the ruby-talk mailing list because there is just too much stuff flying around there. So how to get your hands on all the quiz loveliness? You could find all the quizzes in the archives of the mailing list if you had some time on your hands. Fortunately there are some websites that collect them. Unfortunately, no website (that I know) collects ALL the ruby quizzes. There are three websites though that, put together, contain all the quizzes. Old skool ruby quiz site has quizzes 1 through 156. Mid skool ruby quiz site has quizzes 157 through 188. The new skool rubyquiz site has 157 - 194. Why do they do it like this? I don't know! It is really annoying! If you google for ruby quiz the old skool site is the only one that shows up in your search. I just thought I would link to the new skool site from my blog in the hopes that someday when I search for ruby quiz I'll get a link to the site that has the latest quizzes.

By the way the newest ruby quiz "Polyrhythm Trainer" #194 sounds like a really fun problem to solve. If I had time to do it I'd make my solution a shoes app. Whee!

Saturday, February 28, 2009

Merge Bazaar Repositories With No Common Ancestor


Distributed version control is great for merging. Things like bazaar, git, mercurial, etc. all have sophisticated tools and good support for merging branches of the same code that have diverged even if files have been moved or renamed. But what about merging branches with no common ancestor? I needed to do just that today. I had two bazaar repositories that were separate parts of the same project. One repository was the client and one held the server. I decided that it was pretty inconvenient and a bad idea to have them in separate repositories. I wanted to merge the repositories so I wouldn't lose the history for either project.

Turns out this is pretty easy... In bazaar you can simply do the following:
  • Change directory to the destination working copy.
  • Execute the following command
    bzr merge /path/to/source-working-copy -r0..-1
  • Note the -r0..-1 part of the command. This tells bazaar to merge a range of revisions from the first revision to the most current.
  • Now review and commit the changes. Notice that bazaar gives you an indication that all history is preserved by displaying a list of checkin comments. Nice.
Now the destination working copy will contain all the code and history from the source working copy. Cool. I used this to merge the server codebase into the client codebase for the shellsink project. Of course I tagged and annotated this command in shellsink. On my list of things to do is hook into the blogger api from shellsink so that you can have annotated commands from shellsink automatically show up on your blog, but that is for another post...

Thursday, February 26, 2009

App Engine gets bad gas mileage


A few months ago I wrote an app for google app engine, and less than a month ago I told people about it. One of the reasons I chose app engine was that it boasted a generous free quota allowing you to host applications serving nearly a million requests a month for free... Now in theory this might be possible, but in my case I am about to outgrow the free quota in less than a month by serving up about 7 to 10 thousand requests per day. The google ads I put on the site don't make any money because most people interact with the application via the command line, doing pushes and pulls.

When I run out of free quota then it will mean that everyone who wants to keep using shellsink will have to go out and setup their own app engine account so they can deploy shellsink. I'm pretty bummed about this. I have sent a request to google to lift the quota from my application so I don't have to pay, but I don't expect that to work. The only chance I see for shellsink to be saved would be for someone at google who uses shellsink to take the project under their wing so that the quota monster will go away. Bad quota monster!

Update: There is a thread in shellsink's quiet little google group about this.

More information can be found at the shellsink blog.

Sunday, February 8, 2009

The Unicorn of HTTP responses


Hyper Text error codes are generally unwelcome, but there is one error code that is pure magic and some day I hope to see it. That is error 418. Let me share the meaning of the elusive 418.

418 - I'm a teapot

Any attempt to brew coffee with a teapot should result in the error
code "418 I'm a teapot". The resulting entity body MAY be short and
stout.

To understand when you might need that particular error code it helps to know about RFC 2324, which describes HTCPCP, a protocol for controlling, monitoring, and diagnosing coffee pots. So, if your coffee pot turns out to be a teapot you get a 418 and rightly so. Emacs (being somewhat of a unicorn itself) includes a full implementation of the protocol, and there are patches for firefox. Oh dear. I must be going. A rabbit in a waistcoat just ran by and dropped his pocket watch. I'd better return it.

shellsink works for zsh too


If you are a zsh lover you too can have your shell history in the cloud. Check out these simple instructions.

See this post if you don't know what shellsink is.