---
title: How to Stop Voodoo Programming
teaser: 'Voodoo programming is when we write code that we don''t really understand.
  We know we shouldn''t do it. But how do we stop?

  '
tags: good code
author: Rich Rines
published_on: 2014-10-07
---

[Voodoo programming] is when we write code that we don't really understand.
We know we shouldn't do it. But how do we stop?

[Voodoo programming]: http://www.catb.org/jargon/html/V/voodoo-programming.html

## An example story

We are running tests and making changes to our code
when we see a new error.

We decide we'll upgrade all the Ruby gems (dependencies).
Same error.
We upgrade to the latest version of Ruby.
We check Twitter and email while it installs.
Same error.

We ask our teammates for help in a chat room.
Most folks are unavailable but someone replies:

> "Sorry, I haven't seen that before."

Finally, we copy the error and paste it into Google.
The first result is a Stack Overflow question.
The first answer to the question includes a code block
but no explanation or links to reference material.

We exclaim:

> That solution is so weird! Totally [obscure] behavior.

[obscure]: http://www.catb.org/jargon/html/O/obscure.html

We don't have time to dig deeper, though. So,
we [copy and paste the code][copy] into the appropriate place in our codebase.
The error disappears and the tests pass.

[copy]: http://www.catb.org/jargon/html/C/cargo-cult-programming.html

Pleased,
we check the code into version control,
open a GitHub pull request,
and go to lunch.

We get back from lunch expecting to see a "Looks good to me." comment
from a teammate congratulating us for solving a difficult problem
but instead they commented:

> Why does this solution work?

They smelled something funny and caught us.
They're worried about the code continuing to work
and how those working on the codebase in the future
will know how to maintain it.

Without fully understanding the problem, we can't hope to solve it.
We also wasted our teammates' time in the chat room and code review,
and our clients' time by not using [tracer bullets].

[tracer bullets]: http://pragmatictips.com/15

How do we stop voodoo programming?

## Write a failing test

We have a great start: a failing (or erroring) test.

## Read the backtrace

The first step is to read the backtrace of the failing test.
We can open the file and go to the line number that threw the error.
We may immediately see the problem.

## Explore the source code of our dependencies

If not, we may be able to use our text editor's
"go to file" or "go to definition" features.

Working with Ruby, JavaScript, <abbr title="Cascading Style Sheets">CSS</abbr>,
and similar tools, we have access to the source of languages, frameworks, and
libraries upon which we've written our application code. There's no good reason
not to explore the source.

In Vim's normal mode, we could use the `gf` command, the `2gf` command (jumps to
bundled gems in Ruby files), the `:find` command (which is assisted by tab
completion), the `:tag method_name` command to jump to method definition, or
[grep really fast].

```vim
:help gf
:help :find
:help 'tags'
```

[grep really fast]: https://thoughtbot.com/blog/faster-grepping-in-vim

## Use debugging statements

When we're in the source code at a line from the backtrace, we often need more
context about our program's data at runtime.

In those cases, we put debugging statements in our code and in the code of those
underlying languages, frameworks, and libraries. We most commonly use [debugger]
for JavaScript, [byebug] for Ruby, and byebug and [pry-rails] for Rails.

[debugger]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger
[byebug]: https://github.com/deivid-rodriguez/byebug
[pry-rails]: https://github.com/rweng/pry-rails

This lets us stop the program and examine or change the data
to better understand control flow through the code.

## Read the manual

Running our tests with debugging statements at various levels of our code
is likely going to provide us with the understanding we need.

As we're getting closer to solving the problem,
we may want to also [Read The Manual] of a language, framework, or library.
The documentation may give us explanations and examples
of their appropriate use by client code.

[Read The Manual]: http://en.wikipedia.org/wiki/RTFM

## Write good commit messages

Without a [good commit message],
our teammates reviewing our pull requests
may not understand the change.
Future maintainers of the codebase
may not understand the reason for the code,
adding further time and cost to the work to be done.

[good commit message]: https://thoughtbot.com/blog/5-useful-tips-for-a-better-commit-message

Our reading of the manual may provide us with <abbr title="Uniform Resource
Locator">URL</abbr>s to documentation which we can reference in the commit
message.

## Contribute patches to open source

On occasion,
we will find a bug not in our application code,
but in one of the languages, frameworks, or libraries upon which we depend.

At a minimum,
we can report an issue to the project
with our tests and backtraces.

Even better,
we may have been able to fix the bug while we were
placing debugging statements in the source code.
In that case, we may be able to contribute a full patch to the project,
including tests and
a good commit message with links to further documentation.

## Conclusion

We can stop voodoo programming by
writing failing tests,
reading the backtrace,
exploring the source code of our dependencies,
using debugging statements,
reading the manual,
writing good commit messages,
and contributing to open source.

## What's next

If you enjoyed this post, read our [Back to Basics] series.

[Back to Basics]: https://thoughtbot.com/blog/tags/back-to-basics
