blog?

Jimmy

11 July 2016

Jimmy is a chatoic chatbot that is part of the cultural genome of Truveris. The name and concept was originally sourced from a stackoverflow question which was then deleted (but is now preserved on the Coding Horror blog). Since then, Jimmy-proofing has become a way of thinking and a kind of mantra.

We also did what any reasonable software team would do: bring Jimmy to life. And thus, Jimmy the clueless markov chain bot was born.

And he's got a face, of course:

As the prototypical clueless developer, Jimmy has just graduated from college and is ready to refactor your systems ever so carefully. The havoc that Jimmy can wreak is not to be understated. Awful code is a technical debt that will have to be paid down with a rewrite. Jimmy is inventing new abstractions (think Jackson Pollock style), writing code using only side effects, and passing new and exotic arguments to functions. Jimmy-proofing your system is an attempt to prevent all of these from happening.

You Are Jimmy

"I am become Jimmy, the destroyer of codes" as it was written in the Baghavad Gita. In some ways and at some times, we were, are, and will be Jimmy. Jimmy exists to remind us of the consequences of our well intended but possibly ill informed programming decisions. Jimmy is the chaos monkey of your codebase. The code I wrote many years ago had many problems. It always does. And years from now, you will be trying to modify that code. Or repurpose it slightly. And if you Jimmy-proofed your code, you will be grateful.

What is Jimmy-proofing?

The most important aspects of Jimmy-proofing are failing fast, being explicit, and testing.

I often see statements of the form:

message = None
if state == constants.STATUS_PENDING:
    message = "PENNED IN"
elif state == constants.STATUS_RUNNING:
    message = "RUN IN WITH THE LAW"

return message

That missing else drives me nuts. And it points at two things: failing fast and being explicit. What if this function isn't supposed to handle any other states and is simply relying on the caller to verify it is doing the right thing? What if it is supposed to (possibly even documented that way) but doesn't? What if it's just a thinko? All of these questions can addressed with some good ol' fashioned explicit failure (or maybe not failure). If that if block had ended:

else:
    raise Exception("Unhandled state {}".format(repr(state)))

You would know that only those two states are allowed. Maybe Jimmy just passed the wrong value. Maybe he added a new state and forgot to address this location. But now we have Jimmy-proofed this function because (hopefully) it will fail in development or testing.

On the other hand, maybe this function can be called safely without needing to be one of those two states. You should write:

else:
    pass

This will explicitly state that you know this block can handle arbitrary values. It will upset your coverage checker, but add the appropriate pragma and you'll live.

What about testing you ask? Testing is essential for two reasons. The first is that the above example fails during testing instead of during a live news demo of your application. The other is that testing encourages the construction of testable abstractions. Testable abstractions tend to be distinct, modular blocks of code. Just what we're looking for and just what we're trying to prevent jimmy from not creating. You should have reasonably good test coverage and run your tears frequently and as a part of your build process. This keeps Jimmy (remember, you are Jimmy. I am Jimmy. We are all Jimmy) out of production and behind our desks.

So tell me about the bot

The part you've been dying to hear and I've been living to write. Jimmy was a markov chain bot based on Hailo that was trained on our chat server logs. He had a life of his own. A personality. A guru. A sage. A master of wise sayings. Sometimes spewing gibberish. Jimmy would frequently offer advice, troll other bots, learn foul language, and insult his creator. He was also an important outlet. When someone wanted to say something funny, or sarcastic, or air a complaint, they would say it to Jimmy. Jimmy was a kind of collective catharsis and a safe outlet. Because emotion in written speech is often hard to detect, Jimmy served as a proxy <sarcasm> tag. This allowed frustrations to be vented without actually calling out anyone directly and allowing the problem to be made open.

Jimmy was decommissioned when we moved to mattermost for a few reasons. But his spirit still lives on. He is still addressed directly and most people still understand what that means.

I said earlier that we are all Jimmy. In the programmer sense, we have all written shitty code. In the bot sense, all of our chatter contributed to his personality. We are all Jimmy. Let that keep us humble.

P.S. Jimmy is coming back! The details of that, however, will be the subject of another blog post.