CS 106A Style Guide

These are the general Java style qualities that we expect your programs to have in order to receive full credit. Certainly it is possible to write good code that violates these guidelines, and you may feel free to contact us if you are unclear about or disagree with some of them. But we do expect you to follow these rules (unless there is an error in this document). In most professional work environments you are expected to follow that company's style standards. Learning to carefully obey a style guide, and writing code with a group of other developers where the style is consistent among them, are valuable job skills.

Oracle/Sun's Official Java Coding Conventions are a more comprehensive guide to proper Java programming. The practices outlined on their web site are encouraged for use in CS 106A.

This document is a work in progress.
Last updated Sun 2017/04/02


Homework 1 (Karel the Robot) Style Guide

Whitespace and Indentation
  • Indenting: Increase your indentation by one increment on each brace {, and decrease it once on each closing brace }.

  • Always use {} on control statements: With Java's control statements such as if and for, the {} braces are technically optional if the body of the control statement contains only a single line. Regardless of this, always use the {} braces. Always.

    // bad
    if (beepersPresent())
        pickBeeper();
    
    // good
    if (beepersPresent()) {
        pickBeeper();
    }
    
  • Place a line break after every { .

    // bad
    if (beepersPresent()) { pickBeeper(); }
    
    // good
    if (beepersPresent()) {
        pickBeeper();
    }
    
  • Do not place more than one statement on the same line.

    // bad
    move();  move();  pickBeeper();
    
    // good
    move();
    move();
    pickBeeper();
    
  • Long lines: Avoid lines longer than 100 characters. In HW1 this would most likely be a comment line. When you have a long line, break it into two shorter lines.

  • Blank lines: Place a blank line between methods and between groups of statements.

    public void foo() {
        ...
    }
                              // this blank line here
    public void bar() {
        ...
    }
    
Naming
  • Names: Give methods descriptive names, such as walkToEdge or grabAllBeepers. Avoid one-letter names or non-descriptive names, like x or go or method1.

  • Capitalization: Name methods with camel-casing likeThis, and name classes with Pascal casing LikeThis.

  • (HW1) Do not use variables: In a Karel program, you should not use Java features that are not covered in the Karel reader. Specifically, do not use variables, nor private "fields", nor "instance variables".

    // bad
    int steps = 42;
    
    private int count = 0;   // bad
    
Methods
  • run as a concise summary: As much as possible, avoid directly calling Karel commands like move in your program's run method. Instead, have run call other methods that perform the functionality. In this way, run is easy to read and forms a concise summary of the overall behavior of the program.

  • Minimize redundant code: If you repeat the same code two or more times, find a way to remove the redundant code so that it appears only once. For example, you can place it into a method that is called from both places.

  • Long methods: If you have a single method that is very long, break it apart into smaller sub-methods. The definition of "very long" is vague, but let's say a method longer than 20-30 lines is pushing it. If you try to describe the method's purpose and find yourself using the word "and" a lot, that probably means the method does too many things and should be split into sub-methods.

  • Short methods: It is not useful to make a method that only calls one other existing Karel method. But it can be useful to have a short method if, say, it wraps another method in an if/else statement in a way that is commonly used.

    // bad
    public void makeLeftTurn() {
        turnLeft();
    }
    
    // good
    public void safePickup() {
        if (beepersPresent()) {
            pickBeeper();
        }
    }
    
  • Mutual recursion: Recursion (which you'll learn about in CS 106B/X) is when methods call themselves. Mutual recursion is where you have two methods that each call the other to form a cycle of calls. In CS 106A assignments, mutual recursion is generally a bad algorithmic strategy that should be avoided. In many cases the mutual recursion is being used to avoid a more appropriate usage of a for or while loop.

    // bad
    public void methodOne() {
        if (frontIsClear()) {
            move();
            methodTwo();
        }
    }
    
    public void methodTwo() {
        if (frontIsClear()) {
            move();
            methodOne();
        }
    }
    
    // good
    public void methodOne() {
        while (frontIsClear()) {
            move();
        }
    }
    
Java Control Statements
  • avoid empty if or else: When using if/else statements, don't ever have an if or else branch that is blank. Rephrase your test to avoid this.

    // bad
    if (frontIsBlocked()) {
        // do nothing
        
    } else {
        move();
    }
    
    // good
    if (frontIsClear()) {
        move();
    }
    
  • for vs while: Use a for loop when the number of repetitions is known (definite); use a while loop when the number of repetitions is unknown (indefinite).

    // repeat until the front is blocked
    // (works for worlds up to size 1000)
    for (int i = 0; i < 1000; i++) {
        if (frontIsClear()) {
            ...
        }
    }
    
    // repeat exactly 10 times
    for (int i = 0; i < 10; i++) {
        ...
    }
    
    // repeat until the front is blocked
    while (frontIsClear()) {
        ...
    }
    
  • (HW1+) break and continue: The break or continue statements in loops should not be used on the assignment.

  • if/else factoring: Move common code out of if/else statements so that it is not redundantly repeated.

    // bad
    if (beepersPresent()) {
        move();
        pickBeeper();
        move();
        turnLeft();
        turnLeft();
        move();
    } else {
        move();
        move();
        turnLeft();
        turnLeft();
        move();
    }
    
    // good
    move();
    if (beepersPresent()) {
        pickBeeper();
    }
    move();
    turnLeft();
    turnLeft();
    move();
    
  • infinite loops: Avoid writing loops that never stop, such as the following. An infinite loop will cause your program to never stop executing. Replace an infinite loop with a loop that does terminate.

    // bad
    while (leftIsClear()) {
        if (frontIsClear()) {
            move();
        }
    }
    
    // good
    while (frontIsClear()) {
        move();
    }
    
Comments
  • Class header: Place a descriptive comment heading on the top of every file describing that file's purpose. Assume that the reader of your comments is an intelligent programmer but not someone who has seen this assignment before. Your comment header should include at least your name, course/section, and a brief description of that assignment or file. If the assignment asks you to submit multiple files, each file's comment header should describe that file/class and its main purpose in the program.

  • Method headers: Place a comment heading on each method of your class. The heading should describe the method's behavior.

  • Pre/Postconditions: If your method makes any assumptions (preconditions), mention this in your comments. If it leaves the program in a certain state when it is done (postcondition), mention this as well.

  • Inline comments: Inside the interiors of your various methods, if you have sections of code that are lengthy or complex or non-trivial, place a small amount of inline comments near these lines of complex code describing what they are doing.

  • Implementation details: Comment headers at the top of a method or class should describe the method's behavior, but not great detail about how it is implemented. Do not mention language-specific details like the fact that the method uses a if/else statement, that the method declares an array, that the method loops over a collection and counts various elements, etc.

  • No trivial comments: Do not make obvious comments about the meaning of individual statements. You should assume that the reader is familiar with Karel and Java in general.

    // bad
    turnLeft();     // turns Karel counter clockwise
    
    move();         // this tells Karel to move forward
    
  • Wording: Your comment headers should be written in complete sentences, and should be written in your own words, not copied from other sources (such as copied verbatim from the homework spec document).

  • TODOs: You should remove any // TODO: comments from a program before turning it in.

  • Commented-out code: It is considered bad style to turn in a program with chunks of code "commented out". It's fine to comment out code as you are working on a program, but if the program is done and such code is not needed, just remove it.

Here is a decent overall example of a good comment header on a method. Not every comment header needs to be this long, but since this method takes a parameter and returns something, it needs to mention several things.

/*
 * Jumps Karel over one hurdle of arbitrary height by walking north over it,
 * and then back down to his original row.
 * Pre:  Karel is next to a jumpable hurdle, facing east.
 * Post: Karel will be over the hurdle, one column to the right, facing east.
 */
public void jumpHurdle() {
    ...
}
(HW1) Forbidden Java Features
  • Variables: On a Karel program, you must limit yourself to the Java features shown in the Karel reader document. In particular, you should not use variables such as the following.

    // bad (on HW1)
    int steps = 42;
    while (steps > 0) {
    	move();
    	turnLeft();
    	steps = steps - 1;
    }
    
  • Data fields: These are the 'private' data variables that are declared outside of methods. These are just another form of variables and should not be used on HW1.

    // bad (on HW1)
    public class MyKarel extends Karel {
        private int count;   // bad bad bad
        
        public void run() {
            count = 5;
            ...
        }
    }
    
  • Infinite loops: One loop style, sometimes used as a way to fix a fencepost problem, is to use what is called an 'infinite loop' or a 'while true loop' with a break statement. This is not shown in the Karel reader and is not permitted on HW1.

    // bad (on HW1)
    while (true) {
        if (frontIsClear()) {
            move();
        } else {
            break;
        }
    }
    
  • Parameters: Java methods are able to accept parameters that affect their behavior. This is not shown in the Karel reader and is not permitted on HW1. Returning a value from a method (non-void) is similarly forbidden.

    // bad (on HW1)
    public void walk(int numSteps) {
        for (int i = 0; i < numSteps; i++) {
            move();
        }
    }
    
  • Other Java features: In general, you should not use any Java features on HW1 that are not in the Karel Learns Java document. There are too many features to list them all, but in general you should match the Java features used in the sample programs in class and in the Karel reader and not use any Java features outside of those ones.

(HW2+) New Style Guidelines
  • Variable types: Choose appropriate data types for your variables. If a given variable can store only integers, give it type int rather than double.

  • Variable scope: Declare variables in the narrowest possible scope. For example, if a variable is used only inside a specific if statement, declare it inside that if statement rather than at the top of the method or at the top of the file.

  • Constants: If a particular constant value is used frequently in your code, declare it as a final constant, and always refer to the constant in the rest of your code rather than referring to the corresponding value. Name final constants in uppercase with underscores between words LIKE_THIS.

    private static final int VOTING_AGE = 18;
    
  • if/else patterns: When using if/else statements, properly choose between various if and else patterns depending on whether the conditions are related to each other. Avoid redundant or unnecessary if tests.

    // bad
    if (grade >= 90) {
        println("You got an A!");
    }
    if (grade >= 80 && grade < 90) {
        println("You got a B!");
    }
    if (grade >= 70 && grade < 80) {
        println("You got a C!");
    }
    ...
    
    // good
    if (grade >= 90) {
        println("You got an A!");
    } else if (grade >= 80) {
        println("You got a B!");
    } else if (grade >= 70) {
        println("You got a C!");
    }
    ...
    
  • Minimize redundant code: If you repeat the same code two or more times, find a way to remove the redundant code so that it appears only once. For example, place it into a helper function that is called from both places. If the repeated code is nearly but not entirely the same, try making your helper function accept a parameter to represent the differing part.

    // bad
    foo();
    x = 10;
    y++;
    ...
    
    foo();
    x = 15;
    y++;
    
    // good
    helper(10);
    helper(15);
    ...
    
    void helper(int newX) {
        foo();
        x = newX;
        y++;
    }
    
  • break and continue: In general, you should avoid using the break or continue statements in loops unless absolutely necessary. A break can often be avoided by rewriting the loop test or reordering the statements in/near the loop.

  • System.exit(): Java contains a System.exit method that immediately exits your entire program. You should never call this method in our assignments for any reason. Your program should always exit naturally by reaching the end of your run function and returning.

  • Boolean zen 1: If you have an if/else statement that returns a boolean value based on a test, just directly return the test's result instead.

    // bad
    if (score1 == score2) {
        return true;
    } else {
        return false;
    }
    
    // good
    return score1 == score2;
    
  • Boolean zen 2: Don't ever test whether a boolean value is == or != to true or false.

    // bad
    if (x == true) {
        ...
    } else if (x != true) {
        ...
    }
    
    // good
    if (x) {
        ...
    } else {
        ...
    }
    
  • Save expensive call results in a variable: If you are calling an expensive method and using its result multiple times, save that result in a variable rather than having to call the method multiple times.

    // bad
    if (list.indexOf("abc") >= 0) {
        list.remove(list.indexOf("abc"));
    }
    
    // good
    int index = list.indexOf("abc");
    if (index >= 0) {
        list.remove(index);
    }
    
  • Exception handling: Don't ever catch an exception with an empty catch block.

    // bad
    try {
        foo();
        bar();
    } catch (NullPointerException e) {}
    

    Also, don't use try/catch as a kludge to cover up an error that your program is generating. Debug and sidestep the error to prevent it from happening instead.

    // bad
    try {
        myFunctionThatCrashesForSomeReason();
    } catch (IndexOutOfBoundsException e) {
        // LOL no crash now
    }
    

    Similarly, don't ever catch (Exception) unless told explicitly to do so, because this is overly inclusive and will suppress important system error messages. You should instead catch a more specific subcategory of exceptions such as IOException or SocketException.

    // bad
    try {
        foo();
        bar();
    } catch (Exception e) {}
    
(Later Assignments) Class Design
  • Properly encapsulate your objects by making any data fields in your class private.

    public class Student {
        private int homeworkScore;
        ...
    
  • Avoid unnecessary fields; use fields to store important data of your objects but not to store temporary values only used within a single call to one method.

  • Initialize fields in constructors, not where they are declared.

    public class Student {
        private int homeworkScore = 10;
        private int homeworkScore;
        
        public Student() {
            homeworkScore = 10;
        }
    
  • Avoid empty zero-argument constructors. If you don't need to do anything to initialize your object, just omit the constructor.

    public class Student {
        ...
        public Student() {}
    }
    
  • Helper methods: If you add a method to a class that is not part of the homework spec, make it private so that other external code cannot call it.

    public class Student {
        ...
        private double computeTuitionHelper() {
            ...
        }
    
  • Instance vs. static: A static member of a class is a single occurrence shared by that class and all of its objects. An instance member is one that is replicated into each object of that class. When designing your class, any data that should be individual to each object should be non-static. This still holds even if the assignment's client program only happens to construct one object of your class.

    public class Student {
        private static int homeworkScore;   // all students share one homework score (bad)
        private int homeworkScore;          // each student has his own homework score (good)
        
        public Student() {
            homeworkScore = 10;
        }
    
This document and its content are copyright © Marty Stepp, 2016. All rights reserved. Any redistribution, reproduction, transmission, or storage of part or all of the contents in any form is prohibited without the authors' expressed written permission.