camelCase vs snake_case vs kebab-case: гид 2026 по соглашениям именования
userID или userId? user_profile или userProfile? URL через - или через _? Эти мелкие вопросы по пять раз на дню срывают PR-ревью с курса. Ответ — не «личные предпочтения»: у каждого популярного языка и у каждого веб-стандарта есть устоявшееся правило, и как только все они оказываются на одной странице, шум исчезает до нуля.
В этом гиде разбираются шесть стилей case, с которыми вы реально встретитесь в коде (camelCase, PascalCase, snake_case, kebab-case, CONSTANT_CASE, dot.case / path/case / Header-Case), матрица решений для семи языков, спор parseUrl против parseURL с реальными данными GitHub, SEO-аргументы в пользу kebab-case в URL и шесть ловушек, которые подстерегают при автоматической конвертации между case. Если хочется увидеть все 15 вариантов case для любой строки сразу, Конвертер регистра формирует их вживую в браузере.
Шесть стилей case на одной странице
Прежде чем уходить в сравнения — вот шпаргалка. Распечатайте, вставьте во внутреннюю вики команды или просто держите открытой во вкладке.
| Стиль case | Пример | Типичное применение | Происхождение / популяризатор |
|---|---|---|---|
| camelCase | userProfileImage | Переменные и методы JS, TS, Java, Swift | Smalltalk → Java |
| PascalCase | UserProfileImage | Классы, компоненты React/Vue, типы TS | Язык Pascal |
| snake_case | user_profile_image | Python, Ruby, Rust, столбцы SQL | C / ранний Unix |
| kebab-case | user-profile-image | CSS-классы, URL-слаги, HTML-атрибуты | Lisp / современный веб |
| CONSTANT_CASE | USER_PROFILE_IMAGE | Env-переменные, верхнеуровневые константы, макросы | Макросы C / Unix env |
| dot.case | user.profile.image | Java-пакеты, пути MongoDB, ключи TOML | Соглашение неймспейсов |
| path/case | user/profile/image | URL-пути, файловая система, ref-ы Git | Unix-пути |
| Header-Case | User-Profile-Image | Имена заголовков HTTP/1.1 (каноничные) | RFC 2616 |
Восемь строк на шесть «настоящих» стилей: dot.case, path/case и Header-Case разделяют один и тот же токенизатор с разными разделителями, поэтому большинство библиотек работы с case считают их одним семейством.
Каждый стиль подробнее
camelCase: дефолт JS/Java
camelCase придумали в Smalltalk, но именно Java вывел его в индустриальный мейнстрим. Правила оформления кода Java от Sun образца 1995 года сделали firstName, getUserProfile и xmlParser стандартом, и каждый язык, который хотел выглядеть «как Java» — JavaScript, ActionScript, Swift, Kotlin, Dart — унаследовал ту же форму.
Правило: первое слово полностью строчное, каждое последующее — с заглавной буквы, разделители полностью убираются. Никаких подчёркиваний, никаких дефисов, никаких пробелов. Само название «camelCase» отсылает к горбатому силуэту заглавных букв, торчащих над морем строчных.
Два пограничных случая, которые часто путают: бренды со строчной буквы (iPhone, eBay, iOS) — когда такое название появляется в коде, не нужно силой капитализировать i; пишите так, как пишет сам бренд, и смиритесь с чуть-чуть странно выглядящим идентификатором. И акронимы — о них подробно ниже.
PascalCase: классы и компоненты
PascalCase — это просто camelCase с заглавной первой буквой. Некоторые гайды поэтому так и называют его — «UpperCamelCase». Язык Pascal использовал такую запись в 1970-х, и название закрепилось.
Где живёт: имена классов в любом C-семейственном ОО-языке (Java, C#, C++, Kotlin, Swift, TypeScript), имена компонентов React/Vue/Angular, алиасы типов и интерфейсы TypeScript (type UserProfile, interface AuthState), а также имена модулей и файлов в части экосистем (UserService.cs в C#).
Зачем вообще отдельный case для классов? Это чисто визуальный сигнал. Когда читаешь new userProfile() против new UserProfile(), вторая запись сразу читается как тип, а первая — как сорвавшийся вызов функции. Языки, в которых неймспейсы значений и типов перемешаны, опираются именно на регистр для разрешения неоднозначности.
snake_case: Python, Ruby, Rust, SQL
snake_case старше, чем кажется большинству: C и ранний Unix использовали имена в духе errno_h и fopen_s, потому что клавиатуры терминалов PDP-11 делали подчёркивание лёгким, а капитализацию в стиле Pascal — неудобной. Python принял его как официальную конвенцию PEP 8, сообщество Ruby сошлось на нём органически, а Rust сделал его дефолтом на уровне компилятора с линтом, который жалуется, если переменная названа userId, а не user_id.
Правило: всё в нижнем регистре, слова склеиваются подчёркиваниями. user_profile_image, parse_html, max_retries.
Аспект баз данных тут важен и обычно пропускается в туториалах по языкам. Почти каждый SQL ORM — SQLAlchemy, Hibernate, Sequelize, TypeORM, Active Record — по умолчанию использует имена столбцов в snake_case вне зависимости от соглашения языка-хоста. Причина — переносимость: PostgreSQL приводит неэкранированные идентификаторы к нижнему регистру, MySQL на Linux чувствителен к регистру, MySQL на macOS/Windows — нечувствителен, а SQLite относится к именам столбцов как к непрозрачным строкам. snake_case — единственное написание, которое переживает всё это без кавычек.
kebab-case: выбор веба
Веб сошёлся на kebab-case для всего, что видит пользователь: имена CSS-классов (.user-profile-image), URL-слаги (/blog/naming-conventions-guide), пользовательские HTML-атрибуты (data-user-id), имена тегов Web Components (<user-card> — спецификация буквально требует наличия дефиса).
Само название встречается в старых документах примерно в восьми вариантах — «dash-case», «spinal-case», «lisp-case», «skewer-case», «hyphen-case». Все означают одно и то же. Прижилось именно «kebab-case» — из-за старой шутки на Stack Overflow о том, что слова в нём похожи на куски мяса на шампуре.
Одно неочевидное правило: имена HTML- и CSS-классов на практике нечувствительны к регистру, но каноничное написание — строчное. .User-Profile работает в большинстве браузеров, но ломает серверный тулинг, который считает хеш имён классов, и сбивает с толку код-ревьюеров. Держитесь строчных букв.
CONSTANT_CASE: env-переменные и макросы
CONSTANT_CASE (иногда — SCREAMING_SNAKE_CASE в кругу Rust) — универсальный сигнал «это значение не меняется в рантайме». MAX_RETRIES, API_KEY, DEFAULT_TIMEOUT_MS. У каждого языка есть соглашение для этого, и каждый CI, каждый container runtime и каждый shell ожидают переменные окружения именно в таком виде (DATABASE_URL, NODE_ENV, PATH).
Ловушка: ключевое слово const в JavaScript не значит «используй CONSTANT_CASE». const result = await fetch(url) — абсолютно правильный camelCase. Резервируйте CONSTANT_CASE для настоящих семантических констант — значений, которые в C объявили бы через #define, тех, где смена значения в рантайме была бы багом. MAX_RETRIES = 3 подходит. result — нет.
dot.case, path/case, Header-Case
Три родственника, у которых общий токенизатор, но разные разделители.
dot.case представляет иерархические ключи: пакеты Java (com.example.service), пути полей MongoDB (user.profile.image), ключи конфигурации TOML/INI ([database.primary]), Lodash-пути для методов (_.get(obj, 'user.profile.image')). Читая dot.case-строку, вы должны видеть «неймспейс, неймспейс, лист».
path/case представляет буквальные местоположения: URL-пути, пути в файловой системе, ref-ы Git (feature/add-auth). Выбор «точки против слешей» осмыслен — слеши сигнализируют «это что-то реальное где-то лежит», точки сигнализируют «это просто метка».
Header-Case — соглашение HTTP/1.1: Content-Type, Access-Control-Allow-Origin, X-Forwarded-For. Заголовки HTTP/1.1 формально нечувствительны к регистру (RFC 2616), и content-type сработает, но все фреймворки, вся документация и все разработчики ожидают написание в Header-Case. HTTP/2 и HTTP/3 это изменили: RFC 7540 §8.1.2 предписывает строчные имена заголовков на проводе для упрощения сжатия заголовков (HPACK). На практике это невидимо для кода приложения, потому что каждый HTTP/2-клиент и сервер сами нормализуют, но если когда-нибудь смотреть на сырой HTTP/2-фрейм, заголовки будут целиком в строчном kebab-case.
Матрица решений для семи языков
Самый быстрый способ закрыть спор об именовании — посмотреть, как пишет стандартная библиотека самого языка. Вот матрица.
| Язык | Переменная | Функция | Класс | Константа | Имя файла | Столбец БД |
|---|---|---|---|---|---|---|
| Python (PEP 8) | snake_case | snake_case | PascalCase | CONSTANT_CASE | snake_case.py | snake_case |
| JavaScript/TS | camelCase | camelCase | PascalCase | CONSTANT_CASE | kebab-case.js | snake_case |
| Go | camelCase* | PascalCase** | PascalCase | mixedCase*** | snake_case.go | snake_case |
| Rust | snake_case | snake_case | PascalCase | SCREAMING_SNAKE | snake_case.rs | snake_case |
| Java | camelCase | camelCase | PascalCase | CONSTANT_CASE | PascalCase.java | snake_case |
| C# | camelCase† | PascalCase | PascalCase | PascalCase | PascalCase.cs | snake_case |
| SQL | n/a | snake_case | n/a | n/a | n/a | snake_case |
*Go: строчная первая буква означает unexported (package-private), заглавная — exported (public). Это форсит компилятор.**Go: экспортируемые функции — PascalCase (http.NewRequest); package-private функции — camelCase (http.parseHeader).***Go: константы подчиняются тому же правилу exported/unexported капитализации —MaxRetriesдля экспортируемых,maxRetriesдля package-private. Go намеренно избегает CONSTANT_CASE.†C#: локальные переменные и приватные поля — camelCase (некоторые кодовые базы префиксят поля_:_userName); публичные свойства, методы и типы — PascalCase.
Три слоя, которые проходят сквозь все языки одинаково:
HTML и CSS: имена классов и id — kebab-case (<div class="user-profile-card">). Пользовательские HTML-атрибуты — kebab-case с префиксом data- (data-user-id). Inline CSS-свойства — kebab-case (background-color); их DOM-эквиваленты в JS — camelCase (element.style.backgroundColor).
HTTP: исходящие имена заголовков — Header-Case для HTTP/1.1 ('Content-Type': 'application/json') и строчный kebab-case на проводе HTTP/2. Большинство fetch-библиотек принимают любое написание и нормализуют внутри.
Переменные окружения: CONSTANT_CASE везде — Node, Python, Go, Rust, Bash, Docker, Kubernetes. Соглашение .env-файла такое же: DATABASE_URL=postgres://....
Обработка акронимов: Google vs Microsoft
Это самый спорный вопрос об именовании на ревью кода. Должно быть parseUrl или parseURL? userId или userID? HtmlParser или HTMLParser? XmlHttpRequest или XMLHttpRequest?
Существуют две школы, и за каждой стоит реальный авторитет.
Считать акроним словом (Google, Apple, современный JS): parseUrl, userId, HtmlParser. Google JavaScript Style Guide §5.3 явно рекомендует именно это. Apple Swift API Design Guidelines говорят то же самое. Пакеты lodash и change-case выдают такой вывод по умолчанию. Аргумент — стабильность round-trip: parseUrl чисто токенизируется в parse / url, конвертируется в parse_url и обратно в parseUrl без потери информации. parseURL токенизируется в parse / URL, превращается в parse_u_r_l под наивным токенизатором или в parse_url под акроним-осведомлённым — но затем parse_url уже не может решить, возвращаться ли в parseUrl или в parseURL, потому что полностью строчное написание потеряло сигнал об акрониме.
Сохранять капитализацию акронима (Microsoft, .NET, старый Java): parseURL, userID, HTMLParser, XMLHttpRequest. Microsoft .NET Naming Guidelines ограничивают это правило 2–3-буквенными акронимами (IO, URL, XML) и применяют «считать словом» для более длинных (Html под строгим чтением был бы «сохранить капс», но на практике Microsoft пишет HtmlAgilityPack). Win32 API, .NET BCL и большая часть Java-кода до 2010-х идут этим путём. Англоязычным читателям он кажется более естественным — parseURL читается как «parse U-R-L» — ценой свойства round-trip.
PEP 8 в Python номинально рекомендует «считать словом», но стандартная библиотека Python исторически непоследовательна: http.server.HTTPServer и xml.etree.ElementTree сохраняют акронимы, тогда как json.JSONDecoder делает то же самое. Более новые добавления (pathlib.PurePath, dataclasses) склоняются к «считать словом». Позиция PEP 8 такая: следуйте окружающему коду.
Точечная проверка по публичному корпусу GitHub в начале 2026 года (сэмпл bigquery-public-data.github_repos в BigQuery, отфильтрованный по файлам TypeScript и JavaScript из репозиториев с 1000+ звёзд) показывает соотношение примерно 7:3 для parseUrl против parseURL и 6:4 для userId против userID. Стиль «считать словом» выигрывает в JavaScript. C# остаётся плотно в стиле Microsoft — parseURL доминирует в файлах C#. Python расколот пополам.
Правило решения: (а) следуйте стандартной библиотеке языка, на котором пишете; (б) когда стандартная библиотека непоследовательна, для greenfield-проекта выбирайте «считать словом», потому что он round-trip-ит; (в) запишите выбор в линтер или конфиг стиля и никогда не смешивайте оба подхода в одном проекте. Токенизатор Конвертера регистра следует соглашению «считать словом», чтобы совпадать с lodash и пакетом change-case — вставьте XMLHttpRequest, и на выходе будут xmlHttpRequest, xml_http_request, xml-http-request в качестве camelCase, snake_case и kebab-case.
URL-слаги: почему kebab-case лучше snake_case
Если читать официальную документацию Google Search Central о структуре URL, в ней встречается ровно одна конкретная рекомендация по case: используйте дефисы для разделения слов в URL, не используйте подчёркивания. Причина — токенизация. Поисковый индекс Google разбивает URL по дефисам, но не по подчёркиваниям. https://example.com/buy-running-shoes токенизируется как buy, running, shoes — три индексируемых терма, которые могут совпасть с любым из этих слов запроса. https://example.com/buy_running_shoes токенизируется как единственный терм buy_running_shoes, который совпадает только с этой точной строкой.
На устоявшихся страницах практический эффект для ранжирования невелик (у Google есть другие сигналы), но реален для новых страниц, конкурирующих в плотной выдаче. На равных условиях URL в kebab-case ранжируется выше.
Есть и вторая причина: чувствительность к регистру. URL-пути чувствительны к регистру на Linux-серверах (а это бо́льшая часть веба). /User-Profile и /user-profile — два разных URL, две разные записи в кеше, две разные строки в аналитике. Строчный kebab-case — единственное написание, которое не провоцирует баг «у меня на Mac работает».
Четырёхшаговый рецепт слага, работающий для любого заголовка:
- Привести всё к нижнему регистру.
- Заменить любые последовательности пробелов и пунктуации одним дефисом.
- Срезать ведущие и хвостовые дефисы.
- Опционально выбросить стоп-слова (
a,an,the,of,for) ради коротких URL — но только если CMS сохраняет исходный заголовок для шапки страницы.
Рабочий пример: "10 Tips for Faster JavaScript: A Complete Guide" → 10-tips-faster-javascript-complete-guide. Двоеточие и стоп-слова (for, a) уходят; результат — 39 символов, спокойно влезает в «золотую зону» 50–60 символов для SERP. Подробнее про длину URL и её связь с символьными лимитами платформ — Гид по лимитам символов и слов.
Конвертер регистра выдаёт kebab-case-вариант любого заголовка в одну вставку — пригодится, когда массово генерируете слаги для миграции CMS или sitemap.
Шесть ловушек конвертации
Автоматическая конвертация между case выглядит тривиально. На деле — нет. Вот шесть мест, где она ломается.
1. Границы между цифрами и буквами
Чем становится file2x после snake_case-конвертации? Мейнстримное соглашение — lodash, change-case, PEP 8, Конвертер регистра — считает каждый переход «буква↔цифра» границей токена, поэтому file2x разбирается как file / 2 / x и snake_case-ится в file_2_x. parseUTF8 становится parse / utf / 8 и parse_utf_8.
Некоторые старые библиотеки (и часть рукописных re.sub-сниппетов со Stack Overflow) пропускают это правило и выдают file2x → file2x или parseutf8. Расхождение всплывает только при миграции кода между библиотеками, а симптом такой: «половина идентификаторов переименована, половина — нет». Выберите один токенизатор, убедитесь, что он соблюдает правило цифровой границы, и держитесь его.
2. Подряд идущие заглавные буквы
Регулярное выражение для границы акронима — /([A-Z]+)([A-Z][a-z])/ — оно вставляет разрыв между серией заглавных и финальной заглавной, начинающей новое слово. XMLHttpRequest сначала матчится как XML + HttpRequest, затем как Http + Request, давая токены XML / Http / Request.
Обратный путь — там и кусается: XML / Http / Request, заново собранное в PascalCase, превращается в XmlHttpRequest, а не в XMLHttpRequest. Акроним получил title-case. Это стандартное поведение, потому что альтернатива — пытаться помнить, какие токены изначально были акронимами — требует метаданных вне строки, которых у токенизатора нет. Если ваша кодовая база в стиле XMLHttpRequest и вы прогоните проектное переименование через «считать словом»-конвертер, вы молча перепишете каждый акроним. Сначала тестируйте на ветке или используйте токенизатор, который позволяет помечать акронимы явно.
3. Unicode и locale-aware приведение к регистру
'I'.toLowerCase() в JavaScript обычно возвращает 'i'. Запустите тот же вызов с активной турецкой локалью — и получите 'ı' (бесточечное i, U+0131), потому что в турецком есть две разные буквы i, и строчная для заглавной I — это именно бесточечная. Этот единственный баг выкатывали бесчисленные команды на локализациях: формы входа, приводящие имя пользователя к верхнему регистру для сравнения, тихо отрезают любого пользователя с турецкой локалью по имени İrem.
Ещё два минных поля: немецкое ß.toUpperCase() возвращает 'SS' — один символ превращается в два, и любой код, считающий, что приведение к регистру сохраняет длину строки, ошибается. Греческое Σ.toLowerCase() зависит от контекста: σ в середине слова, ς — в конце.
Исправление: используйте toLocaleLowerCase() и toLocaleUpperCase() с явной локалью или — если локаль пользователя неизвестна — передавайте 'en-US', чтобы получить ASCII-совместимое поведение. Конвертер регистра использует Intl-осведомлённые методы, поэтому все три эти входа обрабатываются корректно. Для regex-стороны вопроса в Шпаргалке Regex разобран Unicode-класс букв \p{L}.
4. Загрязнение «умными» кавычками
Вставьте строку из Microsoft Word, Google Docs или macOS Notes в конвертер регистра — и можете утащить с собой невидимых пассажиров: U+2018 / U+2019 / U+201C / U+201D (фигурные кавычки), U+2014 (em-dash), U+00A0 (неразрывный пробел), U+200B (пробел нулевой ширины). Все они в большинстве шрифтов выглядят неотличимо от своих ASCII-эквивалентов, но кодируются иначе. camelCase-идентификатор с U+00A0 внутри в одних языках скомпилируется, в других — нет, а ваш grep по имени переменной молча промахнётся.
Защита: нормализуйте вход перед токенизацией. Однострочник input.normalize('NFKC').replace(/[“”‘’]/g, '"') снимает большинство нарушителей. Либо подход из Гида по сравнению текста — diff подозрительной строки против её визуального ASCII-близнеца и просмотр невидимок в hex-виде.
5. URL не нужно snake_case-ить
https://example.com/api/users, вставленное в snake_case-конвертер, даст https_example_com_api_users. Технически это валидный snake_case-идентификатор; семантически — катастрофа. URL уже находится в своём каноничном case (path/case со строчными kebab-case-сегментами пути), и попытка прогнать весь URL как один идентификатор уничтожает структурную информацию.
Исправление — разобрать URL, извлечь сегменты пути и при необходимости конвертировать каждый отдельно. Конвертер регистра намеренно не разбирает URL автоматически: угадывание намерения пользователя опаснее буквальности — вставили URL, получили буквальную конвертацию; если нужно посегментное поведение, сделайте его самостоятельно.
6. dot.case против обращения к свойству
Строка user.profile.image — это две разные сущности в зависимости от контекста. Как dot.case-идентификатор в TOML-файле — это одно имя из трёх сегментов. Как JavaScript-выражение — это свойство image свойства profile объекта user.
Если скопировать dot.case-строку из конфига и вставить в JavaScript-консоль, рантайм попытается выполнить её как цепочку обращений к свойствам и либо упадёт, либо вернёт что-нибудь неожиданное. И наоборот, код, который строково манипулирует JS-путями свойств ('a.b.c'.split('.')), иногда получает на вход dot.case-идентификаторы извне и относится к ним как к более глубоким путям, чем задумано. Эти две сущности обязаны сидеть в разных неймспейсах.
Соглашение: dot.case-строки остаются внутри данных (конфиги, пути MongoDB, ключи логов); код с одиночными идентификаторами использует camelCase или snake_case; если в коде нужна иерархическая сущность — используйте вложенные объекты и dot-синтаксис обращения к свойствам родного языка.
Рецепты межязыковой миграции
JS camelCase → Python snake_case
Самый быстрый workflow: скопировать JS-идентификатор, вставить в конвертер, скопировать snake_case-вывод. Для кодовой конвертации в массовом режиме:
import { snakeCase } from 'change-case';
snakeCase('parseHTML'); // 'parse_html'
snakeCase('XMLHttpRequest'); // 'xml_http_request'
snakeCase('parseUTF8'); // 'parse_utf_8'
snakeCase('iPhone'); // 'i_phone'
Последний пример — та самая ловушка: iPhone — это бренд, где camelCase-граница вводит в заблуждение. Бренды и горстку исторических идентификаторов после конвертации правьте руками.
SQL snake_case → API-ответы JS/Java
Большинство ORM делают это автоматически. У Sequelize есть underscored: true, у TypeORM — класс SnakeNamingStrategy, у Hibernate — ImplicitNamingStrategyComponentPathImpl. Дефолтный маппинг — user_profile_id ↔ userProfileId.
Что ломается — столбцы с акронимами. Столбец http_status_code чисто round-trip-ит в httpStatusCode, но если ваша кодовая база предпочитает HTTPStatusCode, ORM будет с вами спорить. Либо переименуйте столбец в httpstatuscode_code (некрасиво), либо настройте ORM на сохранение акронимов (редко), либо примите стандартное соглашение.
React PascalCase-компоненты → CSS kebab-case-классы
// UserProfileCard.tsx
export function UserProfileCard({ user }) {
return <div className="user-profile-card">{user.name}</div>;
}
/* UserProfileCard.module.css */
.user-profile-card { padding: 1rem; }
.user-profile-card__avatar { border-radius: 50%; }
.user-profile-card--featured { background: gold; }
BEM (Block Element Modifier) — самое распространённое CSS-соглашение, парное к React: блок — это имя компонента в kebab-case, элемент — block__element, модификатор — block--modifier. На уровне файлов: UserProfileCard.tsx для компонента, UserProfileCard.module.css для scoped-стилей — оба в PascalCase, совпадая с именем компонента.
Переменные окружения → конфиг приложения
# .env (CONSTANT_CASE)
DATABASE_URL=postgres://localhost/myapp
MAX_RETRIES=3
LOG_LEVEL=info
// Node.js
const dbUrl = process.env.DATABASE_URL;
const maxRetries = parseInt(process.env.MAX_RETRIES, 10);
# Python
import os
db_url = os.environ['DATABASE_URL']
max_retries = int(os.environ['MAX_RETRIES'])
Имя env-переменной остаётся в CONSTANT_CASE; идентификатор на стороне приложения следует соглашению переменных языка. Ключи YAML/TOML-конфига традиционно пишутся в snake_case (database_url, max_retries), хотя они и маппятся на те же CONSTANT_CASE env-переменные в рантайме — фреймворки вроде Spring, dotenv и Pydantic сами берут на себя маппинг между case.
Сравнение библиотек и инструментов
| Инструмент | Языки | Поддерживаемые case | Поведение токенизатора |
|---|---|---|---|
lodash (_.camelCase и т. д.) | JavaScript | 4 основных + startCase | Считать акроним словом |
Пакет npm change-case | JavaScript/TS | Все 8 программных case | Считать акроним словом |
inflection (Python) | Python | camelCase / snake_case | Считать акроним словом |
Крейт convert_case | Rust | 12+ case | Конфигурируемые акронимы |
Go strings + regex | Go | Самописное | Определяется проектом |
| VS Code (встроенный) | Редактор | Только UPPER / lower / Title | Только пробелы |
| Расширение VS Code «change-case» | Редактор | Все 8 программных case | Считать акроним словом |
| Конвертер регистра | Браузер | 15 case (7 текстовых + 8 кодовых) | Считать акроним словом |
Для повседневной работы поставьте change-case (JS) или convert_case (Rust). Для Python пакет inflection — каноничный выбор, но небольшой рукописный regex покрывает 90% случаев. Для разовых конвертаций во время код-ревью или рефакторинга Конвертер регистра показывает все 15 вариантов в одну вставку, чтобы можно было сравнить их одним взглядом. Если попутно нужно посчитать токены или проверить длину идентификатора, эту сторону закрывает Счётчик слов; для проверки самого regex-токенизатора — Тестер Regex с шаблонами из шпаргалки, упомянутой выше.
FAQ
В чём разница между camelCase и PascalCase?
camelCase начинается со строчной буквы (userProfile); PascalCase — с заглавной (UserProfile). Оба пишут каждое последующее слово с заглавной буквы без разделителя. camelCase — соглашение для переменных и функций в большинстве C-семейственных языков; PascalCase — соглашение для классов, типов и React-компонентов.
Почему Python использует snake_case, а JavaScript — camelCase?
Python (1991) унаследовал snake_case от C и языка ABC, а затем PEP 8 закрепил его как стандарт сообщества. JavaScript (1995) скопировал camelCase-стиль Java, а Java унаследовал camelCase у Smalltalk. И то и другое — историческая инерция. Технически ни одно из соглашений не лучше — исследования читаемости дают примерное равенство, — и согласованность внутри экосистемы важнее самого выбора.
Использовать parseUrl или parseURL для акронимов в camelCase?
parseUrl (считать акроним словом) — современный дефолт, используется Google, Apple, lodash и пакетом change-case. parseURL (сохранять капитализацию акронима) — стиль Microsoft .NET, доминирует в коде на C#. Для нового проекта на JavaScript, TypeScript или Swift выбирайте parseUrl, потому что он чисто round-trip-ит через конвертации в snake_case и kebab-case. Что бы ни выбрали, закодируйте выбор в линтере.
kebab-case лучше snake_case для URL?
Да. Официальная рекомендация Google Search Central — использовать в URL дефисы, а не подчёркивания. Поисковые индексы токенизируют по дефисам, но не по подчёркиваниям: /user-profile индексируется как user + profile, а /user_profile — как единственный терм user_profile. Эффект на ранжирование невелик на страницу, но реален, а строчный kebab-case в URL ещё и избавляет от багов чувствительности к регистру на Linux-серверах.
В каком case писать имена столбцов базы данных?
snake_case. Каждый крупный ORM (SQLAlchemy, Hibernate, Sequelize, TypeORM, Active Record) использует его по умолчанию, и каждый крупный SQL-диалект обрабатывает его одинаково. PostgreSQL приводит неэкранированные идентификаторы к нижнему регистру, MySQL чувствителен к регистру на Linux и нечувствителен на macOS/Windows, SQLite относится к именам как к непрозрачным строкам. Строчный snake_case — единственное написание, которое ведёт себя одинаково везде.
Можно ли смешивать соглашения именования в одном проекте?
Да — и обычно приходится. Типичное веб-приложение использует camelCase для JS-переменных, snake_case для базы данных, kebab-case для CSS-классов и URL, CONSTANT_CASE для env-переменных. Правило такое: «одно соглашение на слой, никогда не смешивать внутри одного слоя». Закодируйте выбор для каждого слоя в линтере или гайде стиля, чтобы PR-ревью перестали тратить на это слова.
Как программно конвертировать между case?
Для JavaScript и TypeScript поставьте change-case или используйте lodash — _.camelCase / _.snakeCase / _.kebabCase. Для Python — пакет inflection или короткий regex (re.sub(r'(?<!^)(?=[A-Z])', '_', s).lower() для PascalCase → snake_case). Для Rust — крейт convert_case. Для разовых интерактивных конвертаций Конвертер регистра показывает все 15 вариантов case для любого входа на одной браузерной странице.
CONSTANT_CASE — только для переменных окружения?
Нет, но env-переменные — самый частый кейс. CONSTANT_CASE — для любого «инварианта рантайма»: MAX_RETRIES, API_BASE_URL, DEFAULT_PAGE_SIZE, значения enum, определения макросов, верхнеуровневые конфигурационные константы. Правило: «будет ли изменение значения в рантайме багом?» — если да, CONSTANT_CASE; если нет, обычное соглашение переменных для языка. const result = await fetch(url) остаётся как есть.
В чём разница между dot.case и path/case?
dot.case использует . как разделитель (user.profile.image) и представляет иерархический ключ внутри данных: пакеты Java, пути полей MongoDB, ключи TOML-конфигов, lodash get/set-пути. path/case использует / (user/profile/image) и представляет реальное расположение: URL-пути, пути файловой системы, ref-ы Git. Выбор «точки против слешей» сигнализирует «метка данных» против «фактического расположения».
Шпаргалка решений на 30 секунд
Три правила, закрывающих 95% вопросов:
-
Для идентификаторов в коде копируйте стандартную библиотеку своего языка. Python: snake_case для переменных и функций, PascalCase для классов. JavaScript и TypeScript: camelCase для переменных и функций, PascalCase для классов и компонентов. Go: строчная первая буква — package-private, заглавная — экспортируемое. Rust: snake_case для переменных и функций, PascalCase для типов, SCREAMING_SNAKE для констант.
-
Для сквозных слоёв case фиксирован вне зависимости от языка. URL — kebab-case. CSS-классы — kebab-case. Имена столбцов БД — snake_case. Переменные окружения — CONSTANT_CASE. Заголовки HTTP/1.1 — Header-Case (HTTP/2 нормализует к строчному на проводе).
-
Запишите выбор в линтер один раз — и прекратите спорить. ESLint, Pylint, Clippy, golangci-lint и Rubocop — у всех есть правила для этого. Выберите соглашение, настройте линтер, и следующее PR-ревью ни одним словом не вспомнит про
userIDпротивuserId.
Когда всё-таки требуется конвертация между case — для рефакторинга, миграции CMS, маппинга SQL → API — Конвертер регистра выдаёт все 15 вариантов в одну вставку, чтобы можно было скопировать нужный без ручной токенизации входа. По смежной работе с текстом — Счётчик слов, Тестер Regex и Сравнение текста онлайн. Из углублённого чтения — Шпаргалка Regex разбирает паттерны токенизатора, Гид по сравнению текста — сравнения до/после во время миграции, а Гид по лимитам символов и слов — бюджеты длины URL для SEO-слагов.