Before plunging into the details of different kinds of program configuration, we should ask a high-level question: What things should be configurable?
The gut-level Unix answer is “everything”. The Rule of Separation that we discussed in Chapter 1 encourages Unix programmers to build mechanism and defer policy decisions outward toward the user wherever possible. While this tends to produce programs that are powerful and rewarding for expert users, it also tends to produce interfaces that overwhelm novices and casual users with a surfeit of choices, and with configuration files sprouting like weeds.
Unix programmers aren't going to be cured of their tendency to design for their peers and the most sophisticated users any time soon (we'll grapple a bit with the question of whether such a change would actually be desirable in Chapter 20). So it's perhaps more useful to invert the question and ask “What things should not be configurable?” Unix practice does offer some guidelines on this.
First, don't provide configuration switches for what you can reliably detect automatically. This is a surprisingly common mistake. Instead, look for ways to eliminate configuration switches by autodetection, or by trying alternative methods at runtime until one succeeds. If this strikes you as inelegant or too expensive, ask yourself if you haven't fallen into premature optimization.
A good rule of thumb is this: Be adaptive unless doing so costs you 0.7 seconds or more of latency. 0.7 seconds is a magic number because, as Jef Raskin discovered while designing the Canon Cat, humans are almost incapable of noticing startup latency shorter than that; it gets lost in the mental overhead of changing the focus of attention.
Second, users should not see optimization switches. As a designer, it's your job to make the program run economically, not the user's. The marginal gains in performance that a user might collect from optimization switches are usually not worth the interface-complexity cost.
Finally, don't do with a configuration switch what can be done with a script wrapper or a trivial pipeline. Don't put complexity inside your program when you can easily enlist other programs to help get the work done. (Recall our discussion in Chapter 7 of why ls(1) does not have a built-in pager, or an option to invoke it).
Here are some more general questions to consider whenever you find yourself thinking about adding a configuration option:
Can I leave this feature out? Why am I fattening the manual and burdening the user?
Could the program's normal behavior be changed in an innocuous way that would make the option unnecessary?
Is this option merely cosmetic? Should I be thinking less about how to make the user interface configurable and more about how to make it right?
Should the behavior enabled by this option be a separate program instead?
Proliferating unnecessary options has many bad effects. One of the subtlest but most serious is what it will do to your test coverage.