Skip to main content

Code Style

Pixel art dungeon split in two. Left: Dark corridor where D&D party (warrior, mage, rogue, cleric) encounters dangerous floating magic numbers (98.6, 42, 1750) and bad comments ('i=i+1 //Add one to i', 'RIPJSB', '//You are not expected to understand this'). Trapped chest labeled 'Technical Debt'. Right: Bright corridor where same party confidently reads clear signposts (BODY_TEMP_FAHRENHEIT = 98.6, MEANING_OF_LIFE = 42) and helpful comments with links and context. Treasure chest labeled 'Maintainable Code'. Center portal labeled 'Refactor Your Way to Safety'. Banner: 'Beware the Enchanted Numbers. Seek the Truth in Named Constants.'

Magic Number

Definition: An unnamed numeric literal in code (except for -1, 0, 1, and 2)

Example from L16:

public class EnergyPriceService {
private final EnergyPriceApi api;
private final Clock clock;

public EnergyPriceService(
EnergyPriceApi api, Clock clock) {
this.api = api;
this.clock = clock;
}

public boolean isOffPeakHours() {
int hour = LocalTime.now(clock).getHour();
return hour >= 22 || hour < 6;
}
}

Poll: What's wrong with magic numbers?

public boolean isOffPeakHours() {
int hour = LocalTime.now(clock).getHour();
return hour >= 22 || hour < 6;
}
Poll Everywhere QR Code or Logo

Text espertus to 22333 if the
URL isn't working for you.

https://pollev.com/espertus

Benefits of Named Constants

Readability

static final int SECONDS_PER_MINUTE = 60;
static final int MINUTES_PER_HOUR = 60;
static final int SECONDS_PER_HOUR = 3_600;
static final int HOURS_PER_DAY = 24;
static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;

Safety

startTimer(SECONDS_PER_DAY);
startTimer(86400);

Maintainability

static final int CREDITS_TO_GRADUATE = 128;
static final int NUMBER_OF_CAMPUSES = 14;

Think-Pair-Share: What would be good names?

    private static final int ______________ = 6;
private static final int ______________ = 22;

public boolean isOffPeakHours() {
int hour = LocalTime.now(clock).getHour();
return hour >= 22 || hour < 6;
}

Notorious Example: Fast inverse square root

 float Q_rsqrt( float number )
{
long i;
float x2, y;
float threehalfs = 1.5F;

x2 = number * 0.5F;
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
i = 0x5f3760df - ( i >> 1 ); // wtf?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed

return y;
}

Source: Quake III Arena source code, via Wikipedia

Poll: What were you taught about in-line comments in previous classes?

Poll Everywhere QR Code or Logo

Text espertus to 22333 if the
URL isn't working for you.

https://pollev.com/espertus

Best Practice for Writing Code Comments

Screenshot of a web page showing a large colorful graphic of annotations to a document.
Article headline: 'Best practices for writing code comments'
Date: December 23, 2021

Principles

  • "Code tells you how. Comments tell you why." — Jeff Atwood, co-founder of Stack Overflow
  • Record your brain state for future you and other readers.
Three-frame cartoon titled 'Unfinished Work' by monkeyuser.com
Frame 1 (Friday evening): Smiling person typing away at a computer.
Frame 2: Smiling person says 'Perfect! I'll finish this on Monday'
Frame 3 (Monday morning...): Rattled person shaking computer full of code says: 'What does this mean!?!?!'

"Unfinished Work" by MonkeyUser, CC BY-NC 4.0

Rule 1: Comments should not duplicate the code

Don't do this:

i = i + 1; // Add one to i

What should you write instead?

Probably nothing, unless the behavior is non-obvious:

// Remove consecutive duplicates from array: [1,1,2,2,2,3] -> [1,2,3]
int writePos = 0;
for (int i = 0; i < arr.length; i++) {
arr[writePos++] = arr[i];

// Skip all consecutive duplicates
while (i + 1 < arr.length && arr[i] == arr[i + 1]) {
i = i + 1; // Skip duplicate; already wrote this value
}
}

Don't Write Cat Comments

Title '90% of all code comments:' above a photo of a cat with a label reading 'cat' stuck to its head.

Rule 2: Good comments do not excuse unclear code

private static Node getBestChildNode(Node node) {
Node n; // best child node candidate
for (Node node: node.getChildren()) {
// update n if the current state is better
if (n == null || utility(node) > utility(n)) {
n = node;
}
}
return n;
}

Instead, rewrite:

private static Node getBestChildNode(Node node) {
Node bestNode;
for (Node currentNode : node.getChildren()) {
if (bestNode == null || utility(currentNode) > utility(bestNode)) {
bestNode = currentNode;
}
}
return bestNode;
}

Rule 3: If you can't write a clear comment, there may be a problem with the code

	/*
* If the new process paused because it was swapped out, set the stack level
* to the last call to savu(u_ssav). This means that the return which is
* executed immediately after the call to aretu actually returns from the
* last routine which did the savu.
*
* You are not expected to understand this.
*/
if(rp->p_flag&SSWAP) {
rp->p_flag =& ~SSWAP;
aretu(u.u_ssav);
}

Source: Unix source code

Rule 4: Comments should dispel confusion, not cause it

"[Peter Samson] was particularly obscure in refusing to add comments to his source code explaining what he was doing at a given time. One well-distributed program Samson wrote went on for hundreds of assembly-language instructions, with only one comment beside an instruction that contained the number 1750. The comment was RIPJSB, and people racked their brains about its meaning until someone figured out..."
Steven Levy

Any guesses for the connection between 1750 and RIPJSB?

Source: Hackers: Heroes of the Computer Revolution

Rule 4: Comments should dispel confusion, not cause it

Black-and-white drawing of Johann Sebastian Bach
"[Peter Samson] was particularly obscure in refusing to add comments to his source code explaining what he was doing at a given time. One well-distributed program Samson wrote went on for hundreds of assembly-language instructions, with only one comment beside an instruction that contained the number 1750. The comment was RIPJSB, and people racked their brains about its meaning until someone figured out that 1750 was the year Bach died, and that Samson had written an abbreviation for Rest In Peace Johann Sebastian Bach."
Steven Levy

Source: Hackers: Heroes of the Computer Revolution

Rule 5: Explain unidiomatic code in comments

final Object value = (new JSONTokener(jsonString)).nextValue();
// Note that JSONTokener.nextValue() may return a value equals() to null.
if (value == null || value.equals(null)) {
return null;
}

Eran Yarkon, who commented on the article, suggested this rewrite:

final Object value = (new JSONTokener(jsonString)).nextValue();
if (value == null || value == JSONObject.NULL) {
return null;
}

Why might it be useful to include a link to a StackOverflow post?

Three-key keyboard with Stack Overflow, C, and V keys
Poll Everywhere QR Code or Logo

Text espertus to 22333 if the
URL isn't working for you.

https://pollev.com/espertus

Linking to Source Code Provides Readers with...

  • what problem was being solved
  • who provided the code
  • why the solution is recommended
  • what commenters thought of it
  • whether it still works
  • how it can be improved

Example: /** Converts a Drawable to Bitmap. via https://stackoverflow.com/a/46018816/2219998. */

This also honors the open-source license.

Links to specifications are especially useful.

// http://tools.ietf.org/html/rfc4180 suggests that CSV lines
// should be terminated by CRLF, hence the \r\n.
csvStringBuilder.append("\r\n");

You can get the full details and see if there are any updates.

Rule 8: Add comments when modifying code

This is especially important when fixing bugs.

  // NOTE: At least in Firefox 2, if the user drags outside of the browser window,
// mouse-move (and even mouse-down) events will not be received until
// the user drags back inside the window. A workaround for this issue
// exists in the implementation for onMouseLeave().
@Override
public void onMouseMove(Widget sender, int x, int y) { .. }

Best practice is to include the issue number:

// Use the name as the title if the properties did not include one (issue #1425)

These details help readers understand if code is still needed and how to test it.

Rule 9: Use comments to mark incomplete implementations

Sometimes, it's necessary to commit incomplete code:

// TODO(hal): We are making the decimal separator be a period,
// regardless of the locale of the phone. We need to think about
// how to allow comma as decimal separator, which will require
// updating number parsing and other places that transform numbers
// to strings, such as FormatAsDecimal

Better yet, add an issue to your tracker, and reference the issue in the comment.

Summary

It is well worth taking the time to:

  • give good name to constants
  • write and update comments

Your colleagues and future you will appreciate it.

Words of wisdom

"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. Code for readability."
John F. Woods

https://stackoverflow.com/a/878436/631051

Bonus Slide

3-frame geek & poke cartoon titled 'good questions' featuring a man and a woman in front of a computer.
In frame 1, the man says: 'Don't know. I copied it from Stack Overflow'
In frame 2, both are silent.
In frame 3, the woman asks: 'From one of the answers or from the question'