YAML مقابل JSON مقابل TOML — أي صيغة تكوين يجب أن تستخدمها فعلاً؟
يُستخدم YAML، JSON، وTOML لتخزين الإعدادات. ولا يمكن استبدالها. سيُحول YAML رمز دولةك إلى قيمة منطقية بشكل سري. لن يسمح لك JSON بترك ملاحظة. وTOML هو الأداة التي لم يُستخدمها أي شخص في فريقك من قبل. إليك كيفية اختيار الأداة المناسبة.
في عام 2015، توقف خطة Ansible بسبب هذه السطر:
country: NO
تم تحميل التكوين دون أخطاء. لم تُظهر أي ملاحظات من مُحلل. لكن country لم تُحدد كنص "NO". كانت مُحددة كـ false. لأن في YAML 1.1، NO هي قيمة منطقية. كذلك yes, on, off, yو، و n. هذا هو مشكلة النرويج، وتم تلف التكوينات بشكل سري لسنوات.
هذا ليس تقريرًا عن عيوب YAML. إنه إطار لقرارك الذي ستحدد فيه: YAML، JSON، أو TOML لملف التكوين القادم؟ كل واحد له تناقضات حقيقية، والجواب "استخدم ما يستخدمه النظام" لا ينطبق دائمًا.
نفس الإعداد، ثلاث طرق
قبل التوقف، إليك نفس تكوين التطبيق المكتوب في جميع الأشكال الثلاثة:
يامل
# App configuration
app:
name: my-api
port: 8080
debug: false
database:
host: localhost
port: 5432
name: mydb
pool_size: 10
logging:
level: info
format: json
outputs:
- stdout
- /var/log/app.log
JSON
{
"app": {
"name": "my-api",
"port": 8080,
"debug": false
},
"database": {
"host": "localhost",
"port": 5432,
"name": "mydb",
"pool_size": 10
},
"logging": {
"level": "info",
"format": "json",
"outputs": [
"stdout",
"/var/log/app.log"
]
}
}
تومل
# App configuration
[app]
name = "my-api"
port = 8080
debug = false
[database]
host = "localhost"
port = 5432
name = "mydb"
pool_size = 10
[logging]
level = "info"
format = "json"
outputs = ["stdout", "/var/log/app.log"]
يُعد YAML أبسط من حيث الحجم لكنه يحتوي على أسلوب معقد. يُعد JSON أكثر تفصيلًا لكنه أقل وضوحًا. يقع TOML في المنتصف: قابل للقراءة دون تحويل أنواع ضمني.
YAML: قوي، مرن، ومليء بالمخاطر
يُعد YAML الخيار الافتراضي لسلاسل CI/CD (GitHub Actions، GitLab CI، CircleCI)، وملفات Kubernetes، وملفات Ansible، وغالبية الأدوات المُطوّرة. لا تختار YAML — بل يختار لك.
المسائل المُوثقة:
1. مشكلة القيم المنطقية (مشكلة النرويج)
النسخة 1.1 من YAML — وهي النسخة التي يُستخدمها معظم المُحللين — تُعامل عددًا من السلاسل كقيم منطقية:
# YAML 1.1 boolean values (all parsed as true or false)
enabled: yes # true
disabled: no # false
active: on # true
paused: off # false
valid: true # true
invalid: false # false
# The Norway Problem in practice:
country_codes:
NO: Norway # Key "NO" is fine, but value "NO" becomes false
SE: Sweden
YES: Yemen # "YES" also becomes true
# The fix: quote your strings
country_codes:
NO: "Norway"
SE: "Sweden"
النسخة 1.2 من YAML (مُصدرت في 2009) أعادت هذا — فقط true و false هي منطقية. المشكلة هي أن PyYAML لم تُعتمد تمامًا سلوك النسخة 1.2 حتى النسخة 6.0 في 2021، وGo الذي يُستخدم كثيرًا gopkg.in/yaml.v2 لا يزال يستخدم سلوك النسخة 1.1 حتى عام 2024. إذا كنت تستخدم Psych من Ruby قبل 4.0 أو أي نسخة من PyYAML قبل 6.0، فأنت على النسخة 1.1.
2. التبويب سيُقتل تكوينك
يمنع YAML استخدام أحرف التبويب للإسقاط. فقط المسافات مقبولة. قد يُظهر محررك التبويب والمسافات بشكل متماثل، وقد يبدو الملف صحيحًا، لكن YAML سيُظهر:
yaml.scanner.ScannerError: while scanning a block mapping
found character '\t' that cannot start any token
هذا الخطأ هو الذي يجعل المطورين المبتدئين يشككون في خيارات مهنتهم. قم بتكوين محررك لتغيير التبويب إلى مسافات في ملفات YAML. كل محرر يدعم ذلك؛ لكن ليس كل محرر يُفعّله بشكل افتراضي.
3. النصوص المتعددة الأسطر ليست واضحة
# | (literal block): preserves newlines exactly
description: |
Line one.
Line two.
Line three.
# Result: "Line one.\nLine two.\nLine three.\n"
# > (folded block): folds newlines into spaces
short_desc: >
This will all become
one long line.
# Result: "This will all become one long line.\n"
# Trailing newlines: | adds one, |+ adds all, |- strips them all
desc_stripped: |-
No trailing newline.
لا يُذكر هذا في الذاكرة بدون مراجعة. المُnemonic الذي أستخدمه: | يبدو كنقطة توقف، > يبدو كشيء مُضغط. حتى الآن يُشعر بالارتباك بعد ثلاث سنوات.
عندما يفوز YAML
- أنت تكتب ملفات Kubernetes، أو مسارات GitHub Actions، أو ملفات Ansible — لا تملك خيارًا.
- يحتوي تكوينك على تعليقات تشرح القيم غير الواضحة. يدعم YAML تعليقات داخلية؛ يدعم JSON وTOML أيضًا، لكن YAML يشعر بالطبيعة الأفضل لملفات التكوين المُملوءة بالتعليقات.
- يحتوي بياناتك على هيكل متداخل عميق الذي سيبدو مُزعجًا مع جداول TOML المسطحة.
- الفرق المُستخدم بالفعل وله مُدقق (yamllint) في السيرفر.
JSON: المُشغل البسيط والموثوق
تم تصميم JSON كصيغة تبادل بيانات، وليس كصيغة تكوين. قرر داوس كروكفورد إزالة التعليقات — واعتبر أن التعليقات ستُستخدم لتعليمات تختلف بين المُحللين. وهذا هو السبب الذي يجعل package.json لا يحتوي على تعليقات و tsconfig.json هو تقنيًا JSON مع تعليقات (JSONC)، وهو شيء منفصل لا يدعمه معظم مُحللين JSON.
المشكلات الحقيقية لـ JSON في ملفات التكوين:
- لا يحتوي على تعليقات. لا يمكنك تفسير لماذا
"maxRetries": 3وغير 5. لا يمكنك ترك ملاحظة TODO. لا يمكنك تسمية حقل كمُستبعد. هذا يُسبب ألم حقيقي في ملفات التكوين التي تستمر بعد مُؤلفيها. - لا يحتوي على مسافات ختامية. إضافة عنصر إلى مصفوفة يعني تعديل السطر السابق لإضافة مسافة. كل تغيير في JSON يصبح تغييرًا بسيطًا على سطرين. كل نزاع تكامل يصبح أسوأ مما ينبغي.
- مُفصّل للبيانات المتداخلة. ستحتاج إلى سبعة أسطر من الأقواس والقوسات مقابل ما يُفعله YAML في ثلاث أسطر من التباعد.
- جميع الأرقام من نفس النوع. لا يُميز JSON بين الأعداد الصحيحة والأعداد العشرية.
1و1.0كلاهما مجرد أرقام، وما يُحوّله لغة التحليل يعتمد على المُحلل.
لكن التنبؤية في JSON هي أيضًا ميزة رئيسية. كل لغة تحتوي على مُحلل JSON. المواصفة واضحة. لا توجد تحويلات ضمنية. نص دائمًا يكون نصًا — "yes" لن يصبح trueبشكل سري. إذا كنت بحاجة إلى تحقق من تكوين JSON برمجيًا، IO Tools’ JSON Formatter يمكن أن يكتشف أخطاء التركيب قبل أن تصل إلى الإنتاج — مفيد عندما يُحرر تكوين يدويًا ويُنسى مسافة ختامية.
عندما يفوز JSON
- مُدخلات وحدات مُستهلكة من قبل عدة لغات/أنظمة؟ يُعد JSON عالميًا؛ بينما دعم TOML غير مكتمل في بعض الأنظمة.
- تحتاج إلى ضمانات صارمة للأنواع. تحقق من صيغة JSON مُطوّرة جيدًا، مدعومة جيدًا، ومستخدمة على نطاق واسع (يستخدمها VS Code لملء التوصيات).
- يُولد التكوين تلقائيًا. لا يكتب أي شخص JSON يدويًا إذا كان يمكن تجنب ذلك — لكن الأنظمة تُنتجها بسهولة.
- أنت تعمل في Node.js أو JavaScript للواجهات الأمامية، حيث يُعد JSON مواطنًا مُتسلسلاً.
TOML: تكوين مُوجه بشكل صحيح
تم إنشاء TOML (Tom's Obvious, Minimal Language) من قبل توم برينستون-وينر، مؤسس جيت هاب، خصيصًا لملفات التكوين. وصل إلى النسخة 1.0 في يناير 2021. هو الصيغة الافتراضية لـ Cargo.tomlفي Rust، و pyproject.tomlفي Python، وملفات مواقع Hugo.
مبدأ تصميم TOML: يجب أن تكون الأنواع مُعلنة بشكل صريح، يجب أن تكون الهيكلية مسطحة في الممكن، ويجب أن يكون هناك طريقة واحدة واضحة لكتابة أي قيمة تكوينية.
# Types are unambiguous in TOML
name = "my-app" # string: always quoted
port = 8080 # integer
threshold = 3.14 # float
enabled = true # boolean: only true/false, no yes/no
created = 2024-01-15 # date: native type
tags = ["api", "prod"] # array
# "yes" is just a string. Always.
country = "NO" # string "NO", no boolean nonsense
المسائل المُبقيّة:
- السلاسل المُتعددة للجداول تبدو مُعقدة جدًا.
[[products]]و[products.details]تبدو متشابهة لكنها تُظهر سلوكًا مختلفًا تمامًا. يُفهم من المواصفة، لكن التمييز البصري لا يُفهم. - الانسجام العميق يصبح مُطولًا. ما يفعله YAML في 5 أسطر مُIndented، يفعله TOML في 3 عناوين مُتفرقة. بالنسبة للتكوينات التي تتجاوز 3 مستويات، يبدأ TOML في أن يشعر بأنه الأداة الخاطئة.
- مدى توفر المُحلل. توجد مُحللات TOML لكل لغة رئيسية، لكنها تختلف في الامتثال للمواصفة. تُظهر مُختبر توافق TOML مُحَوّلات للحالات الحدية. بينما تُختبر مُحللات JSON بمقدار هائل من الاستخدام.
- الإلمام بالفريق. إذا كنت تستخدم TOML خارج نظام Rust أو Python، فانتظر أن يفتح أحد أعضاء الفريق طلبًا بـ "ما هذا التنسيق؟"
عندما يفوز TOML
- مشاريع Rust —
Cargo.tomlهي المعيار والدعم الممتاز. - مشاريع Python تستخدم
pyproject.toml(PEP 518) — هذا هو المكان المُوصى به لملفات التحكم مثل Black، Ruff، mypy، وpytest. - تكوينات بسيطة ومسطحة حيث يكون الحساسية للتباعد في YAML عيبًا.
- تريد دعم الأوقات والتواريخ دون تحويلها إلى نصوص.
مُرشد القرار السريع
- Kubernetes / سلسلة CI/CD / Ansible؟ YAML. لا خيار.
- تكوين مُستهلك من قبل عدة خدمات في لغات مختلفة؟ JSON.
- مشروع Rust؟ TOML (مبدأ Cargo.toml).
- تكوين مشروع Python (مُدقق، مُعدّل، أدوات بناء)؟ TOML (الصيغة pyproject.toml هي المعيار الآن).
- تكوين موقع ديناميكي (Hugo، Zola)؟ TOML، رغم أن هذه الأنظمة تدعم جميعها الثلاثة.
- تكوين مشروع Node.js؟ JSON (نظام package.json)، أو YAML إذا كنت بحاجة إلى تعليقات.
- الإنسان سيقوم بتحريره بانتظام ويحتاج إلى إضافة ملاحظات؟ YAML أو TOML (كلاهما يدعم التعليقات). ليس JSON.
- تريد ضمانات صارمة للأنواع وتحقق من التصميم؟ JSON + صيغة JSON.
الجواب الصريح لمعظم المشاريع الجديدة: استخدم ما يُتوقعه النظام الرئيسي. يُتوقع من Rust استخدام TOML. يُتوقع من أدوات Python استخدام TOML أو YAML. يُتوقع من Node.js استخدام JSON. إذا كنت تكتب شيء غير مرتبط باللغة، فإن استخدام TOML لتكوين يُحرر من قبل الإنسان وJSON لتكوين يُولد تلقائيًا أو يُستهلك هو تقسيم منطقي.
تثبيت ملحقاتنا
أضف أدوات IO إلى متصفحك المفضل للوصول الفوري والبحث بشكل أسرع
恵 وصلت لوحة النتائج!
لوحة النتائج هي طريقة ممتعة لتتبع ألعابك، يتم تخزين جميع البيانات في متصفحك. المزيد من الميزات قريبا!
