Monthly Archives: June 2012

Don’t Be Afraid of Imperfection

Marco Arment’s post about being “addicted to PHP” talked about fear involved in switching languages:

Whichever language I choose to replace PHP will have its own problems that will take me years to master, but by the time I know whether I chose the “right” language, I’ll have invested far too much time in it to practically switch any meaningfully sized project to another language: exactly the situation I’m in now with PHP.

The fear of making the “wrong” choice actually makes the familiar, mastered PHP more attractive. That’s the problem Jeff’s identifying, and it’s very real. If you can get PHP programmers to agree that they need to stop using it, the first question that comes up is what to use instead, and they’re met with a barrage of difficult choices and wildly different opinions and recommendations.

I’d like to respond to that by saying “it’s not that hard.” More specifically, I think that these kinds of fears are blown out of proportion out of some misguided drive for perfection.

Web apps are not driven by perfection; this isn’t kernel code that has to be as optimized as possible. It’s not an electronic voting machine where governmental inspectors are going to be poring over each line of code to check it for legitimacy. No, web apps are driven by making things that work. To make things that work in a given language, you don’t have to be a “master” of that language. You don’t have to know the intricacies of how MRO works in Python to write a web app. If you want to write SQLAlchemy? Sure, then knowing how MRO works might be useful to write the best code for something that’s going to be used by tons of people – but most things you write aren’t going to be SQLAlchemy.

Essentially, people like Marco are letting the perfect become the enemy of the good. They’re so focused on “mastering such-and-such language” that they don’t realize that mastery isn’t required to reap the benefits of choosing a different language. You don’t have to be as respected as Guido in the Python community to create good things with Python. Heck, you don’t even have to follow PEP8 or any of the other “pythonic” idioms to create good things with Python. Sure, another Python coder looking at your code will think you’re a bit weird, but weird code is not the same as broken code. Weird code can be refactored as desired as you learn more about the language and what’s considered standard in the Python ecosystem.

So the next time you go to start a personal project, Marco, I’d suggest this: try stepping outside of the comfort zone,  trying something new, and not worrying about it being perfect. If you “pick wrong” it’s not actually that bad; you can make a different choice with the next project. The only reason it seems like a huge investment is because your goalpost is set unreasonably high.

How to Ask for Programming Help

Let me start out by saying that love helping people with programming problems. Giving others a hand as they learn about programming can be both fun and emotionally rewarding. That said, there are definitely a number of factors that can affect how easy it is to help someone with a problem. Here’s some advice that can help improve the quality of your questions and the efficiency of the help you receive.

Try something first.

There’s a whole domain name dedicated to this by now. In short, if you’re asking for help, you should be asking for help, not a solution. Most people are glad to offer advice, but they’re not there to do your job (or hobby) for you. If you have a question, try to figure out what you can on your own first. It’s fine if you don’t manage to make any headway – at the very least, it’ll help the person down the line to rule out what won’t work for you.

If whatever you’re having problems with has documentation (e.g. man pages), try to find your answer there – you might not succeed, but you might be surprised at how many answers are sitting there in plain sight.

Try and see if your question has been answered before. Google searches, FAQs, et cetera can all help in this regard.

Narrow down the problem…

Once you’ve given some thought to the issue, try to narrow down exactly what you need to ask help about. A random person probably isn’t going to want to try to go through your thousands of lines of code to figure out the problem you’re having. If possible, try to create a miniature version of the problem, with only the smallest amount of code necessary to show the issue you’re encountering (see also: SSCCE).

…but provide enough detail.

For instance, when you’re asking for help with something that’s generating an error, always make sure to include the  exact text of the error message – ideally, copy and paste it directly out of whatever log, console, or web page contained it. Oftentimes a tiny detail in an error message can be the key to helping someone else figure out what’s going wrong in your code so that they can point out how to fix it.

If you’re asking for help with a particular piece of code, always provide a code sample. Trying to answer questions about code without actually seeing in the code in question is hard. Having the code available makes it easier to understand what is being asked, and also makes it easier to answer a question, since the answer can be phrased in the context of your actual code rather than abstractions.

Similarly, when you’re providing an example of what your code looks like, try not to remove too much – ideally, your code example should run on its own, but at the very least it shouldn’t be semantically different from your actual code. For instance, hiding particular sensitive values in your code is fine, but you shouldn’t change or paraphrase things like loop conditions.

It’s also often useful to describe the larger context of the code you’re showing, even if you only show a smaller snippet of code. Occasionally, you’ll get suggestions on completely different ways to accomplish your goal that bypass the original problem completely (and are often more efficient).

Don’t be lazy.

If you’re asking for help, you’re asking for someone else to use their own time working on someone else’s problem. Don’t waste their time for silly reasons: check your question for typos, make sure any links you post work, and try to format things reasonably nicely if you can. If you’re asking a question somewhere that doesn’t have built-in facilities for sharing code, use a service like Pastebin.com to provide your code sample (and turn on the proper syntax highlighting).

Be patient.

Unless you’re paying someone for their time, you’re not entitled to their help. There are plenty of people willing to answer questions out there, but they don’t tend to like being badgered. Once you’ve stated your problem or question somewhere, give it some time. Generally, people who are willing to help will do so when they’re able. It’s fine to ask a question in other places if you don’t get a response from the first place where you ask (but if you do get a response somewhere else, be polite and let the other places you asked know – and even better, include the answer if possible).

If you liked this post, you might also like the older (and slightly more abrasive) How to Ask Questions the Smart Way, by Eric S. Raymond.

Please Don’t Abuse repr()

repr() is useful.

Python’s repr() function can be really handy, especially when trying to debug issues. It provides a straightforward way to both print out a representation (hence the name) of a given Python object to a console, and also allows in many cases for easy experimentation with that data (since the results of repr() are often things that can be copy-pasted into a Python session to recreate the object).

The representation of Python primitives is straightforward – it’s just the same syntax Python normally uses for such literals. More complex objects like user-defined classes, however, are not so simple to represent – the Python interpreter has no real way to discern what internal state is important and what is not, let alone to provide a way to construct that object (short of something like pickle).

The default Python behavior for repr() applied to complex objects is to show the type of the object and the memory address of the particular instance, e.g.

"<__main__.Foo instance at 0xd8d998>"

It’s not a bad default – that information can often solve a lot of the problems that you might be using repr() to debug. Python, however, provides a handy way to create a more useful output: __repr__. By overriding the __repr__ method on your class, you can customize exactly what string is returned when repr() is invoked on an instance of it. Here’s an example:

class Foo(object):
    def __init__(self, bar):
        self.bar = bar
    def __repr__(self):
        return "<Foo bar:%s>" % self.bar

If you call repr(Foo(42)), you’ll get…

"<Foo bar:42>"

which lets you easily look inside your objects to assess their state (or at least, the important parts of it) while debugging.

Until you abuse it.

What do I mean by “abusing” it? I mean pretending that something isn’t what it actually is. For instance, let’s say you implemented a linked list class, LinkedList. You might be tempted to have repr() return a simple Python list with the elements from your LinkedList, because that way it’s easy to take that set of elements and use them in another Python session.

Don’t do that. Why? Because it makes it non-obvious that the real object in question is not actually a basic Python list, but an instance of your custom class. Sure, you might know now that what you’re calling repr() on is a LinkedList, but other developers don’t – and you might not either a year from now when you’re trying to track down some bug.

Here’s a real life example of exactly this kind of confusion. A library (mutagen) returns an object that repr()s to a Python dictionary, but isn’t actually a dict. Thus, json.dump hiccups on it, but the error message (which is generated by json.dump() using repr()) makes it seem like json.dump() is behaving inconsistently and failing to encode a simple dict.

The are better ways to do this, while still retaining whatever benefits pretending to be a dict would have:

# Don't do this...
repr(my_object)  --->  "{'foo':1, 'bar': 2}"

# ...do this...
repr(my_object)  --->  "<MyClass {'foo':1, 'bar': 2}>"

# ...or this.
repr(my_object)  --->  "MyClass(foo=1, bar=2)"

Whether you pick the second option or the third depends on both your goals and the kind of class state you’re trying to represent, but what’s important is that you shouldn’t pick the first. If someone really wants a dictionary from your object, well, that’s what __dict__ is for.