The Programmer Phases of Grief: or Language Translation is Harder Than It Looks
One's mind should be pretty clear when programming. I'm a decent enough programmer, but I'm not a bad-ass programmer. At least not anymore.
Back in the day, before marriage, before diabetes, before babies, when I was sleeping a full 8 hours, I could code some nice stuff. Now it's just a miracle it compiles. When it does.
I also tend to, um, not think. At all.
I have been looking into OpenID lately, and had the privilege of meeting the CEO of JanRain, Scott Kveton (pronounced 'k'-vee-ton', but real fast, like the first two syllables are one) and mentioned that I was pleased they had made a .NET compatible OpenID library available (Andrew Arnott has wrapped it in a nice ASP.NET 2.0 Web Control).
I was thinking I'd add OpenID support to Corillian's Voyager eFinance Server as a Proof of Concept, as our authentication system is pluggable. It'll be a nice demo, as our CardSpace one already works great.
I went and download the .NET OpenID Library preparing for a few hours of tedious work.
The .NET OpenID library is written in Boo - I blogged about Boo in 2005 (I wonder if Ayende will update his Boo Reflector support for Reflector 5.0?) - which is a language that is damn-near Python. You can convert your code to Boo with this online tool if you want to play. Here's some Boo examples versus C# 2.0.
Right now the best and easiest way to write Boo is to use SharpDevelop, the Open Source IDE. Boo is a first-class language within SharpDevelop, along side VB and C#, and includes all the usual good stuff like debugging and what-not.
The OpenID .NET Library, as I said, is written in Boo, very likely because the original library was written in Python and Boo offered not only a clear porting direction, but also made the developer comfortable. More on this later.
I figured this evening I'd "port" the Boo source for this library over to a "proper C# library" so the masses wouldn't have to sweat Boo. This experience let me through the...
Phases of Programmer Grief*.
I was of course, like any
religious zealot C# programmer, shocked and offended and looked on with disbelief that anyone would use any language that wasn't the One True Way® to produce perfectly viable and runnable IL. Microsoft's whole multi-language, single-runtime was just to prove a point to the Java guys right? I looked at the code with disdain
Shock is often accompanied by numbness...
No curly braces? Duck typing? Is this how these people live and code? Freaks. Toy Languages, man, toy languages.
At this point, I don't think it'll be hard to port this. The library includes NUnit Tests, but as the library is structured with a lot of things marked internal to the assembly, there's two libraries. The main one, and the test one - but the code is also compiled into the test assembly. I started marking things public, and separated the two.
I've already missed the forest for the trees here, and I'm happily stepping on butterflies in my quest for the big game.
My goal was to use the Test library, as is, to test my glorious new C# library - the one I hadn't started yet. If the same tests passed on my C# version, shiny. I started poking around the code, trying to get an idea on where to start. The library includes a Server and an Consumer, and since I just needed the Consumer in the short term, I figured I start there.
There's not THAT much code in the consumer, but there's not only a number of utility classes, but there's also a bunch of Boo language-specific collections and such. Also, as .NET 2.0 doesn't include Diffie-Hellman support (Orcas does, BTW), the OpenID library referenced Mono.Security to get there BigInteger class and Diffie-Hellman support.
ASIDE: Be aware that
Mono is GPL'edMono Libraries are MIT X11. Mono produces IL, and Mono libraries are CLS compliant, you can reference them in your Windows .NET applications happily, and they'll work fine 99.9% of the time. Adding a Mono library to my Windows .NET CLR program doesn't make it run under Mono, it's just referencing a library. Some people, like myself (yesterday) look down on this like we look down on C# programs referencing Microsoft.VisualBasic.dll, but hey, it's tested code I didn't have to write...you'll no doubt see my own personal epiphany coming later in this post...
I thought I might write my own Diffie-Hellman...
Note that I'm getting totally off the main task-at-hand already here...but I've not noticed it...yet...
...or find one that was already done. If I could just remove that Mono.Security reference...
I started to feel bad, who am I to remove this library? Someone's worked hard on it, it shipped, let's leave it be, and get to the real work. Maybe I can find a better way to port this...ah, yes, Reflector!
I'm completely delusional...lack of sleep? Analysis paralysis or just complete lack of thought? Ah, too much soda, perhaps? High blood sugar?
I'll just reflector the assembly and decompile it into C#. Heh, maybe I'll use Denis Bauer's FileDisassembler. There's probably some Boo specific stuff, but I'll yank that, no problem. It might be sinful, but no one is looking.
Of course, Boo assemblies include dozens of anonymous generated types and adapters to make Boo's closures work (it was designed before Anonymous Delegates could be used for closures) as well as for type inference.
Gosh...this decompiled C# code isn't even close...this may express the intent to the computer, but it doesn't reflect the Programmer's Intent at all.
Stupid piece of crap Reflector! Man, Lutz can't even decompile to something I can freaking read!
Remember that IL is the applesauce on its way to becoming apple juice. Note that Stupid Scott is pissed here because Lutz's Reflector can't turn applesauce back into an apple. Darn Reflector and the Laws of Abstraction.
Shoot...this is going to take longer than I thought. Now I've got to just freaking write thing whole thing from scratch by actually thinking and understanding what the code is intending to do! Man, I wasn't planning to think tonight, I just wanted to get OpenID on my blog.
I'm not a good programmer! I've been coasting on charm for at least the last three years. I remember what closures were in college, but I've been using .NET 1.1 for the last five years and it dulls the senses...I might as well just give up and become a nurse.
Acceptance and Hope
Wait a second. I've already got a library that works. It's got unit tests. It depends on a tested and released Mono library and a 3 year old non-mainstream language, but it works. It's been used and implemented live before and someone has already wrapped it into an even better and more useful abstraction. Maybe it'll work after all.
The moral of this story is that my time would have been better spent learning Boo, reading the source, and using the Library. The source came with a NAnt Task, but I just created a Boo Project in SharpDevelop - THAT wasn't wasted time.
After I'd learned enough Boo, if I really wanted a C# version, for whatever reason, I should have just written it from scratch using the public interface as a template and the Programmer Intent, written in Boo, as my algorithmic scaffolding. Hindsight is 20/20.
Now, how do I get my evening back?
* With Tongue Placed Firmly in Cheek.
** Image stolen from here.