كل مشروع يحتاج إلى تكوين، ولديك ثلاثة خيارات رئيسية: JSON أو YAML أو TOML. استخدمت الثلاثة بشكل مكثف، وكل منها يزعجني بطرق مختلفة. إليكم رأيي الصريح حول متى تستخدم أيًا منها.

JSON: الجندي العالمي

أنت تعرف JSON بالفعل. إنه في كل مكان. كل لغة برمجة تستطيع تحليله. لكن لنكن صريحين بشأن نقاط ضعفه كملف تكوين:

  • لا تعليقات. حرفيًا لا يمكنك شرح ما يفعله إعداد معين. هذا جنون لملف تكوين.
  • لا فواصل زائدة. أضف سطرًا جديدًا في النهاية، انسَ إضافة فاصلة للسطر السابق — وينكسر التكوين.
  • علامات اقتباس في كل مكان. كل مفتاح يحتاج علامات اقتباس مزدوجة: {"port": 8080} بدلاً من مجرد port: 8080.

رغم كل ذلك، يُستخدم JSON للتكوين بواسطة npm (package.json) وTypeScript (tsconfig.json) وVS Code (settings.json) والمزيد. السبب؟ صفر غموض. JSON صارم لدرجة أن هناك طريقة واحدة فقط لتفسيره.

YAML: جميل لكن خطير

YAML يبدو مذهلاً. نظيف، بسيط، مقروء للبشر. لكن لديه بعض الفخاخ سيئة السمعة:

yaml

هذه هي "مشكلة النرويج" التي ذكرتها في مقال YAML. YAML 1.1 يعامل NO وYES وON وOFF كقيم منطقية. تم إصلاح ذلك في YAML 1.2، لكن العديد من المحللات لا تزال تستخدم سلوك 1.1 افتراضيًا.

ثم هناك حساسية المسافات البادئة. مسافة واحدة في غير مكانها يمكن أن تغير معنى ملفك تمامًا — ورسالة الخطأ ستكون فظيعة.

ومع ذلك، YAML هو المعيار لـ Docker Compose وKubernetes وGitHub Actions وAnsible. إذا كنت تعمل في مجال DevOps/السحابة، فإتقان YAML إلزامي.

TOML: متخصص ملفات التكوين

TOML (Tom's Obvious Minimal Language) صُمم خصيصًا للتكوين. يهدف إلى أن يكون واضحًا — بمعنى أنه (تقريبًا) لا توجد طريقة لقراءة ملف TOML بشكل خاطئ.

هكذا يبدو تكوين TOML:

toml

أشياء يفعلها TOML بشكل ممتاز: أنواع أصلية للتاريخ/الوقت (created = 2026-03-08T10:30:00Z)، لا مشاكل مسافات بادئة، تعليقات بـ #، وصياغة يصعب حقًا إفسادها.

العيب؟ الهياكل المتداخلة بعمق تصبح مطولة. TOML رائع للتكوينات المسطحة نسبيًا، لكن إذا كنت تحتاج خمسة مستويات من التداخل، فقد يكون YAML أو JSON أكثر قابلية للقراءة.

TOML يستخدمه Rust (Cargo.toml) وPython (pyproject.toml) وHugo وعدد متزايد من الأدوات.

توصياتي

السيناريوالاختيارلماذا
تكوين مولّد آليًاJSONالأكثر صرامة وتوافقًا
DevOps/البنية التحتيةYAMLالنظام البيئي يتوقعه
تكوين التطبيقTOMLتعليقات + غموض أدنى
إعدادات مفتاح-قيمة بسيطةTOMLالأنظف للتكوينات المسطحة
هياكل متداخلة معقدةYAMLأفضل صياغة للتداخل

الخلاصة

نفس التكوين بالأشكال الثلاثة

رؤية نفس البيانات بالأشكال الثلاثة تبرز الفروقات حقًا. إليك تكوين تطبيق بسيط:

JSON:

json

YAML:

yaml

TOML:

toml

لاحظ كيف يتطلب JSON كل تلك علامات الاقتباس والأقواس المعقوفة، وYAML هو الأكثر إيجازًا لكنه يعتمد على المسافات البادئة، وTOML يحقق حلاً وسطًا مع عناوين أقسام صريحة وبدون اعتماد على المسافات البادئة.

أخطاء شائعة في ملفات التكوين

YAML: تحويل الأنواع العرضي. بالإضافة إلى مشكلة النرويج، YAML سيفسر أيضًا 3.10 كالرقم 3.1 (يحذف الصفر اللاحق)، و1_000 كـ 1000. إذا كانت قيم التكوين لديك سلاسل إصدارات مثل 3.10، ضعها دائمًا بين علامات اقتباس: version: "3.10".

JSON: نسيان أن الترتيب لا يهم. كائنات JSON غير مرتبة حسب المواصفات. إذا كانت معالجة التكوين لديك تعتمد على ترتيب المفاتيح، فأنت تبني على أساس هش. بعض المحللات تحافظ على ترتيب الإدراج، وأخرى لا.

TOML: الارتباك مع مصفوفات الجداول. TOML يستخدم [[أقواس.مزدوجة]] لمصفوفات الجداول، مما يربك المبتدئين. إليك كيف تعرّف عدة خوادم:

toml

تكوينات خاصة بالبيئة

مجال تعاني فيه الأشكال الثلاثة هو التعامل مع التجاوزات الخاصة بالبيئة (التطوير مقابل التجربة مقابل الإنتاج). الحلول الشائعة تشمل:

  • ملفات متعددة: config.base.yaml + config.production.yaml مع دمج عميق
  • استيفاء متغيرات البيئة: بعض أدوات YAML تدعم صياغة ${DB_HOST}، لكنها ليست قياسية
  • أدوات خارجية: Doppler أو HashiCorp Vault أو خدمات التكوين السحابية الأصلية

شخصيًا، أميل نحو نهج بسيط: ملف تكوين واحد بقيم افتراضية معقولة، ومتغيرات بيئة لأي شيء يتغير بين البيئات. الأشكال الثلاثة يمكنها قراءة متغيرات البيئة على مستوى التطبيق، لذا لا يحتاج شكل التكوين نفسه لدعم الاستيفاء.

شعبية التنسيقات حسب النظام البيئي

النظام البيئيالتنسيق الأساسيأمثلة بارزة
JavaScript/Node.jsJSONpackage.json, tsconfig.json, .eslintrc.json
PythonTOMLpyproject.toml, Cargo.toml (Rust)
DevOps/CloudYAMLdocker-compose.yml, k8s manifests, GitHub Actions
GoTOML/YAMLكلاهما مستخدم على نطاق واسع، لا معيار واحد
.NETJSONappsettings.json (حل محل web.config المبني على XML)

الخلاصة

لا توجد إجابة واحدة صحيحة. استخدم JSON عندما تحتاج أقصى توافق. استخدم YAML عندما يتطلبه النظام البيئي (Kubernetes لن يبدأ بقبول TOML). استخدم TOML عندما تريد تعليقات ومفاجآت أقل.

JSONC وJSON5: JSON بعجلات تدريب

حسنًا، لقد انتقدنا JSON لعدم دعمه التعليقات والفواصل الزائدة. لكن هناك شيء لا يخبرك به أحد: هناك فعلاً متغيرات من JSON تصلح هذه المضايقات، وعلى الأرجح أنك كنت تستخدم واحدة منها دون أن تدري.

أولاً: JSONC (JSON with Comments). إذا فتحت يومًا ملف tsconfig.json وفكرت "لحظة، هناك تعليقات هنا... ظننت أن JSON لا يسمح بالتعليقات؟" — نعم، هذا JSONC. إنه أساسًا JSON لكن يمكنك استخدام تعليقات السطر الواحد // وتعليقات الكتل /* */. VS Code يستخدم JSONC لملفات settings.json وlaunch.json وkeybindings.json. ملف tsconfig.json الخاص بـ TypeScript هو أيضًا تقنيًا JSONC وليس JSON صارمًا.

هكذا يبدو JSONC:

jsonc

ثم هناك JSON5، الذي يذهب أبعد من ذلك. JSON5 يخفف العديد من قواعد JSON الأكثر صرامة:

  • سلاسل بعلامات اقتباس مفردة: {'name': 'Sarah'} — أخيرًا!
  • فواصل زائدة: {"a": 1, "b": 2,} — لا مزيد من ضجيج الفروقات
  • مفاتيح بدون علامات اقتباس (إذا كانت معرفات صالحة): {name: "Sarah"}
  • أرقام سداسية عشرية: 0xFF
  • سلاسل متعددة الأسطر مع استمرار الشرطة المائلة العكسية
  • Infinity و-Infinity وNaN كأرقام صالحة

JSON5 رائع لملفات التكوين حيث البشر هم الجمهور الأساسي. بعض الأدوات تدعمه أصلاً — مثلاً .babelrc الخاص بـ Babel يمكن أن يكون JSON5. لكن لا تستخدم JSON5 لاستجابات API أو تبادل البيانات. الهدف من JSON الصارم هو أن الجميع يتفقون على التنسيق. JSON5 للبشر، ليس للآلات.

قاعدتي: إذا كانت الأداة تدعم JSONC أو JSON5، استخدمه. حرفيًا لا يوجد عيب في وجود تعليقات في ملفات التكوين. لكن إذا كنت تكتب مكتبة تقرأ التكوين، ادعم JSON القياسي أولاً وJSONC/JSON5 كإضافات اختيارية.

مراسي وأسماء مستعارة YAML: تكوين DRY

هذه هي الميزة القاتلة الحقيقية لـ YAML التي لا يكتشفها كثير من المطورين: المراسي والأسماء المستعارة. تتيح لك تعريف كتلة تكوين مرة واحدة وإعادة استخدامها في كل مكان. أساسًا DRY (Don't Repeat Yourself) لملفات التكوين.

المرساة تُعلَّم بـ &name والاسم المستعار يشير إليها بـ *name. إليك مثال عملي من Docker Compose:

yaml

هل رأيت ما حدث؟ عرّفنا الإعدادات المشتركة مرة واحدة بـ &common وسحبناها إلى ثلاث خدمات بـ <<: *common. بدون المراسي، كنت ستنسخ سياسة إعادة التشغيل وتكوين التسجيل في كل خدمة. وعندما تحتاج لتغيير تدوير السجلات؟ مكان واحد بدلاً من اثني عشر.

يمكنك أيضًا استخدام المراسي لقيم أبسط — ليس فقط للخرائط:

yaml

الآن، المطبات. مفتاح الدمج << الذي يجعل المراسي قوية حقًا؟ إنه ليس جزءًا فعليًا من مواصفات YAML 1.2. كان امتدادًا لأنواع YAML 1.1، وبينما معظم المحللات الشائعة لا تزال تدعمه، فهو تقنيًا غير قياسي. لذا إذا كنت تستخدم محلل YAML 1.2 صارمًا، قد لا تعمل مفاتيح الدمج.

أيضًا، المراسي تعمل فقط داخل ملف واحد. لا يمكنك الإشارة إلى مرساة معرّفة في ملف YAML آخر. ورسائل الخطأ عندما تخطئ في اسم مستعار؟ عادة شيء مثل "undefined alias" بدون أي سياق عن مكان المرساة المفترض. YAML الكلاسيكي.

TOML بالتفصيل: ميزات متقدمة

معظم الناس يعرفون أساسيات TOML — الأقسام بـ [أقواس]، أزواج مفتاح-قيمة، تعليقات بـ #. لكن TOML لديه بعض الميزات الرائعة حقًا التي لا تحظى بالتقدير الكافي. دعني أشرحها لك.

المفاتيح المنقطة تتيح لك تعريف هياكل متداخلة بدون عناوين أقسام:

toml

هذا مفيد عندما يكون لديك قيمتان متداخلتان فقط ولا تريد إنشاء قسم كامل لهما.

الجداول المضمنة تعطيك صياغة مدمجة شبيهة بـ JSON للكائنات الصغيرة:

toml

استخدم الجداول المضمنة باعتدال — لا يمكنها أن تمتد على عدة أسطر، وتصبح غير مقروءة بسرعة إذا حشوت فيها الكثير.

السلاسل متعددة الأسطر تأتي بنوعين، وهنا يصبح TOML مدروسًا بشكل مدهش:

toml

السلسلة الأساسية ذات الاقتباس الثلاثي (""") تعالج تسلسلات الهروب، بينما النسخة الحرفية (''') تعامل كل شيء كنص خام. هذا مثالي لأنماط regex أو مسارات ملفات Windows حيث لا تريد تفسير الشرطات المائلة العكسية كتسلسلات هروب.

أنواع التاريخ/الوقت الأصلية شيء لا يتعامل معه JSON ولا YAML بهذه النظافة:

toml

هذه أنواع من الدرجة الأولى في TOML، وليست سلاسل تتظاهر بأنها تواريخ. محلل TOML الخاص بك سيعطيك كائنات تاريخ/وقت فعلية، وليس سلاسل عليك تحليلها بنفسك.

لماذا اختار Cargo الخاص بـ Rust TOML؟ لأن تكوينات Cargo هي بالضبط النقطة المثالية لـ TOML: متداخلة بشكل معتدل، يحررها البشر، تحتاج تعليقات، وتستفيد من الأنواع الصارمة. لا تريد أن تُفسَّر إصدارات تبعياتك بصمت كأرقام عشرية (أنظر إليك يا YAML).

اعتبارات الأمان

حسنًا، هذا هو القسم الذي تصبح فيه الأمور مخيفة قليلاً. إذا كنت تحمّل ملفات تكوين من مصادر غير موثوقة — أو حتى إذا كنت تظن أنك لا تفعل ذلك — عليك معرفة هجمات إلغاء التسلسل.

المثال النموذجي هو yaml.load() في PyYAML. في الإصدارات القديمة، هذه الدالة البريئة المظهر كانت قادرة على تنفيذ أي كود Python مضمن في ملف YAML. لا أمزح. انظر إلى هذا:

yaml

إذا دسّ شخص ما هذا في تكوين YAML وحمّله تطبيق Python الخاص بك بـ yaml.load() بدلاً من yaml.safe_load()، سينفذ حرفيًا أمر النظام هذا. يحذف كل شيء. يثبّت بابًا خلفيًا. أي شيء يريده المهاجم.

الحل بسيط للغاية — استخدم دائمًا yaml.safe_load() في Python:

python

وثائق PyYAML تحذر الآن من هذا، والإصدارات الأحدث تظهر تحذير إيقاف إذا استخدمت yaml.load() بدون تحديد Loader. لكن لا تزال هناك دروس وإجابات لا حصر لها على Stack Overflow تعرض النسخة غير الآمنة. إنه لغم مخفي في مرمى البصر.

ثم هناك هجوم "مليار ضحكة" (يسمى أيضًا قنبلة XML، لكنه يعمل على YAML أيضًا). الفكرة هي التوسع العودي — تعرّف كيانات تشير إلى كيانات أخرى، مما يخلق نموًا أسيًا:

yaml

كل مستوى يضاعف البيانات بمقدار 5، لذا بحلول المستوى 8 أو 9 أنت تنظر إلى غيغابايت من البيانات من بضعة أسطر YAML. معظم محللات YAML الحديثة لديها حدود للعمق والتوسع لمنع هذا، لكن من الجيد معرفته.

JSON أكثر أمانًا بطبيعته لأنه لا يملك أي دلالات تنفيذ. لا توجد طريقة لتضمين كود، لا منشئات أنواع، لا توسع كيانات. محلل JSON يقرأ البيانات فقط — سلاسل وأرقام وقيم منطقية ومصفوفات وكائنات. هذا كل شيء. هذه واحدة من المزايا غير المقدرة لبساطة JSON. عندما يهم الأمان، فإن نقص ميزات JSON هو في الواقع ميزة.

TOML أيضًا آمن جدًا — ليس لديه قدرات تنفيذ كود ولا توسع عودي. لكنه أقل اختبارًا في المعارك من محللات JSON، لذا حافظ على تحديث مكتبات TOML الخاصة بك.

الخلاصة: إذا كنت تقبل ملفات تكوين من مستخدمين أو مصادر خارجية، JSON هو الخيار الأكثر أمانًا. إذا كان عليك استخدام YAML، استخدم دائمًا وظائف التحميل الآمنة وفكر في تشغيل أداة تدقيق YAML لالتقاط البنى المشبوهة.

أمثلة واقعية لملفات التكوين

النظرية رائعة، لكن دعنا ننظر إلى ملفات تكوين حقيقية ستصادفها في الواقع. أضفت ملاحظات لكل واحدة لتسليط الضوء على الأنماط الخاصة بالتنسيق.

سير عمل GitHub Actions (YAML):

yaml

هنا يتألق YAML حقًا. صياغة سير عمل GitHub Actions ستكون مؤلمة في JSON — كل تلك القوائم المتداخلة والبنية المبنية على المسافات البادئة تتناسب طبيعيًا مع YAML. يمكنك أيضًا رؤية كيف تساعد التعليقات في شرح استراتيجية المصفوفة.

Cargo.toml الخاص بـ Rust (TOML):

toml

لاحظ كيف يستخدم ملف Cargo manifest الجداول المضمنة للتبعيات مع الميزات. صياغة [[bin]] ذات الأقواس المزدوجة تعرّف مصفوفة جداول — كل مدخل [[bin]] يضيف هدف ثنائي آخر. TOML يبقي هذا مسطحًا وقابلاً للقراءة بدون أي ألاعيب مسافات بادئة.

package.json (JSON):

json

الكلاسيكي. لا تعليقات، الكثير من علامات الاقتباس، لكن كل أداة على الكوكب تستطيع قراءته. ما يجعل package.json يعمل رغم قيود JSON هو أن المخطط معروف جدًا — لا تحتاج تعليقات لشرح ما يفعله scripts.build لأن كل مطور JavaScript يعرف ذلك بالفعل.

.prettierrc (JSON):

json

تكوين مسطح بسيط مفتاح-قيمة. بصراحة، سيكون أجمل قليلاً كـ TOML (تعليقات!) أو حتى JSONC، وPrettier يدعم تنسيقات أخرى. لكن JSON هو الافتراضي، ولشيء بهذه البساطة لا يهم كثيرًا.

الترحيل بين التنسيقات

إذن قررت أن تنسيق تكوين مشروعك كان خطأ وتريد التبديل. أو ربما تسحب تكوينًا من أداة تستخدم تنسيقًا مختلفًا. في كلتا الحالتين، تحتاج للتحويل بين TOML وYAML وJSON. دعني أخبرك، الأمر ليس دائمًا سلسًا كما تأمل.

أدوات التحويل:

  • yq — السكين السويسري لـ YAML. يمكنه التحويل بين YAML وJSON وTOML وXML. yq -o=json config.yaml يعطيك ناتج JSON. إنه مثل jq لكن لـ YAML.
  • toml-cli وtaplo — معالجات TOML من سطر الأوامر. taplo جيد بشكل خاص لتنسيق TOML والتحقق منه.
  • سطر واحد من Python — في الحاجة، python -c "import yaml, json, sys; print(json.dumps(yaml.safe_load(sys.stdin), indent=2))" < config.yaml يحول YAML إلى JSON. ليس جميلاً، لكنه يعمل.
  • محولات عبر الإنترنت — للتحويلات السريعة لمرة واحدة، أدوات التنسيق لدينا يمكن أن تساعد. الصق تكوينك في المنسق المناسب، نظفه، وأعد كتابته يدويًا بالتنسيق المستهدف.

متى ترحّل:

  • فريقك يرتكب أخطاء مسافات بادئة YAML باستمرار في تكوينات CI؟ ربما الانتقال إلى TOML يقلل هذه الصداع.
  • تحتاج تعليقات في ملف تكوين JSON؟ فكر في الترحيل إلى JSONC (إذا كانت الأداة تدعمه) أو TOML.
  • تبني مشروع Rust/Python جديدًا والنظام البيئي يتوقع TOML؟ لا تقاومه — استخدم TOML.

مطبات شائعة عند الترحيل:

تحليل التواريخ الضمني في YAML سيعضك. إذا كان لديك قيمة YAML مثل release: 2024-03-08، YAML يفسرها ككائن تاريخ، ليس سلسلة. حوّل ذلك إلى JSON وقد تحصل على "release": "2024-03-08T00:00:00Z" أو "release": "2024-03-08" حسب المحول. اختبر ناتجك دائمًا.

الأنواع الصارمة في TOML تعني أنه لا يمكنك امتلاك مصفوفات مختلطة الأنواع. في JSON وYAML، [1, "two", true] عادي تمامًا. في TOML، كل عنصر في المصفوفة يجب أن يكون من نفس النوع. إذا كانت بياناتك المصدرية تحتوي مصفوفات مختلطة، ستحتاج لإعادة الهيكلة.

وهذا هو الأهم: التعليقات تضيع. JSON لا يدعم التعليقات، لذا إذا كنت تحول من TOML أو YAML إلى JSON، كل تعليقاتك المكتوبة بعناية تختفي. في الاتجاه المعاكس (JSON إلى YAML/TOML)، ستريد إضافة تعليقات يدويًا لشرح الإعدادات غير الواضحة، لأن نسخة JSON بالتأكيد لم يكن بها.

شيء آخر — مراسي وأسماء YAML المستعارة ليس لها مكافئات في JSON أو TOML. إذا كان تكوين YAML يعتمد على المراسي للتكوين DRY، التحويل إلى تنسيق آخر يعني أنه عليك تكرار تلك الكتل المشتركة يدويًا. هذا يمكن أن يكون توسعًا كبيرًا في حجم الملف للتكوينات المعقدة.

جرّبها بنفسك

أيًا كان التنسيق الذي تختاره، الحفاظ على تنسيق جيد لملفات التكوين يجعلها أسهل للمراجعة والتصحيح. أداة TOML Formatter لدينا تنظف ملفات TOML الفوضوية فورًا. أداة YAML Formatter تصلح مشاكل المسافات البادئة قبل أن تسبب مشاكل. وأداة JSON Formatter تجعل حتى تكوينات JSON المتداخلة بعمق مقروءة بنظرة واحدة.