It's hard to over-emphasize the importance names bring to the maintainability of code. Unfortunately, there is no formula for generating names, just some good heuristics, and some major "don't"'s.
Bad names reduce code maintainability. Names are bad when they are:
- cryptic, e.g.,
- hopelessly vague, e.g.,
- overly verbose, e.g.,
- misleading, e.g.,
numfor something that holds a list of numbers
Good names are:
- plain English or follow common convention
A function name should
- say what a function returns or does, e.g.,
get-test, never how it does it, e.g.,
- be either a verb-object, e.g.,
get-test, or qualified-verb, e.g.,
- be semantic for application-specific functions, e.g.,
- be generic for general utilities,
Avoid names that are:
- hopelessly vague, such as
- verbose, such as
get-first-matching-item; code calling this function will be hard to indent and present readably
- misleading, such as
get-squarefor a function that actually returns a pair of squares
- ambiguous, such as
test-cases; is this returning a set of test cases or testing some cases?
Common Bad Function Prefixes and Suffixes
Avoid the prefix
check- as in
check-date. Other than
saying that something is being checked, this is useless. Is this
a predicate? Does it return true for good data? Does it print a warning?
Does it throw an error? Say what you mean, e.g.,
Avoid the prefix
my- as in
That says nothing about what makes your
different from the standard one.
Avoid the suffix
-helper as in
If there's a subtask in need of a function, there's a name for that subtask.
Sometimes, helpers are created just to get an additional parameter for
recursion. Use optional or keyword parameters instead.
For the same reason, avoid numeric suffixes,
A numeric suffix communicates nothing.
(Note: macroexpand-1 is an exception; the suffix means something,
namely "expand once.")
One common reason for difficulty in finding a short accurate name for a function is because the function violates the Cardinal Rule of Functions.
A bit tricky to name are helper functions, e.g., these two common recursive definitions:
(defun fact (n) (fact2 n 1)) (defun fact2 (n r) (if (= n 1) r (fact2 (1- n) (* n r)))) (defun my-reverse (l) (my-reverse-helper l nil)) (defun my-reverse-helper (l r) (if (null l) r (my-reverse-helper (cdr l) (cons (car l) r))))
The code is fine but the names of the helper functions are bad. If all else fails, use a suffix that at least indicates that this is the function that does the looping, e.g., fact-loop. But often the function can be distinguished by how the parameters differ, e.g., a cube-root function might handle a negative number by calling a helper to get the cube root of the absolute value. In that case, call the helper cube-root-positive.
In the case of my-reverse the helper function actually does a different task, even if it's not used that way. The helper returns a list with the reversed elements of l followed by the non-reversed elements of r. This function actually exists in Lisp and is called revappend for "reverse append."
Most of the rules that apply to function names apply to variable names, as well, except that variables hold objects, not actions, so verb-object and qualified-verb are inappropriate name forms.
In addition, when defining functions that are generic and reusable for a wide variety of tasks, such as a "reverse sequence" function or a "find anywhere" function, there are a number of common conventional short variables names that can and should be used:
zfor variables that can hold any kind of data
nfor variables that hold numbers
lstfor variables that hold lists
fnfor a variable that holds a function object
Thus, a function that adds a number to every element in a list of numbers could clearly be defined using:
(defun add-number (n l) (mapcar #'(lambda (i) (+ i n)) l))
The n and i suggest numbers and the l suggests list. There's nothing wrong with
(defun add-number (num num-list) (mapcar #'(lambda (num-item) (+ num-item num)) num-list))
but it's more verbose without being any clearer. On the other hand,
(defun add-number (x y) (mapcar #'(lambda (z) (+ x z)) y))
is definitely bad. The variables are too general and easily confused with each other.