Code Giants
Posted by Mark at December 17, 2004 03:16 PM
I've been trolling the forums at Processing.org looking at java code samples. Processing (a tool for building graphics applets) has a handy feature to publish an applet to the web, and includes the source code with the applet. By leveraging human laziness -- it's easier to publish the code than to remove it -- Processing is rapidly becoming a mecca of source code snips.
When browsing the many fine demos and virtuoso coding at Processing.org I think of the quote by Albert Einstein "If I have seen farther than others, it is because I was standing on the shoulders of giants". When I look at code -- not code theory, but the actual craft of writing applications and applets -- I don't see many programmers standing on the shoulders of giants. Each programmer starts fairly much from scratch and bangs out algorithms that have been written maybe dozens or hundreds or thousands of times by other coders.
When using Processing we are standing on the shoulders of the authors of that system (a well deserved bravo), but this is where shoulder standing stops. A team of coders writes a system and programmers use that system, benefit from it, but also work within the restrictions of it. This is fair, and valuable, but I'm talking about something else. I'm talking about programmers sharing code among their peers, building on each others code vs. using a tool that has been provided largely complete (ie. flash, shockwave, and to some extent Processing). Cases of shoulder standing among peers are rare and usually involve large projects that attract a lot of attention, ie. Linux or OpenGL.
When I program I typically start with the ideas of others, and perhaps grab some snips of code from a book, and I troll Google for code samples, but rarely do I find a sample that is designed to be reused, meaning it actually works outside of it's original context. In most cases code is hard-wired into the applet it was written in and can't be used anywhere else without substantial hacking.
I teach a beginning programming course at ITP (NYU) using Processing, and one of my students found this class by Robert Hodgin of flight404.com. It looked to be well written and modularized so I tried it out as a case study in reusability.
Called "Meander", the class does exactly that: it moves a point along a semi-random organic path, like an ant exploring a tabletop. What immediately struck me is that this class encapsulates a fairly abstract idea. The class does not encapsulate an ant, or an organism or a ball or any object. It encapsulates the idea of meandering motion. It returns only a point, a pair of x,y coords. It's up to the programmer to decide what to do with that point, and that's exactly what makes it reusable. If Robert coded the graphics right into the class then I'd have to get out the clippers and start snipping wires to remove his drawing and put in what I want to draw, thus creating another un-reusable class. By restricting the class to return just a point the Meander class becomes more usable, not less.
I wanted to use Meander in an OpenGL/Java application, so I tried a simple test. I dropped the class into a Java IDE and compiled it. The compiler found five errors that showed where the class referred to built-in values in Procesing: width and height, keydown, and the noise function. These references hard-wire the class to the Processing applet, but are easy enough to replace with params. To separate Meander from the applet context I needed to:
1) Define a rectangular area in which Meander will work. This not only removes the dependency on global Processing vars but also allows Meander to move in areas that are not equal to the full applet.
2) Define an alternative motion behavior that can be triggered from the keydown event but from outside the Meander class. This removes the dependency on the keydown event and allows Meander's behavior to be altered based on other events.
3) Provide a noise function.
To make Meander a reusable component I made these tweaks:
1) I added four params to the constructor so I can pass in the bounds of the area that Meander will be constrained to. These are floats, since I intended to use this in OpenGL 3D space where coordinates are not limited to whole pixel values. Now Meander can refer to any numeric space without expecting only applet pixel space.
2) I added setTarget(x,y) to switch Meander into a "seek" mode, and removed the keydown reference and replaced with a boolean. Now the class can be switched into different modes without refering to specific keypressed events in the applet.
3) A google search on "Perlin noise" turned up this delightfully reusable class (PerlinNoise.java by Ken Perlin) that takes the same args as the Processing noise function. This class is straight java and compiled with no problems. For my OpenGL app I was able to replace the noise() function with the PerlinNoise class by changing only one line of code.
4) For kicks I made up a wall collision response, and added some variables to clarify the magic numbers that RHwas using. Then I renamed the class to MeanderN to avoid confusion with the original.
The results:
MeanderN.java
PerlinNoise.java
1 meandering line
2 meandering lines in separate areas
To stand on giant's shoulders we need some giants around. I propose that a code giant is not a rocket scientist that produces amazing algorithms. A code giant is anybody that makes code that can
1) be used in many contexts
2) be easily re-worked, scaled up or extended
3) be easily used by an >>average<< programmer
Usually the way to do this:
1) use simpler programming techniques, not more complex.
2) Reduce the features of a component to just what the component is good at.
3) Provide a clear interface that hides complexity.
4) Remove references to outside contexts. Make it self contained.
In this case Meander and PerlinNoise demonstrate how two building blocks can be put together in a completely new context and produce results.
Trackbacks
Trackback for this post: http://www.culturekitchen.com/cgi-bin/movabletype/mt-tb.cgi/2644