tidy first - part 1 - tidyings

Guard clauses

if (not condition) return
if (other condition) return
 
// is easier to read than
if (condition)
  if (not other condition)
    // ..some code

The “single return” rule came from the days of FORTRAN, so no need to follow with more modern languages.

Caution

Don’t overdo guard clauses. A routine with 7 or 8 guard clauses is not easier to read.

Dead code

  • Just delete it.
  • If you suspect code isn’t used, pre-tidy by adding logs and remove it once you’re confident.
  • Delete only a little code easier to revert in case you were wrong.

Normalize Symmetries

  • As a reader, you would like consistency.
  • Convert variants into a single way.

New interface, old implementation

  • If old interface is difficult to work with, create new interface that uses the old implementation.
  • Pass-through interface = micro-scale essence of software design.

Reading order

  • Reorder the code in the file in the order in which a reader would prefer to encounter it.

Cohesion order

  • Reorder the code so the elements you need to change are adjacent.
  • Cohesion order works for routines in a file: if two routines are coupled, put them next to each other. Also works for files: if two files are coupled, put them in the same directory.
  • If you can decouple, do it if you can, but it may not be feasible for various reasons.
cost(decoupling) + cost(change) < cost(coupling) + cost(change)
  • Sometimes better cohesion helps you live with the coupling.

Move declaration and initialization together

  • The name of a variable gives you hint as to its role in the computation.
  • The initialization reinforces the message of the name.
  • Play around with the order. It’s easier to read and understand the code if each of the variables is declared and initialized just before it’s used.

Explaining variables

Some expressions grow. When you understand a part of a big, hairy expression, extract the subexpression into a variable named after the intention of the expression.

Explaining constants

Create a symbolic constant. Replace uses of the literal constant with the symbol.

Explicit parameters

  • It’s common to see blocks of parameters passed in a map, but this makes it hard to read and understand what data is required.
  • Make the parameters explicit.
  • Split the routine: the top part gathers the parameters and passes them explicitly to the second part.
params = { a: 1, b: 2}
foo(params)
 
function foo(params)
  // ...params.a... ...params.b...
// make the parameters explicit by splitting foo:
function foo(params)
  foo_body(params.a, params.b)
 
function foo_body(a, b)
  // ...a... ...b...

Chunk statements

  • Simple tidying.
  • Put a blank link between the parts.

Extract helper

  • Block of code inside a routine that has an obvious purpose and limited interaction with the rest of the code in the routine extract it as a helper routine.
  • Another case for extracting a helper is expressing temporal couling:
foo.a()
foo.b()

// =>
ab()
  a()
  b()

One pile

  • You read code that’s been split into many tiny pieces, but in a way that hinders you from understanding it.
  • Inline as much of the code as you need until it’s all in one big pile.
  • The biggest cost of code is the cost of reading and understanding it, not the cost of writing it.
  • Some symptoms of process gone wrong when making small pieces interact:
    • long, repeated argument lists
    • repeated code, especially repeated conditionals
    • poor naming of helper routines
    • shared mutable data structures

Explaining comments

  • Write down only what wasn’t obvious from the code.
  • Think from the perspective of someone else, and try to preemptively address likely questions.
  • It’s much better to add a comment that points out the coupling issue, rather than leaving it buried in the sand.

Delete redundant comments

When you see a comment that says exactly what the code says, remove it.