Wednesday, November 21, 2007

The Eyes Have It

Software usability has really benefited from the latest and greatest digital technology for eye tracking. If you are not familiar with eye tracking, it is exactly what it sounds like: a camera watching where the user's eyes are focused, and matching that to the screen to identify what the user is REALLY looking at, for how long, and in what order.

Here is a really great summary called "Scientific Web Design: 23 Actionable Lessons from Eye-Tracking Studies" that collects information from several different studies, and packages it up into something pretty, dare I say it, usable.

It is really worth it to read the whole thing, and it is pretty short. Here are a few highlights that got my attention:


  • Text attracts attention before graphics

  • Fancy formatting and fonts are ignored

  • Type size influences viewing behavior

  • One-column formats perform better in eye-fixation than multi-column formats

  • Lists hold reader attention longer

  • Navigation tools work better when placed at the top of the page



There is so much more to UI than drawing a pretty picture. Applying some science to the art of user interface design can result in something truly beautiful.

Monday, November 19, 2007

Werewolf vs. Vampyre

I had read with mild amusement the minor dustup over the craze of Werewolf players at RubyConf 2007. If you don't know what it is, you can read about it here.

Some people just really enjoy playing social games. Let's call them the Werewolves... you know who you are, even if the rest of us do not.

Other people, however, view RubyConf as a place to get together with the other commiters on their beloved project, stay up all night, and crank out a new release before their presentation the next day. Let's call these people the Vampyres... subsisting on mysterious red liquids, and notable for the pallor of their skin.

So what is the problem? Can't we all just get along? Not really, cause these two sub-species have very different priorities and modus operandi. Werewolves come out in droves when the time is right (full moon). They operate as a pack, sniffing out things and then chasing after them collectively.

The Vampyre is by nature a bit more cliquish. You simply cannot have a pack of wild creatures committing patches without *some* kind of arcane ritual involved. You can call it merging branches if you want. There is usually a coven of Vampyres, with a charismatic leader surrounded by younger creatures.

I go to a conference to hang out, drink a few beers, and then go to bed to rest from the inevitable time zone changes. If I want to get into a big social hoopla, I just go to soccer practice. On the other hand, if I want to stay up all night programming in a group, I can certainly go do that whenever I want. Personally, I do not find group programming at all efficient, but if someone else does, go for it.

I feel like a covert human thinking he is hidden among these undead creatures. If the Werewolves and Vampyres want to get together in order to get down, by all means they should. Just don't get stuck in the middle!

Sunday, November 18, 2007

RubyConf 2007 - Day 3

As day 3 of RubyConf 2007 began, the breakfast buffet had to remind us of its presence. This time, it was the main sound system that was taken out by the ultra-powerful toasters. When Dr. Nic was asked if he wanted to get started anyhow, he had to give two of his charmingly nasal "No" rhymes with "Pow" before MC David Black caught his meaning. This gave some of us a moment to try to catch up on the flurry of RubyConf blogging. Not that you could tell that from the extreme lateness of this post. But enough of my feeble excuses.

Finally, Dr. Nic took the stage, and gave an entertaining if kitschy presentation of his new RubiGen generator to make generators. The whole "A-team" gimmick was over the top enough that Dr. Nic himself admitted by the end how he looked forward to retiring it. All I can say is "curse you for planting that theme song in my head for over an hour". On a better note (ouch!) this is for sure some useful stuff, and I will no doubt be doing some "generatin'" of my own coming up soon.

Next up was "Behavior Driven Development in Ruby with RSpec". Although the presentation was not as flashy as the first, it was full of great information presented by smart guys who really know their stuff. I did not know Dave Astels, and although I have spent some time hanging out with David Chelimsky, I don't know him half as well as I would like to. Watching their live demo of ping-pong programming on stage made me wish that I had someone really, really good to pair with these days. It looked fun!

For a former Fitnesse junkie like myself, the syntactical sugar applied to testing of requirements that is Behavior Driven Development using RSpec is really appealing. I really don't know why some really smart people like Chad Fowler and Ryan Davis are not into it. I suppose that I have spent a lot of time with trying to sync up a customer's need with some custom software that was being written, and so the merger of domain specific languages and executable specifications is just particularly compelling.

The last of the three main sessions was Jay Phillips presenting "Adhearsion - Sane VoIP Development". Way back when, I did some telephony stuff on ancient evil AT&T System V boxes, so I have followed from afar the wild and craziness of VoIP with the jaundiced eye of one who has gone there before, and came back having lost half of the party. Poor Vonage... ahem. That said, the Adhearsion project taking a Rails-like approach to the stinking morass that is anything related to telephony is rather ingenious. I think much of the crowd will never use any of this stuff, but it was really neat. I wish Jay luck in his quest!

After the main presentations, I decided to keep close to the cutting edge, and see what the Google Summer of Code hath wrought. Amusingly, I must not have been the only one to lack major interest in the other sessions, cause the Goog room was full up on the "everyone who is anyone in Ruby" crowd. Can you say "time to catch up on feeds"?

Of the Google SOC projects, I cannot remember much. I was most impressed by one student's charming honesty. It would seem that the project hadn't really gone all that well, and the work produced didn't seem like anything usable. But he had learned quite a lot. I think we often forget the value in so-called "failure", cause we of course only extol the virtues of success. But Edison's remarks on failure are instructive, and I took from this kid that he was going to be a lot more ready for real-life programming challenges as a result of his experience. I was a lot more impressed by that than some well-crafted but uninteresting code library that I will probably never use.

The last session of the day for me was Aaron Bedra's extremely cool "Sploitin' With Ruby". It you do not know about Metasploit, it is a security research nee hacking tool, that is written almost entirely in Ruby. Taking an open-source, very plugin-oriented approach allows security professionals and outgunned system administrators to try to keep up with the R & D budgets of black hats, who these days have major economic incentives to hack your systems. Anyone who knows anything about security knows that these is no such thing as a secure operating system. That said, it was pitiful how easily you could probe for these exploits using Metasploit, without even knowing a fraction of what would be required before the invention of such tools.

I just hope a bunch of the people who were making dumb comments in the room understand that breaking into your own computers to test them is smart, and a great way to harden your defenses against various nasty people. Breaking into OTHER people's computers is a recipe for a stay in federal prison.

After the fun and games, I had to join the throng of taxi-seekers and head for the airport. RubyConf 2007 had been great, but now it was time to get back to the enormous piles of work that had only grown in my absence. RubyConf is a fantastic fun time, and a real inspiration to many of us. I will most certainly be back again next year, assuming that my finger is quick enough on the mouse to grab a seat.

Tuesday, November 06, 2007

RubyConf 2007 - Day 2 - "The Ruby VM Smackdown Begins"

As the sun rose over the hills of North Carolina, the quiet betrayed a seething fire blazing in the hearts of three development teams. "Three teams enter, one team leaves!" Yes, I am talking about the main event, people, the one, the only, Ruby VM Smackdown! The room was jam packed, the anticipation was high.

As good fortune would have it, I was sitting right next to the head of the team who was my personal favorite to win the day. Yes, I am referring to Evan Phoenix, leader of Team Rubinius along with co-conspirator Ryan Davis. You should have seen the look at their faces when the JRuby team showed the Rubinius RSpec test suite as part of their demo! But I am getting ahead of myself...

I like the underdog in a fight, when the underdog is tough, and under-estimated by their opponents. On one side, the resources of Microsoft, on the other, the full power of Sun. And then, THE LADS. If you don't want to see that one go down, you have no passion for the cutting edge of innovation. And if you do not know about the history of innovation in the software industry, you might miscalculate the odds. Gentlemen, to your corners... I want a clean fight!

MC Chad Fowler got up, and gave a brief intro to the show. "We are about to see what Matz called 'wonderous' last night," he said. And it was true.

First up, was John Lam of Microsoft with IronRuby armed with "State of IronRuby".

Next, Charles Nutter and Thomas Enebo of Sun with JRuby using "Ruby for the JVM" style.

Last, the challenger, Evan Phoenix with Rubinius wielding "Rubinius 1.0".

Wow. Bread and circuses, indeed!

I will be posting individually about each of the Ruby VM contestants, and will update the above links when I am done...

After all that excitement, the crowd was starved. We shuffled out to eat our lunches, and converse on all we had seen. From everyone I spoke with, the mood in the crowd was firmly in the Rubinius corner, with a close second to JRuby, with third place probably going to YARV. Hardly anyone I spoke with at RubyConf had any interest in using IronRuby at all!

That is to be expected from a conference like RubyConf, well known for its strong ABM (Anything But Microsoft) attitude, which is pretty unfair. That said, I think the uptake in the .NET community will be the measure of the success of IronRuby, not whether they can get the typical RubyConf attendee to switch back to Windows.

In the afternoon, I got to see some great sessions, from:

"Refactotum: Ruby" - Stuart Halloway
"Maximizing Productivity" - Eric Hodel
"Mac OS X Loves Ruby" - Laurent Sansonetti

I will be posting individually for each session when I get a chance, and will update the links here.

Once the afternoon's sessions had wrapped up, a large group of us overran a local BBQ joint named Mac's, with tasty BBQ, a great beer selection, and a bunch of Harleys in the parking lot. Despite our somewhat atypical appearance (nerd chic) for NC, we were welcomed warmly by the locals. There must've been 30+ people from RubyConf there, it was great!

We then returned at the perfect moment to hear Matz's keynote speech. And it was good. Really good. Matz is charming, and quite funny. His wit was so much better able to emerge in a forum where he was simply presenting, rather than the somewhat less successful "town hall" format that had been attempted the evening before. I have a separate posting with his remarks which will be up later:

RubyConf 2007 - Keynote by Matz

Once the keynote had ended, I just had to go up and shake the man's hand. I know it may be corny, but I really did suddenly appreciate what he really does, which is to inspire the community. People keep looking to Matz for all the answers, but the answers are up to us, my friends. No superheros, remember?

Afterwards, I want to the legendary RejectConf, held right next door. Don't ask me how I wedged my way in, but I did it. To everyone who's toes I stepped on: sorry! There was a fun series of lightning talk (5-10 min) presentations of pretty much brand-new stuff. The beauty of RejectConf is its appeal to the ADD'd-out techno-junkie: every few minutes something else. I will be posting a rundown of RejectConf when I get a chance here:

RubyConf 2007 - RejectConf

RejectConf was really a great highlight of RubyConf. Once they kicked us out, the entire crowd immediately migrated directly next door to the hotel bar where we drank beers and chatted loudly about techno-babble to our great enjoyment. I staggered up to my room, to rest up and prepare myself for Day 3.

Monday, November 05, 2007

RubyConf 2007 - Day 1 - "Advanced Ruby Class Design" - Jim Weirich

Jim Weirich is a very smart guy. So smart that his presentation was not about complicated classes, but about Ruby itself and how to take advantage of it to simplify things. Jim's background in computing is long and varied, something like a history lesson in programming languages. Here is the abbreviated list:

FORTRAN > C > Modula 2 > C++ > Eiffel > Java
and in parallel to this:
LISP > FORTH > TCL > Perl

Jim got started programming taking an introduction to FORTRAN class that just so happenened to be taught by Daniel Friedman, author of "The Little LISPer". As such, they studied LISP for the first half of the semester. They did finally get around to FORTRAN, where Jim learned firsthand the adage:

"A real programmer can write FORTRAN (Java) in any language"

Jim took us thru three examples that illustrate some very cool techniques to use as part of elegant class design in Ruby.

Box 1. Rake::FileList
Everyone knows and loves Rake, right? Rake::FileList is like an array but:
- can init with GLOB (an array of filenames, created using a pattern match expression)
- has a specialized to_s
- has extra methods
- uses lazy evaluation

In his first cut, Jim derived from Array:

class FileList > Array
...
end

Here is the first implementation for FileList:

class FileList > Array
def initialize(pattern)
super
@pattern = pattern
@resolve = false
end

def resolve
self.clear
Dir[@pattern].each do |file|
...
end
end
end

The problem is this:

f1 = FileList.new("*.c")

won't work, cause we never call "resolve". What we need to do is to do some lazy loading to "auto resolve", like this:

def [](index)
resolve if ! @resolve
end

Lots of methods need to call resolve in this manner... which is a problem that Jim solves later using a little metaprogramming.

But there is a another problem with the current implementation. This is OK:

f1 = FileList.new('*.rb')
f1 + ['thing.rb']

But this is NOT:

f1 = FileList.new('*.rb')
['thing.rb'] + f1

Why? Because the + method requires passing a literal array to it as an argument, not an object of class Array. If only there was a way for an arbitrary object could indicate that it wants to be treated like an array... ah, but there is! The "to_ary" method was designed to do exactly this. The problem is you cannot call the to_ary method on an Array. The solution is not to derive the FileList class from Array, but instead to use the "to_ary" method to access an Array that is encapsulated into the FileList class.

Another shortcut is instead of calling resolve on each method, using some metaprogramming to add the "resolve" call to every method that might need it, like this:

RESOLVING_METHODS = [:this, :that]
RESOLVING_METHODS.each do |method|
...
end

The big lesson here is when trying to mimic a class, use "to_ary" and "to_str" rather than inheritance.

Box 2 - The Art of Doing Nothing
Builder is a very cool library which is part of the standard Ruby library to create XMl files, but using a friendly Ruby syntax. Did I mention that Jim is the original creator of Builder? Here is an example of Builder in use, if you are not familiar with it:

xml = Builder::XmlMarkup.new(:indent =>2)
xml.student {
xml.name("Jim")
xmp.phone_number
}

Builder uses method_missing to construct tags. This works really well... except what happens if you try to use it with a predefined method? method_missing will not work anymore, since the method is actually there.

Jim solution is to "inherit from Object without actually inheriting from Object", a class he calls BlankSlate. We want to have our Builder class inherit from BlankSlate, instead of Object.

class BlankSlate
instance_methods.each do |method|
undef_method(method)
end
end

That does indeed get rid of all of the methods on the class. But that does not work, because there are some internal methods that Ruby needs that we do not want to get rid of, so we extend the class to this:

class BlankSlate
instance_methods.each do |method|
undef_method(method) unless name =~ /~__/
end
end

This is not the only problem, however. Since in Ruby classes are open, we can also extend them using Modules.

require 'blank_slate'

module Kernel
def name
"hi"
end
end

xml.name("Jim")

class BlankSlate
def self.hide(method)
...
end

instance_methods.each do |method|
undef_method(method) unless method =~ /^__/
end
end


module Kernel
class << self
alias_method :original_method_added, :method_added

def method_added(name)
result = original_method_added(name)
BlankSlate.hide(name) if self == Kernel
result
end
end
end

We will need to do something similar for Object, in order to avoid the same problem. So are we done? Not quite, there is still one more thing... but I didn'y quite catch what it was! I will update this when Jim puts his slides up:

require 'blank_slate'

module Kernel
def name
"hi"
end
end

class Object
include Name
end
...
xml.name("Jim")

Hint: Use #append_features to modify open classes.

Box 3 - Parsing Without Parsing
ActiveRecord is a wonderful abstraction to use, but why is it that we use such a non-Ruby-like technique to select records. For example, we would use this in Rails:

User.find(:all, :conditions => ["name = ?", 'jim'])

Versus using a more standard Ruby language enumerable approach, like this:

user_list.select { |user|
user.name == "jim"
}

Wouldn't it be nicer to do something like this:

User.select { |user|
user.name == "Jim"
}

Jim starts out with a naive implementation, like this:

class User
def self.select(&blk)
find(:all).select(&blk)
end
end

There are several problems, not the least of which is that the above code is far from efficient. A large set of results will use an enormous amount of memory.

Jim then goes on to show a properly "magic" implementation:

class User
def self.select(&blk)
cond = translate_block_to_sql(&blk)
find(:all, :conditions => cond)
end
end

How to implement the magic translate_block_to_sql method?
- write a parser yourself
- Use Parse Tree (Ambition project)
- Just execute the code in the block

As one might suspect, the answer is of course "just execute the code". In other words, create appropriate methods that are called when the block is executed to return the correct SQL conditions clause for the query. Let me warn you, dear reader, that I typed as fast as I could, but some of the code examples here are a little incomplete. As soon as Jim posts his slides online, I will revise and complete them.

class User
def self.select(&blk)
cond = translate_block_to_sql(&blk)
find(:all, :conditions => cond)
end

def translate_block_to_sql(&blk)
instance_eval(&blk) # this is not exactly the code, but I couldn't type fast enough!
end
end

class MethodNode < Node
def to_s
...
end
end

OK, now what about the "==" operator?

class Node
def ==(other)
BinaryOpNode.new("=", self, other)
end
end

class BinaryOpNode < Node
def initialize(operand, left, right)
@operand = operand
@left = left
@right = right
end

def to_s
"#{@left} #{@operand} #{@right}"
end
end

class LiternalNode < Node
...
end

class StringNode < Node # puts quotes around the string for SQL query
...
end

Do not use a case statement to differentiate between types. Instead open core classes, like this:

class Object
def as_a_sql_node
...
end
end

class String
def as_a_sql_node
...
end
end

Be careful how you name methods to avoid collisions.

Possible problems? Literals on left, because "==" is commutative. The solution is to use "coerce" method to handle numeric operators.

More possible problems?
"&&" and "||" operators cannot be overridden in Ruby cause they have short-circuit semantics in the Ruby language interpreter itself. Perhaps & and | instead? Too bad, because we have to write "special" semantics. Also "!" and "!=" cannot be overridden in Ruby

The ruby "criteria' lib already implements some of these ideas.

Conclusion
One important lesson to take away, is that programming languages really shape the way we approach problems. Learn the corners of whatever language you are using to take full advantage of it. Don't be afraid to think outside the box of past experience...

Jim was an amazing and dynamic speaker. All I can say is Joe O'Brian and the people at EdgeCase are very fortunate to have him around.

RubyConf 2007 - Day 1 - "What Makes Code Beautiful" - Marcel Molina

I remember Marcel Molina from the first RailsConf, when the Rails core team was introduced to the audience. What had impressed me at the time, besides his cool glasses, was the fact that Marcel comes from a literature background.

That makes his take on programming in Ruby very interesting, because he approaches it from an aesthetic perspective, not just a functional one. To Marcel, code must achieve both, for it to be considered beautiful.

What Is Beautiful?
Here are some historical definitions of beauty:
Plato - "The ability to grasp mere appearances cannot lead to adequate understanding. At its worst, the appreciation of beauty can mire us in the world of sense experience... but at its best it can lead to the understanding of goodness."
Rousseau - "I have always believed that good is none other than Beauty in action, that the one is inextricably bound up with the other and that both have a common source..."

There is something deeper than appearances that makes something beautiful.

Looking at human language, meaning is often implicit in sentences. Normally in software, using rhetorical effects is considered bad, unlike literature.

Ruby had an appeal to Marcel as a language, as a visceral response to the language itself. But why? Elegance and beauty are used to describe Ruby code, but what does that mean?

Settle On A Working Definition
Marcel goes with Thomas Aquinas for a working definition of beauty requiring three qualities:
Proportion - Economy of size & ratio of parts
Integrity - a glass hammer may look good, but it doesn't work for a hammer - to have integrity, a thing must fit its intended purpose
Clarity - something should be simple and clear. There is a big difference between sophistication and complication

Apply definition of beauty to software
Marcel provided a contrived example, a case study that created a Coercion class to "help" when parsing XML. In his example, he starts with a 25 line class with three methods and such obfuscated code that even the author admitted that he does not understand it. He then proceeds to show how it can be reduced to 12 lines of reasonably clear syntax.

To achieve beauty, we need checks and balances between each of the qualities of beauty - each is necessary, but none are sufficient themselves alone.

Does code quality relate to beauty?
Marcel cites Kent Beck's "Smalltalk - Best Practice Patterns" as a strong influence. The book is full of pearls of wisdom like "most good Smalltalk methods fit into a few lines". After reading the book, Marcel realized that it was a set of descriptions of the elements that make Smalltalk code beautiful.

How Is This Useful?
We may not be very impressed by the beauty in a case statement. But imagine programming before the 'if' statement. 'If' is way better than assembly code... there is a relativity to what makes code beautiful. Today, Ruby is considered beautiful. In the future, we may consider it as ugly as 70's assembly code based on the aesthetics available to us.

"An expert is someone who has made all the mistakes that can be made in a very narrow field" - Neils Bohr

Ruby is optimized for beauty.
- try to imagine better modes of expression
- violations of beauty rules reveal mistakes
- do enough of this and you will innovate

Sunday, November 04, 2007

RubyConf 2007 - Day 1

Where RailsConf is growing to become a spectacle, RubyConf still has that special, small feeling of sharing. It is like the difference seeing a really great band perform at a small club before they get "discovered", and then seeing them again in an arena. Still the same band, but a much different experience. Being here at RubyConf 2007 brings back the joy of hacking Ruby code for its own sake, not just creating the latest and greatest social web application. Although Rails is Ruby, Ruby is not just Rails.

As I arrived for the opening address, I immediately ran into many Ruby friends, starting with Michael Hartl, author of the popular Rails book, RailsSpace. Michael had kindly saved me a seat up front and center. Wow, thanks Michael!

Despite losing our electrical power (due to the ultra-powerful toasters outside interacting badly with the dozens of daisy-chained power strips?), the proceedings were ready to get underway. For those who have not followed the history of RubyConf, this is the 7th annual Ruby conference! According to David Black, who gave the brief introduction, the attendance this year is 15 times the size of the first conference. That is a lot of toast.

And this is going to be a lot of text. Thanks to feedback from many of you, my wonderful friends, I am splitting my RubyConf 2007 in-depth coverage into separate smaller postings. I will post links to each individual session, as soon as I complete them. Here is what I attended on day 1:

RubyConf 2007 - Day 1 Sessions
"What Makes Code Beautiful" - Marcel Molina
"Advanced Ruby Class Design" - Jim Weirich
"Controlling Electronics with Ruby" - Ben Bleything
"Hurting Code For Fun and Profit" - Ryan Davis

After the day's sessions, I went to a very nice dinner with a group of new friends including "The Ruby Way" author Hal Fulton, and David Koontz, creator of a slick new tool for programming Swing entirely in Ruby called Monkeybars. Thanks for a nice time everybody!

We then hurried back, just in time to catch the "town hall" with Matz. Perhaps it was all the rushing around, but to me, the town hall was too chaotic. I'm sure the Ruby Central people had a good concept in choosing that particular format, but I just think it worked out so well. Perhaps doing a town hall on the second night of the conference? Or perhaps just scrap the idea... I'm not sure, but it just wasn't that good, especially after some of the strong sessions we had seen earlier in the day.

Let me be clear that this was no fault of Matz, who was very gracious thru the whole thing, but I think there were too many people with too many different agendas and lines of questioning to pull it off.

After such a very full day of Rubyism, I went back to my room and crashed out, certain that Matz's keynote address the next evening would be much more satisfying.