Naming Conventions & Roman Numerals

camelCase or snake_case? Hyphens or underscores in URLs? How do you write 1999 in Roman numerals? This page tabulates eight naming conventions with their rules and where each belongs, plus the Roman numeral symbols and the subtractive rule.

How It Works

Naming conventions fix the case and separator of identifiers: camelCase (userName), PascalCase (UserName), snake_case (user_name), kebab-case (user-name).

The choice follows language and context: JS/Java use camelCase for variables and PascalCase for classes; Python uses snake_case for variables and functions; SQL tables/columns lean snake_case; URLs and CSS classes lean kebab-case. Internal consistency matters more than which is "best".

When to Use This Table

This table is for adopting a consistent naming style across variables, functions, files and API fields. It lines up camelCase, PascalCase, snake_case, kebab-case, SCREAMING_SNAKE and Train-Case with their composition rules and common uses. Naming is an interface between tools and teammates, and consistency is worth more than personal preference.

When not to consult it: you are designing a full naming convention that must account for language-specific rules such as Go export rules, Rust ownership naming, or reserved words per language. This table gives general styles and mainstream conventions, not per-language exceptions.

Rule of thumb: judge by the scope of the name. Inside a single module, private and small in scope, short and loose is fine; anything exported across modules or forming a public API must follow that language standard strictly. The test is simple: if the name will appear in someone else’s code, follow the language convention; if it is a local variable, the team habit is enough.

Mind that conversion conventions differ in meaning across languages: snake_case is community habit in Python but not mandatory per PEP 8; Go officially discourages underscores in MixedCaps; and in the JavaScript ecosystem camelCase is the de facto standard, where snake_case reads as off-convention.

Boundaries and Common Pitfalls

  • Naming style must be converted explicitly at language boundaries

    The same data often passes through several languages: snake_case in the database, snake_case inside Python, camelCase in the HTTP response, camelCase in the frontend. Relying on convention instead of explicit conversion causes two classes of bug — a missed conversion leaves snake_case keys in the frontend, while a duplicate conversion over-underscores them. The fix is an explicit mapping at each boundary, such as aliases or serializer configuration, with tests that lock the field names.

  • Converters handle acronyms and capitals differently

    Converting HTTPServer to snake_case gives three different answers depending on the library: HTTPServer unchanged, httpserver all lowercased, or http_server correct. Kebab-case has the same problem, yielding htmlparser, html-parser or HTML-parser. These names often end up in URLs, filenames or database column names and are hard to change after launch. Use an explicit mapping table for important names, add snapshot tests on the conversion output, and do not rely on library inference.

  • Boolean and plural naming directly affects readability

    Prefixing booleans with is, has, can or should immediately distinguishes them from value types and prevents mistakes like confusing if (enabled) with if (enabled === "yes"). Name collections with plural nouns and single elements with the singular form; breaking that convention forces readers to backtrack constantly. And avoid zero-information names like data, info or obj, which are useless when searching or debugging.

How This Relates to Neighbours

Checking whether a name collides with a language reserved word belongs to that language’s documentation, not this table.

Bulk conversion of filenames and URL paths is scaffolding work; this page gives style judgement rather than conversion code.

Designing API field naming and version compatibility requires settling the protocol before the style.

If the goal is fixing inconsistent naming on a team, agreeing on the scope rule (loose internally, strict on exports) works better than picking a style first.

Practical Snippet

Key points: (1) judge strictness by scope — exported names must follow the language standard strictly, while internal locals may use team habit; (2) converters differ on acronyms and consecutive capitals (the same HTTPServer yields three results), so use an explicit mapping table plus snapshot tests instead of relying on inference; (3) prefix booleans with is/has/can/should, name collections in the plural and single elements in the singular; (4) avoid zero-information names like data/info/obj; (5) convert names explicitly at every language or layer boundary and lock the field names with tests, because conventions alone will eventually be missed.

// ① 常见风格的构成规则(正则可直接用于校验)
const STYLES = {
  camelCase:    /^[a-z][a-zA-Z0-9]*$/,        // myVariable
  PascalCase:   /^[A-Z][a-zA-Z0-9]*$/,        // MyVariable
  snake_case:   /^[a-z][a-z0-9_]*$/,          // my_variable
  kebab_case:   /^[a-z][a-z0-9-]*$/,          // my-variable
  SCREAMING:    /^[A-Z][A-Z0-9_]*$/,          // MY_VARIABLE
}

// ② 按作用域决定严格程度
function checkName(name, scope) {
  const ok = Object.entries(STYLES).find(([, re]) => re.test(name))
  return {
    valid: !!ok,
    style: ok ? ok[0] : null,
    // 导出的名字必须是语言标准风格,内部变量可放宽
    enforced: scope === 'export' ? ['camelCase', 'PascalCase'] : Object.keys(STYLES),
  }
}
console.log(checkName('myVar', 'export'))      // { valid: true, style: 'camelCase' }
console.log(checkName('my_var', 'export'))     // 导出命名不合 JS 惯例

// ③ 🔴 转换库对缩写/大写的处理各不相同 ⇒ 关键名称用显式映射
const EXPLICIT = { HTTPServer: 'http_server', XMLHttpRequest: 'xml_http_request' }
function toSnake(name) {
  if (EXPLICIT[name]) return EXPLICIT[name]          // 优先查表
  return name
    .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
    .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')       // HTTPServer → HTTP_Server
    .toLowerCase()
}
console.log(toSnake('HTTPServer'))       // http_server(表命中)
console.log(toSnake('parseUserName'))    // parse_user_name

// ④ 布尔用前缀,集合用复数 —— 提升可读性
function describe(order) {
  return {
    isPaid:    order.status === 'paid',   // 布尔一律 is/has/can/should
    hasItems:  order.items.length > 0,
    items:     order.items,               // 集合用复数
    firstItem: order.items[0],            // 单个用单数
  }
}

// ⑤ 避免零信息量命名
const BAD  = { data: 1, info: 2, obj: 3, temp: 4 }
const GOOD = { userProfile: 1, requestHeaders: 2, httpResponse: 3, retryCount: 4 }

// ⑥ 跨语言边界显式转换(API 层 camelCase ↔ DB 层 snake_case)
const toCamel = s => s.replace(/_([a-z])/g, (_, c) => c.toUpperCase())
const toSnakeKey = s => s.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase()
console.log(toCamel('user_id'))          // userId
console.log(toSnakeKey('userId'))        // user_id

Practical Notes

  • camelCase to snake_case breaks on acronymsWhether XMLHttpRequest becomes xml_http_request or x_m_l_http_request depends on the implementation. When auto-renaming across language boundaries, lock acronym and digit boundaries with tests first, or field names will silently mismatch.
  • URLs and filenames conventionally use lowercase with hyphensUppercase in URLs introduces case-sensitivity problems (Linux servers are sensitive, CDN caches may not be). Kebab-case in all lowercase avoids this, and underscores should be avoided because some Markdown renderers treat a_b as italics.
  • Roman numeral subtractive notation covers only six pairsOnly IV, IX, XL, XC, CD and CM are valid subtractive forms; IL and IC are not standard. A converter that naively allows any smaller-before-larger produces invalid results such as writing 49 as IL.

Data Sources

  • Language style guides
  • Unicode Roman numerals (U+2160–U+2188)

Codes, names and definitions above come from public specifications; we claim no originality over the specification data itself. The arrangement, Chinese annotations and practical notes on this page are written by us.

Eight Naming Conventions

StyleExampleRuleCommonly Used For
camelCaseuserNameListFirst word lowercase, later words capitalisedJavaScript and Java variables and functions
PascalCaseUserNameListEvery word capitalisedClasses, components and type names
snake_caseuser_name_listAll lowercase, underscores between wordsPython and Ruby variables, database columns
SCREAMING_SNAKEUSER_NAME_LISTAll uppercase, underscores between wordsConstants and environment variables
kebab-caseuser-name-listAll lowercase, hyphens between wordsURL paths, CSS classes, npm package names
Train-CaseUser-Name-ListWords capitalised, hyphens between wordsHTTP header names, titleised identifiers
flatcaseusernamelistAll lowercase, no separatorPackage names, some domains and CLI flags
dot.caseuser.name.listAll lowercase, dots between wordsConfig keys and telemetry metric names

Roman Numeral Symbols

There are only seven base symbols: I(1) V(5) X(10) L(50) C(100) D(500) M(1000). A smaller symbol before a larger one subtracts; after it adds.

ValueRomanNote
1IBase symbol
4IVSubtractive: 5 minus 1
5VBase symbol
9IXSubtractive: 10 minus 1
10XBase symbol
40XLSubtractive: 50 minus 10
50LBase symbol
90XCSubtractive: 100 minus 10
100CBase symbol
400CDSubtractive: 500 minus 100
500DBase symbol
900CMSubtractive: 1000 minus 100
1000MBase symbol

Frequently Asked Questions

Should I use camelCase or snake_case?

There is no global optimum; following the convention of your language and community matters most. Python, Ruby and Rust idiomatically use snake_case; JavaScript, Java and Swift use camelCase; Go uses PascalCase for exported identifiers. Database columns are almost universally snake_case because most engines are case-insensitive. The real red line is never mixing styles within one project — once you do, code search, refactoring and tooling all become unreliable. At system boundaries, such as a Python backend serving a JavaScript frontend, convert once at the boundary rather than letting both styles seep into the same layer.

Why is kebab-case recommended for URLs rather than underscores?

Three practical reasons. Search engines have traditionally treated the hyphen as a word separator while ignoring the underscore, so kebab-case aids keyword recognition. Underscores also hide beneath the underline of a styled link, hurting readability. And URLs are case-sensitive, so all-lowercase avoids duplicate-content variants of the same resource. Together these make lowercase kebab-case the de facto standard for URL paths.

Why is 4 written IV rather than IIII in Roman numerals?

Roman numerals use a subtractive-left, additive-right rule: a smaller symbol before a larger one subtracts, after it adds. So 4 is IV, meaning 5 minus 1, and 6 is VI, meaning 5 plus 1. This keeps the notation shorter and easier to scan. IIII does appear historically, especially on clock faces, reportedly for visual balance with VIII opposite and to avoid reading IV as an abbreviation for Jupiter. The modern standard is IV.

How do you write 1999 in Roman numerals?

It is MCMXCIX, decomposing into 1000 + 900 + 90 + 9. Convert each part: 1000 is M; 900 is CM, meaning 1000 minus 100; 90 is XC, meaning 100 minus 10; 9 is IX, meaning 10 minus 1. Concatenated, that is MCMXCIX. The general method is to take the largest symbol from high to low, switching to the subtractive form for digits like 4 and 9 instead of repeating a symbol four times.