camelCase مقابل snake_case مقابل kebab-case — دليل اصطلاحات التسمية 2026
هل تكتب userID أم userId؟ user_profile أم userProfile؟ هل تفصل الكلمات في الروابط بـ - أم بـ _؟ هذه أسئلة صغيرة تُعطّل مراجعات PR خمس مرات يوميًا. الإجابة ليست «تفضيلًا شخصيًا» — فلكل لغة برمجية رئيسية ولكل معيار ويب قاعدةٌ مستقرة، وبمجرد أن تراها مجتمعة في صفحة واحدة يسقط الجدل إلى الصفر.
يغطي هذا الدليل الأنماط الستة التي ستقابلها فعلًا في الكود (camelCase، PascalCase، snake_case، kebab-case، CONSTANT_CASE، وdot.case / path/case / Header-Case)، إلى جانب مصفوفة قرار لسبع لغات، ونقاش parseUrl مقابل parseURL ببيانات حقيقية من GitHub، وحجة SEO لروابط kebab-case، والفخاخ الست التي تنخدع فيها عند التحويل التلقائي بين الأنماط. وإذا أردت رؤية المخرجات الـ 15 لأي سلسلة دفعة واحدة، فإن محوّل حالة الأحرف يعرضها مباشرة في متصفحك.
الأنماط الستة في لمحة
قبل أي مقارنة، إليك بطاقة المرجع السريع. اطبعها، أو الصقها في ويكي فريقك، أو اتركها مفتوحة في تبويب.
| نمط الـ 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 | متغيرات البيئة، الثوابت العلوية، الماكروات | ماكرو C / بيئة Unix |
| dot.case | user.profile.image | حزم Java، مسارات MongoDB، مفاتيح TOML | اصطلاح فضاء التسمية |
| path/case | user/profile/image | مسارات URL، نظام الملفات، مراجع Git | مسارات Unix |
| Header-Case | User-Profile-Image | أسماء ترويسات HTTP/1.1 (الشكل القانوني) | RFC 2616 |
ثمانية صفوف تمثل ستة أنماط «حقيقية» — dot.case وpath/case وHeader-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 في السبعينيات وعلق الاسم.
أين يعيش: أسماء الأصناف في كل لغات عائلة C الكائنية (Java، C#، C++، Kotlin، Swift، TypeScript)، أسماء مكوّنات React/Vue/Angular، تعريفات أنواع TypeScript وواجهاتها (type UserProfile، interface AuthState)، وأسماء الوحدات/الملفات في بعض البيئات (UserService.cs في C#).
لماذا نمط مستقل للأصناف أصلًا؟ السبب بصري بحت. حين تقرأ 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.
يهم هنا الجانب المتعلق بقواعد البيانات، وهو ما تتخطّاه أغلب الدروس اللغوية. تقريبًا كل أداة ORM لقواعد بيانات SQL — SQLAlchemy، Hibernate، Sequelize، TypeORM، Active Record — تعتمد snake_case لأسماء الأعمدة بصرف النظر عن اصطلاح اللغة المضيفة. والسبب هو قابلية النقل: PostgreSQL يطوي المعرّفات غير المقتبسة إلى أحرف صغيرة، وMySQL على Linux حسّاس لحالة الأحرف، أما على macOS/Windows فلا، وSQLite يعامل أسماء الأعمدة كسلاسل معتمة. وsnake_case هو الكتابة الوحيدة التي تنجو من كل هذا دون اقتباس.
kebab-case: خيار الويب
تجمّع الويب على kebab-case لكل ما يراه المستخدم: أسماء أصناف CSS (.user-profile-image)، روابط URL (/blog/naming-conventions-guide)، خصائص HTML المخصّصة (data-user-id)، أسماء وسوم مكوّنات الويب (<user-card>، وهي بحسب المواصفة يجب أن تحتوي واصلة).
يظهر اسم النمط نفسه بنحو ثمانية متغيرات في الوثائق القديمة — «dash-case»، «spinal-case»، «lisp-case»، «skewer-case»، «hyphen-case». جميعها تعني الشيء نفسه. «kebab-case» هو الذي بقي بفضل نكتة قديمة على Stack Overflow عن أن الكلمات تبدو كقطع لحم على سيخ.
ثمة قاعدة غير بديهية: أسماء أصناف HTML وCSS غير حسّاسة لحالة الأحرف عمليًا، لكن الكتابة القانونية بأحرف صغيرة. تعمل .User-Profile في أغلب المتصفحات، لكنها تُعطّل أدوات الخادم التي تجزّئ أسماء الأصناف، وتربك مراجعي الكود. التزم بالأحرف الصغيرة.
CONSTANT_CASE: متغيرات البيئة والماكروات
نمط CONSTANT_CASE (يسميه أحيانًا أوساط Rust SCREAMING_SNAKE_CASE) هو الإشارة الكونية إلى «هذه القيمة لا تتغير في وقت التشغيل». MAX_RETRIES، API_KEY، DEFAULT_TIMEOUT_MS. لكل لغة اصطلاح له، ويتوقّع كل نظام CI وكل بيئة حاويات وكل صَدَفة أن تكون متغيرات البيئة بهذا النمط (DATABASE_URL، NODE_ENV، PATH).
تنبيه: كلمة const في JavaScript لا تعني «استخدم CONSTANT_CASE». فالسطر const result = await fetch(url) صحيح تمامًا بنمط camelCase. احفظ CONSTANT_CASE للثوابت الدلالية الحقيقية — القيم التي ستُعرَّف بـ #define في C، النوع الذي يكون تغيير قيمته أثناء التشغيل عيبًا برمجيًا. 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، مسارات نظام الملفات، مراجع 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 | — | snake_case | — | — | — | snake_case |
*Go: الحرف الأول الصغير يعني غير مُصدَّر (خاص بالحزمة)؛ والحرف الأول الكبير يعني مُصدَّر (عام). يفرض المترجم ذلك.**Go: الدوال المُصدَّرة بنمط PascalCase (http.NewRequest)؛ والدوال الخاصة بالحزمة بنمط camelCase (http.parseHeader).***Go: تتبع الثوابت قاعدة الأحرف نفسها للتصدير/عدمه —MaxRetriesللمُصدَّر،maxRetriesلغير المُصدَّر. تتجنّب Go CONSTANT_CASE عمدًا.†C#: المتغيرات المحلية والحقول الخاصة بنمط camelCase (تستعمل بعض قواعد التعليمات سابقة_للحقول:_userName)؛ والخصائص والطرق والأنواع العامة بنمط PascalCase.
ثلاث طبقات تقطع عرضيًا كل اللغات:
HTML وCSS: أسماء الأصناف والمعرّفات بنمط kebab-case (<div class="user-profile-card">). خصائص HTML المخصّصة بنمط kebab-case مع بادئة data- (data-user-id). خصائص CSS المضمّنة بنمط kebab-case (background-color)؛ ومكافئاتها في JS DOM بنمط 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 مقابل Microsoft
هذا أكثر سؤال تسمية مثيرٍ للجدل في مراجعات الكود. هل نكتب parseUrl أم parseURL؟ userId أم userID؟ HtmlParser أم HTMLParser؟ XmlHttpRequest أم XMLHttpRequest؟
ثمة مدرستان، ولكلٍّ منهما سلطة حقيقية في الميدان.
معاملة الاختصار ككلمة (Google، Apple، JS الحديثة): parseUrl، userId، HtmlParser. يوصي بذلك دليل أسلوب JavaScript من Google §5.3 صراحة. وكذلك إرشادات تصميم واجهات Swift API من Apple. وتنتج حِزم lodash وchange-case هذا المخرج افتراضيًا. الحجّة هي استقرار الذهاب والإياب: يتجزّأ 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. تقصر إرشادات تسمية .NET من Microsoft هذا النمط على اختصارات من 2-3 أحرف (IO، URL، XML) وتستخدم معاملة-ككلمة للأطول (يبدو Html معاملةً-بالأحرف-الكبيرة في القراءة الصارمة، لكن Microsoft تكتب HtmlAgilityPack عمليًا). تسلك واجهة Win32 API ومكتبة .NET BCL ومعظم كود Java قبل 2010 هذا الاتجاه. تقرأ أنيقًا بالإنجليزية — يبدو parseURL كأنه «parse U-R-L» — لكن على حساب خاصية الذهاب والإياب.
يوصي 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 من مستودعات بأكثر من ألف نجمة) تُظهر نسبة 7:3 تقريبًا بين parseUrl وparseURL، ونسبة 6:4 بين userId وuserID. نمط معاملة-ككلمة يكسب في JavaScript. أما C# فيبقى ثقيل الانحياز إلى أسلوب Microsoft — يسود parseURL في ملفات C#. وPython منقسم فعلًا.
قاعدة القرار: (أ) اتّبع المكتبة القياسية للغة التي تكتب بها؛ (ب) إن كانت المكتبة القياسية غير متّسقة، اختر معاملة-ككلمة للمشاريع الجديدة لأنها تذهب وتعود بنظافة؛ (ج) اكتب الاختيار في الـ linter أو إعدادات الأسلوب، ولا تخلط بين النمطين داخل المشروع نفسه أبدًا. يتبع مجزّئ محوّل حالة الأحرف اصطلاح معاملة-ككلمة ليتطابق مع lodash وحزمة change-case — الصق XMLHttpRequest لترى xmlHttpRequest وxml_http_request وxml-http-request بوصفها مخرجات camelCase وsnake_case وkebab-case.
روابط URL: لماذا يتفوّق kebab-case على snake_case
حين تقرأ الوثائق الرسمية لـ Google Search Central عن بنية الروابط، تجد توصية واحدة بعينها: استعمل الواصلات لفصل الكلمات في الروابط، ولا تستعمل الشَّرطات السفلية. السبب هو التقطيع. يُقسّم فهرس بحث Google الروابط على الواصلات لا على الشَّرطات السفلية. يُقطَّع https://example.com/buy-running-shoes إلى buy وrunning وshoes — ثلاثة مصطلحات قابلة للفهرسة يمكن لأيٍّ منها مطابقة كلمات الاستعلام. أما https://example.com/buy_running_shoes فيُقطَّع كمصطلح واحد buy_running_shoes، يطابق هذه السلسلة بالضبط فقط.
الأثر العملي على الترتيب صغير للصفحات الراسخة (لدى Google إشارات أخرى) لكنه حقيقي للصفحات الجديدة المتنافسة على نتائج بحث ضيقة. وعند تعادل صفحتين، يحتل رابط kebab-case مرتبة أعلى.
ثمة سبب ثانٍ: حسّاسية حالة الأحرف. مسارات الروابط حسّاسة لحالة الأحرف على خوادم Linux (وهي أغلب الويب). الرابطان /User-Profile و/user-profile رابطان مختلفان، ومدخلا تخزين مؤقّت مختلفان، وصفّان مختلفان في التحليلات. والكتابة الصغيرة بنمط kebab-case هي الكتابة الوحيدة التي لا تستدعي عيب «لكنه يعمل على جهازي Mac».
وصفة من أربع خطوات لتحويل أي عنوان إلى رابط:
- اجعل كل شيء بأحرف صغيرة.
- استبدل سلاسل المسافات وعلامات الترقيم بواصلة واحدة.
- أزل الواصلات من البداية والنهاية.
- اختياريًّا احذف كلمات الإيقاف (
a،an،the،of،for) لروابط أقصر — افعل ذلك فقط إن كان نظام إدارة المحتوى لديك يحتفظ بالعنوان الأصلي لعنوان الصفحة.
مثال محلول: "10 Tips for Faster JavaScript: A Complete Guide" ← 10-tips-faster-javascript-complete-guide. تُحذف النقطتان وكلمات الإيقاف (for، a)؛ وتكون النتيجة 39 حرفًا، أقل بسهولة من النطاق الأمثل 50-60 حرفًا للعرض في نتائج البحث. وللمزيد عن طول الروابط وتفاعله مع حدود الأحرف لكل منصة، راجع دليل حدود الأحرف والكلمات.
يمنحك محوّل حالة الأحرف مخرج kebab-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. الاختصار أصبح بنمط العنوان. وهذا السلوك المعياري لأن البديل — محاولة تذكّر أيٍّ من الرموز كان أصلًا اختصارًا — يتطلب بيانات وصفية خارج النطاق ليست لدى المجزّئات. إن كانت قاعدة الكود لديك بأسلوب XMLHttpRequest وأجريت إعادة تسمية على مستوى المشروع عبر محوِّل بمعاملة-ككلمة، فستعيد كتابة كل اختصار صامتًا. اختبر على فرع أولًا، أو استخدم مجزّئًا يسمح بوسم الاختصارات صراحة.
3. Unicode وتحويل حالة الأحرف الواعي باللغة المحلية
في JavaScript، يعيد 'I'.toLowerCase() عادةً 'i'. شغّل الاستدعاء نفسه واللغة المحلية التركية نشطة فيُعيد 'ı' (i بلا نقطة، U+0131)، لأن للتركية حرفي i مختلفين، والصغير من I الكبيرة هو ذو دون نقطة. شُحن هذا العيب الواحد في عمليات تدويل لا حصر لها — نماذج تسجيل الدخول التي ترفع اسم المستخدم إلى الحرف الكبير للمقارنة تحجب صامتةً كل مستخدم باسم İrem على لغة تركية محلية.
ثمة لغمان آخران: في الألمانية يعيد ß.toUpperCase() السلسلة 'SS' — حرف واحد يصير حرفين، فيخطئ أيُّ كود يفترض أن تحويل الحالة يحفظ طول السلسلة. وفي اليونانية، تحويل Σ.toLowerCase() يعتمد على السياق: σ في وسط الكلمة، ς في نهايتها.
الإصلاح: استخدم toLocaleLowerCase() وtoLocaleUpperCase() مع لغة محلية صريحة — أو إن لم تعرف لغة المستخدم، مرّر 'en-US' للحصول على سلوك متوافق مع ASCII. ويستعمل محوّل حالة الأحرف الطرق الواعية بـ Intl، فتعالج المدخلات الثلاثة المذكورة بشكل صحيح. ولجانب التعابير المنتظمة من ذلك، يغطي دليل التعبيرات المنتظمة فئة الحروف Unicode \p{L}.
4. تلوّث الاقتباسات الذكية
الصق سلسلة من Microsoft Word أو Google Docs أو macOS Notes في محوّل حالة فقد تحمل ركّابًا غير مرئيين: U+2018 / U+2019 / U+201C / U+201D (اقتباسات منحنية)، U+2014 (شَرطة طويلة)، U+00A0 (مسافة غير قابلة للكسر)، U+200B (مسافة بصفر عرض). تبدو هذه الأربع متطابقة مع نظائرها في ASCII بمعظم الخطوط لكنها تُرمَّز بشكل مختلف. سيبني معرّفُ camelCase يحوي U+00A0 في بعض اللغات ولن يبني في أخرى، وسيتخطّى grep على اسم المتغير المطابقةَ صامتًا.
الدفاع: طبِّع المدخل قبل التجزئة. يكفي سطر واحد input.normalize('NFKC').replace(/[“”‘’]/g, '"') لإزالة معظم المخالفين. أو استخدم منهج دليل مقارنة النصوص — قارن السلسلة المشبوهة بتوأمها البصري في ASCII ورصد غير المرئيات في عرض ست عشري.
5. لا تُحوِّل روابط URL إلى snake_case
يُنتج لصق https://example.com/api/users في محوّل snake_case السلسلة https_example_com_api_users. معرّف snake_case صالح تقنيًا؛ كارثة دلاليًا. الروابط أصلًا في شكلها القانوني (نمط path/case بمقاطع مسار بنمط kebab-case صغير)، ومعاملة الرابط بأكمله كمعرّف واحد تفقد المعلومة البنيوية.
الإصلاح: حلّل الرابط، واستخرج مقاطع المسار، وحوّل كل مقطع باستقلال إن احتجت فعلًا. لا يحلّل محوّل حالة الأحرف الروابط تلقائيًا عمدًا، لأن تخمين نيّة المستخدم أخطر من الالتزام بالحرفية — الصق رابطًا تحصل على تحويل حرفي؛ وإن أردت السلوك مقطعًا مقطعًا، فافعل ذلك بنفسك.
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؛ وإن احتجت شيئًا هرميًا في الكود، فاستخدم كائنات متداخلة وصيغة الخصائص بالنقطة الخاصة باللغة المضيفة.
وصفات هجرة بين اللغات
من camelCase في JS إلى snake_case في Python
أسرع سير عمل: انسخ معرّف 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 مضلِّلة. للأسماء التجارية وحفنة من المعرّفات التاريخية، حرّر يدويًّا بعد التحويل.
من snake_case في SQL إلى استجابات API في JS/Java
تتولّى أغلب أدوات ORM هذا تلقائيًا. في Sequelize الخيار underscored: true، وفي TypeORM صنف SnakeNamingStrategy، وفي Hibernate ImplicitNamingStrategyComponentPathImpl. التحويل الافتراضي هو user_profile_id ↔ userProfileId.
ما يكسر: الأعمدة التي تحمل اختصارات. عمود اسمه http_status_code يذهب ويعود إلى 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 للأنماط المحصورة — كلاهما بنمط 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'])
يبقى اسم متغيّر البيئة بنمط CONSTANT_CASE؛ ويتّبع المعرّف على جانب التطبيق اصطلاح متغيرات اللغة. أما مفاتيح إعدادات YAML/TOML فمن المتعارف عليه أن تكون بنمط snake_case (database_url، max_retries) رغم أنها تقابل متغيرات البيئة نفسها بنمط CONSTANT_CASE في وقت التشغيل — وتتكفّل أُطر مثل Spring وdotenv وPydantic بمطابقة الأنماط نيابة عنك.
مقارنة المكتبات والأدوات
| الأداة | اللغات | الأنماط المدعومة | سلوك المجزّئ |
|---|---|---|---|
lodash (_.camelCase، إلخ) | JavaScript | 4 رئيسية + startCase | معاملة-الاختصار-ككلمة |
| حزمة change-case على npm | JavaScript/TS | كل الأنماط البرمجية الثمانية | معاملة-الاختصار-ككلمة |
| inflection (Python) | Python | camelCase / snake_case | معاملة-الاختصار-ككلمة |
| convert_case (crate) | Rust | 12+ نمطًا | اختصارات قابلة للتهيئة |
| Go strings + regex | Go | مكتوب يدويًّا | حسب المشروع |
| VS Code (مدمج) | محرّر | UPPER / lower / Title فقط | على المسافات فقط |
| إضافة «change-case» لـ VS Code | محرّر | كل الأنماط البرمجية الثمانية | معاملة-الاختصار-ككلمة |
| محوّل حالة الأحرف | متصفح | 15 نمطًا (7 نصي + 8 برمجي) | معاملة-الاختصار-ككلمة |
للعمل اليومي على الكود، ثبّت change-case (لـ JS) أو convert_case (لـ Rust). ولـ Python، حزمة inflection هي الخيار القانوني، لكن تعبيرًا منتظمًا صغيرًا مكتوبًا يدويًا يغطي 90% من الحالات. وللتحويلات لمرّة واحدة أثناء مراجعة كود أو إعادة هيكلة، يعرض لك محوّل حالة الأحرف كل المخرجات الـ 15 بلصقة واحدة لتقارنها بنظرة واحدة. وإن احتجت أيضًا عدّ الرموز أو التحقق من طول المعرّف، فإن عداد الكلمات يتولّى ذلك؛ ولاختبار تعبير منتظم لمجزّئ، استخدم أداة اختبار regex مع الأنماط الموجودة في الدليل المرتبط أعلاه.
الأسئلة الشائعة
ما الفرق بين 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، التي ورثته بدورها من Smalltalk. كلاهما تبعيات تاريخية على مسار النشأة. لا اصطلاح منهما أفضل تقنيًا — دراسات قابلية القراءة متعادلة تقريبًا — ويهم الاتساق داخل البيئة أكثر من الاختيار نفسه.
هل أكتب parseUrl أم parseURL للاختصارات بنمط camelCase؟
parseUrl (معاملة-الاختصار-ككلمة) هو الافتراضي الحديث — تستخدمه Google وApple وlodash وحزمة change-case على npm. أما parseURL (الإبقاء على حروف الاختصار الكبيرة) فهو أسلوب Microsoft .NET ويسود في كود C#. لمشروع جديد بـ JavaScript أو TypeScript أو Swift، اختر parseUrl لأنه يذهب ويعود بنظافة عبر تحويلات snake_case وkebab-case. وأيّا كان اختيارك، رمّزه في الـ linter.
هل kebab-case أفضل من snake_case للروابط؟
نعم. توصية Google Search Central الرسمية باستخدام الواصلات لا الشَّرطات السفلية في الروابط. تُجزِّئ محرّكات البحث على الواصلات لا على الشَّرطات السفلية: يُفهرس /user-profile بوصفه user + profile، بينما يُفهرس /user_profile بوصفه المصطلح الواحد user_profile. أثر الترتيب صغير لكل صفحة لكنه حقيقي، كما تتجنّب روابط kebab-case الصغيرة عيوب حسّاسية الأحرف على خوادم Linux.
ما النمط الذي ينبغي لأسماء أعمدة قواعد البيانات أن تستخدمه؟
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 والروابط، وCONSTANT_CASE لمتغيرات البيئة. القاعدة «اصطلاح واحد لكل طبقة، ولا خلط داخل الطبقة الواحدة». رمّز الاختيار لكل طبقة في الـ linter أو دليل الأسلوب لتتوقّف مراجعات PR عن النقاش في ذلك.
كيف أحوّل بين الأنماط برمجيًّا؟
لـ JavaScript وTypeScript، ثبّت change-case أو استخدم _.camelCase / _.snakeCase / _.kebabCase من lodash. ولـ Python، حزمة inflection أو تعبير منتظم قصير (re.sub(r'(?<!^)(?=[A-Z])', '_', s).lower() للتحويل من PascalCase إلى snake_case). ولـ Rust، crate convert_case. وللتحويلات التفاعلية لمرة واحدة، يعرض محوّل حالة الأحرف كل المخرجات الـ 15 لأي مدخل في صفحة متصفح واحدة.
هل CONSTANT_CASE فقط لمتغيرات البيئة؟
لا، لكن متغيرات البيئة هي أكثر استخدام شائع. 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، مسارات get/set في Lodash. ويستخدم path/case / (user/profile/image) ويمثّل موقعًا فعليًّا: مسارات URL، مسارات نظام الملفات، مراجع Git. وخيار النقاط مقابل الشَّرطات المائلة يشير إلى «تسمية بيانات» مقابل «موقع فعلي».
بطاقة قرار في 30 ثانية
ثلاث قواعد تغطي 95% من الأسئلة:
-
لمعرّفات الكود، انسخ من المكتبة القياسية للغتك. Python: snake_case للمتغيرات والدوال، وPascalCase للأصناف. JavaScript وTypeScript: camelCase للمتغيرات والدوال، وPascalCase للأصناف والمكوّنات. Go: حرف أول صغير للحزمة الخاصة، حرف أول كبير للمُصدَّر. Rust: snake_case للمتغيرات والدوال، وPascalCase للأنواع، وSCREAMING_SNAKE للثوابت.
-
للطبقات العرضية، النمط ثابت بصرف النظر عن اللغة. الروابط بنمط kebab-case. أصناف CSS بنمط kebab-case. أسماء أعمدة قواعد البيانات بنمط snake_case. متغيرات البيئة بنمط CONSTANT_CASE. ترويسات HTTP/1.1 بنمط Header-Case (وHTTP/2 يطبّع إلى الأحرف الصغيرة على السلك).
-
اكتب الاختيار في الـ linter مرّةً واحدة وتوقّف عن الجدل. لدى ESLint وPylint وClippy وgolangci-lint وRubocop قواعد لهذا. اختر الاصطلاح، اضبط الـ linter، ولن تضيع مراجعة PR التالية كلمةً واحدة على
userIDمقابلuserId.
حين تحتاج فعلًا للتحويل بين الأنماط — لإعادة هيكلة، أو هجرة نظام إدارة محتوى، أو ربط SQL بـ API — يمنحك محوّل حالة الأحرف كل المخرجات الـ 15 بلصقة واحدة لتنسخ الصحيح دون تجزئة المدخل يدويًّا. ولأعمال نصية ذات صلة، راجع عداد الكلمات وأداة اختبار regex ومقارنة النصوص عبر الإنترنت. وللقراءات الأعمق، يغطي دليل التعبيرات المنتظمة أنماط المجزّئات، ويغطي دليل مقارنة النصوص مقارنات قبل/بعد أثناء الهجرة، ويغطي دليل حدود الأحرف والكلمات موازنات طول الروابط لروابط SEO.