People often hire me to grab their codebase by the horns and introduce a modicum of engineering standards. Eventually I get to implement new features, but they usually come at the cost of heavy refactoring before I can even get started.

JavaScript

JavaScript (Photo credit: Johannes_wl)

A good month ago a founder emails me “Hey, I have this product, customer development at a point where big customers are waiting with fat checks to use product. I can’t even get it to run, original developers nowhere to be seen. Can you help?”

The original developers fleeing was a bit of a red flag, but the product was right up my alley: node.js, mongodb, plenty of real-time data flow and speed requirements for updating the UI. The names of waiting users made my ears perk up as well.

I’ll do it! How bad could it be?

A daily dose of WTF

It could be very bad.

Part of the project is done in Java. This makes sense, strict typing is the only logical decision considering what the codebase is doing.

Everything else is done in JavaScript. The communication protocol between Java and server JavaScript and frontend JavaScript … well that’s got a ban on parameter names being longer than three characters.

Okay, saving bandwidth, right? We’re talking about a high volume of data so let’s keep those json objects small.

That’s where things get tricky.

Because the core protocol only features names that are 3 characters long, so does the database. And because the database is full of such objects, guess what happens next? That’s right! Most of the codebase is an incoherent mess of variable names are no longer than 3 characters.

The habit leaks beyond variables touching the data.

Why write label when you can have lbl? And so on and on … in almost two months of working on this codebase, I still have no idea what most of the names actually mean. I use them as pictograms describing vague concepts. I’m starting to get a feel for how they fit together.

It gets better.

How do you make a boolean value fit this protocol? By doing this:

function fix(boolean_value) {
    return boolean_value ? 'tru' : 'fls';
}

So much for saving space. Encode 1bit values into 24bit strings! Booyah!

Oh I wish that was all, here’s another interesting thing I discovered … this is repeated through much of the code and I don’t dare touch it because I don’t know what crazy things will break.

Did I mention there’s no unit tests? How about that I’m discouraged for writing them? Yep. But hey, it’s not like this application needs to go through a proper security audit when it’s done … oh wait, it does.

if (!thing || thing === 'null') ...

Lovely huh? Of course null is encoded as a string. How else would you do it?

I try to convince myself there was a good reason for this originally.

But I could live with all of that, some of it might have sounded reasonable at the time, or might simply be a result of deluded optimisations and whatnot. It’s bad, but something I can live with.

Here’s the stuff that really makes my life difficult:

function getPurple(cake) {
   cake.color = global_color_setting;
   return cake;
}

I don’t know how to even begin refactoring that so it makes sense … it’s just … what? Who does that!?

However, the worst thing, the absolute worst thing is that some time in the past this application was moved from traditional jQuery to Backbone. Nothing wrong with that, great move I’d say, I love Backbone!

They forgot to move most things. A lot of times Backbone is just a thin wrapper around old stuff. Most of the code doesn’t even leverage Backbone and there’s still a bunch of $.ajax peppered everywhere.

And don’t even get me started on “Hey, we changed name X in the protocol, can you change all references to that please” in a weakly typed language with no unit tests … fun times. I never know when something’s going to blow up because I forgot to click on a button when testing.

Grep only gets you so far …

Enhanced by Zemanta