The most important (in my opinion) is good naming, but how can we choose suitable names?
This is the pattern that I am starting to see (and recommend), and I think it is pretty effective.
What? How? Who? Why?
If we think of the code as a medium of communication, what questions should the code be able to answer?
What are we trying to achieve?
The method name should be a summary of what we are trying to achieve. For example,
public void selectTheCustomerNamed(String customerName) {...}
It is (hopefully) clear from the method name what will happen when we call it, and what we need to pass in in order for the code to work.
How do we do this?
The body of the method should be the steps needed to achieve what it is we said we would do in the method name. The steps should be at the same level of abstraction. (See Composed Method)
public void selectTheCustomerNamed(String customerName) {
theUser.clicksOn(Application.SEARCH_BUTTON);
theUser.types(customerName,into(SearchPage.CUSTOMER_NAME));
theUser.clicks(SearchPage.BEGIN_SEARCH);
theUser.clicks(ResultsPage.FIRST_RESULT);
}
Who is doing the work?
In the example above, by naming the receiver of the messages after the actor who is likely to perform these steps, it helps focus the mind, and can help with appropriate method naming. For example, we can ask ourselves "What does theUser need to do next?"
Why are we doing this?
At one time or another, you will probably come across a comment like this:
// Add one to foo
foo++;
This kind of comment is irrelevant at best, it is telling us what the next line is doing. If the methods are well named, or the code is idiomatic, this is unnecessary. One negative consequence may be a kind of "comment blindness" where your mind filters the majority of comments as "noise".
A better use of comments is to explain why we are doing things in a certain way, especially if it seems unusual. Martin Fowler briefly mentions this in the "Code Smells" chapter in Refactoring.
An example of this type of comment is shown below. This represents a hard-won piece of knowledge, and will hopefully prevent a well-meaning programmer from replacing the code with the
getFooByQuery
variant without checking the caching behaviour.
// We query the id first before trying to retrieve the object, because if we try to
// retrieve the object directly (with getFooByQuery), it always bypasses
// the cache (see @link{...})
Integer fooId = findFooIdByQuery(query);
return getFooById(fooId);
JavaDoc can also be used to tell your users why they might need to pay special attention. If the code is well named, you are unlikely to need JavaDoc for all classes.
Here are some examples of where you might like to use JavaDoc:
- If you have a number of pluggable modules, why would you want to use this module
- Reasons why a user might want to provide their own implementation of this class
- Reasons why this code throws exceptions, and why a user might want to handle them
This is still a work in progress, but the results that I have seen so far have been encouraging. Please let me know in the comments if you have any suggestions for refinements or improvements.
No comments:
Post a Comment