Not so simple code.
By: Jeff Foster
Tags: Software Development, Programming

We want our code to all be simple, but sometimes it’s not that easy.

44 Pages of Legacy class.

Today we ran a mobbing session looking at some examples of not-so-simple-code. We framed with the Prime Directive, code got that way as a result of people taking the best decisions with the information they had.

We had three examples of complicated code and they all had different levels of crazy.

So complicated we had to kill it….

We started with some code from one of our long-lived web products, SQL Monitor. Interesting fact — SQL Monitor was where the genesis of Knockout.js was created.

In this particular example there was a host of pain that stopped the code being simple. There was the obvious (== vs === or ‘this’) problems that are associated with legacy JavaScript and a few other typical code smells (big methods, lots of local variable capture, inconsistent naming).

The more interesting stuff to me was what made it difficult to change.

We didn’t know how customers used the feature — that meant it you changed it what would you test in the UI?

It was a graveyard of JavaScript libraries — you had to understand an awful lot to do not a lot

In this example, the code was so bad that it was tackled in the thermonuclear way. Deleted and replaced with a cleaner implementation with new features.

Good idea, but…

Our next example was a test that asserted you added new PowerShell cmdlets in a manner consistent with the existing. The goal is laudable — we want consistency! The way in which this was achieved didn’t help achieve that goal.

A lack of documentation meant that test failures didn’t tell you the why. Why is “Should have been of type X” important?

The result was jumping through hoops and editing the code until the test passes without really understanding the why.

Ye Old Faithful

Our final example was a monster. The code was so big that the print out made an audible thud.

The code had a seemingly simple reason for existing. Given a data structure, generate a SQL statement. This should be ideal for writing a unit test for, right?

Well, not so fast.

The underlying data structure is auto-generated and there are no interfaces.

There are ref parameters (C# specific)

It makes SQL by using WriteLine

Commented out code and #region tags all over the place.

The end result was that instead of writing a “proper” test, the new functionality was added and unit-tested in isolation. This is great, but the bigger beast still remains.

Now what?

OK, so we now we’ve got complicated code. What are we going to do about it?

There’s a motivation theme that prevents us doing stuff sometimes.

“bad code discourages tidying” (Simon H) “If you touch the thing on fire you get burnt” (Michelle T)

At Redgate, we’re not typically hugely deadline driven. It’s really unlikely you’re going to have to make that compromise between speed / quality. We want to do things right. However, maybe we’re not creating the conditions to encourage that. We ask how long till X? Maybe that creates the perception that all we care about is performance?

We also realized that there’s a grab bag of tips and tricks for dealing with legacy code. Just in a simple read through of the code we found we shared loads of techniques.

We’re going to try and extend this by introducing a Code Clinic. If you’re staring at some Not-So-Simple code and want the benefit of a fresh pair of eyes, post a message on our Slack channel and a willing participant will pair until we’ve beaten it to simplicity.

I’ll leave you with a quote from Julia about legacy code.