(Last modified Wed Mar 19 12:53 2008)
There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies.
-- C.A.R. Hoare (cited in Bowen, "Ten commandments of formal methods")
Program code is read by two audiences: people, and compilers. Both must be satisfied. Write your code so that there are obviously no deficiencies. Complicated code always has deficiencies, they're just hard to find and hard to fix.
First get it right, then maybe get it efficient.
Only make it efficient if efficiency is needed for that part of the code. But always make it right. Correctness is always needed for every part of your code. It is often the case that early effort spent making code efficient gets in the way of making it right, and frequently is thrown away anyway when the specification changes.
It is never appropriate to make it fast before making it right. After all, it's easy to write software that does the wrong thing quickly (if you are in a real hurry, just use the class below).
public class FastButWrong {
public FastButWrong() { throw new RuntimeException(); }
}
cc" for the character
(but there must be just one character that your program deals with
at a time for this to be effective),
j" and "k" for integer indexes
(but there must be just one or two possible things being indexed),
and
pv", "cu", and "nx"
for the previous, current, and next one
(but there must be just one kind of thing that your program deals with
in that region of your code).
Formula left;
Formula right;
/**
Constructs the disjunction of two subformulas.
@param _left The first subformula.
@param _right The second subformula.
*/
public Disjunction(Formula _left, Formula _right) {
left = _left;
right = _right;
}
package.html
description for every package,
and make it the overview that explains
the concepts that describe the package
and how those concepts fit together.
Someone should be able to use your packages, classes, and methods correctly after reading just the javadoc description.
If it is hard to come up with javadoc comments and variable/method/class/package names that clearly describe what your code is doing, then your code is probably either
Try writing a simpler, clearer description. Instead of struggling to make the description match the code, write a clear description and make the code match that. Reorganize your design so that you can describe the components easily and simply.
These rules have a long history of helping people write better code.
if /**/ (null == result) { ... }
else if (0 == result.length()) { ... }
else { ... }
if, else, while,
or for
that has jut one statement.
But don't do it!
Put the braces in anyway.
The classical reason is that
later someone will want to add a second statement,
they will forget to put in braces,
and the bug will be almost impossible to find.
// NO! if (onlyOne) m = 1; // this is bad
// Yes. Always use braces.
if (onlyOne) { m = 1; }
// NO!
if (ref == null) { ... } // this is unwise
// Yes. Put the rvalue on the left.
if (null == ref) { ... }
(An lvalue (pronounced "el-value") is an expression that can be on the left side of an assignment; a variable, or an expression that produces a variable. An rvalue (pronounced "are-value") is an expression that can only be on the right side of an assignment; a value, or an expression that produces a value.)
As you write your code, put in assertion checks for every condition you are assuming is true. A good rule of thumb is: if you realize you are assuming something while you are writing code, stop and put in assertion code that checks that the assumption holds at the point where your code assumes it and throws an informative exception if the assumption is violated. Assertion checks are always appropriate if:
At a minimum, write checks of incoming parameter and attribute values for every method.
Assertion checking is crucial for software whose external and internal interfaces are unstable, as is almost always the case in research projects.
Where possible, make objects immutable.
That is, design your classes so that
the value of each object of a class
is set when the object is constructed,
and never changed.
Taking two examples from java.lang,
String objects are immutable,
and StringBuffer objects are mutable.
Strings are much easier to reason about and get right.
Researchers have long known that using immutable objects makes it far, far simpler to construct a proof of correctness for a program or an aspect of a program. More recently, the best practitioners have realized that it also makes it far, far simpler to understand and reason about your programs. That means they are easier to design, easier to write, and easier to debug. If an object is immutable, then you don't have to take its context and history into consideration, and context and history are the aspects that are the most difficult to understand and reason about.
if (...) {
...
}
while (...) {
...
}
if (...) {
while (...) {
...
}
}
if (...) { x = 2; }
^^ ^^
while (...) { y += 5; }
/**
Align the start and end markers with each other
and the entity you are commenting.
*/
public interface Javadoc {
/** Short ones can go on a single line (two spaces before and after). */
String oneLiners();
/**
Longer ones have the start marker on a line by itself,
and the end marker on a line by itself.
Text is indented two spaces further in.
*/
String longerOnes();
}
The Eclipse placement of a * at the beginning of each line is troublesome to do in a text editor and not worth the trouble.
/**
Returns the left subformula.
*/
public Formula left() { return left; }
/**
Sets the left subformula.
*/
public void left(Formula _left) { left = _left; }
Testing is essential, but it's difficult to test code effectively if you don't know what it is supposed to do yet.
If you are in a prototyping situation, as is often the case in writing code for research projects, you should not spend too much time on writing tests. Just write tests for what you are pretty sure your code is going to have to do.
As the specification for your code stabilizes, add more tests. If your code is something whose correctness is going to be essential, then write a full set of tests when the specification settles.
Run your tests often, even early on when you don't have many.