Disclaimer

Note that the code we create during class and in the notes is for illustrative purposes – it often will not adhere to these guidelines.

Design Guide

A good design is easy to implement in stages, easy to debug, and easy to change.

Intentional Coding

Submitted code should be clean and concise.

  • Every line of code should have a deliberate effect on your program. Pointless lines of code are called kruft. There should be no kruft in your program. Remove all commented code, unused variables, and lines with no purpose from your programs.

  • Do not copy and paste code and then change small details. Instead, declare a method or function and parameterize it.

    • Keep your programs DRY, e.g. Don’t Repeat yourself!

  • Avoid magic numbers: constant numerical values that are scattered throughout your program and difficult to understand.

  • Do not guess when your programming!

    • Make sure you understand every line of code in your program.

    • Do not cut and paste code from the internet, hoping some random combination will work. (This is the SLOWEST and most inefficient way to program!).

    • Do not randomly make changes to your program, hoping it will work. Instead, systematically make hypotheses about what might be wrong and test it.

  • A bug is not truly fixed until

    • You understand why it happened

    • You understand why changing the code fixed it

Scoping and encapsulation

  • Declare variables in the smallest scope possible. Prefer local variable to instance variables. Avoid global variables.

  • Never use public instance variables. Use private or protected access and then define a getter method.

Class design

Typically, there will be many good ways to organize your program. A good design will have the following properties.

  • If you allocate data in a constructor, be sure to delete that data in the destructor!

  • Classes should either be independent, or have one-way dependencies with other classes. If work is duplicated between classes or methods, there is something wrong with the design.

  • Classes should coordinate with each other only through their public API.

  • Methods should assume that all instance variables are up-to-date.

  • Methods should be responsible for a single, clearly defined task.

Data Structure Design

Typically, there will be many good ways to store data. A good design will have these properties:

  • Do not store the same thing more than once, or in more than one place.

  • Choose the smallest storage.

  • Choose storage based on how data will typically be accessed. For example, if data will mostly be accessed sequentially, store it in an array or vectors.

Naming Conventions

  • Use meaningful names! For example, if your program needs to a variable to represent a color, call it color instead of c. In graphics, the exception to this rule is common variable abreviations, such as

    • r,g,b,a for the red, green, blue, alpha components of colors

    • x,y,z for positional components

    • t for time

    • Re-using variables to match a mathematical formula (use a comment to document)

  • Use single letter variables for simple loop indices and occasionally generic integers.

  • The use of very obvious, common, meaningful abbreviations is permitted. For example, "number" can be abbreviated as "num" as in numStudents.

  • Use camel case for variables, instance variables, and method names. Camel case starts with a lower-case letter and putting the first letter of subsequent words in uppercase. For example, numStudents.

  • Use a naming convention to distinguish instance variables from other variables. Commong choices are to

    • pre-pend or post-pend underscore, e.g. radius or radius

    • pre-pend m or my, e.g. mRadius or myRadius

    • Be consistent with your choice!

  • Struct and class names are written in PascalCase, starting with a capital letter. For example, CircleShape

  • Constants (static as well as #define) are written in ALL_CAPS.

Whitespace

The most-readable programs are written with prudent use of whitespace (including both blank lines and spaces).

  • Use blank lines to separate major parts of a source file or method. These are like paragraph breaks in English writing.

  • After every {, indent by least 2 spaces until the matching }. A good editor like emacs will help you with indentation - remember to keep pressing those tabs!

    • Do not use tabs. Instead, configure your editor to substitute spaces for tabs

    • You can configure the number of spaces in your editor.

    • Your editor should have a feature to automatically format your document. For example, in Vim, you do gg=G to fix the indentation within an entire file.

  • Separate an operator from its operands by spaces.

  • There should never be a need for 2 blank lines in a row or two spaces in a row.

Line Length

All lines should have length at most 80 characters. This makes it easier to read code on a potentially small screen. If you need to break a line in order to satisfy this, the rest of the line should be indented more than its current block. In cases where the line length is within a pair of parentheses, one good option is to indent the rest of the line to match with the opening parenthesis. For example:

if (here is a long condition for an if statement and
    the rest of the condition) {
  here is a long statement inside the if statement and
    the rest of the statement below it;
}

Comments

Comments should be brief and informative.

File header comments

Every source code file should contain a header comment that describes the contents of the file and other pertinent information. It must include the following information (different order is fine):

  • A description of the contents of the file

  • Your name

  • Date

  • The file name (optional)

For example:

/**
* The main driver program for Assignment 1.
*
* This program reads the file specified by the first command line
* argument, counts the number of words, spaces, and characters and
* displays the results in the format specified in the project
* description.
*
* @author: Dianna Xu
* @version: February 7, 2020
*/

Variable comments

All instance variables must be commented (it is okay to use a single comment to refer to more than one instance variable though). Most local variables should be commented, too. Method comments

All methods must be commented. The comments should explain what the method does, what its parameters represent (not their types, we already know that), and what it returns. The comment should describe how the function handles special cases (for example, if a given index is out of range), domains for the input (for example, are negative values allowed?). You should use the javadoc method comment style, which lists and comments all parameters and return values, shown below:

/**
* Returns random integer in the interval [x, y)
* @param x The start of the interval
* @param y The end of the interval
* @return A random value between x and y, not including y
*/
int randRange(int x, int y) {
...
}

In-Line Comments

You should strive for your code to be self-explanatory. However, it is inevitable that some lines of code are more intricate. In these cases, a comment describing the code is well-advised. The comment should not simply translate the code to English, but should explain what’s really going on. For example:

// Unhelpful comment:
starSides = 5; // set starSides to 5

// Helpful comment:
starSides = 5; // reset starSides to original value

Well-structured code will be broken into logical sections that each perform a simple task. Each of these sections of code (typically starting with an if statement or a loop) should be documented. An in-line comment too long to appear to the right of your code appears above the code to which it applies and is indented to the same level as the code. For example:

// increment all the odd values in the array
for (int i = 0; i < n; i++) {
  // add 1 only to the odd values
  if (array[i] % 2 == 1) {
    array[i] = array[i] + 1;
  }
}

Remember, good comments tell us things we don’t already know, or can’t easily decipher among dense code blocks.

Indentation

Choose one of the two styles and use it consistently (note how the braces are placed):

if (condition) {
  ...
}
else if (condition) {
  ...
}
else {
  ...
}

for (control expression) {
  ...
}

while (condition) {
  ...
}

switch(condition) {
  case val1: ...
    break;
  case val2: ...
    break;
  default: ...
}

class ClassName {
 public: // 1 space for access modifiers
   returnType method(params) {
    ...
   }
  ...
};

struct TypeName {
  ...
};
if (condition)
{
  ...
}
else if (condition)
{
  ...
}
else
{
  ...
}

for (control expression)
{
  ...
}

while (condition)
{
  ...
}

switch(condition)
{
  case val1: ...
    break;
  case val2: ...
    break;
  default: ...
}

class ClassName
{
 public: // 1 space for access modifiers
  returnType method(params)
  {
    ...
  }
  ...
};

struct TypeName
{
  ...
};