|
Comments on Problem Set 0
RandomHello Revisited
We saw a "Hall of Fame" example of RandomHello in lecture this week,
but I wanted to juxtapose it with a "Hall of Shame" example
to reveal and reinforce good code versus bad code.
"Hall of Shame" RandomHello1.java Example: |
"Hall of Fame" RandomHello2.java Example: |
public class RandomHello1 {
public void sayHello() {
// array of greetings
String greetings = new String[5];
// first greeting
greetings[0] = "Hello World";
// second greeting
greetings[1] = "Hola Mundo";
// third greeting
greetings[2] = "Bonjour Monde";
// fourth greeting
greetings[3] = "Hallo Welt";
// fifth greeting
greetings[4] = "Ciao Mondo";
// random number generator
Random random = new java.util.Random();
// print random greeting
System.out.println(random.nextInt(4));
}
}
|
import java.util.Random;
public class RandomHello2 {
private String[] greetings = {
"Hello World",
"Hola Mundo",
"Bonjour Monde",
"Hallo Welt",
"Ciao Mondo"
};
private Random random = new Random();
public void sayHello() {
int index = random.nextInt(greetings.length);
System.out.println(greetings[index]);
}
}
|
Differences between RandomHello1 and RandomHello2:
- RandomHello2 uses an clear import statement at the top of the file
instead of hiding the import in the code.
This makes it easier to locate the dependencies of RandomHello.
You will appreciate the benefits of this later when you have to
start drawing Module Dependency Diagrams.
(Eclipse Tip: remember that you can
organize your imports in Eclipse by using Ctrl-Shift-O)
- RandomHello1 is littered with uninformative comments.
For an explanation of what is an informative comment, see
Supplementary Handout 1: Java Style Guide.
For some additional info about comments, you should also see
last week's recitation notes.
- The
4 in nextInt(4) is incorrect!
Because the developer misread (or failed to read) the
specification for nextInt() , he plugged in the wrong
literal value it should be 5 . Although...
- RandomHello1 has magic numbers.
A magic number is a number besides -1, 0, or 1 that is
embedded in your code. Such constants should be abstracted out
of your methods as static final fields at the top of your class
as follows:
public static final int MAX_GREETING = 4;
Note that the name of this variable is capitalized because it is
static which is the convention for static variables in Java.
Capitalization makes these variables stand out in your code.
If magic numbers are not abstracted out, then developers will start
pasting the literal number all over place. Then what then number
needs to be changed (in this case, when a greeting is added),
you have to do a search-and-replace for the literal value.
When this number is
a static final int , it only needs to be changed in one
place.
The numbers -1, 0, and 1 are exempt from this rule because they are
often used in simple comparisons where such abstraction would just be
overkill:
// an example of too much abstraction!
public static final int NEGATIVE_ONE = -1;
public boolean containsCharacter(String s, char c) {
int index = s.indexOf(c);
return (index > NEGATIVE_ONE);
}
As you can see, this is a little silly, so don't worry about
abstracting out numbers such as this. Although, whenever possible,
generate numbers that depend on other values instead of declaring
them as constants:
- RandomHello2 uses
greetings.length so that
the number passed to nextInt will always be correct,
even if the length of greetings changes.
These issues culminate to the following major difference between
RandomHello1 and RandomHello2:
- If a greeting is added to RandomHello1, the code needs to be
changed in three places, but if a greeting is added to RandomHello2,
the code only needs to be changed once.
In your code, you should try to localize information as much
as possible. RandomHello1 spreads this information out
unnecessarily, making the code more difficult to maintain.
- RandomHello2 creates the variables
random and
greetings once whereas RandomHello1 creates these
two variables every time sayHello() is called.
Thus, RandomHello1 unneccessarily uses more memory than RandomHello2.
(Arguably, the behavior varies between RandomHello1 and RandomHello2
because of the differences between using a new Random every time
or a seeded Random multiple times, but this is probably
inconsequential in this case.)
RandomHello1 may be obfuscated with all of the comments,
but even if you removed all of them, there
is still a distinct simplicity in RandomHello2 over RandomHello1.
Strive for simplicity in your code. As Albert Einstein said,
"Make everything as simple as possible, but not simpler."
|