As it turns out, human beings cannot concentrate constantly on writing code. Sometimes we need a break. In this week’s post, I’m going to suggest a few ways that you can use your down time somewhat productively.
Suggestion 1: Podcasts
Stuck on a train? Have a long commute? Going for a long walk? I really suggest listening to podcasts about computer programming. Now, podcasts are not a great way to learn specific syntax or algorithms or anything. If someone started reading code out loud on the radio, they probably wouldn’t have a very big following, and their listeners would have car wrecks trying to remember how deep the curly braces were nested. But, podcasts are awesome for a few things.
Spinning wheels, in the literal, automobile-stuck-in-mud usage, has two characteristics: The wheels are spinning, and the car is not moving. For programming, this means frantic action, but without forward progress.
Here’s an example of wheel spinning: Method A in project B threw an exception. That’s probably because it called Method B, which got some data from a database, and that data was weird. Was the data weird, or is Method B wrong? What about Method A? Maybe Method A is broken, and the data was right? Is one of the more senior developers busy? Maybe if I step through Method A six more times, I can just figure it out? (For best effect, please read this paragraph aloud four times without inhaling.)
Here are the symptoms of wheel spinning for programmers. You are stuck in a loop where:
There are multiple causes to a problem, or multiple related problems.
You have considered each of these problems more than once.
Your last time through this loop, you did not either decompose the one of the possible causes, prove that one of the possible causes was irrelevant, or find someone to ask.
And here’s why you’re spinning your wheels: If you consider the same problems, without decomposing, eliminating, or asking about them, you will be stuck in this loop forever, because you will always have the same amount of information about the same set of problems. When you are here, the only wrong answer is to stay stuck in the loop.
Instead, you have to make some progress. Pick one possible cause, and temporarily ignoring the others, either:
Figure out that it is composed of other possible causes, and recur OR
Prove that your problem still exists in its absence, so you can stop looking at it OR
Decide that you need to ask someone about it.
“Obviously,” you might object, “but you just told me to break out of the loop by breaking out of the loop. What do I do?”
Here are some specific things that work for me:
Heuristic approach: the most recently changed, most specific code is probably the problem. My first week at the new job, I was stepping through some method, and a security exception was thrown in the middle of our most general purpose, most widely used library. Did I find a bug in the database access code that a bunch of client projects depend on? Of course not. If that code were broken, everything would be broken. Instead of suspecting old, reliable code of suddenly failing, I should look up the call stack for the most specific or most recently changed code, and start there. (Or maybe, you know, check the credentials. It was a security exception, after all.)
Algorithmic approach: make a “what else must be true” graph. I list the possible causes on a piece of paper, choose one, and start finding facts that it would imply if true. “If Method C retrieves the wrong data, either the query it executes is wrong or the data itself is wrong.” This procedure makes a tree where the root is the original problem, the inner nodes are hypotheses about its cause, and the leaves are things I should test. After making the graph, I look at each leaf. If I can determine its truth value on my own, I do so and update the graph. If not, I mark it as something to ask about and continue processing the other leaves. At the end, I have either solved the problem on my own, or proved to my own satisfaction that I need to ask for help.
Surrealistic approach: try “rubber duck debugging.” Put a rubber duck on your desk. Explain the code to the duck as through to a child or a person completely unfamiliar with your technology; justify every line of code. Rubber duck optional. (I believe this technique comes from The Pragmatic Programmer: From Journeyman to Master.)
I hope this post gave you a push out of the mud. Till next week, happy learning!
During year 0, I was a high school Latin teacher. And, as the saying goes, if I had a nickel for every time I had to defend studying Latin from people who thought it was useless, I could buy a sandwich and maybe some fries. (But that’s like, 200 nickels!)
“Latin’s dead and you’ll never use it!” people would say. True, there are no native speakers of Latin, and the only time I’ve used it professionally I was teaching it, but there’s a huge benefit of translating sentences from one language into another: It forces you to separate meaning from representation.
If we only study one human language, the sounds we use to represent thoughts and the meaning of those thoughts are very tightly coupled, so we get the impression that meaning and representation highly connected, but there not. We could even argue that (poetry aside), meaning and representation are only accidentally related.
Let’s take integers, for example. 57 is a good integer. In a computer’s memory, it will be represented by some bits, little endian or big endian, or I could write “fifty seven” in English, or I could say it out loud. Not to mention the other human languages, or writing a binary string or a hex string. All these point to the same integer, so we can say they all mean the same thing, but the representations are completely different.
Computer programmers spend a lot of time choosing between different semantically equivalent ways of representing the same idea. Being able to consider meaning and representation separately is a very important skill.
My goal for this post is to put one simple trick in your mental toolbox: You can now explicitly decide whether you are considering the meaning of something, or its representation, or both. Congratulations! Now that you have this trick, what should you do?
I think, first off, you should apply this trick to information hiding. Code that is calling the public methods you write should care about the meaning but not care about the representation. I am writing code that represents a collection of customers with their phone number. The calling code wants to ask a question like “What is Steve’s phone number?” It does not care that you put Steve’s phone number in a Dictionary<Guid, string>, and therefore it should not know. The meaning of the public API you are writing should be able to remain the same while you change the internal representation of your program. What if your database decides to use integers instead of guids as keys? If your client can see the Dictionary<Guid, string> directly, this change might break every piece of code that uses yours. If all the client can see is a method like GetPhoneNumber(string name), the caller does not care if you swap out the internal data structures.
The second place you can use the differences between meaning and representation is in choosing a readable implementation. Let’s look at the following code snippets.
//Part of both snippets:
IEnumerable<Customer> customers = GetCustomers();
private bool MyAwesomePredicate(Customer customer)
//Decide whether customer is awesome.
bool found = false;
foreach(Customer customer in customers)
found = true;
bool found = customers.Any(MyAwesomePredicate);
//after one snippet or the other runs
They both mean essentially the same thing: look at the collection ‘customers’ and if you find a customer that meets the criteria in ‘MyAwesomePredicate’ then celebrate. Yay!
The difference is that in the first snippet, whoever is reading this code later is caught up in the ‘foreach’, that is, in the fact that you’re iterating a collection, not in the question that you’re trying to answer. The representation is more evident than the meaning. In the second example, the meaning is evident; you could almost read the code aloud: “The value found equals ‘do any customers meet MyAwesomePredicate'”. (Also, thanks to Eric Lippert; the example is based on an old blog post of his, which I can’t find right now, about LINQ.)
This is a pretty simple example, and its also one specific to C#, but it demonstrates the point well: separating meaning from representation allows you to consider which representation best serves the meaning of the code, which allows you to write better code.
So the next time you’re writing a method, and you have an extra few minutes, try some synonymous ways of writing the method. And ask yourself, first “are these really synonymous?” And if they are, choose the one where the representation provides the fewest barriers to future programmers understanding the meaning.