Lesson 8 of 54

The Art of Naming

Naming Functions and Methods

A function name is a contract. It promises what the function does. When the name lies, bugs follow.

I once debugged a function called getUser that, deep in its implementation, also sent a welcome email to new users. The name said "get." The behavior said "get and send email and log analytics."

That's a lie. Lies in code cost time and trust.

Verbs That Describe Behavior

The verb in a function name should accurately describe what happens.

Fetching Data

VerbMeaningImplication
getReturn existing valueSynchronous, from memory, no side effects
fetchRetrieve from external sourceAsync, network call, might fail
loadBring into memoryMight read from disk, affects state
findSearch for somethingMight return nothing (null/undefined)
queryDatabase operationSQL or similar, returns results
readRead from storageFile, database, stream

Using these consistently means readers can predict behavior from the name:

Javascript
getUser()       // Returns cached user, fast, never fails
fetchUser()     // Hits API, might throw, needs await
findUser()      // Might return undefined if not found
loadUserData()  // Reads from disk, populates state

Modifying Data

VerbMeaningImplication
setAssign valueUsually local state, synchronous
savePersist to storageDatabase, file, external system
updateModify existingAssumes thing exists
createMake new thingAssumes thing doesn't exist
deleteRemove thingPermanent removal
removeTake out of collectionMight not be permanent
addPut into collectionAppend, insert

Transforming Data

VerbMeaningImplication
toConvert formattoString(), toJson(), toDate()
parseExtract structure from textparseJson(), parseUrl()
formatConvert to display stringformatDate(), formatCurrency()
calculateCompute from inputscalculateTotal(), calculateTax()
buildConstruct complex objectbuildQuery(), buildResponse()
normalizeStandardize formatnormalizeEmail(), normalizePhone()
validateCheck correctnessvalidateEmail(), validateInput()

Naming Side Effects Honestly

This is critical: if a function has side effects, the name must say so.

Bad: Hidden Side Effects

Javascript
function getUser(id) {
  const user = cache.get(id) || db.fetch(id);
  analytics.track('user_accessed', { id });  // Hidden!
  if (!user.welcomeEmailSent) {
    email.sendWelcome(user);  // Hidden!
  }
  return user;
}

The name says "get." The function does three more things. Every caller is surprised.

Good: Honest Names

Option 1: Split the functions

Javascript
function getUser(id) {
  return cache.get(id) || db.fetch(id);
}

function trackUserAccess(user) {
  analytics.track('user_accessed', { id: user.id });
}

function sendWelcomeEmailIfNeeded(user) {
  if (!user.welcomeEmailSent) {
    email.sendWelcome(user);
  }
}

Option 2: Name the combination honestly

Javascript
function getUserAndTrackAccess(id) {
  const user = getUser(id);
  trackUserAccess(user);
  return user;
}

The name now tells the truth.

Command-Query Separation (CQS)

Bertrand Meyer's principle: a method should either do something (command) or return something (query), but not both.

Commands

Commands change state. They're usually named with imperative verbs:

Javascript
saveOrder(order)
deleteUser(userId)
updateInventory(productId, quantity)
sendEmail(to, subject, body)

Commands can return success/failure status, but shouldn't return data.

Queries

Queries return data. They don't change state:

Javascript
getOrderById(orderId)
findUsersByRole(role)
calculateTotalPrice(items)
isUserActive(userId)

Queries are safe to call multiple times with no side effects.

Why This Matters

When you follow CQS, readers know:

  • getUser(id) — safe, no side effects, can call freely
  • deleteUser(id) — dangerous, has permanent effect, call carefully

When you violate CQS:

  • getUser(id) — might do anything, have to read implementation

Practical Exception

Sometimes combining is pragmatic:

Javascript
// Returns the new state after mutation
const newCount = incrementAndGet(counter);

// Returns created entity with generated ID
const savedUser = createUser(userData);

These are acceptable when:

  1. The side effect and return value are tightly related
  2. The name makes the combination clear
  3. Separating them would be awkward

Function Length and Name Complexity

A function that does one thing can have a short name.

A function that does many things needs a long name—which is a smell telling you to split it.

Javascript
// Doing too much, name tries to compensate
function validateParseAndStoreUserInputWithEmailNotification(input) {
  // ...
}

// Split into focused functions
function validateInput(input) { ... }
function parseUserData(validInput) { ... }
function storeUser(userData) { ... }
function notifyUserCreated(user) { ... }

If you can't name a function simply, it's probably doing too much.

Symmetrical Names

Related functions should have related names:

OperationOpposite
openclose
startstop
beginend
createdestroy
addremove
insertdelete
showhide
enabledisable
acquirerelease
lockunlock

If you have openConnection, the cleanup should be closeConnection, not terminateConnection or endConnection.


Key insight: Function names are promises. Use verbs that accurately describe behavior. Be honest about side effects. Follow command-query separation so readers can predict what functions do without reading their implementation.