في التصميم المعماري للأنظمة الموزعة، واجهات برمجة التطبيقات (APIs) ليست مجرد قنوات للتفاعل بين الأنظمة؛ بل هي عقود تربط بين مكدسات تقنية مختلفة، وثقافات تنظيمية، وحتى عصور تطويرية. ضمن تفاصيل تصميم واجهات برمجة التطبيقات من نوع RESTful، يثير موضوع واحد يبدو ثانويًا نقاشًا لا نهاية له: هل يجب أن تستخدم أسماء حقول JSON camelCase أم snake_case؟
هذا ليس مجرد خيار جمالي. إنه يمس "عدم توافق المعاوقة" بين طبقات استمرارية الواجهة الخلفية (Backend persistence layers) وطبقات عرض الواجهة الأمامية (Frontend presentation layers)، ويتضمن أداء التسلسل، وكفاءة نقل الشبكة، وتجربة المطور (DX)، وعلم النفس المعرفي.
بناءً على تاريخ لغات البرمجة، وآليات التنفيذ التقنية الأساسية، والقرارات المعمارية للشركات العملاقة في الصناعة مثل Google وStripe، يقدم هذا المقال دليلًا لاتخاذ القرار على مستوى الخبراء.
1. الأصول التاريخية: خيار دلالي
لفهم هذا النقاش، يجب أن نتتبع تطور لغات الكمبيوتر. لم تظهر اصطلاحات التسمية من فراغ؛ بل هي نتاج قيود الأجهزة وثقافات المجتمعات في عصور محددة.
أصل snake_case: لغة C وفلسفة يونكس
تعود شعبية snake_case (على سبيل المثال، user_id) إلى لغة C ويونكس في السبعينات. على الرغم من أن لوحات المفاتيح المبكرة (مثل Teletype Model 33) كانت تحتوي على مفاتيح Shift، إلا أن العديد من المترجمات المبكرة كانت غير حساسة لحالة الأحرف. لتمييز الكلمات بوضوح على الشاشات ذات الدقة المنخفضة، أدخل المبرمجون الشرطة السفلية لمحاكاة المسافات في اللغة الطبيعية. ترسخت هذه العادة بعمق في معايير قواعد بيانات SQL. وحتى يومنا هذا، لا يزال النمط الافتراضي لتسمية الأعمدة في PostgreSQL وMySQL هو snake_case، مما يضع الأساس للاحتكاك المستقبلي في الربط بين واجهات برمجة التطبيقات وقواعد البيانات.
صعود camelCase: هيمنة Java وJavaScript
ظهرت camelCase (على سبيل المثال، userId) مع البرمجة الشيئية (Smalltalk, C++, Java). وضعت Java المعيار الصناعي "PascalCase للفئات، camelCase للتوابع/المتغيرات". كانت نقطة التحول الحاسمة هي ولادة JavaScript. على الرغم من أن JSON نشأت من كائنات JS الحرفية، فقد اعتمدت مكتبة JS القياسية (على سبيل المثال، getElementById) camelCase بشكل عام. مع حلول AJAX وJSON محل XML كتنسيقات تبادل البيانات المهيمنة، اكتسبت camelCase مكانة "أصلية" في عالم الويب.
2. الصراع الجوهري: عدم توافق المعاوقة بين المكدسات التقنية
عندما تتدفق البيانات بين لغات مختلفة، فإنها حتمًا تواجه "عدم توافق المعاوقة".
منظور الواجهة الخلفية (Python/Ruby/SQL)
في الواجهة الخلفية، توصي مجتمعات Python (PEP 8) وRuby بشدة بـ snake_case.
- Python/Django/FastAPI: عادةً ما تتوافق نماذج Pydantic الخاصة بك مباشرةً مع هياكل جداول قاعدة البيانات:
class UserProfile(BaseModel):
first_name: str # Python convention
last_name: strإذا كانت واجهة برمجة التطبيقات تتطلب camelCase، فيجب عليك تكوين أسماء مستعارة (aliases) أو محولات (converters) في طبقة التسلسل. على الرغم من أن هذا ممكن، إلا أنه يضيف طبقة من منطق الربط.
- قواعد بيانات SQL: تستخدم معظم أسماء أعمدة قواعد البيانات
snake_case. إذا كانت واجهة برمجة التطبيقات تستخدمcamelCase، فيجب أن تتعامل طبقة ORM مع التحويل باستمرار. - اختيار Stripe: السبب الذي جعل Stripe وGitHub يختاران
snake_caseبقوة يرجع إلى حد كبير إلى أن بنيتهما المعمارية المبكرة بنيت على مكدس Ruby. كشف النماذج الداخلية مباشرةً ضمن الاتساق في الواجهة الخلفية.
منظور الواجهة الأمامية (JavaScript/TypeScript)
في المتصفح، camelCase هو الحاكم المطلق.
- تجزئة نمط التعليمات البرمجية: إذا كانت واجهة برمجة التطبيقات تُرجع
snake_case، تصبح التعليمات البرمجية للواجهة الأمامية غير متسقة:
const user = await fetchUser();
console.log(user.first_name); // يخالف قاعدة ESLint camelcase
render(user.email_address);سيقوم ESLint بالإشارة إلى هذا كتحذير، مما يجبر المطورين على تعطيل القاعدة أو تحويل البيانات فور استلامها.
- ألم التفكيك (Destructuring): في تطوير JS/TS الحديث، أصبح تفكيك الكائنات (object destructuring) منتشرًا. إذا كانت الحقول
snake_case، فيجب إعادة تسميتها أثناء التفكيك لتجنب تلويث النطاق المحلي:
// إعادة تسمية مطولة
const { first_name: firstName, last_name: lastName } = response.data;هذا يزيد من التعليمات البرمجية المتكررة واحتمالية حدوث الأخطاء.
3. خرافات الأداء: التسلسل ونقل الشبكة
فيما يتعلق بالأداء، توجد خرافات شائعة: "تحويل اسم الحقل بطيء جدًا" و "الشرطات السفلية تزيد من حجم الحمولة." دعنا نوضح بالبيانات.
الخرافة 1: النفقات العامة لتحويل وقت التشغيل
- اللغات الديناميكية: في Python أو Ruby، يؤدي تحويل أسماء الحقول عبر استبدال regex في كل طلب إلى استهلاك وحدة المعالجة المركزية. ومع ذلك، تعمل الأطر الحديثة (مثل Pydantic v2، التي أعيدت كتابتها في Rust) على تقليل هذه النفقات العامة من خلال خرائط المخططات المحسوبة مسبقًا.
- اللغات الثابتة (Go/Java/Rust): هذا في الواقع "بتكلفة صفر". يتم تحديد علامات هياكل Go (
json:"firstName") أو ذاكرة التخزين المؤقت لخرائط Jackson في Java في وقت التجميع أو بدء التشغيل. يتضمن تنفيذ وقت التشغيل نسخًا بسيطًا للبايت، وليس حسابًا ديناميكيًا.
ملاحظة: لا تقم أبدًا بإجراء تحويل متكرر عالمي في الواجهة الأمامية (الخيط الرئيسي للمتصفح) باستخدام المعترضات (interceptors) (مثل Axios). بالنسبة للاستجابات الكبيرة، يتسبب هذا في تقطع الصفحة واستهلاك الذاكرة. الاستنتاج: يجب أن تتعامل الواجهة الخلفية مع التحويل.
الخرافة 2: حجم الإرسال والضغط
نظريًا، first_name أطول بايت واحد من firstName. ومع ذلك، مع تمكين ضغط Gzip أو Brotli (تكوين HTTP القياسي)، يختفي هذا الاختلاف فعليًا.
- المبدأ: تعتمد خوارزميات الضغط على "الإشارة المرجعية المتكررة للسلاسل النصية". في مصفوفة JSON، تتكرر المفاتيح بشكل كبير. تخزن الخوارزمية
first_nameفي قاموس عند أول مصادفة وتستبدل التكرارات اللاحقة بمؤشر صغير. - المقاييس: تظهر الاختبارات أنه تحت مستوى Gzip 6، يكون الفرق في الحجم بين النمطين عادةً بين 0.5% و 1%. ما لم تكن تنقل البيانات عبر وصلات الأقمار الصناعية، فإن هذا ليس مشكلة.
4. تجربة المطور (DX) وعلم النفس المعرفي
الهندسة المعمارية ليست مجرد آلات؛ إنها تتعلق بالبشر.
- سهولة قراءة
snake_case: يشير علم النفس المعرفي إلى أن الشرطات السفلية توفر فصلًا بصريًا واضحًا. يتم تحليلparse_db_xmlبواسطة الدماغ بشكل أسرع منparseDbXml، خاصة عند التعامل مع الاختصارات المتتالية (على سبيل المثال،XMLHTTPRequestمقابلXmlHttpRequest). هذا أحد الأسباب التي تجعل وثائق Stripe تعتبر سهلة القراءة للغاية. - اتساق
camelCase: حالة التدفق التي يجلبها الاتساق الشامل (full-stack consistency) أكثر أهمية. بالنسبة لفرق JS/TS الشاملة، يتيح استخدامcamelCaseعبر الواجهة الأمامية والخلفية إعادة استخدام تعريفات الأنواع (Interface/Zod Schema) مباشرةً، مما يزيل تمامًا العبء المعرفي "للترجمة الذهنية".
5. معايير الصناعة والأساس المنطقي
| المؤسسة | الاختيار | المنطق الأساسي والخلفية |
|---|---|---|
| جوجل (Google) | camelCase |
تتطلب إرشادات Google API (AIP-140) استخدام lowerCamelCase لـ JSON. حتى لو كانت تعريفات Protobuf الداخلية تستخدم snake_case، فإن طبقة التحويل الخارجية تتحول تلقائيًا إلى camelCase لتتوافق مع نظام الويب البيئي. |
| مايكروسوفت (Microsoft) | camelCase |
مع تبني .NET Core للمصادر المفتوحة واختراع TypeScript، تحولت Microsoft بالكامل إلى معايير الويب، وتخلت عن نمط PascalCase المبكر. |
| سترايب (Stripe) | snake_case |
شركة نموذجية تعتمد على مكدس Ruby. إنهم يخفون الفارق من خلال توفير حزم تطوير البرامج (SDKs) للعميل قوية للغاية. عندما تستخدم حزمة Node SDK، على الرغم من أن snake_case يتم نقلها، فإن توقيعات توابع SDK تتبع عادةً اصطلاحات JS. |
| JSON:API | camelCase |
يوصي المعيار المدعوم من المجتمع صراحةً بـ camelCase، مما يعكس إجماع مجتمع الويب. |
6. نصيحة معمارية عميقة: فصل و DTOs
نمط خاطئ شائع هو "Pass-through": تسلسل كيانات قاعدة البيانات مباشرة لإعادتها.
- إذا قمت بذلك، وكانت أعمدة قاعدة البيانات الخاصة بك
snake_case، فستصبح واجهة برمجة التطبيقات الخاصة بكsnake_case. - المخاطرة: هذا ينتهك مبدأ إخفاء المعلومات، ويكشف عن هياكل الجداول، ويخلق اقترانًا قويًا بين واجهة برمجة التطبيقات وقاعدة البيانات. إذا تم إعادة تسمية قاعدة البيانات، تتعطل واجهة برمجة التطبيقات.
أفضل الممارسات: قدم طبقة DTO (كائن نقل البيانات). بغض النظر عن كيفية تسمية قاعدة البيانات الأساسية، يجب عليك تعريف عقد واجهة برمجة تطبيقات مستقل (DTO). وبما أنك تقوم بتعريف DTO، فلماذا لا تعرفه بـ camelCase ليتوافق مع معايير الويب؟ تتعامل أدوات الربط الحديثة (MapStruct, AutoMapper, Pydantic) مع هذا التحويل بسهولة.
7. التطلع إلى الأمام: GraphQL و gRPC
GraphQL: يتبنى المجتمع تقريبًا 100% camelCase. إذا كان فريقك يخطط لإدخال GraphQL في المستقبل، فإن تصميم واجهات برمجة التطبيقات RESTful باستخدام camelCase الآن هو استراتيجية "توافق أمامي" حكيمة.
gRPC: يفرض معيار Protobuf: تستخدم ملفات .proto snake_case لتعريفات الحقول، ولكن يجب تحويلها إلى camelCase عند ربطها بـ JSON. هذا هو حل Google القياسي لبيئات متعددة اللغات.
8. الملخص ومصفوفة القرار
لا يوجد صواب أو خطأ مطلق، فقط مفاضلات. إليك إطار القرار النهائي:
موصى به: الافتراض هو camelCase
لغالبية واجهات برمجة التطبيقات RESTful الجديدة والعامة التي تواجه عملاء الويب/التطبيق، يوصى بشدة بـ camelCase.
السبب: التوافق مع هيمنة JSON/JavaScript/TypeScript، واحتضان عادات 90% من المستهلكين.
الأدوات: احصل على أفضل دعم من مولدات أكواد OpenAPI، وSwagger UI، وبيئات التطوير المتكاملة الحديثة.
متى تستخدم snake_case؟
1. مستهلكون محددون: المستخدمون الأساسيون لواجهة برمجة التطبيقات هم علماء بيانات Python أو مهندسو تشغيل الأنظمة (Curl/Bash).
2. الأنظمة القديمة: واجهات برمجة التطبيقات الموجودة بالفعل تستخدم snake_case. الاتساق > أفضل الممارسات. لا تخلط الأنماط داخل نفس النظام.
3. التطرف في سرعة الواجهة الخلفية: استخدام Python/Ruby دون موارد للحفاظ على طبقة DTO، وتمرير نماذج قاعدة البيانات مباشرة.
جدول القرار
| البعد | النمط الموصى به |
|---|---|
| واجهة الويب الأمامية / تطبيق الهاتف المحمول | camelCase (عدم وجود معاوقة، أمان النوع) |
| تحليل البيانات / الحوسبة العلمية | snake_case (يتناسب مع عادات Python/R) |
| واجهة Node.js / Go / Java الخلفية | camelCase (دعم أصلي أو مكتبة مثالية) |
| واجهة Python / Ruby الخلفية | camelCase (موصى به المحول) أو snake_case (للأدوات الداخلية فقط) |
| فريق كامل المكدس (Full-Stack) | كلما زادت درجة تكامل المكدس، زادت التوصية بـ camelCase |
جوهر تصميم واجهة برمجة التطبيقات هو التعاطف. في سياق واجهات برمجة التطبيقات للويب، فإن تغليف التعقيد في الواجهة الخلفية (التعامل مع الربط) وترك الراحة للمستخدم (الالتزام بعادات JS) هو الخيار الذي يعكس احترافية أكبر.
