Friday, August 31, 2007

Terracotta + Jetty = Awesome

I hate to double-post on one day, but I just had to share this video. I've been following Jetty (the OSS Java application server) and Terracotta (Java clustering) for quite a while. You absolutely must watch this video if you want a glimpse of the future: . Finally the promise of server-side Java is being realized - super-scalability (note the use of Maven too)!

Not only are they smart, but the Jetty and Terracotta people are some of the nicest folks I've ever met in our often soul-less and cut-throat business.

Cheap Tricks V - Pwning Nil

A Healthy Respect of Null

I recently traveled from the over-populated World of Java into the beautifully rustic Land of (professional) Ruby. Like any traveler, I had a few companions (ideologies, habits and conventions) which kept me safe and sound in Java's harrowing landscape. But when I left Java for newer pastures some of those companions trailed along. One of them is named Scary Null.

In Java - null is not an object - just ask it:
null instanceof Object
will be false. Worse yet, attempting to use it for anything other than a place-holder and he'll throw his even scarier friend NullPointerException at you. Over the years I learned a healthy respect for null. He has one and only one job: to hold the place of something. How dare I use null in a capacity for Which He Was Not Intended!

A Healthy Disrespect of Nil

In Ruby Land, however, he has a cousin: nil. But nil is not a fearful beast like null. Nil is a charming little scamp, a first class object that does her best to help you out. This took some getting used to for me. I'm so used to writing code like this in Java:
int i = str == null ? 0 : Integer.parseInt(str);
that it almost feels awkward to do it the Ruby way:
i = str.to_i
In the back of my mind I think: "Eric, what are you doing! What if 'str' is nil? I'll get an exception!" Au contraire. Since nil is a real object, it doesn't throw exceptions - nil is an object of the type NilClass which implements plenty of useful methods, like:

  • &

  • |

  • ^

  • nil?

  • to_a

  • to_f

  • to_i

  • to_s

  • to_yaml

Let's take the first three: &, | and ^. Since those are respectively "and", "or" and "xor", you can imagine what nil represents: false. That makes code like this possible:
c is true. No exception. If I was smacked upside the head with a board and the ensuing brain damage caused me to want nil to throw an exception in this situation, I could always override the method in nil
The other methods are equally kind. nil.to_s (to string) returns "" (empty string), nil.to_a (to array) returns [] (empty array), and my favorite nil.nil? return true - and is the only object that does.

Bring on the Fun

Nil is fun, but so what? If I attempt to use a method that doesn't exist, I'll still get an exception! True. However, since we know that nil is a real object, and since Ruby can override object implementations on the fly (weee!) we can also add methods to nil.

Consider the following code, that iterates until a string is constructed that is over 10 character long, then returns the string:
It outputs:
la
lala
lalala
lalalala
lalalalala
lalalalalala
Did you see something wrong with that picture? Not if you are from the World of Java. Initialize a variable, iterate, append and finally return the value on the correct conditions. But:

Why declare a variable that we only use inside the loop and return? Why indeed. Let's try it again without declaring the variable.We get an error :(.
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.+
Oh - it looks like Ruby requires us to define variables first. And since str += "la" is the same as str = nil + "la" when str is not yet defined, it makes sense that it complains.

But wait! Re-read the last sentence. Of course! Ruby thinks that str is nil, and is attempting to append the string "la" to it. So what would happen if the nil.+ method was declared? What if it just returned whatever was passed to it?
def nil.+(o)
o
end
Now we're cooking with gas! Try and run the above code now. It works(!) since our nil.+ method just set str to "la". For each successive loop, str just uses the standard string append method instead.

There are a few methods I like to add to nil. Just create a file named "safe_nil.rb" in your library, and add it like any requires.
Now you can safely do things like this:instead of

Wednesday, August 29, 2007

Code Te Ching - Verse 29

Heaven and earth may be unkind,
but coders should not be treated as such.

The wise manager treats his coders
not like straw dogs,
not like straw puppies.

If quality is the goal, you must do as the wise do:
Respect the coders who make the real profit.

Monday, August 27, 2007

Convention over Configuration

Convention over configuration has been out in mind-space for a couple years now, yet unlike the Agile Manifesto, I have not seen any roadmap on how a project can achieve it. This is a gap in human knowledge. Since I love nothing more than to fill gaps on my free time, here are a few principles recurrent in my work with two of the top CoC-based projects: Ruby on Rails and Apache Maven.

I. Conventions are emergent.

Sitting down beforehand and designing a convention is only useful as a touchstone, a point of reference, and should only appear out of practical experience with many real-world examples. Any convention not born of real use-cases is doomed to failure. Don't be afraid to throw away "flexibility" in the beginning. Maven 2 had to fight through the pain of Maven 1 before it got it's modern architecture, and Rails stood on the backs of years and years of experience, the dynamics of the Ruby language, and still several versions.

II. Lack of a real example for a convention is the strongest argument against it.

The burden for denying change should not depend on counter-examples - the lack of an example is enough for denying a convention creation/change.

Here is an example: someone recently wanted to make a fundamental change to Maven but could not provide a valid use-case for it to be so. The arguer would not let the matter drop until someone came up with a counter-example on why the change would not be good. This should not be the case. The fact that the arguer could not come up with an example for the change should always be enough to discount the idea. Hypothetical "well - in the future we may want to..." answers are not examples - they are hypotheticals... refer to point 1.

III. A convention should provide as few ways to do a single task as possible.

This is the exact opposite of configuration - which states that the best configurations allow you the flexibility to do whatever you want. Convention should have an opinion - this is the correct way to do this action.

Fewer options are easier to communicate and learn. There are already a Vast scope of options - it is simpler to conceive and convey when there is only one or two ways to execute a specific task.

IV. Conventions should have a narrow scope.

Don't go too far. A large complex convention must be managed, and managing them requires more configuration, which negates the purposes of the conventions, to wit.

Ruby on Rails is a great example of this. They provided a few useful tools and a way to extend those tools via third party plugins. Rails itself is surprisingly simple - it is the large number of plugins that makes it powerful.

V. When in doubt, simplicity.

This should go without saying - but it doesn't. A simple convention should always win out over an equal but more complex one - despite the perceived add power. Assuming conventions are emergent and should have a narrow scope then conventions will, over time, become more focused on solving precise use-cases. Complex conventions which attempt to solve a wide-berth of problems are harder to manage, and thus, the convention is wiped-out due to necessary configuration complexity. Good conventions should work out of the box.

Friday, August 24, 2007

Cheap Tricks IV - Colloquy Command Extension

Nothing big today, except how much fun I have on a daily basis, making toys like the following. If you have a Mac and use IRC, you must have Colloquy - there is literally nothing better until 2038 when our robot overlords do away with IRC forever. Until then, it's trivial to make extensions like the following:
function viewMessage( body, connection, view ) {
var msg = new JVMutableChatMessage('', connection.localUser());
msg.setBodyAsHTML(body);
view.sendMessage(msg);
view.echoSentMessageToDisplay(msg);
return true;
}

function processUserCommand( command, arguments, connection, view ) {
if( command == "rtfm" ) {
switch( arguments[1] ) {
case "air":
return viewMessage("http://labs.adobe.com/wiki/index.php/AIR:Documentation", connection, view);
case "maven":
return viewMessage("http://maven.apache.org/guides/index.html", connection, view);
case "google":
return viewMessage("Google it! http://www.google.com", connection, view);
default:
return viewMessage("RTFM!", connection, view);
}
}
return false;
}
You need to copy the above code into a plugin file (RTFM.js) and put it in a Colloquy plugin directory
~/Library/Application Support/Colloquy/PlugIns
/Library/Application Support/Colloquy/PlugIns
/Network/Library/Application Support/Colloquy/PlugIns

The Javascript hook is in the processUserCommand method. This one I created out of frustration with repeating myself - answering questions with the answer "RTFM", then posting a link to said "fucking manual":
/rtfm air
Will output a link to the AIR documentation of the following style onto the current channel:
http://labs.adobe.com/wiki/index.php/AIR:Documentation
As I said, nothing big. All of the details are here - though documentation could really improve... I had to read through a little bit of Objective-C to even figure out the above.

Thursday, August 23, 2007

Cheap Tricks III - Installing Groups of Gems

Having a small ruby team, it is sometimes useful to get moving quickly by throwing a list of required gems at them. Our list was getting a tad long to manage manually, so I wrote a little script to automate installation of gems - the list resides in a YAML file of the following structure:
gems:
# FasterCSV is CSV, but faster, smaller, and cleaner.
fastercsv: '1.2.0'
# An implementation of SOAP 1.1 for Ruby.
soap4r: '>1.5.5'
# Client library for the AdWords API.
adwords4r: '0.7'

And here is the script. Use it by typing ./gems_install.rb gems_file.yml
#!/usr/bin/env ruby
require 'yaml'

exit if ARGV.empty? && (puts "usage: gems_install.rb [GEMS_YML_FILE]").nil?

def gem_install(gem, version)
puts `sudo gem install #{gem} -f -y -v '#{version}'`
end

YAML::load_file(ARGV[0])['gems'].each { |gem| gem_install(gem[0], gem[1]) }

Short and useful, just like me :)

Wednesday, August 22, 2007

Code Te Ching - Verse 28

To know Code is to know the abstract.
To know code is to know the real.

How do we know the abstract?
    Mathematics.
How do we know the real?
    Engineering.
How do we realize both?
    The Machine.

Math without engineering is fruitless.
Engineering without math is expressionless.
The machine without both is lifeless.

Therefore:
Code gives pure math a purpose.
Code gives engineering expression.
Code gives the machine life.

Friday, August 17, 2007

Maven Less Ugly

OK - I know I said I wanted to clean up the POM this summer. Well, the season wanes and it is still not done... mostly because I am barely involved with the Maven project these days, though I am apparently still speaking at Apache Con US, OSSummit in Hong Kong, and will talk at the St. Louis JUG on Sept 13 -- but mostly to fulfill promises. Speaking of promises, here is something I whipped up two nights ago whilst at the AIR Bus Tour.

It is a YAML to POM converter:

Cool, eh? It converts a nice little compact YAML file into a giant ugly (and I do mean ugly) POM file.

For example - this concise 37 line "pom.yml" file:

Notice the profiles using a node reference (&core). This is a built-in YAML feature which makes it trivial to reuse giant redundant blocks of configuration, and only overwrite the values you want (in the example above, we overwrite the profile ID to be "test".

Gets converted to this 103 line pom.xml mess by running ./yaml2pom.rb pom.yml:

Not a great example, really. It's nicer if you have a mountainous dependency list. Also, it'd be cooler if the POM wasn't nigh-gobbeldygook. Of course - you shouldn't really need to manage the POM xml if you use this script (and IDE integrations) anyway.

You know - if you really wanted to be slick, you could add something like
exec "ruby yaml2pom.rb pom.yml"
to your mvn (or equivalent mvn.bat version). Then you could make projects with pom.yml files instead of pom.xml... the script will just generate pom.xml prior to execution.

Naturally, it helps if you know YAML.

Thursday, August 16, 2007

80 Columns, Unwillingly Continued...

Wow - who knew I'd have to write about this again so soon - if ever. Please understand, I'm not advocating lack of style. I'm not an anarchist, just a fan of practicality. And practically speaking, most people code on monitors made past 1988.

Time for an example.

I didn't write this code, but here is an example - I searched for all of 10 seconds to find it, I'm sure there are worse ones in our system:

Do you see that? One < 80 column wrapped line - one unwrapped line.

The "data" line is 56 columns wide. Can anyone tell me what the point of wrapping this line was? I know! habit. Were the second line not wrapped, it would have been 104 columns wide - still shorter than the next line. The "out" line is 107 columns.

Let's first try and cram that into an 80-column-width cheerleader's wet dream (I'll even be kind and add spaces):

Now let's keep the above spacing. Some people seem to think I'm advocating no coding standards whatsoever - well, plain not true.


One operation per line. Concise - easy to understand. Get client body, send that body as a soap message, parse the data. No added lines, no added breaks, no added complication just to keep everything crammed into a weird artificial and archaic constraint.

When looking through thousands of lines of code for the first time, I always prefer chunks of code that each execute a single step. I don't care that the regular expression is one long line - because in normal maintenance, I'll never need to know. In the off chance I do need to know what the expression does, well, I'm going to have to read it anyway - but I have to find it first.

Just don't miss the forest (overall project code) for the trees (individual lines).

Finally Maven Help is Helpful

Thank you, John, for applying the patch! Finally the maven-help-plugin is actually, well, helpful.

So, next time you have a Maven plugin and you want to know all of its available goals, just type (assuming you want to see the maven-ear-plugin):
mvn help:describe -Dplugin=ear -Dmedium

And you'll be in for a treat.

I wish I could add that kind of information to my book but, alas, I cannot.

Wednesday, August 15, 2007

Floating On AIR

Well, I'm currently at the Adobe "On AIR Bus Tour" in St Louis, MO. For those who have never heard of AIR, allow me to enlighten: AIR (Adobe Integrated Runtime - formerly Apollo) is Flash, Flex, and HTML/Javascript all bound together into a common runtime that is - get this - runnable on your desktop (Windows and Mac only for now, but Linux is coming in a few months)!

I'll go into it later in detail, but in a nutshell, imagine an environment where you can take all of your cool web Flex apps, or cool Web 2.0 JavaScript/HTML apps, and run them as their own process on your desktop outside of your browser... oh yeah, with full access to system resources (like, say, highlighting a table and dragging to your desktop and *poof!* magically it turns into a Spreadsheet file). Think SWT - but written in ActionScript, or Flex, or JavaScript/HTML... not yucky Java.

There is also an awesome competition for whoever can create the best AIR application by September. I wanted to create a web server - but apparently AIR beta cannot yet bind ports. Ah well, better come up with something new... those prizes are just too sweet to ignore.

Tuesday, August 14, 2007

Code Te Ching - Verse 27

These words are dull compared to process,
    But nourishing.
Just as water is bland compared to wine,
    But nourishing.

When process management robs the manager of the task at hand
When false structure blinds the coder to real uncertainty
When confident release dates fool the customer into believing them
This is the path of static process.

When the manager listens to his developers and reduces friction
When coders collaborate with the customer and keep focused
When the customer is integral to development and open to change
This is the path of least resistance.
This is the superior way still of Code.

Horse Asses are 80 Columns Wide

When I was younger my dad told me a story - which I deign to say sounds somewhere between half- and un-true (as most of his stories tended to be). It went something like this:

When designing the first rockets, early engineers had to consider transportation along the ground to their destinations. They chose to make the boosters half the width of the road so they could be loaded onto a truck and transported after manufacturing.

Trucks - as it were - are limited to the width of the road and were originally built to be of similar width to train tracks, which until the advent of automobiles were the only long-distance terrestrial transport available and a spacing-unit comfortable to those who manufactured the first cars and roads.

Trains and carriages were of a similar width - having descended from old European standards which were based on their roads which were patterned after the roads first carved out by the Roman Empire.

The Roman roads were little more than solidified paths which were packed by the grooves made by chariots - which of course were merely the width of two horses.

The punchline of the joke was something like "This goes to show that engineers just follow the horses asses that came before them."

Good story, eh? Its truthfulness notwithstanding - it makes a good point. I have a term for it - I call it "trimming the ham". Since I already have my slippers and pipe, and you, nestled by the fireplace in love-worn jammies, I'll spin another yarn.

There were once two college roommates, preparing their first big meal out in the world on a crisp fall day. Like any intelligent and innocent country girls, they decided that a ham would make a super-duper centerpiece to their array of delicious and healthful accouterments: baked beans, salad and cornbread. Before placing the ham in the pot, the sweet, amateur cook took a large knife and proceeded to cut the ends off - safely of course.

Her roommate - a curious girl with golden locks and a chocolate brown complexion inquired innocently: "What the fuck are you doing?"
"That is how you cook a ham. You trim the ends off before cooking."
"That's fucking crazy. I've never seen that shit," she replied coyly.
"Watch your fucking mouth," the cook suggested.
"Fuck you!" The golden-hair girl objected.
"Fine - I'll call my mom and we'll settle this. I bet 20 bucks I'm right."
"You're on, bitch!" Goldilocks agreed to the proposal.

So they skipped off to the public phone where the girl with golden braids and the cook called home.
"Hey mom, is that you?" She said into the phone. "Shut the hell up Sissy, and put mom on the phone you little brat!" she added, cheerily.
"Mom - you cut the ends off of your ham, right?" pause, "OK, so you do?" The black girl with the golden hair frowned. "I see - grandma does it that way too? Uh huh... she is a great cook... OK... yeah, thanks mom - bye... Please send money," she added with love.

The ham chef beamed with pride and informed her lovely roommate that, "You see? I told you, I fucking told you... now give me my twenty bucks."
"Listen," she nodded, "Your mom, you, even your granny are all nuts."
"Twenty... dollars," she repeated, ready for her congratulations.
"OK - enough of that shit," Goldie interjected. "Let's call your Granny - I gotta know what's wrong with your family."

So back to the phone the happy chef turned - this time to ring her loving grandmother. This time, she held the phone up so both could hear.

Ring ring... ring ring... ring ring

"Old people," she said with familial pride, "sleep all the goddamn time." Eventually the phone picked up.
"Hello"
"Hi Granny!" She shouted courteously
"Oh hello Deary! You know, I was just talking about you the other day to Mildred, you remember Mildred, right? Well - you know what her grandson is doing..."
"Sounds good Granny," she interjected, "Hey, I have a cooking emergency I need some help with."
Grandma cooed on the other end of the line.
"You cut the ends off of hams, right? Mom said you did."
Grandma laughed, "Oh dear - I haven't done that in years! I don't do that anymore."
The cooks grin and Goldie's frown switched places. "Why not?"
"I have a larger pan now. You see, Dear, I cut the ends off to fit in my old small pan."

Did you enjoy that? I hope so... a modern classic if I say so myself (which I don't). The moral is quite clear, though - "because it's always been that way" is no excuse to continue doing stupid things. Find out why, then adapt to new circumstances. Common wisdom - it seems to me - is rarely very wise.

Do I have a point? Sure. 80 column width programming. Stop. Please, oh please, for the love of Jesus Helguera (Google it) stop adhering to this outdated standard. I have worked with - oh, about 25 different programming teams over the years - and a disturbing majority are obsessed with that 80 column thing. It made sense back with old fixed-width displays, it even made sense a few years ago when people coded via telnet+vi. But not anymore. I hear the same damn arguments: but what if someone needs to connect and edit code in a terminal? You want to know my answer? Fuck 'em. It's 2007 - even terminals can stretch further than 80 column width anymore. Besides, why let those highly unlikely, exceedingly rare situations dictate standards? All editors these days can scroll right or autowrap - only retards and Satanists code remotely. Seriously... all non-trivial projects should have version control. Check out the damn code. If you find yourself modifying code via ssh+emacs (et al), you're probably modifying live code which is punishable by defenestration in some circles.

I'd rather a line be a single operation, even if it is 300 columns long (I have a 23 inch cinema display... are you a professional programmer? yeah, then you should too) even if I had to scroll. If you are a halfway decent coder those rare long lines should be far and few between - making the rest of your code more readable overall.

"But Eric, I travel a lot and have to code on my tiny laptop." Yeah, me too, but most people don't. Don't you care about them, you selfish punk? Please, think of the children.

I just started a new job last week, and I see a weird mix. Some lines are 150 columns wide, and some are broken into max 80 column chunks. Why?

Justkeeptypinguntiltheactionthatmakessenseasasingleoperationisdoneevenifitmightbealittlelongatleastthenitsasinglelineandifpeoplereallycaretolookatallofhtedynamicsoftheactionthentheycanscrolloffthesideofhtescreenjustthatonetime.

Of course, that whole thing fits on my screen - but even if it didn't at least I know it's one operation. Now if you'll excuse me, I need to find my medication.

Monday, August 13, 2007

Cheap Tricks II - Finding Maven Artifacts

It's not always easy to find out projects supported by Maven or what their IDs are. Despite repeated promises by the core team that "we're working on it" progress has been slow (read: not being made) on an open source (hell, even a commercial) solution.

But don't worry - something already exists: http://www.mvnrepository.com/. You can even subscribe to its feeds to find out when new artifacts are added. Just search for something you want (eg. junit) then a list of all matching artifacts will appear. Select the version you want and you'll be treated with the actual dependency configuration for your pom:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.3.1</version>
</dependency>
Word of caution: it points to ibiblio which has not been the central repository for a year. The real core repository is http://repo1.maven.org/maven2.

Sunday, August 12, 2007

Code Te Ching - Verse 26

Good coders leave no tracks
Good strings need no pointers
Good variables need no comments

Good systems have no security
    yet cannot be forced.
Good code has no pointers
    and cannot overflow.

In this way the coder:
    Always thinks of completeness and ignores none.
    Always thinks of extension and ignores none.
This is called thinking widely.

Therefore the good coder is
    the bad system's trust
And the bad code is
    the good system's "moment to shine."

Not to value the system
Not to love the code
Can drive the genius mad with despair.

Friday, August 10, 2007

Cheap Tricks I - Maven Offline

I've decided to pepper my unhealthy obsession with posting Code Te Ching, comics and really long articles with short little snippets and tricks. Nothing fancy, just because I like you (and I really do).

If you find yourself having to run Maven offline, the -o option is what you want on the command-line.
mvn -o compile
However, if you want to stay offline, there is an option you can add to your settings.xml file to ensure it (which is also ready by Maven IDE integrations).
<settings>
<offline>true</offline>

<!-- ... -->
</settings>
This is all well and good as long as you have already downloaded the artifacts you needed. You can do this before hand by going to your project and typing:
mvn dependency:go-offline

Thursday, August 9, 2007

Code Te Ching - Verse 25

The weak mind leans on the collective.
This is known.

The weak coder leans on meetings.
This is ignored.

Beware the frequent meeting caller.
His mind does not work alone.
Because he has little to contribute.

Do not mistake time clocked as progress.

Tuesday, August 7, 2007

Code Te Ching - Verse 24

There was something formed out of chaos
That was born before the network and the computer
Quiet and Still! Pure and Deep!
It stands on its own and does not change
It can be regarded as the mother of the network and computer

It is abstractness.
Were I forced to give it a name, I would call it "mathematics"

"Math" means to "symbolize"
"Symbolize" means to "abstract"
To be "abstract" is to be "mathematical"

Abstract is math.
Network is math.
Computer is math.
Programming is also math.
There are four greats, and programming occupies one place among them.

Programming sets a computer;
Computer makes the network;
Network is abstracted;
And the abstract is that which is so on its own.

Monday, August 6, 2007

Job Jumping should be an Olympic Event

I've started my new job today at Landing Media. Big deal, right? Wrong. Dead wrong. This is not your average programming position (but it should be). This is my .COM dream. This is what drove me into this field in the first place: free lunch and free coffee, a staff of 20-somethings, awesome hardware (their first question to me was: So what do you want? I replied: I want an Apple Cinema display for my new Macbook Pro. Someone ran to the store, 2 hours later I have it all unpacked and set up), awesome software (we run Ruby on Ubuntu - processing very large datasets), and work doesn't start before 10 AM... not even the CEO is here until 11. Moreover - I still get to do my scheduled speaking engagements (St. Louis JUG, Apache Con US, and OS Summit in Hong Kong). Unlike my previous job I actually get paid for it.