camelCase vs snake_case vs kebab-case: przewodnik 2026 po konwencjach nazw
userID czy userId? user_profile czy userProfile? URL z - czy _? To drobne pytania, które potrafią pięć razy dziennie zatrzymać przegląd PR-u. Odpowiedź nie brzmi „kwestia gustu” — każdy mainstreamowy język i każdy webowy standard ma ustaloną regułę, a kiedy zobaczy się je na jednej stronie, szum spada do zera.
Ten przewodnik obejmuje sześć styli case, z którymi naprawdę spotkasz się w kodzie (camelCase, PascalCase, snake_case, kebab-case, CONSTANT_CASE, dot.case / path/case / Header-Case), macierz decyzyjną dla siedmiu języków, debatę parseUrl vs parseURL opartą na realnych danych z GitHuba, argumenty SEO za adresami URL w kebab-case oraz sześć pułapek, które gryzą przy automatycznej konwersji między case. Jeśli chcesz zobaczyć od razu wszystkie 15 wariantów case dla dowolnego ciągu, Konwerter wielkości liter renderuje je na żywo w przeglądarce.
Sześć case’ów w skrócie
Zanim przejdziemy do porównań — oto ściąga. Wydrukuj ją, wklej do wiki zespołu albo zostaw otwartą w karcie przeglądarki.
| Styl case | Przykład | Typowe zastosowanie | Pochodzenie / popularyzator |
|---|---|---|---|
| camelCase | userProfileImage | Zmienne i metody w JS, TS, Java, Swift | Smalltalk → Java |
| PascalCase | UserProfileImage | Klasy, komponenty React/Vue, typy TS | Język Pascal |
| snake_case | user_profile_image | Python, Ruby, Rust, kolumny SQL | C / wczesny Unix |
| kebab-case | user-profile-image | Klasy CSS, URL slug, atrybuty HTML | Lisp / nowoczesny web |
| CONSTANT_CASE | USER_PROFILE_IMAGE | Zmienne env, stałe top-level, makra | Makra C / env Uniksa |
| dot.case | user.profile.image | Pakiety Java, ścieżki MongoDB, klucze TOML | Konwencja namespacingu |
| path/case | user/profile/image | Ścieżki URL, system plików, refy Git | Ścieżki Uniksa |
| Header-Case | User-Profile-Image | Nazwy nagłówków HTTP/1.1 (kanoniczne) | RFC 2616 |
Osiem wierszy dla sześciu „prawdziwych” case’ów — dot.case, path/case i Header-Case dzielą tę samą tokenizację z różnymi separatorami, dlatego większość bibliotek case’owych traktuje je jako jedną rodzinę.
Każdy case dogłębnie
camelCase: domyślny wybór JS/Java
camelCase to pomysł Smalltalka, ale to Java wyeksportowała go do reszty branży. Konwencje kodu Javy Suna z 1995 roku uczyniły z firstName, getUserProfile i xmlParser domyślny zapis, a każdy język, który chciał wyglądać po javowemu — JavaScript, ActionScript, Swift, Kotlin, Dart — odziedziczył ten sam kształt.
Reguła: pierwsze słowo z małej, każde kolejne z wielkiej, separator znika całkowicie. Bez podkreśleń, bez myślników, bez spacji. Nazwa „camelCase” pochodzi od garbatego konturu wielkich liter wystających z morza małych.
Dwa skrajne przypadki, w których ludzie się mylą: nazwy marek zaczynające się małą literą (iPhone, eBay, iOS) — kiedy taka pojawi się w kodzie, nie wymuszaj wielkiego i; zapisz tak, jak robi to marka, i zaakceptuj nieco dziwnie wyglądający identyfikator. I akronimy — szczegóły poniżej.
PascalCase: klasy i komponenty
PascalCase to camelCase z wielką pierwszą literą. Niektóre przewodniki stylu z tego powodu nazywają go „UpperCamelCase”. Język Pascal używał go w latach siedemdziesiątych i nazwa się przyjęła.
Gdzie żyje: nazwy klas w każdym obiektowym języku z rodziny C (Java, C#, C++, Kotlin, Swift, TypeScript), nazwy komponentów React/Vue/Angular, aliasy typów i interfejsy TypeScript (type UserProfile, interface AuthState) oraz nazwy modułów/plików w niektórych ekosystemach (UserService.cs w C#).
Po co w ogóle osobny case dla klas? To czysto wizualny sygnał. Czytając new userProfile() versus new UserProfile(), drugi od razu czyta się jako typ, a pierwszy jako pomyłkę w wywołaniu funkcji. Języki mieszające przestrzenie wartości i typów opierają się na wielkości liter, by je odróżniać.
snake_case: Python, Ruby, Rust, SQL
snake_case jest starszy, niż większość osób sądzi — C i wczesny Unix używały nazw w stylu errno_h i fopen_s, bo klawiatury w terminalach PDP-11 ułatwiały podkreślniki, a wielkie litery w stylu Pascala były kłopotliwe. Python przyjął to jako oficjalną konwencję PEP 8, społeczność Ruby ustaliła się na tym organicznie, a Rust uczynił z tego domyślną konwencję wymuszaną przez kompilator, z lintem narzekającym, gdy zmienna nazywa się userId zamiast user_id.
Reguła: wszystko małymi literami, słowa łączone podkreślnikami. user_profile_image, parse_html, max_retries.
Kontekst bazodanowy ma znaczenie i jest tym, co większość językowych tutoriali pomija. Niemal każde SQL ORM — SQLAlchemy, Hibernate, Sequelize, TypeORM, Active Record — domyślnie używa nazw kolumn w snake_case, niezależnie od konwencji języka hosta. Powód to przenośność: PostgreSQL składa niecytowane identyfikatory do małych liter, MySQL na Linuksie rozróżnia wielkość liter, MySQL na macOS/Windows nie rozróżnia, a SQLite traktuje nazwy kolumn jak nieprzezroczyste ciągi. snake_case jest jedynym zapisem, który przeżywa to wszystko bez cytowania.
kebab-case: wybór webu
Web zbiegł się na kebab-case dla wszystkiego, co widoczne dla użytkownika: nazwy klas CSS (.user-profile-image), URL slugi (/blog/naming-conventions-guide), niestandardowe atrybuty HTML (data-user-id), nazwy tagów Web Component (<user-card>, gdzie specyfikacja faktycznie wymaga obecności myślnika).
Sama nazwa pojawia się w starszej dokumentacji w mniej więcej ośmiu wariantach — „dash-case”, „spinal-case”, „lisp-case”, „skewer-case”, „hyphen-case”. Wszystkie znaczą to samo. „kebab-case” się przyjął dzięki starym żartom na Stack Overflow o tym, że słowa wyglądają jak mięso na szpadce.
Jedna nieoczywista zasada: nazwy klas HTML i CSS są w praktyce nieczułe na wielkość liter, ale kanoniczny zapis to małe litery. .User-Profile działa w większości przeglądarek, ale psuje narzędzia po stronie serwera hashujące nazwy klas i wprawia w zakłopotanie osoby przeglądające kod. Trzymaj się małych liter.
CONSTANT_CASE: zmienne env i makra
CONSTANT_CASE (czasem SCREAMING_SNAKE_CASE w środowiskach Rusta) to uniwersalny sygnał „ta wartość nigdy nie zmienia się w czasie wykonania”. MAX_RETRIES, API_KEY, DEFAULT_TIMEOUT_MS. Każdy język ma na to konwencję, a każdy system CI, runtime kontenerów i powłoka oczekują zmiennych środowiskowych w tej formie (DATABASE_URL, NODE_ENV, PATH).
Pułapka: słowo kluczowe const w JavaScripcie nie oznacza „użyj CONSTANT_CASE”. const result = await fetch(url) jest całkowicie poprawnym camelCase. Zachowaj CONSTANT_CASE dla prawdziwych semantycznych stałych — wartości, które w C byłyby zdefiniowane przez #define, takich gdzie zmiana wartości w czasie wykonania to bug. MAX_RETRIES = 3 się kwalifikuje. result nie.
dot.case, path/case, Header-Case
Trzy rodzeństwo dzielące tę samą tokenizację z różnymi separatorami.
dot.case reprezentuje klucze hierarchiczne: pakiety Java (com.example.service), ścieżki pól MongoDB (user.profile.image), klucze konfiguracji TOML/INI ([database.primary]), ścieżki metod Lodasha (_.get(obj, 'user.profile.image')). Czytając ciąg dot.case, powinno się widzieć „namespace, namespace, liść”.
path/case reprezentuje literalne lokalizacje: ścieżki URL, ścieżki w systemie plików, refy Git (feature/add-auth). Wybór kropek versus ukośników jest znaczący — ukośniki sygnalizują „to jest realny byt gdzieś tam”, kropki sygnalizują „to jest etykieta”.
Header-Case to konwencja HTTP/1.1: Content-Type, Access-Control-Allow-Origin, X-Forwarded-For. Nagłówki HTTP/1.1 są technicznie nieczułe na wielkość liter (RFC 2616), więc content-type działa, ale każdy framework, każda dokumentacja i każdy programista oczekuje zapisu Header-Case. HTTP/2 i HTTP/3 to zmieniły — RFC 7540 §8.1.2 wymusza nazwy nagłówków małymi literami na drucie, by uprościć kompresję nagłówków (HPACK). W praktyce jest to niewidoczne dla kodu aplikacyjnego, bo każdy klient i serwer HTTP/2 normalizuje to wewnętrznie, ale jeśli kiedykolwiek przyjrzysz się surowej ramce HTTP/2, nagłówki będą w całkowicie małym kebab-case.
Macierz decyzyjna dla siedmiu języków
Najszybszy sposób na rozstrzygnięcie sporu o nazewnictwo to sprawdzić, co robi biblioteka standardowa danego języka. Oto macierz.
| Język | Zmienna | Funkcja | Klasa | Stała | Nazwa pliku | Kolumna DB |
|---|---|---|---|---|---|---|
| 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/d | snake_case | n/d | n/d | n/d | snake_case |
*Go: mała pierwsza litera oznacza unexported (prywatne dla pakietu); wielka pierwsza litera oznacza exported (publiczne). Kompilator to wymusza.**Go: eksportowane funkcje są w PascalCase (http.NewRequest); funkcje prywatne dla pakietu są w camelCase (http.parseHeader).***Go: stałe stosują tę samą regułę exported/unexported —MaxRetriesdla eksportowanych,maxRetriesdla prywatnych. Go celowo unika CONSTANT_CASE.†C#: zmienne lokalne i prywatne pola są w camelCase (niektóre bazy kodu prefiksują pola znakiem_:_userName); publiczne właściwości, metody i typy są w PascalCase.
Trzy warstwy przecinające każdy język:
HTML i CSS: nazwy klas i ID są w kebab-case (<div class="user-profile-card">). Niestandardowe atrybuty HTML są w kebab-case z prefiksem data- (data-user-id). Inline’owe właściwości CSS są w kebab-case (background-color); ich odpowiedniki w DOM JS są w camelCase (element.style.backgroundColor).
HTTP: wychodzące nazwy nagłówków są w Header-Case dla HTTP/1.1 ('Content-Type': 'application/json') i małym kebab-case na drucie HTTP/2. Większość bibliotek fetch akceptuje oba zapisy i normalizuje wewnętrznie.
Zmienne środowiskowe: CONSTANT_CASE wszędzie — Node, Python, Go, Rust, Bash, Docker, Kubernetes. Konwencja pliku .env jest taka sama: DATABASE_URL=postgres://....
Obsługa akronimów: Google vs Microsoft
To pojedyncze najbardziej kontrowersyjne pytanie nazewnicze w przeglądach kodu. Powinno być parseUrl czy parseURL? userId czy userID? HtmlParser czy HTMLParser? XmlHttpRequest czy XMLHttpRequest?
Istnieją dwie szkoły i każda ma za sobą realny autorytet.
Traktuj-akronim-jak-słowo (Google, Apple, nowoczesny JS): parseUrl, userId, HtmlParser. Google JavaScript Style Guide §5.3 wprost to zaleca. Apple Swift API Design Guidelines robi to samo. Pakiety lodash i change-case domyślnie produkują takie wyjście. Argument to stabilność round-tripu: parseUrl tokenizuje się czysto do parse / url, konwertuje na parse_url i z powrotem na parseUrl bez utraty informacji. parseURL tokenizuje się do parse / URL, konwertuje na parse_u_r_l przy naiwnym tokenizerze albo na parse_url przy świadomym akronimów — ale wtedy parse_url nie potrafi zdecydować, czy wrócić do parseUrl, czy parseURL, bo zapis w pełni małymi literami stracił sygnał akronimu.
Zachowuj wielkie litery akronimów (Microsoft, .NET, starsza Java): parseURL, userID, HTMLParser, XMLHttpRequest. Microsoft .NET Naming Guidelines ogranicza to do akronimów 2-3 literowych (IO, URL, XML) i używa traktuj-jak-słowo dla dłuższych (Html w ścisłym czytaniu byłoby preserve-caps, ale Microsoft w praktyce pisze HtmlAgilityPack). API Win32, .NET BCL oraz większość kodu Javy sprzed 2010 idzie tą drogą. Czyta się to bardziej naturalnie dla anglojęzycznych — parseURL wygląda jak „parse U-R-L” — kosztem własności round-tripu.
Python PEP 8 nominalnie zaleca traktuj-jak-słowo, ale standardowa biblioteka Pythona jest historycznie niespójna: http.server.HTTPServer i xml.etree.ElementTree zachowują akronimy, podczas gdy json.JSONDecoder robi to samo. Nowsze dodatki (pathlib.PurePath, dataclasses) skłaniają się ku traktuj-jak-słowo. Linia PEP 8 brzmi: stosuj się do tego, co robi otaczający kod.
Sondaż na publicznym korpusie GitHuba z początku 2026 (próbka BigQuery bigquery-public-data.github_repos, filtrowana do plików TypeScript i JavaScript z repozytoriów z 1k+ gwiazdek) pokazuje mniej więcej stosunek 7:3 między parseUrl a parseURL oraz 6:4 między userId a userID. Styl traktuj-jak-słowo wygrywa w JavaScripcie. C# pozostaje silnie microsoftowy — parseURL dominuje w plikach C#. Python jest naprawdę podzielony.
Reguła decyzyjna: (a) stosuj się do biblioteki standardowej języka, w którym piszesz; (b) gdy biblioteka standardowa jest niespójna, wybierz traktuj-jak-słowo dla nowych projektów, bo robi round-trip; (c) zapisz wybór w lincie lub konfiguracji stylu i nigdy nie mieszaj obu w jednym projekcie. Tokenizer w Konwerterze wielkości liter stosuje konwencję traktuj-jak-słowo, by pasować do lodasha i pakietu change-case — wklej XMLHttpRequest, a zobaczysz xmlHttpRequest, xml_http_request, xml-http-request jako wyjścia camelCase, snake_case i kebab-case.
URL slug: dlaczego kebab-case bije snake_case
Czytając oficjalną dokumentację Google Search Central o strukturze URL, znajdziesz dokładnie jedno konkretne zalecenie co do case: w adresach URL używaj myślników do rozdzielania słów, nie używaj podkreśleń. Powód to tokenizacja. Indeks wyszukiwarki Google dzieli adresy URL na myślnikach, ale nie na podkreśleniach. https://example.com/buy-running-shoes tokenizuje się jako buy, running, shoes — trzy indeksowalne terminy, które mogą pasować do dowolnego z tych słów w zapytaniu. https://example.com/buy_running_shoes tokenizuje się jako jeden termin buy_running_shoes, który pasuje tylko do dokładnie tego ciągu.
Praktyczny wpływ na rankingi jest niewielki dla ustabilizowanych stron (Google ma inne sygnały), ale realny dla nowych stron walczących o ciasne SERP-y. Przy remisie URL w kebab-case rankuje wyżej.
Jest drugi powód: wrażliwość na wielkość liter. Ścieżki URL są wrażliwe na wielkość liter na serwerach Linuksowych (a to większość webu). /User-Profile i /user-profile to dwa różne URL-e, dwa różne wpisy w cache, dwa różne wiersze w analytics. Mały kebab-case to jedyny zapis, który nie zaprasza buga „ale u mnie na Macu działa”.
Czterokrokowy przepis na slug, który działa dla dowolnego tytułu:
- Wszystko małymi literami.
- Zamień ciągi spacji i interpunkcji na pojedynczy myślnik.
- Usuń myślniki z początku i końca.
- Opcjonalnie odrzuć stop words (
a,an,the,of,for) dla krótszych URL-i — tylko gdy CMS zachowuje oryginalny tytuł dla nagłówka strony.
Przykład: "10 Tips for Faster JavaScript: A Complete Guide" → 10-tips-faster-javascript-complete-guide. Dwukropek i stop words (for, a) zostają usunięte; wynik ma 39 znaków, łatwo poniżej słodkiego punktu 50-60 znaków dla wyświetlania w SERP-ach. Więcej o długości URL i jej interakcji z limitami znaków na platformach — zob. Przewodnik limitów znaków i słów.
Konwerter wielkości liter zwraca wyjście kebab-case dla dowolnego tytułu jednym wklejeniem — przydatne przy masowym generowaniu slugów dla migracji CMS lub mapy strony.
Sześć pułapek konwersji
Automatyczna konwersja między case wygląda trywialnie. Nie jest. Oto sześć miejsc, w których się psuje.
1. Granice cyfra-litera
Czym jest file2x po konwersji na snake_case? Mainstreamowa konwencja — lodash, change-case, PEP 8, Konwerter wielkości liter — traktuje każde przejście litera↔cyfra jako granicę tokenu, więc file2x staje się file / 2 / x i snake_cases się do file_2_x. parseUTF8 staje się parse / utf / 8 i parse_utf_8.
Niektóre starsze biblioteki (i niektóre ręcznie pisane snippety re.sub, które znajdziesz na Stack Overflow) pomijają tę regułę i produkują file2x → file2x albo parseutf8. Niezgodność ujawnia się dopiero przy migracji kodu między bibliotekami, a objaw to „połowa moich identyfikatorów została przemianowana, druga połowa nie”. Wybierz tokenizer, sprawdź, czy stosuje regułę granicy cyfr, i trzymaj się go.
2. Sąsiadujące wielkie litery
Wyrażenie regularne granicy akronimu to /([A-Z]+)([A-Z][a-z])/ — rozdziel między ciągiem wielkich liter a końcową wielką literą rozpoczynającą nowe słowo. XMLHttpRequest pasuje jako XML + HttpRequest, potem Http + Request, dając tokeny XML / Http / Request.
Powrót to miejsce, gdzie gryzie: XML / Http / Request przepisane z powrotem na PascalCase staje się XmlHttpRequest, nie XMLHttpRequest. Akronim został zamieniony na Title Case. To standardowe zachowanie, bo alternatywa — próba zapamiętania, które tokeny były pierwotnie akronimami — wymaga metadanych poza pasmem, których tokenizery nie mają. Jeśli baza kodu jest w stylu XMLHttpRequest, a uruchomisz na niej projektowy rename przez konwerter traktuj-jak-słowo, po cichu przepiszesz każdy akronim. Najpierw przetestuj na branchu albo użyj tokenizera pozwalającego jawnie oznaczyć akronimy.
3. Mapowanie wielkości liter wrażliwe na Unicode i locale
'I'.toLowerCase() w JavaScripcie zwykle zwraca 'i'. Uruchom to samo wywołanie z aktywnym tureckim locale, a zwróci 'ı' (bezkropkowe i, U+0131), bo turecki ma dwie odrębne litery i i małą literą wielkiego I jest właśnie ta bezkropkowa. Ten pojedynczy bug pojawił się w niezliczonych wdrożeniach i18n — formularze logowania robiące uppercase nazwy użytkownika do porównania po cichu blokują każdego tureckojęzycznego użytkownika o imieniu İrem.
Dwie kolejne miny: niemieckie ß.toUpperCase() zwraca 'SS' — jeden znak staje się dwoma, a każdy kod zakładający, że konwersja case zachowuje długość ciągu, jest błędny. Greckie Σ.toLowerCase() jest wrażliwe na kontekst: σ w środku słowa, ς na końcu słowa.
Rozwiązanie: używaj toLocaleLowerCase() i toLocaleUpperCase() z jawnie podanym locale lub — jeśli nie znasz locale użytkownika — przekazuj 'en-US', by uzyskać zachowanie kompatybilne z ASCII. Konwerter wielkości liter używa metod świadomych Intl, więc wszystkie trzy z tych wejść obsługuje poprawnie. Po stronie wyrażeń regularnych Ściąga wyrażeń regularnych omawia klasę liter Unicode \p{L}.
4. Zanieczyszczenie smart quotes
Wklej ciąg z Microsoft Word, Google Docs lub macOS Notes do konwertera case, a możesz nieść niewidocznych pasażerów: U+2018 / U+2019 / U+201C / U+201D (kręte cudzysłowy), U+2014 (em-dash), U+00A0 (twarda spacja), U+200B (spacja zerowej szerokości). Wszystkie cztery wyglądają identycznie jak ich odpowiedniki ASCII w większości czcionek, ale kodują się inaczej. Identyfikator camelCase zawierający U+00A0 skompiluje się w niektórych językach, a w innych nie, a grep po nazwie zmiennej po cichu przegapi wystąpienie.
Obrona: znormalizuj wejście przed tokenizacją. Wywołanie input.normalize('NFKC') w połączeniu z regexem, który zastępuje znaki U+201E, U+201C, U+201A, U+2019 zwykłym ASCII ", usuwa większość winowajców. Albo użyj podejścia z Przewodnika porównywania tekstów — porównaj podejrzany ciąg z jego wizualnym bliźniakiem ASCII i wypatrz niewidoczne znaki w widoku hex.
5. URL-i nie należy snake_case’ować
https://example.com/api/users wklejony do konwertera snake_case produkuje https_example_com_api_users. Technicznie poprawny identyfikator snake_case; semantycznie katastrofa. URL-e są już w swoim kanonicznym case (path/case z małymi segmentami ścieżki w kebab-case), a traktowanie całego URL-a jako pojedynczego identyfikatora gubi informację strukturalną.
Poprawka to sparsować URL, wyciągnąć segmenty ścieżki i przekonwertować każdy segment niezależnie, jeśli naprawdę musisz. Konwerter wielkości liter celowo nie parsuje automatycznie URL-i, bo zgadywanie intencji użytkownika jest groźniejsze niż bycie literalnym — wklej URL, dostań literalną konwersję; jeśli chciałeś przetwarzania segment po segmencie, zrób to samodzielnie.
6. dot.case versus dostęp do właściwości
Ciąg user.profile.image to dwie różne rzeczy w zależności od kontekstu. Jako identyfikator dot.case w pliku TOML jest jedną nazwą o trzech segmentach. Jako wyrażenie JavaScript jest właściwością image właściwości profile obiektu user.
Jeśli skopiujesz ciąg dot.case z pliku konfiguracyjnego i wkleisz do konsoli JavaScript, runtime spróbuje go oszacować jako łańcuch właściwości i albo wyrzuci błąd, albo zwróci coś zaskakującego. Odwrotnie, kod manipulujący ścieżkami właściwości JS jako ciągami ('a.b.c'.split('.')) bywa, że dostaje identyfikatory dot.case skądinąd i traktuje je jako głębsze ścieżki, niż zamierzono. Te dwa byty muszą pozostać oddzielnymi namespace’ami.
Konwencja: ciągi dot.case zostają w danych (pliki konfiguracyjne, ścieżki MongoDB, klucze logów); kod pojedynczych identyfikatorów używa camelCase lub snake_case; jeśli potrzebujesz hierarchii w kodzie, użyj zagnieżdżonych obiektów i składni dot-property języka hosta.
Przepisy na migrację między językami
JS camelCase do Python snake_case
Najszybszy workflow: skopiuj identyfikator JS, wklej do konwertera, skopiuj wyjście snake_case. Dla konwersji na poziomie kodu na masową skalę:
import { snakeCase } from 'change-case';
snakeCase('parseHTML'); // 'parse_html'
snakeCase('XMLHttpRequest'); // 'xml_http_request'
snakeCase('parseUTF8'); // 'parse_utf_8'
snakeCase('iPhone'); // 'i_phone'
Ostatni to pułapka — iPhone to nazwa marki, gdzie granica camelCase wprowadza w błąd. Dla nazw marek i garstki historycznych identyfikatorów edytuj ręcznie po konwersji.
SQL snake_case do odpowiedzi API w JS/Java
Większość ORM-ów robi to automatycznie. Sequelize ma underscored: true, TypeORM ma klasę SnakeNamingStrategy, Hibernate ma ImplicitNamingStrategyComponentPathImpl. Domyślne mapowanie to user_profile_id ↔ userProfileId.
Co się psuje: kolumny zawierające akronimy. Kolumna http_status_code robi czysty round-trip do httpStatusCode, ale jeśli baza kodu preferuje HTTPStatusCode, ORM będzie się z tobą wadził. Albo przemianuj kolumnę na httpstatuscode_code (brzydkie), albo skonfiguruj ORM tak, by zachowywał akronimy (rzadkie), albo zaakceptuj standardową konwencję.
Komponenty React w PascalCase do klas CSS w 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) to najpopularniejsza konwencja klas CSS pasująca do Reacta: blok to nazwa komponentu w kebab-case, element to block__element, modyfikator to block--modifier. Poziom plików: UserProfileCard.tsx dla komponentu, UserProfileCard.module.css dla scoped styles — oba w PascalCase, zgodne z nazwą komponentu.
Zmienne środowiskowe do konfiguracji aplikacji
# .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'])
Nazwa zmiennej env zostaje w CONSTANT_CASE; identyfikator po stronie aplikacji idzie za konwencją zmiennych języka. Klucze konfiguracji YAML/TOML są umownie w snake_case (database_url, max_retries), mimo że w czasie wykonania mapują się na te same zmienne env w CONSTANT_CASE — frameworki takie jak Spring, dotenv i Pydantic obsługują mapowanie case automatycznie.
Porównanie bibliotek i narzędzi
| Narzędzie | Języki | Wspierane case | Zachowanie tokenizera |
|---|---|---|---|
lodash (_.camelCase itd.) | JavaScript | 4 główne + startCase | Traktuj-akronim-jak-słowo |
pakiet change-case npm | JavaScript/TS | Wszystkie 8 case programistycznych | Traktuj-akronim-jak-słowo |
inflection (Python) | Python | camelCase / snake_case | Traktuj-akronim-jak-słowo |
crate convert_case | Rust | 12+ case’ów | Konfigurowalne akronimy |
Go strings + regex | Go | Ręcznie pisane | Zdefiniowane w projekcie |
| VS Code (wbudowane) | Edytor | Tylko UPPER / lower / Title | Tylko białe znaki |
| Rozszerzenie VS Code „change-case” | Edytor | Wszystkie 8 case programistycznych | Traktuj-akronim-jak-słowo |
| Konwerter wielkości liter | Przeglądarka | 15 case (7 tekstowych + 8 kodu) | Traktuj-akronim-jak-słowo |
W codziennej pracy z kodem zainstaluj change-case (JS) albo convert_case (Rust). Dla Pythona pakiet inflection jest kanonicznym wyborem, ale krótki ręcznie napisany regex pokrywa 90% przypadków. Dla jednorazowych konwersji podczas przeglądu kodu lub refaktoryzacji Konwerter wielkości liter pokazuje wszystkie 15 wyjść jednym wklejeniem, więc można je porównać na jednym ekranie. Jeśli potrzebujesz też zliczyć tokeny lub zwalidować długość identyfikatora, Licznik słów zajmuje się tą stroną; do weryfikacji wyrażenia tokenizera użyj Testera wyrażeń regularnych z wzorcami ze ściągi linkowanej powyżej.
FAQ
Jaka jest różnica między camelCase a PascalCase?
camelCase zaczyna się małą literą (userProfile); PascalCase zaczyna się wielką literą (UserProfile). Oba zapisują każde kolejne słowo wielką literą bez separatora. camelCase to konwencja zmiennych i funkcji w większości języków rodziny C; PascalCase to konwencja klas, typów i komponentów React.
Dlaczego Python używa snake_case, a JavaScript camelCase?
Python (1991) odziedziczył snake_case z C i języka ABC, a PEP 8 skodyfikowało to jako standard społeczności. JavaScript (1995) skopiował styl camelCase z Javy, a Java odziedziczyła camelCase ze Smalltalka. Obie to historyczne zależności ścieżki. Żadna konwencja nie jest technicznie lepsza — badania czytelności są mniej więcej zremisowane — a spójność w ekosystemie znaczy więcej niż sam wybór.
Czy w camelCase używać parseUrl czy parseURL dla akronimów?
parseUrl (traktuj-akronim-jak-słowo) to nowoczesny domyślny wybór — używany przez Google, Apple, lodasha i pakiet change-case npm. parseURL (zachowaj-wielkość-akronimu) to styl Microsoft .NET i dominuje w kodzie C#. Dla nowego projektu w JavaScript, TypeScript lub Swift wybierz parseUrl, bo robi czysty round-trip przez konwersje snake_case i kebab-case. Niezależnie od wyboru — zapisz go w lincie.
Czy kebab-case jest lepszy od snake_case w adresach URL?
Tak. Oficjalne zalecenie Google Search Central to używać myślników, nie podkreśleń, w URL-ach. Indeksery wyszukiwarek tokenizują na myślnikach, ale nie na podkreśleniach: /user-profile jest indeksowane jako user + profile, podczas gdy /user_profile jako pojedynczy termin user_profile. Wpływ na ranking jest niewielki na stronę, ale realny, a małe URL-e w kebab-case unikają też bugów wrażliwości na wielkość liter na serwerach Linuksowych.
Jakiego case użyć dla nazw kolumn w bazie danych?
snake_case. Każdy ważny ORM (SQLAlchemy, Hibernate, Sequelize, TypeORM, Active Record) domyślnie tego używa, a każdy ważny dialekt SQL obsługuje to identycznie. PostgreSQL składa niecytowane identyfikatory do małych liter, MySQL rozróżnia wielkość liter na Linuksie i nie rozróżnia na macOS/Windows, a SQLite traktuje nazwy jak nieprzezroczyste. Mały snake_case to jedyny zapis, który zachowuje się tak samo wszędzie.
Czy można mieszać konwencje nazewnicze w jednym projekcie?
Tak — i zwykle trzeba. Typowa aplikacja webowa może używać camelCase dla zmiennych JS, snake_case dla bazy, kebab-case dla klas CSS i URL-i oraz CONSTANT_CASE dla zmiennych env. Reguła brzmi „jedna konwencja na warstwę, nigdy nie mieszać w obrębie pojedynczej warstwy”. Zapisz wybór per warstwa w lincie lub przewodniku stylu, by przeglądy PR przestały o tym dyskutować.
Jak konwertować między case programatycznie?
Dla JavaScript i TypeScript zainstaluj change-case lub użyj _.camelCase / _.snakeCase / _.kebabCase z lodasha. Dla Pythona pakiet inflection albo krótki regex (re.sub(r'(?<!^)(?=[A-Z])', '_', s).lower() dla PascalCase do snake_case). Dla Rusta crate convert_case. Dla jednorazowych konwersji interaktywnych Konwerter wielkości liter pokazuje wszystkie 15 wyjść case dla dowolnego wejścia na jednej stronie w przeglądarce.
Czy CONSTANT_CASE jest tylko dla zmiennych środowiskowych?
Nie, ale zmienne env to najczęstsze użycie. CONSTANT_CASE jest dla każdego „niezmiennika w czasie wykonania”: MAX_RETRIES, API_BASE_URL, DEFAULT_PAGE_SIZE, wartości enum, definicje makr, stałe konfiguracyjne top-level. Reguła brzmi „czy zmiana tego w czasie wykonania byłaby bugiem?” — jeśli tak, CONSTANT_CASE; jeśli nie, normalna konwencja zmiennych języka. const result = await fetch(url) jest w porządku tak, jak jest.
Jaka jest różnica między dot.case a path/case?
dot.case używa . jako separatora (user.profile.image) i reprezentuje klucz hierarchiczny wewnątrz danych: pakiety Java, ścieżki pól MongoDB, klucze konfiguracji TOML, ścieżki get/set Lodasha. path/case używa / (user/profile/image) i reprezentuje realną lokalizację: ścieżki URL, ścieżki w systemie plików, refy Git. Wybór kropek versus ukośników sygnalizuje „etykietę danych” versus „rzeczywistą lokalizację”.
Ściąga decyzyjna na 30 sekund
Trzy reguły pokrywające 95% pytań:
-
Dla identyfikatorów kodu skopiuj bibliotekę standardową swojego języka. Python: snake_case dla zmiennych i funkcji, PascalCase dla klas. JavaScript i TypeScript: camelCase dla zmiennych i funkcji, PascalCase dla klas i komponentów. Go: mała pierwsza litera dla prywatnych w pakiecie, wielka pierwsza litera dla eksportowanych. Rust: snake_case dla zmiennych i funkcji, PascalCase dla typów, SCREAMING_SNAKE dla stałych.
-
Dla warstw przekrojowych case jest ustalony niezależnie od języka. URL-e są w kebab-case. Klasy CSS są w kebab-case. Nazwy kolumn DB są w snake_case. Zmienne środowiskowe są w CONSTANT_CASE. Nagłówki HTTP/1.1 są w Header-Case (HTTP/2 normalizuje do małych liter na drucie).
-
Zapisz wybór w lincie raz i przestań się kłócić. ESLint, Pylint, Clippy, golangci-lint i Rubocop mają reguły na to. Wybierz konwencję, skonfiguruj lint, a następny przegląd PR nie wyda ani słowa na
userIDversususerId.
Kiedy naprawdę musisz konwertować między case — dla refaktoryzacji, migracji CMS, mapowania SQL na API — Konwerter wielkości liter daje wszystkie 15 wyjść case jednym wklejeniem, więc można skopiować właściwe bez ręcznej tokenizacji wejścia. Z powiązanych prac tekstowych zob. Licznik słów, Tester wyrażeń regularnych i Porównanie tekstów online. Z głębszych lektur Ściąga wyrażeń regularnych omawia wzorce tokenizera, Przewodnik porównywania tekstów omawia porównania przed/po podczas migracji, a Przewodnik limitów znaków i słów omawia budżety długości URL dla slugów SEO.