Skip to content

Clean Code

Stephen Cresswell edited this page Jun 27, 2023 · 7 revisions

Naming

Good and consistent naming is important. It improves coherence and cohesiveness. Good naming is also hard, which in itself is good. To come up with a distinct and meaningful name you have to think about responsibilities. Many things need names...

Abbreviations

Be suspicious of abbreviations. Industry standard abbreviations like UTC are fine. Company standard abbreviations are also usually OK. Defacto standard language / framework abbreviations like cb for callback are also OK, providing they will be understood by new developers. Any other abbreviations are likely to cause confusion, and increase cognitive load.

Class Names

Be suspicious of class names ending in "er" and "or". A ResilientConnectionPool is a far more meaningful name than a ConnectionManager. A toExternalFormat method on the Job class will not break encapsulation, whereas a JobTransformer will have to interrogate the job for all of it private data.

File Names

When not mandated by the language, consistency is still a good thing. In languages like JavaScript where files can be required or imported, and assigned to variables it's clearer to keep the variable name and filename as consistent as possible. Repeating directory names within the filename (a.k.a stuttering), is an anti-pattern in languages which can be navigated via an IDE (e.g. Java), but may be the lesser of two evils where navigation is commonly filename based (e.g. JavaScript)

Service Names

Adopting a hierarchical naming strategy (e.g. service-namespace-name) helps reduce conflicts, identifies service responsibilities and likely maintainers. The downside of a hierarchical naming strategy is that project names become tedious and long. Abbreviating risks compromising coherence. There's no right answer. Find a balance and be consistent with it.

Comments

Comments are usually meaningless to the person who didn't write them. Comments are usually meaningless to the person who did write them a few months later. Comments grow stale. Therefore...

Don't

  • Write comments which explain complicated code. Instead write simple code and unit tests.
  • Write comments to visually break up large functions. Instead write small functions.
  • Write TODO or FIXME comments. Instead DO/FIX the code within a short enough timeframe that you won't forget.

Do

  • Write comments which explain complicated code that can't be simplified (e.g. because of a bug in a 3rd party library)
  • Write comments that make people smile (but only occasionally).

Functions

Functions should be short - REALLY short. On average no more than a few lines. It's quite possible to write large applications with an average function body of under 4 lines. Functions should also operate at a single level of abstraction, e.g.

Instead of...

async function invite(user, organisation) {
  if (user.preferences.contact ==== 'email') {
    await emailService.sendInvitation(user, organisation)
  } else if (user.preferences.contact === 'sms') {
    await smsService.sendInvitation(user, organisation)
  } else {
    throw new Error('No preferred contact method');
  }
}

Consider...

async function getNotificationService(contact) {
  if (contact === 'email') return emailService;
  if (contact === 'sms') return smsService;
  throw new Error('No preferred contact method');
}

async function invite(user, organisation) {
  const notificationService = getNotificationService(user.preferences.contact);
  await notificationService.sendInvitation(user, organisation);
}

When is code done?

When it...

  1. Works
  2. Communicates
  3. Has no duplication
  4. Has no unnecessary bits

Clone this wiki locally