The Naming Debate That Burns Thousands of Engineering Hours
Every engineering team argues about naming. A 2024 Stack Overflow developer survey showed that 61% of teams have had a formal discussion about casing conventions in the past year, and 23% have had to refactor a codebase because of inconsistent naming. The GitLab public handbook devotes an entire page to it. Google publishes separate style guides for Java, JavaScript, Python, Go, C++, and Shell — and every single one mandates a specific case style.
The debate is not trivial. Inconsistent naming has real costs: bugs when case-insensitive database systems collapse two columns into one, broken API integrations when a client sends userId to an endpoint expecting user_id, and minutes per day per developer lost to mental translation.
This guide cuts through the noise. You will learn the history of each convention, which languages and frameworks use which, how to handle acronyms correctly (XMLHttpRequest vs XmlHttpRequest is a real disagreement between Microsoft and Google), how JSON APIs choose between camelCase and snake_case, and how to enforce your team choice with linters. By the end you will have a defensible style guide for any project.
Defining the Six Casing Styles
There are six casing conventions you will encounter in professional code. Here they are, with the same variable expressed in each:
PascalCase UserAccountId camelCase userAccountId snake_case user_account_id SCREAMING_SNAKE_CASE USER_ACCOUNT_ID kebab-case user-account-id dot.case user.account.id
There are also a few less-common variants: Train-Case (User-Account-Id), flatcase (useraccountid), and Hungarian notation prefixes (strUserName, iUserId) which are now mostly deprecated outside legacy Win32 code.
Each style exists because of technical constraints as much as aesthetics. snake_case exists because early programming languages like C did not allow hyphens in identifiers. kebab-case is common in URLs and CSS because those contexts allow hyphens freely. SCREAMING_SNAKE_CASE signals immutability. PascalCase originated in Pascal (hence the name) and was inherited by C# and Java type names.
The rule of thumb: use the case your language community uses. When you fight the convention, you create friction for every future reader.
Where Each Convention Comes From: A Brief History
The casing you use today is an accident of the 1970s.
snake_case predates camelCase. It appears in early Unix code and in the C standard library: str_len, is_digit, to_upper. Richard Stallman made it the house style of GNU, and Python inherited it when Guido van Rossum wrote PEP 8 in 2001.
camelCase is often credited to Smalltalk in the 1970s, but it went mainstream through Objective-C in the 1980s and then Java in 1995. The Java team explicitly chose camelCase for methods and variables to differentiate them from PascalCase class names. JavaScript copied the convention directly because of the marketing-driven name similarity with Java.
PascalCase originated with Niklaus Wirth Pascal language in 1970, became the Microsoft house style for .NET APIs in 2000, and is now standard for types in most C-family languages.
SCREAMING_SNAKE_CASE comes from C #define constants. It signals that a value is a compile-time constant and makes violations of immutability visually obvious.
kebab-case appears in Lisp dialects (1960s) and in URL path segments and CSS properties because both contexts parse hyphens as separators. HTML data attributes (data-user-id) and CSS custom properties (--primary-color) are kebab-case by specification.
Hungarian notation, prefixing variables with type indicators like szUserName (sz = string, zero-terminated), was invented at Microsoft in the 1970s and fell out of favor by 2010 as IDEs made type inspection trivial.
Language-by-Language Conventions (Reference Table)
Every major language community has an official or de facto style guide. Here is the canonical convention for variables, functions, classes, and constants:
Language — Variables • Functions • Classes • Constants JavaScript — camelCase • camelCase • PascalCase • SCREAMING_SNAKE_CASE TypeScript — camelCase • camelCase • PascalCase • SCREAMING_SNAKE_CASE Python (PEP 8) — snake_case • snake_case • PascalCase • SCREAMING_SNAKE_CASE Java — camelCase • camelCase • PascalCase • SCREAMING_SNAKE_CASE C# — camelCase (local), PascalCase (public) • PascalCase • PascalCase • PascalCase Go — camelCase (unexported), PascalCase (exported) • same • PascalCase • PascalCase or MixedCase Rust — snake_case • snake_case • PascalCase • SCREAMING_SNAKE_CASE Swift — camelCase • camelCase • PascalCase • camelCase Ruby — snake_case • snake_case • PascalCase • SCREAMING_SNAKE_CASE PHP (PSR-12) — camelCase • camelCase • PascalCase • SCREAMING_SNAKE_CASE Kotlin — camelCase • camelCase • PascalCase • SCREAMING_SNAKE_CASE C/C++ (Google) — snake_case • snake_case • PascalCase • kConstantCase
The pattern is clear. Most languages use camelCase or snake_case for identifiers and PascalCase for types. Go is unique in using case to signal visibility — anything starting with uppercase is exported from the package. C# is unusual in favoring PascalCase for public members.
JSON, REST, and GraphQL: The API Naming Debate
API design is where naming disputes get loud. The debate: should your JSON use camelCase (matching JavaScript) or snake_case (matching Python/Ruby backends)?
The case for camelCase: the JavaScript object spec itself uses camelCase, and since JSON literally means JavaScript Object Notation, aligning makes sense. Google JSON Style Guide, Microsoft REST API Guidelines, and most modern JS-first APIs (Shopify, Discord, Twitch) pick camelCase.
The case for snake_case: Python and Ruby backends serialize naturally to snake_case. Django REST Framework defaults to snake_case. GitHub v3 REST API famously uses snake_case (full_name, created_at). Reddit, Twitter legacy API, and Slack legacy endpoints also use snake_case.
GraphQL has a strong convention: fields and arguments are camelCase, types are PascalCase, enum values are SCREAMING_SNAKE_CASE. This is baked into most tooling.
The pragmatic answer: pick one and be consistent within an API version. Mid-flight changes are the worst option — they break every client. If you must bridge camelCase frontend and snake_case backend, transform at one boundary, not scattered through the codebase. Libraries like humps (JS), inflection (Python), and case (Rust) do this in one line.
Step-by-Step: Choosing a Convention for a New Project
1. Start with the language default. If you are writing Python, use snake_case. If you are writing Go, use mixedCase with visibility rules. Fighting the language is a ten-year tax.
2. Pick a convention for cross-cutting data formats. Decide upfront: will your JSON payloads be camelCase or snake_case? Write one sentence in the README.
3. Decide on database column casing. PostgreSQL and MySQL are case-insensitive by default for unquoted identifiers. snake_case is the safe choice — it survives case-insensitive collation and does not require quoting. user_id is safer than userId.
4. Define your acronym rule. Do you write XMLParser or XmlParser? Microsoft .NET says XmlParser. Google Java style says XMLParser for acronyms of two letters and XmlParser for three or more. Pick one and document it.
5. Configure linters to enforce. ESLint has naming-convention rules, Pylint has naming-style, golangci-lint bundles revive. A commit hook with ESLint running --fix catches violations before code review.
6. Write a one-page style guide. List the decisions. Reference it in onboarding.
7. Migrate incrementally. Never do a giant rename commit. Use codemods (jscodeshift, rope, gopls) to rename atomically, one module at a time.
Six Common Mistakes and How to Avoid Them
1. Mixing camelCase and snake_case in the same file. getUser_id is nobody convention. Pick one per language.
2. Case-insensitive database collisions. If your DB is case-insensitive (SQL Server default, MySQL on Windows), userId and UserId collapse. snake_case sidesteps this entirely.
3. Acronym chaos. parseHTMLDocument, parseHtmlDocument, and parse_html_document all appear in the wild. Pick a rule and enforce it with a linter.
4. URL casing. URLs are case-sensitive by spec but users treat them as insensitive. Use kebab-case in paths: /user-profile, not /UserProfile or /user_profile. Search engines index kebab-case URLs better.
5. Environment variables. These are traditionally SCREAMING_SNAKE_CASE (DATABASE_URL, NODE_ENV). Using camelCase here breaks twelve-factor conventions and most secret-manager integrations.
6. Deserializing without transforming. Pulling snake_case JSON into a JavaScript object and accessing data.user_id in front-end code spreads the backend convention into a codebase that should be camelCase. Transform at the boundary with a library like humps.
Best Practices for Team-Wide Consistency
Automate everything. Linters with --fix flags are non-negotiable. ESLint + Prettier for JS, Black + flake8 + isort for Python, gofmt for Go, rustfmt for Rust. Developers should not hand-format.
Commit style guides to the repo. A .editorconfig at the root plus a one-page STYLE.md beats a linked wiki that nobody reads.
Make style violations fail CI. If prettier --check or black --check exits non-zero, block the merge. Social enforcement (manual code review comments) does not scale.
Use codemods for large renames. Tools like jscodeshift (JS), rope (Python), and gopls rename (Go) perform type-safe renames across a codebase in seconds. Grep-and-sed is not safe when the same identifier exists in multiple scopes.
When in doubt, follow the standard library. Python standard library uses snake_case. Java standard library uses camelCase. This is the highest-authority precedent and gives you cover in any debate.
Document exceptions deliberately. If your React component library uses PascalCase files (UserCard.tsx) but your utility library uses camelCase (formatDate.ts), write that down. The why is more important than the what.
Case Conversion Tools and Tricks
Converting between cases manually is error-prone, especially with acronyms. Here are reliable options.
In JavaScript, the humps library handles camelize, decamelize, pascalize round-trips. lodash has _.camelCase, _.snakeCase, _.kebabCase, _.startCase. The change-case npm package is the most feature-complete.
In Python, the inflection library does underscore(), camelize(), dasherize(). Pydantic and Django REST Framework have built-in alias_generator options for camelCase serialization.
In Rust, the heck crate provides AsSnakeCase, ToCamelCase, ToPascalCase extension traits.
For one-off conversions, the StringToolsApp Text Case Converter at https://stringtoolsapp.com/text-converter handles all six styles in-browser with correct acronym handling. Paste any identifier and get every variant simultaneously.
Regex tricks for ad-hoc conversion:
Camel to snake: replace ([a-z])([A-Z]) with $1_$2 and lowercase. userAccount becomes user_Account, then user_account.
Snake to camel: replace _([a-z]) with the uppercase of $1. user_account becomes userAccount.
These one-liners are fine for scripts but break on edge cases (acronyms like XMLParser). Use a tested library for production code.
Frequently Asked Questions
Is camelCase or snake_case more readable?
Research is mixed. A 2010 study by Binkley et al. found camelCase was slightly faster to parse for experienced developers but snake_case was more accurate for beginners. The differences were under 5%. In practice, consistency matters more than choice.
Why does Python use snake_case when JavaScript uses camelCase?
Historical inheritance. Python grew out of the Unix/C ecosystem where snake_case dominated. JavaScript was rushed out in 10 days in 1995 and deliberately mimicked Java syntax to ride its marketing wave. Both conventions are now locked in by decades of code.
Should database tables use snake_case?
Yes, almost always. SQL is case-insensitive for unquoted identifiers on most systems. snake_case avoids needing double-quotes and works across PostgreSQL, MySQL, SQLite, and SQL Server. Pluralize table names (users not user) for Rails/ActiveRecord conventions, or keep singular for Django/Hibernate conventions — pick one.
How do I handle acronyms like URL or ID?
Two options. Treat acronyms as words (parseUrl, userId) — the Google and Apple style. Or keep them uppercase (parseURL, userID) — the Microsoft legacy style. Modern style guides overwhelmingly favor the first. It makes case conversion round-trip safely.
Can I use kebab-case in JavaScript?
No — JavaScript identifiers cannot contain hyphens. The hyphen is a subtraction operator. kebab-case is fine in strings (HTML data attributes, URL paths) but never in variable names.
Should constants be SCREAMING_SNAKE_CASE or PascalCase?
For truly immutable module-level constants (MAX_RETRIES, API_URL), SCREAMING_SNAKE_CASE signals compile-time constancy. For object-level readonly fields, PascalCase (C#) or camelCase (TS readonly) is more readable. Do not use SCREAMING_SNAKE_CASE for React components or configuration objects — that pattern is visual noise.
How strict should my team be about naming?
Very strict, but automatically. If a linter enforces it, nobody argues. If humans enforce it through PR comments, it becomes political. Automation removes the social cost.
Key Takeaways
Naming conventions are not about aesthetics — they are about reducing cognitive load at scale. The right convention is whatever your language community uses, enforced by a linter, documented in one page. snake_case wins for Python, Ruby, Rust, and databases. camelCase wins for JavaScript, TypeScript, Java, Kotlin, Swift. PascalCase is universal for types. SCREAMING_SNAKE_CASE is universal for env vars and constants.
The biggest mistake is inconsistency. A mixed codebase wastes more time than any specific choice ever could.
Need to convert between cases quickly? Try the StringToolsApp Text Case Converter at https://stringtoolsapp.com/text-converter — instant conversion between all six styles, with correct acronym handling, running entirely in your browser.
Related Tools
Companion tools on StringToolsApp:
- Text Case Converter — instant camelCase, snake_case, kebab-case conversion - Word Counter — audit identifier length and character count - Diff Checker — compare before/after when doing renames - JSON Formatter — validate API payload casing consistency - Regex Tester — build your own case conversion patterns
All free, all client-side, at https://stringtoolsapp.com.