Self-Documenting Code

Use of || / short-circuiting for control flow

  • Many dislike patterns like cond || throwError() in JS: seen as non-idiomatic, harder to read, and potentially dangerous due to truthiness (e.g., 0/""/false).
  • Some note this is common in shell/Ruby, but others respond that shell syntax is notoriously opaque and not a good readability model.
  • Short-circuiting is generally seen as fine for a few conventional patterns (defaults, “cheap || expensive”, guarded conditions in loops), but controversial when used to encode primary control flow and exceptions.
  • A minority say they’d get used to it if consistently applied, but most call it cleverness over clarity.

Self-documenting code vs comments

  • Broad agreement that “self-documenting” really means “code that reads clearly,” not literally zero comments.
  • Several argue all comments (including JSDoc) are a smell: they rot, are ignored by tools/people, and often cover for confusing code that should be refactored.
  • Others push back: comments are essential for explaining why code is the way it is, documenting edge cases, hacks, business decisions, and serving as a “parity bit” to detect when behavior has drifted.
  • Middle-ground view: comments should explain non-obvious logic and rationale; avoid narrating obvious code.

Types, TypeScript, and JSDoc

  • Some see TypeScript (or strong typing in general) as the best form of documentation: machine-checked, close to the code, and more readable than JSDoc.
  • Others criticize heavy JSDoc/“docstring for every function” styles as redundant boilerplate that no one maintains.
  • There is concern that calling JSDoc-based static checking “self-documenting” contradicts the “no comments” ethos.

Password validation example & regex readability

  • Many call uncommented regexes a “code smell” and advocate brief comments or mapping rule names to regexes.
  • Suggestions include:
    • Using named constants for rules.
    • Refactoring to return specific failing rule or user-friendly error messages.
    • Avoiding \W due to subtle character-class issues.
  • Some note the article “missed the opportunity” to better factor this example.

Function structure, abstraction, and early returns

  • Disagreement on “tiny functions” vs single larger function:
    • One camp prefers local booleans and fewer jumps, arguing too many helpers make control flow hard to follow.
    • Another camp values small, well-named functions for abstraction, testability, and top-down understanding.
  • Similar split on early returns vs if/else nesting:
    • Early-return proponents like linear “guard clauses” and a clear happy path.
    • Critics warn that many return points can obscure which conditions apply at a given line.

Error handling and control flow

  • Debate over using exceptions for expected conditions, like invalid user input:
    • Some insist returning result objects/union types is superior and more type-safe.
    • Others argue exceptions are fine for these errors and more ergonomic than error codes.
  • Fail-fast styles are defended in some domains, but others warn about timing attacks and misusing abstractions like throwError().

Broader reflections

  • Several point out there is no universally self-documenting code; readability depends on audience, shared norms, and context.
  • Multiple comments stress that naming and visual structure do matter, though some downplay their impact relative to domain complexity.
  • A recurring theme: favor clarity over cleverness; refactor when feasible, but accept that comments and non-ideal structures are sometimes the pragmatic choice.