The Underscore Survived
Domain-Specific Encoding
The Underscore Survived
Someone recently published a tidy list of naming rules. Seven of them. Rule two: hyphens between words. Never spaces. Never underscores.
Clean. Decisive. Wrong about the interesting part.
Not wrong because hyphens are bad — they're fine. Wrong because the rule treats the separator as a style choice. It's not. It's a dialect marker. And if you look at where each separator actually survived, the pattern tells you something the style guide doesn't.
The Double-Click Test
Try this. Open a terminal. Double-click my-file-name. Your terminal selects my, or file, or name. Three words. Three selections.
Now double-click my_file_name. Your terminal selects the whole thing. One token.
This isn't a quirk. It's the environment telling you what it considers a word boundary. Hyphens are separators. Underscores are joiners. The terminal knows this even if the style guide doesn't.
Editors know it too. Word-motion commands (w, b, e in vim; Ctrl+Left/Right everywhere else) stop at hyphens. Underscores sail through. The tooling treats hyphen-name as three words and underscore_name as one.
If your naming convention fights the tools, the tools win. People will adapt around your rule, not because they're lazy, but because the environment selects against it.
The Identifier Test
Here's the harder one.
my_file is a valid identifier in Python. And C. And SQL. And bash. And Make. And Ruby. And Rust. And Go. And every environment variable on every Unix system ever shipped.
my-file is subtraction.
Not metaphorically. Literally. my-file means my minus file in every language that uses - as an operator — which is nearly all of them. The hyphen is overloaded. The underscore isn't.
This matters when names cross boundaries. A filename becomes a variable. A database column becomes a key in a dictionary. A config value becomes an environment variable. At every crossing, the underscore passes through. The hyphen needs escaping, quoting, or renaming.
The style guide says "hyphens." The actual system says "underscores, or you'll be writing adapter code forever."
Where Each One Won
Look at where underscores dominate:
- Python — PEP 8:
snake_casefor everything. Not because Guido liked the aesthetics. Because Python identifiers can't contain hyphens. - C —
standard_library_functions()since 1972. Same constraint. - SQL —
customer_order_line_item. Column names are identifiers. Hyphens aren't legal. - Shell —
$MY_ENV_VAR. Every environment variable on every server you've ever touched. - Makefiles —
build_output,source_dir. Variables again. - Filesystems at the boundary — the moment a filename needs to be referenced programmatically, underscores stop requiring special handling.
Now look at where hyphens dominate:
- URLs —
my-page-title. Google treats hyphens as word separators for indexing. SEO drove this. - CSS —
.my-class-name. CSS chose hyphens because class names aren't programming identifiers (except they are in JavaScript, where you need bracket notation to access them —element.style['background-color']— because the hyphen breaks dot notation). - CLI flags —
--output-dir. Convention inherited from Unix, where-was already the option prefix. - Prose-adjacent contexts — anywhere a human reads the name as words in a sentence.
The pattern: underscores won where code talks to code. Hyphens won where code talks to humans reading prose.
Nobody coordinated this. No committee met. The environments selected independently, and the same answer kept emerging.
The Separator Is a Dialect
This is the compression angle.
When you see underscores in a name, you're looking at something that grew up in a programming environment. It was named by someone who expected it to be referenced in code. The underscore is a signal: this name is an identifier.
When you see hyphens, you're looking at something that grew up in a presentation environment. URLs, documentation, style guides. The hyphen is a signal: this name is meant to be read.
Neither is wrong. They're dialects. And like all dialects, they encode where the speaker comes from and what they expect the listener to do with the information.
The naming rules article says "the specific rules matter less than having them." That's the Rosetta Stone view — pick a standard, any standard, and enforce it. It works. It's also shallow.
The deeper question isn't which separator to mandate. It's why different environments keep independently arriving at different answers. When you understand that, you stop writing rules and start reading the terrain.
The Thing the Rule Misses
A naming convention isn't a style choice. It's a compression decision about which boundary your names need to survive crossing.
If your files live in a folder and never leave — hyphens are fine. Humans read them, humans organize them, done.
If your filenames show up in code, configs, database schemas, shell scripts, URLs, API responses — underscores cost you nothing at every boundary. Hyphens cost you something at most of them.
The seven rules were presented as universal. Rule two works for one context. The underscore works at more of them.
That's not a style preference. That's selection pressure.
The hyphen is the separator you pick in a style guide. The underscore is the one that keeps showing up when nobody's writing style guides.