Saturday, December 31, 2005

Egoless development

When you’re the only one you know working with a programming language it’s easy to ignore style. There’s no one to criticize anything so it’s easy to just focus on the problem at hand and use it to get the job done any old way you can.



That’s the way I’ve always felt about working with Ruby, at least until now. I’ve used Ruby off and on since 2001 but I’ve never known anyone else interested in it. Also, I’ve only used it for small side projects so I’ve never developed great fluency. All of sudden now, though, it seems like the whole damn world is interested and I’m starting to think I need to hone up my Ruby skills. This includes trying to actually code like a 'Real' Ruby coder.




So that was my mindset as I sat down last night to write a little chunk of Ruby code to process the comment file created by the PHP comment system I use in my blog. The file is called comments.txt and has a very simple format. Each line is a comment in the form:




ID | DATA | TIME | NAME | EMAIL | HOMEPAGE | CONTENT




My goal was to load this file into an array of hashes, so my first chunk of Ruby was super simple and looked like this:





def load_comments()
ra = Array.new
IO.foreach("comments.txt") do |line|
a = line.split('|')
h = Hash.new
h[:id] = a[0];
h[:date] = a[1];
h[:time] = a[2];
h[:name] = a[3];
h[:email] = a[4];
h[:web] = a[5];
h[:comment] = a[6];
ra.push h
end
ra
end

comments = load_comments()




This worked fine and if I had had a deadline or still wasn't concerned with style, I would have lived with this, but now a nagging little voice was creeping into my thoughts telling me there had to be a better way. If someone fluent in Ruby saw those seven lines mapping the array elements into a hash they would laugh. I knew, there had to be a Ruby way to deal with this type of repetition. So I put on my thinking cap and read some ruby code on the web and came up with this solution.




class Array
def to_h_for_keys(keys)
hash = {}
counter = 0
each do |value|
hash[keys[counter]] = value;
counter = counter + 1
end
hash
end
end

class String
def split_to_h(delim, keys)
split(delim).to_h_for_keys(keys)
end
end

def load_comments()
ra = Array.new
IO.foreach("comments.txt") do |line|
h = line.split_to_h('|', [:id, :date, :time, :name,:email, :web, :comment])
ra.push h
end
ra
end

comments = load_comments()




With this technique I extended the Array class by adding a method that created a hash from the contents of the array. The method took an array of keys that mapped to the receiving array's offset. At first I liked this solution, but it seemed like a lot of code to solve something fairly simple. In addition I just hated how I had that counter value in Array.to_h_for_keys. It just seemed wrong to mix iteration with indexed based access. So I started to think how I could solve that and I came up with the following.




class Iterators
def Iterators.each(c1, c2)
l1 = c1.length
l2 = c2.length
count = if l1 > l2 then l2 else l1 end
count.times() {|x| yield c1[x], c2[x]}
end
end

class Array
def to_h_for_keys(keys)
hash = {}
Iterators.each(self, keys) do |v1, v2|
hash[v2] = v1;
end
hash
end
end

def load_table(filename, seperator, columns)
a = []
IO.foreach(filename) do |line|
a << line.split(seperator).to_h_for_keys(columns)
end
a
end

comments = load_table('comments.txt', '|', [:id, :date, :time, :name,:email, :web, :comment])




Here I've built a parallel iterator and used that to implement to_h_for_keys(). I also made a few other changes. I got rid of String's split_h method, it didn't seem worth cluttering the String classes namespace with a method that wouldn't be that useful in the long run. I also pulled some of the constants of load_comments and turned it into a more generic load_table.


I liked this better from an engineering standpoint, but again, it was a lot of code. I might have kept this too, If I hadn't been reviewing the documentation for Array where I noticed an iterator method I had forgotten about: each_index(), that iterates a collection by indexes instead of values. I immediately realized I could have used this to implement my previous version without the ugliness of mixing the value iteration with indexed offset access. So as much as I liked my parallel iterator, I rewrote the code once again to look like the following:





class Array
def to_h_for_keys(keys)
hash = {}
each_index() do |x|
hash[keys[x]] = self[x];
end
hash
end
end

def load_table(filename, seperator, columns)
a = []
IO.foreach(filename) do |line|
a << line.split(seperator).to_h_for_keys(columns)
end
a
end

comments = load_table('comments.txt', '|', [:id, :date, :time, :name,:email, :web, :comment])




Now this is feeling better, but the to_h_for_keys() method is bugging me now. Much like the String.to_h method I expunged earlier, I now feel to_h_for_keys needs to go as well. So now my final version follows:





def load_table(filename, seperator, columns)
a = []
IO.foreach(filename) do |line|
parts = line.split(seperator)
hash = {}
parts.each_index() do |index|
hash[columns[index]] = parts[index]
end
a << hash;
end
return a
end

comments = load_table('comments.txt', '|', [:id, :date, :time, :name,:email, :web, :comment])



OK, so now I have 14 lines of code that does the same work as the original 18 but is more flexible and hopefully easier to maintain and reuses; I've also learned a thing or two on the way. So why did I tell this story?



There were two reasons. First, I wanted to document how screwy learning a programming language can be. Second, the whole experience is troubling me. I really just wanted to build something and I got diverted by the whole 'doing it right' thing.



The fact is we talk a lot about egoless programming when discussing team programming, but I'm thinking we should apply the idea to individual development as well. While it's good to strive to do things right, there's a line that can be crossed were you descend into creeping elegance. In this case the effort was probably worth it since I needed to learn a few things, but I know that wont always be the case; at some point the rewrites will be more out of ego than necessity. The problem is that just gets in the way of the real goal - building cool things.

Wednesday, December 28, 2005

Giant Salmon - A short story

As I mentioned earlier, I've been trying to do more creative writing. Here's a very short story I recently finished. I hope you like it.




Giant Salmon



Why was the boat stopping? It wasn't supposed to
stop. I had only jumped into the water because the
boat would soon pull me up again and now it was
stopping. Why did I let them talk me into this? I
don't even like water skiing. Crap, they're taking
the engine cover off.



"Hey", I yell, hoping there's a serious problem and I
wouldn't need to follow through with this.



"It will just be a minute", the call comes back.



I look down and see my legs and the water skis
dangling above the darkness below. How deep is
this really, I wonder; 15 feet, maybe, over my head
for sure. Suddenly the image of shark looming up
from the murky darkness flashes through my mind.



Stop that, I scold myself as I mentally measure the
distance to the boat and the nearest shore. I'm
floating just about in the center of the cove, but the
boat is only 50 feet away. I can see Billy
and Richie poking and prodding the engine and I can
hear them laughing and talking but I can’t make out
the words.



"Glad you’re having fun", I yell again.



I start to regret that we smoked that joint. They
were obviously enjoying it, but I’m just feeling
paranoid.



The shark thoughts well up again. Damn, damn, damn!
I splash some water on my face to break the negative
train of thought. There’s probably not a shark within
a mile of here, I tell myself, at least none bigger
than a couple feet long. Even if there was they
don’t generally just up and bite you, they sniff you
over on few times, bump into you, see what you’re made
of, before they attack.



Intellectually I know there's little to worry about
but I can’t shake the deep seeded fear. Heck, if
there’s anything to worry about, it’s probably a
school of Blue fish. They could really rip a person
apart. I again start to stare into the water below me
looking for tell tales flashes of silver in the dark.
I’m so tense; I’m practically scrunched in ball.



Just stop thinking and enjoy this, I tell myself



It's a beautiful day; the water is warm and salty. I
can still taste the flowery marijuana we smoked earlier.
Lots of pot tastes bad, but this was really nice.
There are a couple of pretty girls in bikinis back at
the dock too, think about them.



I start to feel safe; the buoyant tugging of the
floatation belt I’m wearing feels nice as it lifts my
shoulders out of the water and into the warm sun.
Across the harbor I see two other water skiers
crisscrossing. The browns and oranges of the rocky
coast are practically glowing in the bright noon sun.
I wish I could paint that, I think.



BUMP.



I didn't imagine that; something just hit me on my
bottom. Holy shit! Shit! Shit! In a panic, I kick
off the water skis and start swimming as fast as I can
to the boat. Just swim, just swim I tell myself,
waiting for another bump, or worse a bite.



I cover the distance to the boat in wild flurry of
splashes and kicks. Then just as I grab onto the boat
and pull myself out of the water, it dawns on me; when
I relaxed, the tail of a water ski floated up and
smacked me on the rear. There was no blue fish; there
was no shark.



I'm on my belly now, half out of the water, laying on
the gunnel of the boat like a trained seal. The look
on my friends’ faces is a mix of concern and surprise.



"What the hell happened?" they ask.



I know I will never live this one down, so I try and
make the best of it.



I look them in the eye and allow a sheepish grin to
cross my face and sum it up as best I can,



"Giant Salmon."




Postscript: While the above is technically a work of
fiction, it was based on very real events that
happened to me during the summer of 1979. After the
movie Jaws was released in 1975, sharks were on my
mind, a lot. This situation marked the culmination of
a lot of pent up fear. While I still think
about sharks when I’m sitting out in deep water,
they've never scared me quite the same since. The
giant salmon reference is also movie related. Near the time of this event, my friends and I had seen a bad, John Frankenheimer, horror flick called Prophacy that had a short sequence containing a giant salmon.

Tuesday, December 27, 2005

Ruby Honesty

In case you missed the opinion piece A little anti-anti-hype on O'Reilly Ruby it's worth a read. I found the following paragraphs particularity insightful:




Pedantry: it's just how things work in the Python world. The status quo is always correct by definition. If you don't like something, you are incorrect. If you want to suggest a change, put in a PEP, Python's equivalent of Java's equally glacial JSR process. The Python FAQ goes to great lengths to rationalize a bunch of broken language features. They're obviously broken if they're frequently asked questions, but rather than 'fessing up and saying "we're planning on fixing this", they rationalize that the rest of the world just isn't thinking about the problem correctly. Every once in a while some broken feature is actually fixed (e.g. lexical scoping), and they say they changed it because people were "confused". Note that Python is never to blame.



In contrast, Matz is possibly Ruby's harshest critic; his presentation "How Ruby Sucks" exposes so many problems with his language that it made my blood run a bit cold. But let's face it: all languages have problems. I much prefer the Ruby crowd's honesty to Python's blaming, hedging and overt rationalization.



I'm not involved enough with the Python world to know if the first paragraph is really accurate, but from my pokes and prods from the perimeter it seems true enough. What really got me thinking however was the second paragraph about Matz and Ruby. The whole demeanor of the Ruby crowd really is a lot more laid back and plain speaking. (Note to self: this probably partially explains why I like it). As a futher example of like minded thinking check out the post Dividing with 'such careless honesty' by David H Hansson on the reaction on Slashdot to the Rails tag line: "...it works mostly right, most of the time, for most of the people". If you don't want to read it all here's the summary bits.



Naturally, I don't just like this statement for the outrage it caused. I like it because it's a dividing issue. One which can garner as much love and appreciation as it can cause outrage and despair. It exposed a set of deep cultural lines that in my mind separated the wheat from the chaff.



So if that statement rubbed you the wrong way, it's an early warning signal that Ruby on Rails wouldn't be for you. It's kinda like applying the principle of "fail fast" to tech stack selection. There's no reason to waste your time, or that of the Rails community, by investigating further, if this level of truthfulness is rejected in your bones.



It would be easy to misunderstand the above as a religious argument - you must have faith in Ruby, Brother - but that would miss the real more human point and the great irony in all of this. The Ruby enthusiast isn't preaching programming religion, they're simply excited about being productive and the creative potential of the platform's tools, warts and all.

Thursday, December 22, 2005

Importance of small things

I was reminded recently about how important small things can be in getting people to like your software. I've been a user of Bloglines for a long time but I've never really liked it. For some reason it just never clicked with me. That was until yesterday, when I found the option 'Show only updated feeds'. Now that I've enabled that little option, I love Bloglines. My list of blogs I'm watching seems small and manageable even though it's bigger than ever. It's amazing how a little things like this could change my whole relationship with the product. Food for thought.

Wednesday, December 21, 2005

Hyper-enthusiasts

I don't know if Bruce Eckel coined the term 'hyper-enthusiast' but his recent mention of it, in his Artima article, was the first time I heard it. He uses it to describe developers who extensively hype technology. It's a great phrase. I think it captures the essence of something I was acutely aware of but had never labeled.

Tuesday, December 20, 2005

Caganer Bush

One of my first posts was about the Caganer, the Catalan Christmas figurine taking a poo (See Wikipedia). Given the European opinion of President Bush, this years new model isn't really a surprise. It would probably sell well in nearly 50% of this country as well.


Update: If you follow the Wikipedia link above, make sure you check out the Tio de Nadal Christmas tradition. Tio de Nadal is a tradition where kids care for a log for a few days and then on Christmas everyone beats the log with stick to encourage it to poops treats. I love old school, pagan traditions like this. It actually sounds fun.

10 Things Every Java Programmer Should Know About Ruby

Here's a nice concise presentation by Jim Weirich on the cool bits of Ruby.



I love this part that demonstrates the message based behavior of Ruby.




class VCR
def initialize
@messages = []
end
def method_missing(method, *args, &block)
@messages << [method, args, block]
end
def play_back_to(obj)
@messages.each do |method, args, block|
obj.send(method, *args, &block)
end
end
end

vcr = VCR.new
vcr.sub!(/Java/) { "Ruby" }
vcr.upcase!
vcr[11,5] = "Universe"
vcr << "!"

string = "Hello Java World"
puts string

vcr.play_back_to(string)
puts string



This prints out:




Hello Java World
HELLO RUBY Universe!



This is like nuke powered dynamic proxies. My brain swirls just thinking of the possibilities.

Saturday, December 17, 2005

Patriots vs Colts

Watching the Patriots destroy the Buccaneers I'm starting to believe we actually have the ability to go into Indy in the playoffs and kick Manning's ass. There are a lot of games to play before then but if you had asked me a couple weeks ago, I wouldn't have thought it possible. Now, I'm smelling another Super Bowl. It's great being a Patriots fan.

How to lose your job

I can't set this clip up better than the web site I found it on (wetasschronicles.com)


Approaching harbor is a bad time for a helmsman to fall asleep, or an officer of the watch to be in the head, or drunk, or whatever. In fact, here's what can happen:



A vessel was due to arrive at a port in Spain at 0800 local time (LT). It would appear that at about 0600 LT the vessel contacted the Pilot Station confirming the ETA and was instructed to contact again some 20 minutes before arrival.



At 07.59 hours LT, and despite the calls from the Traffic Control, the vessel grounded at full speed on the breakwater at the entrance to the port.



A video, taken by surveillance cameras, shows "live" the sequence of the grounding, and needs no comments.



Watch it--and cringe....



(video link)

Thursday, December 15, 2005

Selling Simple

Will simplicity ever sell? Currently it's a hook for grass roots engagement; but can it compete with the big guns of functionality, scalability and performance at the enterprise level?. Given its very real impact on total cost of ownership, it seems like it should. But how do sellers quantify simplicity into the TCO equation or use it counter claims of less than stellar performance? Searching the web for "TCO Simplicity" yields a lot of results so people are talking about it, but is it working?



I know simplicity sells to some degree at the consumer level. My old employer, Alpha Software built itself on developing approachable products. You might think that the fact that most of you know of a product called 'Microsoft Access' but not of our product called 'Alpha Five' invalidates this thesis, but I don't think so. How many small companies, that went head to head with MS in the 80's and 90's, are still around to talk about it? Not many. But Alpha is and that's because they made developers, who were willing to risk a less traveled path, more productive.



This whole post came about because of my continuing work with Ruby on Rails. Once the hype wears off from it and people understand its capabilities and limitations will they see that its inherent simplicity trumps its less stellar attributes? The fact is I don't know how it performs head to head against other similar products in terms of raw performance, I'm just guessing that it's slower given its foundation. The fact is I just don't think that matters.



In the not so distant future I see a world were reasonable performance is a given and the talk is more about simplicity and maintainability. In many ways Java started down this road as well, but got hijacked by the J2EE chowder heads. Perhaps it was just too early on the curve and not quite simple enough even by itself. I for one look forward to the new world. It's going to be fun.

Wayfaring

Wayfaring is a cool website built with Ruby on Rails that lets you build topical maps using Google Maps technology. For example, I built this map of bars and restaurants in and around the Westford, and Littleton area of MA. Wayfaring is built for community editing so it will be neat to see how the map evolves, if at all. It's worth a look.

How to lose your job

I can't set this clip up better than the web site I found it on (wetasschronicles.com)


Approaching harbor is a bad time for a helmsman to fall asleep, or an officer of the watch to be in the head, or drunk, or whatever. In fact, here's what can happen:



A vessel was due to arrive at a port in Spain at 0800 local time (LT). It would appear that at about 0600 LT the vessel contacted the Pilot Station confirming the ETA and was instructed to contact again some 20 minutes before arrival.



At 07.59 hours LT, and despite the calls from the Traffic Control, the vessel grounded at full speed on the breakwater at the entrance to the port.



A video, taken by surveillance cameras, shows "live" the sequence of the grounding, and needs no comments.



Watch it--and cringe....



(video link)

Wednesday, December 14, 2005

Kubi in the news

While the Kubi development staff recently suffered a sad loss with the departure of Ned Batchelder, the company as a whole is starting to gain some traction and visibility in the CRM market place with our new product Kubi Enable. Here's a recent article from CRMguru.com that highlights Kubi as one of the new kids to watch.




Kubi Software (Lincoln, Massachusetts). The basic premise of Kubi Software, and one that I agree with, is that while we would like all of the notes and communications associated with every sales opportunity to be kept in our CRM systems, the reality is they are not. Instead, they are far more often found in emails. For example, when a rep answers a prospect's question, negotiates with finance for a better price or strategizes with management on how to win the deal, he or she is more likely to store all that information in email, not the CRM system. Designed to be an extension of your existing CRM framework, Kubi organizes all those messages, priorities follow-ups and creates an audit trail of who said what to whom during the sell cycle.



FYI: With the departure of Ned there will be an opening in development for a top-notch senior engineer. I'll post a link to the job description when I have it.

(Updated: 12/14/05 at 1:00pm)
Here's the job posting




Senior or Principal Software Engineer – Boston



You will be part of a small team of very experienced engineers creating a new generation of sales effectiveness and business process automation software that uniquely bridges Email metaphors with structured business processes. The perfect candidate will be hard-working, self-driven and highly motivated and thrive in producing high quality, customer-focused software while continuously seeking to strike the right balance between agile software development methodologies and the time, quality and customer-driven pressures of a dynamic, rapid start-up company.





Qualifications required:



  • 8+ years of architecting, designing and developing commercially successful software products

  • Proven problem solving

  • Strong C/C++ programming skills and object oriented programming

  • Multi threaded programming/SMP

  • Strong relational database background (SQL Lite, Postgres)

  • .NET, COM, ATL, WIN32, SQL

  • Web Services, XML, SOAP, XSLT, CSS

  • Multi and cross-platform development skills in a client-server environment (Windows, Linux and Unix)

  • Excellent verbal/written communication and interpersonal skills

  • Bachelor’s degree or equivalent



    Qualifications desired:


  • C#

  • Java

  • Tools knowledge and languages such as Perl/Python/Ruby

  • Client, Server, Offline Networks, Replication, Collaboration




  • If you're interested contact me at plyons AT kubisoftware.com

    Monday, December 12, 2005

    .NET headache - MeasureString

    I've been working on a .Net custom control that displays a mix of text and graphics in a flow layout. The work required that I know the exact size of text strings in order to position the next widget relative to the previous string. .Net provides a method called MeasureString that you would think solves the problem but in fact it doesn't. MeasureString has the documented behavior of including 'a small amount of extra space before and after the string to allow for overhanging glyphs' (link).
    While I'm sure there was a good reason for doing this, it would seem prudent for MS to also give developers a straight forward way of knowing the actual size of the string. The help for MeasureString mentions that if you want to know the real size of the string you should use another method called MeasureCharacterRanges(). While MeasureCharacterRanges can provide the answer, calling it with the proper settings is not exactly obvious. I found a bunch of chatter out on the web (circa 2002) about the issue but no simple solutions, so I decided to blog mine. Here's a version of a method that does what I needed that's as simple as I could make it. Most people probably know this already but if you're like me and new to .NET, maybe this will save you some grief.




    public static Size JustMeasureTheDamnString(Graphics graphics, string str, Font font)
    {
    CharacterRange[] characterRanges = {new CharacterRange(0, str.Length)};
    SizeF sizef = graphics.MeasureString(str, font);
    RectangleF layoutRect = new RectangleF(0, 0, sizef.Width, sizef.Height);
    StringFormat stringFormat = new StringFormat();
    stringFormat.FormatFlags = StringFormatFlags.NoClip |
    StringFormatFlags.MeasureTrailingSpaces;
    stringFormat.SetMeasurableCharacterRanges(characterRanges);
    Region[] stringRegions;
    stringRegions = graphics.MeasureCharacterRanges(str, font, layoutRect,
    stringFormat);
    if (regions.Length == 0)
    {
    return Size.Empty;
    }
    return regions[0].GetBounds(g).Size.ToSize().
    }

    Wednesday, December 07, 2005

    Deep sea template

    Those of you not reading via RSS will see I've totally changed the look of the site. It's still a work in progress but It's close enough for now that I've posted it. I gave up on being table free and went for an easier to manage table based template. The right side border I made myself in paintshop pro 8. The actual sea creatures I clipped from a thumbnail of this poster. I did some blending and clipping to make the fit but the real hard work was done by illustrator Frank Walsh. I hope you all like it.

    Built in Code Generation

    I'm always looking for new ideas in programming languages. While looking at the Ferite language, I came across something I had never seen before; something the Ferite folks call a 'directive'. A directive lets you instruct the compiler to execute certain parts of the code at compile time in order to modify the existing code. It's like COG but built into the language. I don't know if the people behind Ferite came up with the idea themselves or if they borrowed this from another language, but regardless, It's the first time I've seen it. An example follows:




    class modifies Obj {

    directive access( ... ) {
    array a = arguments();
    string code = "class modifies ${Class.name(self)} {";
    Array.each( a ) using ( name ) {
    if( name isa string ) {
    code += "
    function set$name( void value ) {
    .$name = value;
    }
    function get$name() {
    return .$name;
    }";
    }
    };
    code += "}";
    eval( code );
    }
    }

    class Example {
    private number X = 10;
    private string foo = "hi";

    [access X, foo];
    }

    Monday, December 05, 2005

    Tailgate Shrimp

    Here's a simple recipe I came up with for the Patriots game this weekend. It's spicy, quick and can pretty much all be eaten with just your fingers. It's perfect for tailgating



    Ingredients

    1 Kielbasa Sausage

    1 Chorizo Sausage

    1 Onion

    1 2lb. bag of uncooked frozen shrimp

    1 Shaker of Cajun spice such as Emeril's Essence

    1 Can/bottle beer



    Equipment

    1 Tin foil pan

    1 Knife

    1 Tongs or a spoon

    1 Grill



    I never have time to do any preparation before hand so this recipe is tailored to on site preparation. We actually stopped at the grocery store on the way to the game. You can do all the chopping and peeling ahead of time if you want.



    Preparation

    Start the grill. Chop the Kielbasa and Chorizo into 1 inch chunks (finger food size) and put into the tinfoil pan. Chop the onion into chunks and add. Put the tinfoil pan on the grill and spinkle in a heavy dose of Cajun seasoning. Let the sausage mixture cook until the onions are translucent and the sausage is hot. Now add a beer to the tinfoil pan. When the beer starts to boil stir in the shrimp to the mixture. Sprinkle more Cajun seasoning. Close the grill lid (or add tinfoil cover) and cook until the shrimp are done.




    Serving

    Remove the tinfoil pan from the grill and place and place in a central location. Ring the dinner bell. Note, I didn't peel the shrimp but you can certainly do that if you desire. I figured since we are eating with our fingers it's easy enough to just let everyone dig in and peel their own.

    Friday, December 02, 2005

    Envisioning a new language

    In a new interview on SDN, Sun's Victoria Livschitz talks about her research language called Metaphors. This is 'pie in the sky', make your brain hurt, sort of stuff but there's some interesting ideas presented.


    Link

    Thursday, December 01, 2005

    Try Ruby

    You know you want to. Now it's easier than ever to take a quick peek and see what all the over-hyped fuss is about. Try Ruby is both an interactive Ruby shell and a very cool tutorial system. In the Ruby window type 'help' and just follow along. It's pretty damn slick.
     
    The Out Campaign: Scarlet Letter of Atheism