A while ago I read about Poka-Yoke, a Japanese quality assurance technique. To me it really seems like attention to the small processes we go through in performing our tasks; an example:
This kind of attention to detail in manufacturing obviously applies very much to software development as well, where small defects can cause difficult bugs. Keith Ray also writes about this.
An obvious Poka-Yoke for Python is PyChecker, which checks Python source for many common problems. But I find the most important Python Poke-Yokes are the ones built right into the languages. Exceptions are our defect detection mechanisms, moreso than analysis. Prevention is done in a more ad hoc manner.
My little Poke-Yoke: don't use default arguments. It's tempting to find a sort of "preferred" value for an argument, or a trivial value, and use that as a default. For instance, every boolean input can probably be thought of in terms of a default and non-default input. This especially becomes tempting when you have a large number of inputs to a function, as with some constructors.
But what seems to be the obvious default value when writing the function isn't necessarily obvious when reading the function invocation. Even worse, the reader may not even recognize that the default exists.
More importantly, though, is that you not cover up complexity. Given a long, complicated function signature, when you use that function you need to look up the signature, and understand all the arguments. You should explicitly and consciously choose values for all the arguments. If you do not do so, you'll get an exception -- problem detected. With default arguments, you may miss something unintentionally but have your mistake "fixed" by the default value. But the default can't think for you, and it can't make the context-sensitive decision about the appropriate value for that argument.
This should not be confused with an indictment of keyword arguments -- quite the contrary, in fact. Keyword arguments are another Poka-Yoke, that protect you against misremembering the order of arguments, or having that order changed. They also mean that the values are tightly bound to the argument names, which are indicative of semantics -- change the semantics, then change the argument names, then change all function invocations. You don't need default values to use keyword arguments, so you can use keywords copiously, and almost always increase readability in the process.
Of course, these aren't hard rules. But in the right context these can save you some problems -- or maybe just make you immediately aware of the problems.
(Hi, I'm back. Happy 2004 y'all)
Occasionally you find you need to change the declaration of a function to add a small amount of additional functionality which is only needed by a few callers of the function. Default values can allow you to make the change without having to modify all callers *at the same time*. This is especially important if the functions you need to change are part of a published interface.
A better way to accomplish the same thing is to:
1. Create a new function that takes the new parameters you need.
2. Move the implementation of the existing function into the new function.
3. Change the original function to call the new function with the correct "default" parameters.
This lets the users of the older version still use it without changing, and still provides the extended functionality. Moreover, having two separate APIs makes a potential user think about which version he wants before calling. Naturally, this can be taken to unhealthy extremes, but it's usually safer than having a pile of assumptions in default parameters.
Yeah. And after some years you end up with the Windows API, where you are lost in a maze of twisty little functions, all alike ..
I guess I should say that I think things like this should really be used when you are writing something error-prone -- something that is complex and easily misused. It's not even something I'd consider a "rule". I often use default arguments, and changing APIs is a frequent reason. This is more a suggestion that we be a bit reluctant in using default arguments, not that we go so far as to avoid them.# Ian Bicking