Thursday, November 27, 2008

W3C - A Decade+ of Fail

Back in the wild days of the early web, it was pretty clear that someone needed to get their shit together and tell people how it was and how it should be. Everyone had their strange little additions to HTML to twist and turn it different ways, and there was no clear delineation between right and wrong. Are tables OK? Are frames? What about iframes?

Thankfully, the W3C was there to clear things up and make sure that there was a clear path between right and wrong.

Thanks to the magnificent stewardship of the W3C, we've seen reference browsers so that it's clear how web pages should look.


Just think - if it weren't for the W3C, we'd be stuck with goofy tags like blink and marquee that were added in by Netscape and Microsoft respectively to this day!


That'd be terrible!


Thank god they locked that shit down and slapped people's hands when they tried to add inane crap like that in, right?

Except, judging by the fact that you're blinking and rubbing your eyes and probably cursing me for being such a dick and stuffing those two proprietary tags in there and your browser rendering them, they failed.

CSS was put out with the best of intentions, but when it comes to CSS, you can count on one thing - it will not work right the first time in all browsers. Ever.

Which doesn't stop them from diving ever deeper into never-never land and releasing specs on how to generate tables using nothing but CSS and magic to the public. Not that CSS1's all that well-supported. Or CSS2. But don't worry, just use CSS3 and suddenly everything gonna be OK! Oh, if only we had some way to express tabular data that's supported in all browsers. If only.

The simple use cases don't work right but it doesn't stop them from putting out ever more elaborate specs based deeper and deeper in fantasy land. Worse yet, you'll find supporters who say things like...

The difference is that an HTML table is semantic (it describes the data). The 'table' value of the display: property has no semantic meaning, and simply tells the browser how to display something. There is a huge difference there.

You dare to question the sanity of an elaborate hand-waving solution that doesn't work in, oh say, 25% of browsers out there when there's a simple way that works reliably?

It's only silly if you refuse to distinguish between content and layout.

In a sense, this is correct. Of course, this is in the same sense as me saying "I can go ahead and chop my legs off because it's silly to walk when jetpacks and rocket cars are obviously the way of the future."

I will give the W3C credit - I didn't know that there was a terser abbreviation for You Aren't Gonna Need It than YAGNI, but it looks like "W3C" will do.

So why a decade+ of fail? They did start churning out the XML spec back in 1996, and they managed to not fuck that up too badly (probably despite their best efforts). I know, LISP people - XML is a mangled version of sexprs. I have no idea what that means, but I will nod and slowly back away. I know, internet. XML is the worst format ever invented. Angle bracket tax! Excessively verbose! Have you seen the stupid things that people have done with it? Why didn't we settle on JSON or YAML?

But you know what? I can produce XML here and have confidence that whoever I hand it to is going to be able to do something meaningful with it. It's readily (if not speedily) parsed on just about every platform out there. For a lowest common denominator intercommunication, I gotta admit - it doesn't suck much worse than any other option available.

That doesn't excuse the W3C from strapping on the complicator's gloves and trying to make it do things that it utterly fails at. SOAP? OK in theory, but were they not aware that interchange was going to be happening over public networks and maybe encryption was something that should be built into the messaging by default? Violate the spec and you've got what you want. Was there a point to the spec in the first place?

Oh and did I mention that you can count on SOAP calls across heterogenous clients to be a massive pain in the balls? When we started on our new project, calling across the wire to a service written in Java, we had two options - XML using their little format or SOAP. I put my foot down on using XML and refused to say more than "the only benefit to using SOAP will be hearing me laugh a lot at whoever has to implement it, because I won't even try it." I didn't even need to drop a "told you so" when our SOAP services started failing for no particularly good reason other than it was written in WCF and the consumer had the temerity to be written in .Net 2.0.

And SAML? Godawful. Over-wrought. A solution in search of a problem. A magnificently high face-to-palm ratio. I brushed up against that turd once upon a time and I can still taste the bile in the back of my throat because of it. For that one alone I would like to firebomb the collective crotches of the W3C's membership.

But they keep on trucking and suckers keep slurping it up.

I'm a caveman and a terrible designer and I write pages using tables instead of divs. On the bright side, I don't spend days lost in trying to figure out why float isn't working in IE6 when it is in Firefox and now it's working in IE6 and Firefox and not IE7 and... who else is up for a trip over to W3C headquarters to visit unimaginable horrors on their collective genitalia?

Tuesday, July 29, 2008

Tripping into the valley of fail

C# 2.0 introduced nullable types to the language (apparently late in the dev cycle - more on that soon), something that I could have used way back when.

I know, LtU duders - nobody can prove that we really need null and it's a terrible idea. Or an OK enough idea in the absence of rigorous mathematical proofs but, and don't let nobody in on this, I nearly flunked out of my 9th grade math class (which was really the advanced 10th grade math class; I can't explain it neither) because I could not prove my way out of a paper bag. Calculus eluded me and vector math haunts my nightmares. I'm no math pro and this is a blind spot I'm all too aware of.

But null's really useful, honest.

In our application, we have to deal with dates that the user's supplying. Since this is client-side input, we have to deal with two possible fundamental problems with the dates. Did they forget to enter a (mandatory) date? Did they enter an invalid date?

I mention dates because they're (in .Net) a value type. Like other value types, once you create the variable, they're automatically assigned a value as opposed to reference types, which are null until you instantiate them (the pointer, she points nowhere). And then there's string, which lives in a state of sin in the gray area between value and reference (it's a reference type but when you pass/copy it, you get a copy of the string rather than a pointer to the object). Officially, a string's an "immutable reference type" (thanks, Google!). Tangentially, are there other immutable reference types in the .Net framework? Damned if I can think of one.

So what's any of this have to do with nullable values?

The user forgot to enter a date. OK. What value should we use to represent the fact that that the user entered an invalid date? DateTime.MinValue, maybe? Sounds reasonable.

That's covered, so on to fundamental bloops number two - the user entered an invalid date. Hmm. DateTime.MinValue's already been recycled as a magic number to represent "missing date", so we'll use DateTime.MaxValue. Game, set, ma... oh, wait.

You mean we'll have a need throughout the application to use DateTime.MaxValue to represent things that are open-ended?

Now we've got a problem. Do we want to pick out a second magic number to represent the fact that the user entered an invalid date? Maybe treat an invalid date and a date that hasn't been entered identically? Maybe we want to wrap dates in a struct that contains a DateTime and booleans for invalid/missing date?

Hmm. That code's starting to stink pretty badly. There's got to be a better way.

That's where I was hoping nullable types would come to the rescue. Where previously we had to use magic numbers to represent error states in our values, we can now use a not-so-magic value - null.

Suddenly, we're not looking to wrap things in a struct and perform all sorts of acts that no shower will ever quite rinse off. User forgot to enter a value? Null. Invalid date? DateTime.Minvalue. Take in the win.

Did I mention that nullable types came late in the development cycle? Let's take a look at a little code and see how it works out.

string nullStr = null;

nullStr.ToString();

Trying to execute a method on an uninitialized variable - what do you get? A NullReferenceException. No-brainer.

int? nullInt = null;

nullInt.ToString();

Let's try the same thing on a nullable integer. We should get the same thing, right? Wrong. It returns string.Empty. To get the same result, you'd have to say...

int? nullInt = null;

nullInt.Value.ToString();

What the shit? Nullable types have a .Value property? Pro move, guys. Way to leak the fuck out of that abstraction.

Truth be told, ToString() not horking a NullReferenceException doesn't bother me that much. It's the unexpected coalescing of a null value that gets me. I set out with my golden hammer to create a new li'l method called ToStringOrNull() and hang it off of Nullable<T> that does what I'd have designed ToString() to do in the first place - return a null string if the value's null and call the generic ToString() function otherwise. But I can't attach a constraint to that function because Nullable<T> is a structure, not a class. Fail, fail again.

Polluting the namespace with this feels wrong, so what do I do?

Tell other developers to always use nullableType.Value.ToString() and hope that nobody slips up?

Add bunches of tests to our increasingly tag soup-y MVC app (and hope that nobody forgets to do it)?

Not good times. Small inconsistencies pile up until you're so busy bookkeeping for them that you can pretty easily lose sight of the bigger picture. Either that or you grow your Unix beard out and spend your days using your phallus to point to chapter and verse for the reference specification for your language of choice on Usenet. The latter's not an option for me since I can't grow a beard and the former ain't pretty neither.

I'm hoping that I can sneak in some elegant solution to calm this jittery behavior, but I've got no idea what it'll look like.

I just wanted to give a special shout-out to whoever for the head-scratching behavior. Wait. Is the person behind [DebuggerStepThrough] behind this? By all that is unholy, I will get you for this. These. Whatever.

Sunday, July 20, 2008

Unit testing - prefer messages

tl;dr version - if your unit test tool lets you associate (informational) messages with your test assertions, use the fuck out of them.  It's great that you're driving towards 100% code coverage.  How much greater will it be in 2 months when someone (probably you) breaks a test and has a useful indicator of what exactly was being exercised rather than trying to puzzle out a simple assertion? 
I'm sadly new to the unit testing game, so I've been learning the wrong way to do things at an astonishing clip, while mistakenly stumbling over things that work by accident every now and then.
I never quite understood the hubbub over unit testing - why do I want to do extra work that doesn't go towards getting a working product out the door?  Now that I'm writing oodles of unit tests, I understand exactly why I want to write them - they save my ass early and often.
Case in point - the object to XML mapper (this isn't NIHS; I genuinely can't use LINQ to XML because the hierarchy the external service produces is not only unpublished but subject to change) I'm writing.  It's been working, but I noticed that it was... how shall I say... less than performant?
So I set out to start refactoring critical sections of the code.  I started by gut - I started taking FxCop up on its suggestion to use IXPathNavigable and knocked bunches of stuffs out.  Minor improvements.
Then I stopped programming by guesswork and profiled a generic run pattern.  Creating objects (with objects creating other objects), updating the persistent XML store, blah blah blah.  Found the genuinely astonishingly slow parts of my code and broke out the chainsaw to fix them up.
For a change, I had a really, really high level of confidence in all the changes that I was making.  Before unit tests, it was just more guesswork as to what I might be breaking outside of the code that I was touching just by looking at it funny and changing this postfix increment to a prefix increment (OK; that's an exaggeration, but you kinda know what I mean).  Now that I've got unit tests in place, it's a whole different story.  I can try things out and see if anything breaks in real time.  If the coverage is good enough, I've got silly confidence that everything's on the up-and-up.  If it isn't, whatever.  Adding a few more tests isn't moving mountains.
But a strange thing happened along the way - unit tests that I'd written a month or two earlier started breaking.  Even stranger, I had no idea what some of them were doing.  Not many of them, but I was clueless about the provenance of some of the tests that I'd written a couple of months earlier.
That sends up red flags for me - there's still value in having those unit tests, but I can recognize that if I don't have a little more context associated with them, they're going to bit rot really, really fast.  I started by putting comments above the tests explaining what they were doing, but that felt kind of unsatisfying.
I find that when I write unit tests, I slip into a lightweight QA state of mind - I think less about the cases that should work and more about the edge cases, the awkward states that I can put my code into to get it to break.  It gives me a chance to stand back and re-examine the code from that stance as well as getting a feel for how easy the class is to use, since I have to instantiate objects (and everything else in its dependency graph) before I can start to test it.
The time that I'm thinking about what the class is doing for me and how to use it lends itself naturally to embedding context in the tests.  Not simple messages like "validating that CountryCode gets populated when the object's hydrated from XML" but "validating that nullable enumerations are being populated properly."
Prefer messages in the unit tests you write.  They'll help you make the most out of your unit tests as you write them and they'll help you understand your unit tests when they break down the road.

Sunday, July 13, 2008

Mea culpa

When I first started writing .Net code, I was all about implementing IDisposable because I figured that the GC wouldn't be as smart, as fast, as efficient as the stuff I could write. I mean, sure - they optimize for the general case, but who knows better than I do just when to free memory and resources? Not some jackhole Microsoft programmer, amiritepeople?

Since those were the heady days of VC and no clients demanding things change yesterday, I actually spent half a day working with the clumsy spike I'd slapped together and let it fly - it worked well enough under load, so I was happy. Then I ripped out my destructor and let it roll again - I was figuring I'd see the CPU thrashing as .Net's garbage collector did its thing, working on the general, sub-optimal, case it was written for. No egghead knows better than I do how and when this should run!

Except that there was no difference that I could see. If anything, run time was a little faster and memory overhead was a little lower. I mean, probably statistical noise faster and lower (that Excel spreadsheet's been lost to the river of time at this point), but that was a pretty well-defined zenslap moment for me.

I thought about it a little and realized that oh yeah - that garbage collector. I'm not allocating memory either. People way smarter than me have already implemented a garbage collector so I don't have to worry about allocating and freeing memory on the fly. The bold promise of distilling your codebase down to actual business logic rather than bookkeeping allocations and all that.

It's a solved problem, so why am I solving it again, only invariably worse this time? Maybe it was written for a "general case" (whatever the fuck that means because I obviously can't defend it) but it was a pretty good general case.

This all came flooding back to me on Friday. I'm working on a bit of code - an object-XML mapper. This isn't as stupid as it sounds (I hope), honest. It's running, well. Not so good. I mean, it does what I want it to, just way way way slower than I want it to run.

One of the "optimizations" I made was ripping out a lambda expression iterating over a singleton (I know, I know) - I figured that there ain't nothing faster than a hand-rolled for loop with a break condition... right? But I wasn't making any headway with the other two offending methods after re-ordering my if block, so I decided that I might as well, you know, test it out to see how it performed.

I didn't check memory this time around, but damn if it wasn't just as fast as the for loop. Maybe a little faster, even.

Again, the zenslap - the framework's made by people way smarter than I am. I need to count on them to have done their homework and made stuff easy to use and scary fast.

Stop reinventing the wheel. I'd bark at co-workers who tried to roll their own second-rate mechanism for mapping objects to an XML hierarchy we don't control, so why am I confident in my ability to roll my own iteration loop? On some level, doesn't it make sense that smart people who get paid to work on iterators might find a way to wring a little more out of them?

It's not easy discovering that something so simple that you've taken for granted for so long (a for loop!!!) is halfway obsolete, but it's liberating once you get over yourself and embrace it.

So here's to you, whoever implemented .Any() - you did a helluva job. Way better than the jackass who shat out [DebuggerStepThrough].

Tuesday, June 24, 2008

Software management - The Oregon Trail model

OK, forget reading Peopleware and The Mythical Man-Month. If you want to manage developers, there's only one - no wait! - two things you need to do.

  1. Be born in the late 70's/early 80's
  2. Play The Oregon Trail on an Apple II

That's it! If you can make it to the end of the trail, you know everything that you need to know about successfully managing software, so go successfully manage the shit out of a project or three!

Wait. You're still here? I should go on? OK.

You have your hunters, guys who strike out in hopes of lucking into a bounty of delicious, delicious meat. Speaking authoritatively as someone who's never hunted or caught anything of note while fishing, I'll say that a good hunter operates off of instinct, innate ("animal") intelligence, skill and luck. Legends tell the tale of the hunter who struck off into the deep of the jungle with nothing but a knife and came back carrying a gorilcopterous (work with me people, I live on the edge of the tundra) or some big tasty animal that lives in the jungle0.

Then you've got the gatherers who plant crops and (hopefully) eventually got to harvest the bounty. It takes a deep investment in time and resources to see a field from seed to harvest, and even then there's any number of natural disasters that can beset you along the way. This isn't to say it's easy. On some level, we all understand how plants grow. They eat sunshine, water and carbon dioxide and crap oxygen and chlorophyll, right? On another level, there's a hell of a lot that goes into it - seeds cost money. Machines to till and harvest cost money. Irrigation costs money. You've got to know when to plant. What to plant. When to rotate your crops.

Developers are an impatient bunch, which means that we don't generally have the patience for the small, far-off, rewards and repetitive work that it takes to grow a crop. But we get hungry, so we're going to strike out and hunt, hoping to bag the next seminal idea. OK, it's probably not a seminal idea by any stretch of the imagination, but for a brief moment in time, you really feel like you've crafted something brilliant and have found something more than you could have hoped for, something that's somehow bigger than you could have imagined.

cup overfloweth

But eventually, the quarry of the once-fertile plains and forests of imagination!!!!!!! will run dry. Your hunters will pick up on the fact that there's no more ideas to be hunted, only tedious fields that demand regular, monotonous maintenance, and they'll migrate elsewhere. This is all well and good, but every now and then wouldn't you like a steak to go with those potatoes?

But again, I get ahead of myself - let's take a step back to see what a dated educational game has to do with any of this.

In The Oregon Trail, you're in charge of seeing a family1 make the trip on the Oregon Trail from Missouri2 to Oregon3.

overview

You notice how they emphasize "try"? It's because of a simple fact that you don't want to admit to yourself - no matter how simple it seems like it should be, that shit is fucking hard to accomplish4. To the outsider, it's as simple as getting from point A to point B. That's really all there is to it, right?

when to leave

Go figure - there's nuances that you hadn't even considered when you started out. Could this mean that you'll eventually discover that there are nuances upon nuances? This makes the decision of something that seems as simple as when to leave a dizzyingly difficult one.

Leave early and you'll be freezing and making slow, painful, progress5. Leave too late and you'll face the unenviable, super-difficult, task of over-wintering6. Face it - you've tried to make a trip like this before and you've probably still got the bruises and scars from the last one, but you keep telling yourself that this time will be better.

intro

You need supplies to make the trip. Oxen to move your cart7, clothing to keep you warm8, food9, replacement parts10... and bullets for hunting11. And naturally, you're constrained to a budget that's tighter than you'd like.

store

Making matters worse (you mean it gets worse?), you're probably making the trip with a bunch of egomaniacal (wo)man-children. I mean, we all strive to be egoless in our tasks, but we all take an undue amount of pride in an elegant solution and invariably take it the wrong way when someone points out the glaring flaws in our implementation. Or maybe I'm the only one, who knows?

ego

But... about those supplies. Some of them are effectively interchangable. If you've got a good hunter (you have a good hunter, right?), you can exchange bullets for food in the wild - that's the biggest bang (pun unintended) for your buck. Then you can trade food for just about anything else you need along the way12. You can run pretty lean-and-mean13 but you need enough food to keep your bellies full.

You're going to want to hunt (because it's fun!), but not every hunt can be a winner.

hunting is tough

What can I tell you? Times is tough out there. Even with a gang of elite hunters firing on all cylinders and a pile of food (ideas!) as high as the eye can see, sometimes nature just doesn't smile on you. As in any pursuit, it's entirely seemly that you can do everything right and still fail.

times is tough

Not only are times tough as hell, but you're fairly constantly reminded of your own failures and the failures of others in a big, somber way.

einstein's grave

Is there any wonder why Einstein up there didn't make it? Wasn't cut out for it. You can't teach people how to hunt - they're born with it or they'll never get it, now matter how blue in the face you get trying to explain it to them.

The trip itself? It's possible that your people are entirely happy in Missouri right now. You can crack that whip all they want, but if you don't instill a powerful longing in them to reach the promised land of Oregon, you'll never make it. In fact, you might find yourself unwillingly invited to a Donner Party. And not to ruin the surprise, but everyone at the party will be eating but you.


0. you know, your run-of-the-mill whispered about in legends superhacker
1. your development team
2. the start of the project
3. the project's end (you do have a concrete end-point in mind, right?)
4. #9 on Software's Classic Mistakes - Wishful Thinking
5. sometimes you have the toolchain you need to complete your project, other times you're kind of winging it as you go along - bootstrapping too much of your own technology stack only shrinks the chances that you'll ever make it
6. running out of funding
7. computers
8. technology stack - compiler, language, yadda yadda
9. ideas
10. source control and the other niceties of modern development (build server, unit tests)
11. ain't nothing more dire than running out of bullets - there's no metaphor here
12. dumbest way of describing the point of open source ever?
13. agile??!?

Saturday, June 21, 2008

This week's dispatch from the seventh circle

"I don't understand why FxCop is complaining about this static property on a static class."

"Probably because static classes are stateless, so exposing properties doesn't make a whole lot of sense."

"Yeah, but I want to expose properties so that a caller can set the values that they want."

"But that's really not such a great idea. Either overload methods with the parameters you're trying to read from properties or let callers instantiate the class and set the properties themselves."

Why did I find this so disturbing? Probably because it took two days for the chap to make the change.

The other reason I found it disturbing? I did the math in my head and decided that there would be approximately zero point in trying to get him to understand why globally mutable state can quickly lead to misery (false negatives/positives) when you're dealing with the MTA that NUnit runs in.

Tuesday, June 17, 2008

Design patterns as religion

I've come to an understanding of and guarded appreciation for design patterns.

They're not at all useful in and of themselves, but they are useful at a level of abstraction - they give us a common language to explain our implementations with ("...so basically, the model objects are just kind of structs and we cajole them into doing interesting things by Decorating them...") and, more importantly, they let us learn about the boundaries, limitations and realities of the design space that we're working in by revealing the problems that get solved and solved again and again and... you get the picture.

If your objects start to look like a pattern, it's a curiosity. Patterns were discovered "in the wild" to begin with, so don't tire your arm out patting yourself on the back for rediscovering one. No gold star for knocking out a Flyweight, sorry. On the flip side, don't flagellate yourself when you realize that you've implemented a Singleton - if it emerges from solid design, why would you throw it away?

It doesn't matter if you're blindly implementing a pattern or blindly rejecting an implementation because it looks like a pattern that someone on the Internets doesn't like - it's cargo cult programming either way.

Design patterns are there and were there before anyone started looking for them or writing about them. People have classified subroutines as a design pattern - like other "patterns", this isn't a reason to use or not use them, it's further establishing where they come from - introspection on how we make programs work. There's something to be said for taking a stroll through that meta-field, but I don't linger there too long. Most of the time.

All this is a long-winded way of explaining why my monocole absolutely popped out the other day at work. I was busy doing something or other at the time (transliterating objects to an XML format I don't control using unhealthy amounts of Reflection, I think?) when I saw one of the other developers explaining something or other. I popped out my earphones to catch the explanation midway through.

He had the Head First Design Patterns book open on his desk and was walking through his ideas.

"Why are we bothering with inheritance? The domain model you guys put together is too convoluted and doesn't work in this case."

"If there's something we missed, it's not like it's set in stone. If it's really hairy, we can walk through it and see if there's some reasonable way to get it factored in and if there isn't, we can go further back and see how we can make the model work for us."

"The <I forgot already!> pattern says that you can use hashtables to store the data for your objects, rather than inheriting from a base class."

"Well, yeah. But think about why we use objects and I think you'll see why that's probably a bad idea."

...

"For our model objects, we're use them not only to encapsulate associated data but to make it easily discoverable - when you're working with them internally, it may seem pretty convoluted that your parent base Foo class has property Bar that's exposed by a child Buz object (which has more properties and methods from the IBaz interface that Foo implements), but that's all readily discoverable by anyone who's consuming a Buz object. They could kind of care less how it works, they just need access to have access to its state and be able to send it messages to have it do interesting things."

He was not sold by my explanation and the discussion closed in on arguing (something about our respective tones and the other developers in the office getting quiet and looking uncomfortable) about whether it makes more sense to have the classes representing data internally like a struct or as a hashtable - I scoffed (and still scoff!) at the idea but told him that he was the one implementing it, so if he had a good reason for properties exposing a hashtable behind the scenes, I was fine with it.

I started to look up hashtables and figure out whether he was really on to something or whether my gut feeling that it was adding an unnecessary level of complexity to the design (OK, I was premature optimizing in my head and wondering about the relative weight of sparsely-populated hashtables, too) when, a few minutes and pages in the book later, he announced to another developer in the office (!!!) that the book said that you should only use hashtables when you're dealing with a lot of inheritance and a lot of properties.

I don't think there was any amount of selling I could have done to get him to walk away from the curious implementation - it was design pattern as dogma. Blinders on, reject facts, implement on faith and The Pattern will see you through.

I'm still trying to figure out if I was wrong (probably, yeah) for knee-jerking away the use of hashtables or not. I'll let you know when I turn that page.

Thursday, May 29, 2008

Aging codebases, a postscript

Ron Avitzur's comment on my post wondering aloud as to whether code can age gracefully done tickled my brain. I mean, I think about code a lot. I think about software and making software a lot.

But for some reason, I hadn't ever pondered how truly strange software is - if you look at it a certain way, it's never truly broken. It may be old, it may be ungainly, but it will always do something.

Sure, the hardware that it ran on may disappear or cease to function and the compilers may evaporate... but that doesn't mean that the code's broken. It just means that you've got a little work ahead of you porting that software to the latest and greatest hardware and toolchain and bingo bango your software's back from the dead.

Of course, there's always the question of "should we?". Times move on and inevitably reach a tipping point where maybe it makes sense to let that sleeping codebase lie.

Steve McConnell refers to this as a "doghouse problem" - when it comes to building a doghouse, everyone has an opinion on what color to paint it, what the roofing tiles should be, the exact dimensions, yadda yadda because it's a problem so eminently tractable that we can easily wrap our heads around it. Hell, it's within the realm of reason that we could build it ourselves. We have a pretty good idea of what it'll cost to make and how long it'll take.

But ask us to price the cost, materials, resources and time required to build a skyscraper and... good luck on estimating that one. How hard can it really be though? They're both buildings, right?

A couple of real-world buildings brought this into clear focus for me.



First is an old mill building not too far from where I live. For the years I've been here, it's been uninhabited - a hulking, crumbling mess of a building. 100 years ago, I'm sure it was a bustling center of commerce, an economic powerhouse. Now it's gone past creepy and into sad. It's being demolished to make way for... I don't know. Probably another drug store or something.



(zoom on the crumble)


Second is This Old House, or what's left of it. There was a house there once, nothing here now but the bones of the old building rising like so many dinosaur bones from the ground.



(check them bones)


Either one of them could be broken down as much as possible to be built back up to work again, but it's the house whose bones will remain in place while the mill's ground into the dust. Looking at it, the possibility of fixing it piecemeal doesn't even enter into your mind - it's over a hundred years old, frigging brick and huge. The house, on the other hand? Over a hundred years old, but the frame and chimney are still sound - we can rebuild around them, putting the walls and stairs and windows in different this time.

When looking at open source projects, it's not uncommon for one of the mentioned features to be their "clean codebase" - on some level, this is kind of laughable because who but a geek gives a shit what the code looks like as long as it runs well enough and does something useful for you?

On another level, it shows that there's people who have taken pride in their work, that fix broken windows, and have a vested interest in making sure that a year from now, it will have crumbled less than that mill building.


Think about building something that will stand the test of time and it just might. Make it concise and useful enough and who knows? Its framework just might live a decade or so.

I hope to someday build something so good that I won't be able to hear the lamentations of the developers responsible for supporting it because I'm busy watching Wheel of Fortune too loud or whatever it is that incredibly old people do. Did I mention that I'm watching The Wheel in my rocket car? Because ideally, I'm incredibly old, reasonably well-to-do and the future finally delivers on its promises.


Postscript



I biked by the house again earlier this week. Nothing remained.

I still hold out hope for a rocket car-filled future.

Monday, May 5, 2008

SQL Server, we need to have a talk

So I'm working on normalizing the database the other day.  I want to move some columns from a table that I'm about to make vanish to another table and I can't remember the syntax for it.  I should have hit up The Google (the SQL syntax for adding tables/columns to tables really is dead simple) but instead I was extra lazy and fired up the table designer inside of SQL Server Management Studio and scripted out the changes to the tables.

I finish that up, finish modifying the stored procedures, everything looks good.  I run the SQL script, fire my black box tests against it.

Hmm.  Things ain't working right.  The column that I just defined to hold a decimal is causing problems.  I check my stored procedures to make sure I'm not doing anything insane, check my business logic to make sure I didn't bork anything there, it all looks good.

I take what I'd just scripted and distill it down to its essence.

create
table scratch
(
percentage decimal (18,0)
)
go

insert
into scratch
values (0.5)

select *
from scratch


Not-so-curiously, the scratch table now contains a lone value of 1.0.


When you look at it, it's obvious what went wrong here - I just defined a decimal with zero digits of decimal precision.  Or, as I like to call it, a fucking integer.


I obviously biffed in the first place, but this left me scratching my head - why on earth would you make the default for a decimal (effectively) an integer?


As an added bonus head scratcher, there's no warning about the loss of precision/silent rounding when you store the value in there.  I don't know what should happen there (do you want an exception because of that sort of thing?) but I do know that it rhymes with "leaky abstraction."  I'm not an RDBMS guru, people.


Times like these, I understand why it's regarded as best practice to treat money as two integer values (dollars and cents!) - databases are a bit funky when it comes to storing out your decimal values.

Saturday, April 19, 2008

Can codebases gracefully age?

Terrible shame. Monstrous shame.

I really need to stop looking at my old code. More than that, I need my old code to work all the time in the face of needs and requirements that didn't exist when I first wrote it. Is that even possible? It isn't when I put it like that.

Probably not. At this point, I'd say "almost certainly not," but it's not like I've seen a whole lot of other projects' codebases (it's not something that I do for fun).

The sad thing is that, not to sound like a monstrously arrogant prick (even though I am), I'm the best developer where I work, by far. When Larry O'Brien made the observation that bad developers are actively counter-productive, it riled some people, but I'm in complete agreement. I'm the best developer at my office (sometimes by more than an order of magnitude) and I'm out-and-out embarrassed by code I wrote six months ago. As in "how the fuck did this shit ever work?" embarrassed. As in "if I ever come across a time machine, I'm going back in time to punch myself in the throat for that mess" embarrassed.

And it only gets worse.

This isn't humility, this is common sense. Microsoft doesn't want me, Google wouldn't fart in my general direction. I'm pretty sure even Fake Steve Jobs would prefer that I not have any Apple products.

I'm certainly no superstar developer (do they really exist in nature?), but even developers way smarter and better than I am have problems with their codebases, especially as they age.

Microsoft's not having such a smooth time of things with Vista - people are hating it so much that they're apparently seriously thinking about doing away with backwards compatibility, regarded by some as the albatross around Vista's neck. But... backwards compatibility is what sells Microsoft products for a whole lot of people. Microsoft's got scary smart dudes working to insure that your old software will keep working, even if it means that old, really questionable stuff, stays in the OS to keep it working.

They must make bunches of money off of it (there's a school of thought that says that the solid support/backwards compatibility fuels the virtuous cycle that keeps large companies from jumping ship from Microsoft), but with the time overrun and backlash about how assy Vista is, they're thinking about sacrificing a cash cow for a restart on the accretion of bugs they have to support in their codebase.

Apple's another company that's got scary smart dudes working for them. Like, even the guys that don't really work for them are scary smart. Another place where I'm sure I'm the janitors are smarter than I am. Even they've got problems with their codebase.

Even there, when it came time for OS X to come out, they broke backwards compatibility with System 9. There was an emulator or something for it (I could swear my PowerBook has it on it) but they made a clean break of it. With point releases of OS X, they brutally deprecate features and functions, leaving developers to clean up their act or not run in the new version.

It's kind of rough, but it's probably also the right way to go. Yes, as a first course, you want to refactor the hell out of your code. But they've accepted the fact that their codebase doesn't age gracefully and when they find really objectionable code, they rip it out as soon as they can. Developers who support Apple apps seem to not mind it all that much (maybe they do?). As for the users... compare and contrast people's reaction to Leopard and Vista.

I just don't think that it's possible for code to age well. Bits and pieces may stand the test of time, but the whole will become a not-so-secret shame. Well, maybe TeX has aged gracefully, but (and no offense intended) nobody who's as smart as Donald Knuth is wasting their time reading this blog.


(click for more bigger brick)

I think that's a totally lovely sight, but if that were software, a bunch of people (the developers supporting it, the people trying to sell it) would be in a lot of pain because that is unfit.

I mean, OK. First it was designed as a brick edifice to hold a building up. Then someone decided that we could slap an ad for Coca-Cola on it. Then a real genius figured "hey, it worked for Coke, why not make it work for Gold Medal", and in the process, they lost sight of what it could reasonably support.

If that were software, I'd be scared to touch it - if I do anything with it, I'm going to lose the Gold Medal ad or the Coca-Cola ad or both or the lovely interplay between the two. I don't want to be responsible for fucking them up.

It only overtly serves one of its intended functions well at this point, when, if it were software, people would be demanding it support all three. At this point, we can all agree that there are simpler ways to support multiple ads (they're called billboards, have you heard of them?) and maybe we should just strip it back to what it can do well (be a brick wall).

In the face of all this, why do I keep developing? In the hope that next time I'll get it right.

So what about you out there - do any of you work on applications that only get better with age?

Python Hack - Unicode Sniffer

Unfortunately, I sort of built the build system we use at work.

I say unfortunately because, since I'm the one that built it and I'm cheap, it was rolled with a minimum of brains and a maximum of free software.

On the database side of things, I use a handy little program called GSAR (global search and replace) that does what it sounds like it does - searches and replaces strings in files.  Unfortunately, it isn't exactly Unicode-aware, which means that files not saved as ASCII can slip through the cracks, causing subtle problems (depending on how subtle of a problem you see a missing piece of functionality being).

This normally wouldn't be a problem, but SQL Server Management Studio seems to flip a coin on installation to decide whether it's going to save files as ASCII or UCS-2/UTF-8/UTF-16 encoded by default.  Most computers in the office save files as ASCII, but there's a few that like to emit Unicode (especially when scripting out tables and stuff).

Like a hawk, or a ninja, or a ninja hawk, I quickly figure out who the offenders are and keep an eye on their check-ins.  I've got an RSS feed for the repository and, to be honest, they don't check in a whole lot of code so it's not a monstrous burden.  I keep an eye on check-ins anyway because, well.  I'm anal like that.

But why bother grepping the files manually when I've got a computer to do the grunt work for me?  I've been putting off knocking together a C# program to do it for me (why should I do it?  I'm not the one who sucks!), Ruby isn't so Unicode-savvy... but wait!  I'm a world-famous Python hacker now and Python knows Unicode!

So I put together a script that will recurse down the directory tree you put it in and, if it finds a file that isn't saved as Unicode, print its name out.  As a word of warning, it's not the greatest thing I've ever done and it catches binary files in its trawl line as well.  For my purposes, that's just fine - there's just text files living in the /Database portion of the central repository.  Now I can have it shut the build down when it finds the file straight-away.  Everyone goes home happy!  Except for the developers who got the bum install of SSMS and have to do some Save As... gymnastics every time they touch a file.

You can grab the little script here.  Feel the magic!  Feel the power!  Marginal utility!

Oh, and I updated the links to my world-famous marginal utility IsDebug for .Net 2.0, too.


4/23/2008 update - I've gone ahead and slapped the WTFPL on it. So do WTF you want with it now. Or don't. You won't hurt my feelings either way, honest.

Sunday, April 13, 2008

I don't care about money (except when I do)

I walk and bike the same general paths on a regular basis, but every now and then I'll notice a really odd building or landmark and wonder how I went by it every day for months or years without noticing it, at which point I'll be struck by my ability to take something so obvious for granted.

I have the same reaction to reading - I'll read things and they'll resonate in a bizarre "how did you know I was thinking that" way.

One thing that programmers don’t care about

They don’t care about money, actually, unless you’re screwing up on the other things.

- Joel's Field Guide to Developers

I hadn't ever really thought about it, but when I read that a few years back, it really did strike a chord. When I got started developing professionally, I had to bike to work because I couldn't afford a car. That was OK. A few years later, people close to me told me that I needed to look for a new job because I was woefully underpaid (I was), but I still felt like I was learning so I never dusted off my resume.

Today I find myself in another awkward situation - I get paid more or less well but am completely unfulfilled by my job, but looking at the job market out there, I have to pick my jaw up off the ground. I see companies just outside of major metropolitan areas offering $45K-$65K for senior developers with 5+ years of experience. Normally I'd roll my eyes at another obvious H1B workaround, but these were genuine-sounding postings on developer-friendly spots (37 Signals/Joel on Software/The Daily WTF) and didn't have the laundry list of insane system experience for the lame salary they were offering. I take one look at those job postings and immediately swat that tab closed.

But hold on a second - I thought I told myself that I don't care about money?

Well, here's the thing - I don't care about money, but I do care about respect. I don't wake up sobbing each morning because the hundred thousand or so stock options I've been promised over the course of my career have been worth a total of 200 bucks (that's counting the plenty of options that are worth zero dollars because the companies went bust). I didn't even cash them in because what the fuck two hundred dollars.

The value you put on stock is a measure of your belief in the company.

- Rands in Repose*, The Business

Signing on to a start-up, you have no idea whether it'll go Google or go Pets.com (and it could go way worse than Pets.com), but if you don't believe that the options will be worth anything, it's already a sign that you should keep looking.

In the same way, I see salary as a measure of how much the company values its developers. Are they looking to hire an intelligent person? Will they be paying them enough money that it'd be borderline suicidally stupid for them to ignore their input into the product and process? Or are they just looking for a clerk who happens to speak a little C#? $45K-$65K fairly screams "dead-end clerk" to me, but it's no guarantee - you can make plenty more than that and still feel like a dead-end clerk.

I hate to sound like Joe Bitter or whatever, but when Jeff Atwood pondered why developers don't always use the best products that money can buy, instead opting for so-so free software, I knew the answer as soon as I saw the headline.

It's so nice to just download the thing that gets the job done without having to fill out forms, get permission, wait for a PO, or anything.

- malcontent**, programming.reddit.com

So, so very right. When it comes to doing what I do for myself, I'm A-OK with figuring out what's the best for the job and paying money for it if I need it. When it comes to work, I try to do the same, but how hard will I fight to get the resources bought for me that will make me more productive?

I've heard developers on forums talking about how they've bought their own licenses and that's just insane to me - why would I spend money to save my employers money? I tried to get them to put out cash to support developers doing good work and instead, they end up putting out cash in the form of my time to support developers (me!) cobbling together mediocre (just kidding; my stuff's all brilliant!) workarounds.

Money it is an excellent signifier for figuring out just how important things are to people. When gauging desire for features, it's the first thing I grab for - how many people will buy in because of this feature? If it's a custom build, how much are they willing to pay for this feature? Will they really walk if we don't deliver?

This is why open-source people get riled up when you ask how to do something trivial and will ask you where your patch is when you complain about "needed" features - you're implying that your time is more valuable than theirs. They've already given you something free, and now you're rifling through their wallet looking for a $20 on top of it.

For someone who claims to not care about money, I find myself thinking about it more than I should, when I should be spending my time thinking about carrots in the toaster or something.

* Man, Rands really has come a long way from his days in Jerkcity.

** How apropos a nickname is that?

Carrot in the toaster

I realize that it lacks the effortless panache of the banana in the tailpipe, but I'd like to introduce the world to a new, insane meme, the meaning of which will take generations to decipher - the carrot in the toaster.



(blow it up!)


Come summertime, I like to grill carrots. I'm OK with cooked carrots, honest. But an unpeeled carrot thrown right in a grimy toaster oven? There's something so very wrong with that.


This is truly a disturbing world that we live in.

Tuesday, April 1, 2008

What does your app's codebase look like?

I took this snapshot in the parking lot at my building. I can't say that our application's architecture intentionally derived its inspiration from it, but there is an eerie similarity.



(click to blow up the tragedy)


Ha ha, only serious.

Sunday, March 30, 2008

My (current) favorite picture in the world

I was walking through downtown Manchester a couple of weeks ago, and this sign called out to me with its beautiful, terrible siren cry.



(click to blow it up)


If you're going to ask me what's so beautiful about it, you may as well ask me where it all went wrong and where you lost your soul from childhood up to here. It's really the final admonition ("NO ESCORTS") that puts it over the top for me - it displays a remarkable economy of language that I obviously have no facility for. At the very least, it tells the passer-by "we've been asked that goddamned question so many times we have to put it out in front so people don't ask again (and they probably will anyway)."


I love this picture in an inappropriate way. Or appropriate, I don't know.

Friday, March 28, 2008

Taking your lumps like an enterprise

Obie Fernandez posted recently about SAP, enterprise software peddlers par excellance, getting their asses sued by Waste Management, a behemoth of a company, for a clusterfuck of a deployment.

This reminds me why I want to keep working for small companies - I want to know when other people are making absurd promises that they'll then expect me to uphold as soon as possible and if at all possible, I want to be able to correct them or speak directly to the client and say "Sorry, they fucked up when they said that. Not gonna happen in that amount of time, but let's see how many items on that checklist we can realistically get done in the time and cost constraints you've set forth for us." Scrum has embarrassingly juvenile terms, but I think they really nailed it with the pigs and chickens metaphor.

It also reminds me of a talk I had with my COO a few years back, back in the heady days when I thought software could solve all ills and had no interest in moving any further up the food chain than architect. We were talking about some other clusterfuck that was in the news - a huge enterprise software vendor, a huge client, tens of millions of dollars and... nothing to show for it.

The developer in me was all righteous indignation - "How can they get away with that? Isn't that kind of thing embezzlement or something? If that were me, I would sue the bastards."

His response (and I'm paraphrasing) was a thunderously mighty zenslap.

"There's no point in suing them."

"How can there be no point? It'll serve notice to the next vendor in line that they're not to be trifled with."

"No, there's really no point. Even if they win, they'll never recoup their costs. They'll scare away other vendors and they still won't have what need. It's over."

I couldn't argue with that. I can't.

The contracts are dozens of miles long, filled with all manner of Cover Your Ass wording and dense, vague terminology that likely provide a Get Out of Jail free card to both sides. It'll be tied up in the courts for years, but it doesn't change the essential problem - you've already slipped what you thought was your deadline and run over-budget.

Do you spend time, money and focus trying to chase what you already know is a dead-end or do you effectively shrug your shoulders and focus on what will make you money? Were you completely up-front with all your needs? Were they all clearly outlined (and signed in blood in the contract)? Really?

And remember - if you do go with suing them, your chances of getting that software you swore you needed probably just evaporated. That's money that's probably coming out of your implementation budget (which is, again, already exhausted). If you could have done it in-house, you would have (right?) but you couldn't, so it means you need to find a new vendor. Who is going to be very wary of signing on with you because of the lawsuit, which means even more time and cost to get to the point where you can convince them to start building for you (which is going to take even more time and cost more because they know about your lawsuit and need to double-cover their asses). Knowing that it'll be a pyrrhic victory at best, do you still sue?

So I'm surprised that Waste Management is nutting up and suing the holy bejeesus out of SAP. I am, make no mistake about it, cheering for SAP to lose in the most majestic manner possible. I hope other large companies sue other large, shitty, enterprise software vendors.

And I am hoping that when they're eradicated, I'll figure out a way to become the next SAP. Money isn't the be-all and end-all, but I'm not too much of an asshole to say no to obscene amounts of money for nothing more than putting on a suit and having a nice little dog-and-pony show.

The difference between a shoplifter and a very successful enterprise software firm is that you're scared as fuck to prosecute the enterprise vendor when they rob you blind.

Tuesday, March 25, 2008

So, about that Microsoft-Yahoo Merger

So it was a slow day and I was reading about the Microsoft-Yahoo merger. How developers at Yahoo are fleeing in droves because Microsoft doesn't get the 'net and will ruin Yahoo.

And this isn't so say that they're wrong, but how about fleeing Yahoo for a better reason? Like, say, because of this embarrassment puddle parked out on the street in front of my shonky whip? I mean, come on Yahoo. I've never seen a Googlemobile, but I suspect that they're not quite as... butch as this one is.


(click to engorge this shameful display)

I've got no eye for color or detail, but... fuscia with the cheesy flame job? Really?

Then again, it did bring a smile to my face. For all the wrong reasons, but I was smiling. Way to go, Yahoo. Good luck keeping the corrupting influence of Microsoft far away from your pristine shores.

Sunday, March 23, 2008

It's official - I'm a Python hacker!

Lately, it hasn't been building the application that's captured my imagination so much as figuring out a way to validate the correctness of the application. When you're dealing with a sprawling behemoth of an application of varying levels of quality (this isn't a dig at co-workers - I've got more than my share of turds baked in there) that's so absurdly data-driven that... well. I've come to grips with the fact that chunk by chunk, we've built a borderline unmanageable enterprise application.

There's blocks of the application that I'm flat-out scared to touch because of their fragility. There's a reason that Jenga never took off as an application platform.

There's so many tables (I'll ballpark it at 300, but it could be more than that) that I have to walk through stored procedures and table definitions to figure out why many of them exist. Thankfully, at least they're well-normalized even if, again, some are really, really arcane.

More interesting to me than anything else lately is testing the application. When it comes to a giant database-driven web application, there are no easy answers to "how do you prove it is working correctly?". Well, at least none that The Google is willing to impart on me.

As I've mentioned before and will be talking about again soon (I'm busy hacking, d00dz!), I heart the hell out of Watir. You run WatirMaker, you walk through your application, you're 80% or more of your way to a test case. But... it runs slow. It takes over 3 hours to run 130-ish test cases of varying complexity on the old desktop I snuck the regression automation environment on to. I love it, but I worry about its scalability.

Over on programming.reddit, I saw a new tool announced that tickled me in all the right spots - Pylot. It was designed as a web load-testing tool (I've seen the QA folks at work use Quick Test Pro, but it's a fragile piece of shit if I've ever seen (and built) one) and has lightweight validation features built into it. On that end, it's not as fully-featured as Watir (I've updated WatirMaker to do 31337 things like generate automagic tests when you click on text in table cells/spans/the body) but... speed! Free replacement for Quick Test Pro (maybe)!

I saw it and immediately got to wondering about writing tests for it - is there anything that will get me 80% there? Not yet. Could I take WatirMaker and update it so that it emits Pylot-friendly XML? Sure, but doesn't that feel just a lot unholy?

So I downloaded Python and got to work doing the crappiest, stripped-down-est translation of a useful Ruby meta-script to Python that you've ever seen. A few hours of grunting and banging my head later, I've got something to show for it, thanks in part to the duders over in #python on EFNet.

Does anyone have any experience working with buffer objects? I'm getting one handed back to me and I'm completely lost as to how to coax it back to a string.

um, str(yourbuffer)

that's what makes python so difficult to pick up -- its simplicity

If I were them, I'd clown on me too. In my defense, The Google wasn't all that helpful when it came to working with buffers in Python and I'm a complete new jack and calling yourbuffer.tostring() wasn't getting me anywhere useful and enough ball-aching.

So here's my first stab at PylotMaker.py. It requires the Win32 extensions for Python to run and you run it the same way as WatirMaker - pop open a command prompt and "PylotMaker.py > test.xml", browse around the Internet Explorer window that opens up, close IE when you're done and test.xml is set up for you. Minus tests.

Did I really spend 5 hours knocking out 44 lines of Python instead of playing Team Fortress 2? There's something way wrong with me.

Wednesday, March 19, 2008

A Few Binary Propositions I'm Comfortable Making

By the time I got to high school, I was ready to get serious about programming. OK, not get serious, but at least take some classes in it because that's how you meet ladies (note: that's not how you meet ladies).

I learned some lessons that I regarded as stupid then and quaint now (pseudocode your program completely before you sit down at a keyboard (read: hi UML or we pay for cycles on the VAX cluster)), but I also learned some rules which have honest to god stood the test of time.

When it comes to programming, I'm pretty uncomfortable making binary propositions - there's a time and a place for a lot of things. That time isn't the future because in hindsight, you can count on recognizing just how wrong you were to think that you could get away with that.

But fret not! Here are a (very) few rules that you will never kick yourself for following. These are laws. These are immutable.


Use clear, concise, self-descriptive variable names

Our task was to write a function to calculate the area of a rectangle. After laboriously pseudocoding it out, I sat down in Turbo Pascal and banged out some gorgeously hand-crafted code, using x1 and x2 as parameters for the length and width because they were easy to type. It worked. Flawlessly.

My teacher took a look at the print-out of my code and asked "Why not call them length and width instead?" I started to argue because that's how I roll, but then it hit me like a Zen slap - code is words, structured a bit differently and with a bunch of funny-looking symbols interrupting it, but you should try to make it as readable as possible. This starts with meaningful variable names and grows from there.

Thankfully, this is one rule that I don't break. Ever.

You should be able to describe what any function does in one sentence (and the word "and" should not be part of that sentence)

I try to decompose my functions, but I'm not nearly merciless enough in my pursuit of it. I don't set out to get there, but big gnarly if blocks in my business logic can spiral methods out of control, leaving me at the point where I'm afraid to extract out blocks because things might break.

This is probably reason enough to extract out blocks, but I'm bullshitting myself into not doing it for any number of reasons - I tell myself things like "the code is complex because it's modeling a complex process" but I know just how much of a cop-out that is. It's lame and embarrassing and if only that code weren't working and I wasn't so afraid of it, I'd do something about it.

Honest. Probably.

Thanks to playing around in Haskell, I'm rediscovering just how powerful decomposition can be. You can, like, build big things out of little things and stuff. It's easier than the God Functions because you're just building ever-bigger functions out of ever-smaller, easy-to-test functions.

Next time I'll get it right. I hope.

A cat should be able to walk across the keyboard without interrupting your program

Does this sound like "validate client input"? Because it is. If you want to be fancy about it, you could say "don't trust client data any more than you absolutely have to." Either way, this is rock-solid advice.

You should not be building software where you're afraid to enter a number for a name, a letter in a date or (god help you because I've used garbage like this) click in a form while it's processing because something disastrous will happen.

I also manage to not break this (most of the time). That said, when I do things like, say, set maximum lengths on input boxes on my pages and don't test the form data on the server side, I have a pang of guilt that I'm not really solving this properly (and I ignore it and move on).

When the dam breaks, work on the first problem first

The blogosphere will tell you that this is Tilton's law. When our programs would invariably break, I'd look at the jumble of garbage on the screen and start inventing ever more elaborate explanations for what just happened. Maybe I overwrote the video buffer with a whoosiwhatsit and flargened the backplane with a sympatasultic bitmask!

My teacher sat down and asked me what went wrong. I started to spout some nonsense about this and that. He listened to me for a minute, then stopped me and said "Why don't we start from the beginning and see where it leads us?" Surprise surprise, I'd made some bonehead mistake or other (but 17 years later, I couldn't tell you what).

This came back to haunt me just today. A hot issue that must be fixed now got dropped in my lap yesterday in an application that's kind of sort of orthogonal to the one that I develop and support. So I start looking into it, but I can't get it to run out of the box. I fight with it more and more and more and a day and a half gets burned making just about no progress as I'm trying to chase the downstream effects, waiting for them to lead me back to the cause.

We get on a conference call to talk about the status and I hear people say what they were trying to do (it had been e-mailed to me before) and it clicks - check the data setup.

I'd taken for granted that someone else had done this already, but lo and behold - it's wrong. 12 hours of wasted time could have been saved by 5 minutes of fact-checking.

It's easy to get caught up in Rube Goldberg contraptions to explain what could have gone wrong and on some perverse level kind of fun, but on another, it's more fun to start simple and fix the root problem rather than chasing a symptom.

I'm batting .500 or so. It's enough to get me to the big leagues, right?

Sunday, March 2, 2008

Working Hard to Get You Fired

When we first started porting from ASP 3.0 to C#, I'd never heard of test-driven design (why hast thou forsaken me (in 2000), blogosphere?!??!).

When we had a second round of developer hires, the two guys were gung-ho to get us on the Path Of Continuous Integration and get us all test driven and stuff. Were it not for the fact that we already had 200-odd KLoCs of legacy code of varying quality that would need to be refactored to be testable (in retrospect, I'm aware of just how big of a cop-out that is) and deadlines looming, we might have gotten on board the TDD train. But had the blinders on, so that never happened.

I've done some refactoring to bake in poor man's testability (objects that audit themselves and throw exceptions for as many offenses as possible) but the fact remains that building new functionality and fixing old issues often feels like sticking thumbs in the dam - I can feel when something's going to break, I just can't tell what or where.

About a year ago, the QA department hired someone to do automation for them. I was pretty pumped about it the application that we've built is that it's so big (400 KLoCs of C#, some ASP.Net controls, another 75-100KLoCs of T-SQL, bits and pieces of BizTalk) and so data-driven, at this point it would take something just short of an act of god to get it to a point where it's testable. I have little to no desire to be part of that and have never pushed for that sort of intra-object testing. I remain unsold on the promise of TDD, but I'm not so arrogant as to completely discount it; it's more that, like security, it's not something that can be bolted on. Maybe.

Simulated end-user QA automation - that's the testing that I can get on board with. I've been using the super-hella-sweet Watir for a while now and have handed it out to developers, product development, QA, even customer service reps when I want to replicate problems; it's been a godsend. I've built smoke tests that I can run on each deployment build that have saved my bacon more than once. I don't know how much you can tell about how the application's working or not working from inside of an object, but it's pretty easy to tell when things aren't working with it when your scripts break while being run.

The QA automation guy? Nice enough chap. He's personable, seems to know what he's doing and all, but... a year in and I've got no test suite to run. Enterprise-grade tools mean awkward enterprise licenses (we actually run a fucking license server somewhere or other- what the shit is that?) and all the user-friendly quality you'd expect from anything enterprisey. Plus I suspect that the goals were too lofty, that they were intent on building something beautiful and perfect and settling for nothing less. Which is great and all, but daddy wants his application tested already.

We've hit one of our cyclical lull periods at work. This isn't to say that there aren't issues cropping up all the time, patches being sloppily built and hurriedly and incompletely tested (business as usual!), just that the volume of issues is decreasing and management's hemming and hawing about what new features to build out. I've been sitting on my hands, getting micromanaged on what issues need fixing and what can be left to slide, so I took a look in my Watir folder - hey look, 100-odd scripts testing and regressing issues that we've logged for the past year or so. Most of them broken at this point because of genuine application changes, but whatever.

I set out to fulfilling the promise I saw in testing when I first brought it up - that not only were we saving time with each test, but that we were organically building up a test suite, testing the things we needed to. Getting all of my test scripts working was step one. Step two, the uglier step, was taking the user out of it. Before, I was relying on the end user (the QA person it was aimed at) to push a button in an internal GUI here, look at a piece of data there. But with a few Ruby system() calls and poking at the content of spans and tables (time-consuming as that is), that's fallen by the wayside.

The next hurdle was the database side of things - there's some pieces of data that don't make themselves evident in the application to the end user, so how the hell am I supposed to test for those? Oh - you can pass variables (like the auto-generated user's ID) in to SQLCMD.

So a week and change of me ignoring this and that piddly little issue later, and I've got 3 dozen or so scripts built out and checking things. Another couple of weeks or so and I'm going to have an honest-to-god test suite and, if anyone's paying attention, a QA automation pro's going to have some explaining to do when I've come correct with a reasonably not-too-shitty regression suite in what amounts to my free time and he's over a year in and still hasn't produced smoke tests. And if no one's paying attention and nobody gets canned for it, I'm not losing any sleep over it because I'll have scratched one hell of a big itch.

If only my solution was enterprise-grade, we'd be able to use it too.

Saturday, February 2, 2008

Breaking the Hype Cycle

Like a good .Net drone (haw haw), I rambled on down to Waltham, Mass. this past Thursday to get introduced to the brave new world of .Net 3.5 and Visual Studio 2008.

I found myself going through various phases of confusion, boredom and then (eventually) excitement. Confusion over David Chappell (sadly, not the sometimes Rick James impressario) and his speech there. Given that he's written books on stuffs, has a consulting firm and talked about opening for Bill Gates at some development conference, I take it that he knows his thing. That's great and all, but... this was a developer's conference or so I thought? The man can give a good speech, but I'm still clueless as to why he felt the need to sell developers on the .Net ecosystem as a viable platform. Preaching to the converted and all that.

Todd Mancini came out next to give a talk on Visual Studio Team System. When I first started reading about it, it felt like it was just another enterprise Rorschach test but seeing concrete examples of what it does (how many use cases have been fulfilled, how many have been tested by QA, how many have unit tests, code churn, yadda yadda) I can see that behind the scenes it's a pretty slick little piece of work... more on that later.

I was remarkably confused by the talk that Allan da Costa Pinto gave. I'd signed up for a couple of sessions on .Net 3.5 and Visual Studio 2008 and for some reason got treated to an hour and a half on Windows Workflow Foundation and the Windows Communication Framework. He gave an OK enough presentation, but goddamned if I could tell you what either of the technologies are. Repeated over and over is that "you can paint your business processes" but what drawing a workflow diagram's achieving me is still beyond me. I get the feeling that there must be a lot in there, but I also have no idea what's in there or why I'd want to use it. Maybe it's targeted at a different user space or maybe it's a solution in search of a problem? I do know that you can start a process and wait up to 30 days to take the next step in it! Yes, it means fuck all to me too.

Chris Bowen, the last speaker of the day, was finally the guy who got me excited to have gone down there. Away with the 10,000 foot view of what's new with the .Net platform (too goddamned much to follow) and into the new language features (anonymous functions! anonymous types! lambda expressions! extension methods! all that good shit that perversely makes perfect sense since I've been embarrassing myself by trying to wrap my head around Haskell and functional programming) and a good, quick, runthrough of LINQ.

When I first heard about LINQ, it sounded kind of retarded to me. Hey look, it's sort of SQL. Except the select clause comes at the end and it's uglier? No thanks! How is this supposed to do anything for me? Why would I want to write not-quite-SQL and then deal with object/relation impedance on top of that? I can see it working for CRUD, but I've got joins that pull together 25 tables (god help me) and I really have no desire to try to get that to work in code.

But curiously, seeing it in action, it all made sense. LINQ-to-SQL is something that actually had my mouth watering. That same terrifying stored procedure I mentioned relies on an underlying user-defined function that broke the other day as well as views as well as... well, you get the picture. I'm mixing and matching business logic with data retrieval logic and I'm not happy about it. I was never really sold on having data retrieval logic in the business classes (I dallied OR mappers and was never really impressed by what they were doing for me) but I'm changing my mind now.

Autogenerated paramaterized SQL queries? Internet says that LINQ-to-SQL can actually outsmart you when it comes to query optimization... not that this is saying much when it comes to my SQL-fu. Chris gave a run-through of the features that went from what they were in clear terms to how they work in clear terms, and it all really clicked. I was pumped to go home and start ripping out that library of 250-odd stored procedures and start rewriting them in LINQ-to-SQL!
Except, oh yeah. We already have 250-odd stored procedures and they generally run pretty well. Writing them isn't hard, maintaining them isn't that bad. Sure, we've got business logic turds floating in our database punchbowl, but I'm too lazy to fish them out when I've got so many freaking bugs in the application to fix. The language features are really nice (extension methods still have my mouth watering) but by the time I was in the elevator down, I could already feel my excitement to Change The Way We Program dying as I got to thinking what Fred Brooks would say - this all is attacking accidental complexity, leaving the essential complexity of what we do untouched.

So it was the talk on Visual Studio Team System that left me the most sort of excited. The idea that the application forces you to work in sane, cohesive process (unit tested code, tracking user stories and the work projects associated with making them happen, lines of code, bugs open with the stories) seems like it'd be forcing you into dealing with the essential complexity of software development. Rather than pretend that you can crush that Gantt chart down and cut QA out of the cycle, you're forced to accept the fact that the constituent components of the project are missing in action and until that's done, the application isn't.

Nice stuff. Now all I have to do is find a company that'd understand the need for it.

Tuesday, January 22, 2008

How I Got My Silver Programmer Certificate

OK, I didn't. It doesn't exist. It won't exist.

There's more than one way to look at the ongoing kerfuffle over whether schools are falling down on the job or not. You can play the hyper-cynical devil's advocate and point out that in a sense, undergraduate computer science degrees are right up there with vo-tech degrees (not that there's anything wrong with that).

a degree is only as meaningful as its scarcity

Which brings us to another way to look at it - we can quit the ball-aching already because the knowledge that colleges are teaching Java instead of Lisp means pretty much fuck-all for us. Seriously. If I'm staffing for a company, I'm not pinning my hopes and dreams for future success on the fact that I've got a few recent computer science graduates working for me, even if they're from an ostensibly top-tier school. I'm hiring the guys with track records for delivering software that can talk the business domain talk (and it's a really awesome bonus if they can talk radix tries too).

College degrees don't prove that you're ready to develop in the real world. Holy shit.

Wait. This is news?

Certificates, whether they're diplomas, training certificates, passing the bar, getting your doctor stethoscope, being a certified engineer, whatever - I read them as signifying one thing only - "this person's certified to prevent me from doing anything immediately catastrophic." The lawyer may be grossly incompetent at what they do, but they'll be able to advise you enough to not land you on death row for your parking tickets. The doctor's not going to prescribe dioxin for that headache. The engineer's not going to say "what the hell, it might work" to your grand plan to replace the steel girder wire on the bridge with Silly Putty. That comp sci grad will probably be able to put something together that compiles.

You're looking for a piece of paper that certifies that the holder is an all-world programmer who's going to fix all your code problems? Sorry, doesn't exist.

Still another takeaway from this - enough already with whatever feedback loop there may be. Businesses think that they need more computer people, so they drive up demand for comp sci graduates, so colleges lower the bar for what it means to be a comp sci graduate so you can get churned out to go work at a conglomerate. I'm a schlub who went this route (or this route found me, your call), so who am I to turn my nose up at it?

This seems to presuppose the notion that there's a supply-side fix to be made here - get businesses to understand just how meaningless the comp sci degrees are and academia will disentangle itself from business and we'll find ourselves in some sort of OK-well-maybe-it-never-existed nirvana where every computer science graduate can knock out a generational garbage collector blindfolded and works on their own system kernel just for kicks; that academia's gotten too caught up in what business needs rather than keeping their heads in the clouds and looking decades down the road.

I don't buy it. I became a programmer because I've got a terrible craving for learning. I think that's the thread that underscores all at least mediocre programmers - we're auto-didacts. It's why I giggle to myself when I see the "how can I teach my son to program" question thrown out there. If they really want to, they'll find a way. If they have to be dragged there, I'm sure they'll find a 9-5 in the cube next to mine some day.

It's why I'm left scratching my head about people bemoaning the death of the comp sci degree. Saying silly things like "you go to school to learn how to learn." Bullshit. You're born knowing how to learn. Some people will learn no matter what, others are content with what they've learned and will figure out how to apply it in new, interesting and sometimes inappropriate ways and still others make me wonder just how fictional Idiocracy was (kidding! (maybe)).

Tuesday, January 15, 2008

Management Conundrums - The Cowboy

I read an article refuting the value of crunch time and got to wondering about it.
I've been the cowboy before, working 100+ hour weeks. Dreaming in code, pulling 24 hour days, a real Team Player. I don't want to ever go back there again. I'd like to prevent people I work with from going there too.
I found crunch time to be a vicious cycle. Rather than sit back and think my way through the problem, I dove in head-first and bumped my head on the bottom. Hard. Repeatedly.
I found myself working long hours, making mistakes along the way, and then working longer hours because I told myself "I'll just fix this later." And then working longer days because I couldn't remember the fix that I had in my head earlier but it all seemed so clear to me and in retrospect, fuck embracing death march values.

To push my street cred through the roof, I'll just quote Bun B who puts it better than I do.

Start with your head, homie, then use your hands / If you try it in reverse, you don't even stand a chance.

I don't know if it's confirmation bias on my part - I'm a pretty lazy guy (note to anyone daydreaming of hiring me: I'm totally joking about that). Am I just buying into what these people and their so-called "studies" are saying because I'm (*cough* not) lazy and want to believe anyone that's telling me that working a square 40 hours a week is really OK and even preferable?

The thing is, not everyone believes it - and this is not just managers that I'm talking about, either. As the comments on the article over on programming.reddit show (and as my anecdotes reinforce), some developers have an almost bloodthirsty need to believe in the power of crunch time. There were a couple of chaps in there extolling the virtues of brutal hours of work, stating that without doing months of crunch mode, their projects wouldn't have finished. I prodded, trying to lead them down a path to questioning whether the projects might have finished in the same amount of time without crunching for it, but it was rejected out-of-hand.

The Mythical Man-Month gave us the should-be-more-famous truism that "you can’t get a baby in one month from 9 women" - some tasks really are going to take a set amount time no matter how many resources you throw at them. The mother can start pushing on day one or wait until month nine to start pushing; the baby's not coming out any faster no matter how many months she's been pushing. I think that believing that you can accelerate nature (I'm talking development projects now not babies; work with me, people) is equal parts foolhardy and arrogant, but I also think that a good developer needs a healthy dose of both of these qualities.

When it's a team gelling and putting in the overtime because they want and need to, you let it go. That's a no-brainer. Of course, you can't go on auto-pilot. You need to figure out when they're sprinting to a dead end, when they've started sprinting too soon and have been sprinting so hard that it's counter-productive and maybe you should kick them the fuck out of the office at 5 PM on Friday so they can see their families and come back ready to do good work on Monday. You need to reel them in at some point. Like any design pattern, "crunch time" has its use. Just take care to not treat it like a golden hammer and you'll be fine.

It's the lone cowboy that I'm concerned about, and I'm concerned about what to do with them. When it's a team working to a goal, they're building together. When it's the lone person banging away at all hours, they're using their back more than their brain and will miss simple, obvious solutions to their problems and get aggravated at everyone else who isn't putting in the same brutal hours they are.

Part of me wants to save them, but then again I'm not sure that anything can be done with or for them. Reason, logic and studies seem to bounce off of them (it did off of me) like bullets off of Superman's skin.

At my current job, we had a cowboy developer. Good developer, smart guy, put in long-ass hours. Went on vacation, came back in with a custom XML business rules engine (like Drools) that used .Net Reflection and all that good stuff to drive it. It's pretty good code, just that in retrospect... we didn't really need it. I never had the heart to tell him that outright and thousands of lines of code nobody wants to refactor out of the application remain today.

When he eventually left, another of our developers quietly became the new "hard worker" to pick up the imaginary slack left behind. I don't know that I'd even have noticed this quiet change if I hadn't read The Lucifer Principle by Howard Bloom (this and The 48 Laws of Power are Dave Solomon picks for bizarroland must-read management books).

In The Lucifer Principle, Bloom relates an anecdote about a researcher's study at a summer camp. The researcher had identified four major archetypes for kids in group behavior - the "alpha male", the "bully", the "joker" and the "nerd" and conducted an experiment with them (nothing on the level of Milgram or the Stanford Prison Experiment).

The scientist assembled a cabin composed entirely of "leaders," boys who had been dominant, "alpha males" in their old groups. Very quickly, the new cluster sorted itself out according to the familiar pattern. One of the leaders took charge. Another became the bully. A third became the group joker. And one of the formerly commanding lads even became the new group's nerd.

- The Lucifer Principle, Howard Bloom, pg. 92

I know I'm doing a terrible job explaining this, but what it comes down to is that I've seen the shift in my co-worker and I don't think it's a conscious one. He may think that he "needs" to work longer hours (I've certainly danced around it trying to get him to feather the brake pedal on it, so to speak) to get things to work, but could he explain why?

Of course, self-interest on my part demands that I don't push them too hard to not kill themselves. I'm not the boss and if he's not doing the long hours, I'm sort of afraid that someone else is going to give me the stink eye because I'm not checking in code after midnight just before I leave on vacation to show that I'm a team player, never mind that the code's invariably broken in some hideous ways and people are going to have to quickly find and fix all the mistakes I've made because I was tired and rushing.

Moreover, like I said, I suspect that there's some subconscious understanding about the archetypes (for developers, read: "design pattern") of a team, and that the "overachiever" is one of them. I know just how loaded the word archetype is which is why I think it's probably an aft metaphor - if our work habits are indeed an unconscious manifestation of our identity, then there's no clean way to divorce one from the other - the cowboy's going to keep drawing for that six-shooter no matter what you do and resent you for telling him to keep it on safety before he blows his foot off. They may not be able to do it any more than you could conquer someone's fear of snakes just by bringing to their attention the fact that they are, in fact, terrified of snakes (I suspect this is an easier one to break though). Moreover, you get rid of one and another will rise to the occasion.

Unless you do what you can to make them and everyone else on the team aware of your distaste for their overwork and unless your boss (and bosses all the way up) are on board with holding people to a square forty, I doubt it will happen.

Sadly, getting everyone to throw fallacious common sense overboard and accept the fact that working smarter and working harder are just about always mutually exclusive and working smarter beats working harder just about every time isn't an easy task. If it was easy and if these work archetypes didn't exist, then everyone wouldn't be positive that today's Dilbert (for pretty much any value of Dilbert) just had to have been sent in by one of their co-workers.

But I'm no manager, so I keep on doing what I can to make things better, forty hours a week.