Herhangi bir Rust projesini alın, bir Cargo.toml bulursunuz. Bir GitHub reposunu klonlayın,
YAML dolu bir .github/workflows/ klasörü bulursunuz. Her iki format da yüzeysel düzeyde aynı işi yapıyor
— insanların düzenlediği yapılandırılmış yapılandırmayı depolama — ancak çok farklı dengeler kuruyorlar.
YAML'ın bir değeri sessizce tahrip ettiğini yaşadıysanız veya Rust'ın paket manifestesi için neden YAML
yerine TOML'u seçtiğini merak ettiyseniz, bu makale tam size göre.
Temel Fark: Açık vs Örtük
TOML ve YAML arasındaki temel ayrım, ayrıştırıcının ne kadar tahmin yapmasına izin verildiğiyle ilgilidir.
TOML açıktır: her değerin belirsizliksiz bir tipi vardır.
Dizeler her zaman tırnak içindedir. Boolean'lar tam olarak true veya false'dur.
Tarih/saatler kendi sözdizimiyle birinci sınıf değerlerdir. Örtük tip zorlaması yoktur — ayrıştırıcı
akıllı olmaya çalışmaz.
YAML ise öte yöne eğilir.
Kullanışlı olmaya çalışır: çoğu dize etrafında tırnak gerekmez ve ayrıştırıcı değerin görünümünden
tipleri çıkarsar. Bu çıkarsama insanları ısıran şeydir. YAML 1.1 spesifikasyonu (hâlâ birçok araç
tarafından kullanılan) yes, no, on, off,
true ve false'un tümünü boolean olarak ele alır. 1.0 gibi
tırnak işaretleri olmayan sürüm dizelerini ondalık sayı olarak ele alır. Ve bir de Norveç Sorunu var.
YAML'ın Ünlü Tuzakları
Norveç Sorunu, DevOps çevrelerinde bir tür meme haline geldi. YAML 1.1'de, ülke kodu NO
boolean false olarak ayrıştırılır. Bu nedenle, ISO ülke kodlarını ayarlara eşleyen
bir yapılandırma, Norveç'in girişini sessizce bir boolean'a dönüştürürdü.
YAML 1.2 spesifikasyonu bunu
düzeltti, ancak yaygın olarak kullanılan birçok ayrıştırıcı — yakın zamana kadar PyYAML'ın varsayılan modu
dahil — hâlâ YAML 1.1'i hedefliyor. Güvenmeden önce araçlarınızın hangi spesifikasyon sürümünü
gerçekten uyguladığını kontrol edin.
NO,
Yes, on ve off'un tümü boolean olur. Düzeltme basittir —
dizelerinizi tırnak içine alın — ancak sorun sessizdir. Yapılandırmanız hatasız yüklenir ve
bir dize beklediğiniz yerde bir boolean alırsınız.# YAML 1.1 implicit type coercion — all of these silently become booleans:
countries:
norway: NO # → false ← The Norway Problem
sweden: SE # → "SE" (fine, not in the boolean list)
enabled: yes # → true
disabled: no # → false
feature_flag: on # → true
another: off # → false
# Version strings can become numbers:
python_version: 3.10 # → float 3.1 (trailing zero dropped)
api_version: 1.0 # → float 1.0
# Safe: quote anything that could be ambiguous
python_version: "3.10"
country: "NO"
enabled: "yes"- Sekizli sabit değerler. YAML 1.1'de,
01010değil8olarak (sekizli) ayrıştırılır. Bu,0755gibi dosya izin değerleri için önemlidir. - Tab vs boşluk. YAML, girinti için sekme karakterlerini yasaklar. Sekme kullanmak üzere yapılandırılmış bir editörden kod yapıştırın ve şifreli bir ayrıştırma hatası alırsınız — ya da daha da kötüsü, sessiz hizasızlık.
- Örtük null'lar. Değeri olmayan bir anahtar
nullolur. Elle düzenlerken yanlışlıkla oluşturmak kolaydır. - Girinti duyarlılığı. Bir boşluk fazla ve bir değer sessizce bir üstden diğerine geçer. Hata yok, sadece yanlış veri.
TOML: Açık Tiplerin Gerçekte Nasıl Göründüğü
TOML'un tip sistemi TOML v1.0 spesifikasyonunda
belirtilmiştir. Dizeler tırnak içinde olmalıdır (tek veya çift). Boolean'lar true veya
false'dur ve başka bir şey değildir. Tam sayılar tam sayıdır. Ondalıklılar ondalıklıdır.
Ve tarih/saatler — JSON'un ve YAML'ın yerel tip olarak sahip olmadığı bir şey — TOML'da birinci sınıf
değerlerdir.
# TOML types are always unambiguous
name = "my-app" # string — must be quoted
version = "1.0.0" # string — quotes make it clear this is not a float
port = 8080 # integer
debug = false # boolean — only true/false, nothing else
threshold = 0.95 # float
# Datetime is a first-class type — no string parsing needed
created_at = 2024-01-15T09:30:00Z
build_date = 2024-03-20
# Arrays
allowed_hosts = ["localhost", "staging.example.com", "api.example.com"]
# Inline tables
[database]
host = "postgres.internal"
port = 5432
name = "payments_prod"
pool_size = 20NO ülke kodu TOML'da tırnak içine alınmadığı için bir dize olmaz, ancak TOML
dize benzeri değerlerden tipleri çıkarsamaz — tırnak içine alınmamış değerler katı sözdizim kurallarını
izler. Dize olmak için tırnak gerekir. TOML'da YAML'ın tuzaklarına neden olan örtük zorlama mekanizması
yoktur.
Yan Yana: Bir CI Boru Hattı Yapılandırması
İşte bir GitHub Actions iş akışı — bu YAML'ın ev sahasıdır. Format doğal biçimde oturur çünkü GitHub Actions YAML bekler, girinti tabanlı iç içe geçme mantıksal yapıyı yansıtır ve yorumlar açık olmayan adım yapılandırmalarını açıklamak için gereklidir.
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
jobs:
build-and-publish:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build
run: npm run build --if-present
- name: Publish to npm
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}Şimdi işte eşdeğer proje manifestinin TOML versiyonu — TOML'un parladığı yer burası. Gerçek bir Cargo.toml yapısını aynı yapılandırmanın YAML'da nasıl görüneceğiyle karşılaştırın:
# Cargo.toml — Rust package manifest
[package]
name = "payments-service"
version = "2.4.1"
edition = "2021"
description = "Payment processing microservice"
license = "MIT"
authors = ["Alice Chen <[email protected]>"]
[dependencies]
tokio = { version = "1.35", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sqlx = { version = "0.7", features = ["postgres", "runtime-tokio-native-tls"] }
tracing = "0.1"
anyhow = "1.0"
[dev-dependencies]
tokio-test = "0.4"
wiremock = "0.6"
[profile.release]
opt-level = 3
lto = true
codegen-units = 1TOML'un Zayıflıkları: Tablo Dizisi
TOML'un pürüzlü kenarları da yok değil. Tablo dizileri için sözdizim — [[çift parantezler]]
— spesifikasyondaki en kafa karıştırıcı şeylerden biridir. JSON'ın bir nesne dizisi olarak yazacağını
nasıl ifade ettiğinizdir ve ilk başta garip okunur.
# TOML array of tables — [[double brackets]] creates array entries
[[server]]
host = "web-01.example.com"
port = 443
region = "us-east-1"
[[server]]
host = "web-02.example.com"
port = 443
region = "us-west-2"
[[server]]
host = "web-03.example.com"
port = 443
region = "eu-west-1"
# The above is equivalent to this JSON:
# { "server": [
# { "host": "web-01.example.com", "port": 443, "region": "us-east-1" },
# { "host": "web-02.example.com", "port": 443, "region": "us-west-2" },
# { "host": "web-03.example.com", "port": 443, "region": "eu-west-1" }
# ]}YAML'da aynı yapı daha doğal okunur — yalnızca girintili özelliklerle bir liste.
Tekrarlanan dizi girişlerine sahip derinlemesine iç içe geçmiş veriler için, YAML'ın
girinti tabanlı iç içe geçmesi TOML'un [[bölüm]] başlıklarından gerçekten daha az
ayrıntılıdır. TOML'un ayrıca YAML'ın çıpa ve takma ad sistemine eşdeğeri yoktur, bu nedenle
paylaşılan bir bloğu bir kez tanımlayıp başka yerlerde başvuramazsınız. Birden fazla TOML
tablosunda aynı değer kümesini çoğaltırken kendinizi bulursanız, bunları elle kopyalamak
zorunda kalırsınız.
Pratikte Her Formatın Kazandığı Yerler
YAML bu ekosistemlerde varsayılan olarak kazanır:
- GitHub Actions. Tüm iş akışı sözdizimi YAML'dır. Burada seçim şansınız yok ve sorun değil — girinti, iş, adım ve koşulların iç içe yapısıyla iyi uyuşur.
- Kubernetes. Her manifest — Deployment'lar, Service'ler, ConfigMap'ler, Ingress kuralları — YAML'dır. Kubernetes nesne modeli derinlemesine iç içe geçmiştir ve YAML bunu zarif biçimde işler.
- Docker Compose. Servis tanımları, ağlar, birimler — hepsi YAML. Bir portun neden açıklandığını veya belirli bir healthcheck aralığının neden kullanıldığını açıklayan yorumlar belgelemenin bir parçasıdır.
- Ansible. Playbook'lar, roller, değişken dosyaları — YAML boyunca. Yorum desteği, açık olmayan görev parametrelerini açıklamak için aktif olarak kullanılır.
TOML formatı kontrol ettiğinizde kazanır:
- Rust projeleri.
Cargo.tomlaltın standarttır. Bağımlılık bildirimleri, özellik bayrakları, derleme profilleri — hepsi TOML'da. Açık tipler,"1.0.0"gibi sürüm dizelerinin dize olarak kalmasını sağlar. - Python projeleri.
pyproject.toml, Python proje meta verisi, derleme yapılandırması ve araç ayarları (Black, isort, mypy, pytest hepsini okur) için standart haline gelmiştir. - Belirsizliğin hatalara neden olduğu araç yapılandırması. Yapılandırmanız sürüm dizeleri, ülke kodları veya boolean ya da sayı gibi görünebilecek diğer değerler içeriyorsa, TOML'un açık tipleri ayrıştırma sürprizlerinin tüm bir kategorisini ortadan kaldırır.
- Düz yapılandırmalar. Yapılandırmanız çoğunlukla bir veya iki iç içe geçme düzeyindeki anahtar-değer çiftlerinden oluştuğunda, TOML YAML'dan daha okunabilir ve JSON'dan daha temizdir.
Pratik Karar Kılavuzu
Çoğu zaman seçim, ekosistem tarafından sizin için yapılır. GitHub Actions YAML'dır. Kubernetes YAML'dır. Rust TOML'dur. Python araçları TOML'dur. Gerçekten özgür bir seçiminiz olduğunda, bunu kılavuz olarak kullanın:
- YAML kullanın araçlar bunu zorunlu kıldığında — CI/CD platformları, Kubernetes, Helm chartları, Docker Compose, Ansible. Kurala karşı savaşmak kazandığından daha maliyetlidir.
- YAML kullanın karmaşık bir yapılandırmayı DRY tutmak için çıpalara ve takma adlara ihtiyaç duyduğunuzda — TOML'da eşdeğeri yoktur.
- TOML kullanın kontrol ettiğiniz proje manifestleri ve araç yapılandırmaları için — paket meta verileri, linter ayarları, derleme yapılandırması.
- TOML kullanın yapılandırmanız YAML 1.1'in yanlış yorumlayabileceği değerler içerdiğinde — sürüm dizeleri, ülke kodları, boolean veya sayıya benzeyen her şey.
- YAML dizelerinizi tırnak içine alın değer bir boolean, sayı veya null ile karıştırılabilecekse.
Özellikle: sürüm numaraları, ülke kodları, rakamla başlayan her şey ve
yes,no,on,offgibi değerler.
Her İki Formatla Çalışma
Üzerinde çalıştığınız bir yapılandırma dosyasını doğrulamanız veya güzel yazdırmanız mı gerekiyor? TOML Biçimleyici TOML dosyalarını işler ve YAML Biçimleyici YAML'ı kapsar. Bir yapılandırmayı bir formattan diğerine taşımanız gerekiyorsa — diyelim ki bunu tercih eden bir proje için YAML tabanlı bir araç yapılandırmasını TOML'a dönüştürmek — hem TOML'dan JSON'a hem de YAML'dan JSON'a dönüştürücüler JSON çıktısı verir, daha sonra hedef formatınıza dönüştürebilirsiniz. Bazen ara adım olarak JSON'dan geçmek en güvenilir yoldur.
Bilmeye değer bir şey: her iki formatın da kendi JSON uyumlu alt kümeleri vardır. Geçerli JSON, geçerli YAML'dır (YAML, JSON'un bir üst kümesidir). TOML'un JSON ile bu ilişkisi yoktur, ancak TOML spesifikasyonu kasıtlı olarak basit tutulur — kısa bir okumadır ki bu, tam YAML 1.2 spesifikasyonu için söylenemez.
Sonuç
TOML ve YAML gerçekten rekabet etmiyor. Tasarım önceliklerine göre farklı nişlere yerleştiler. YAML'ın örtük tipleri ve girinti tabanlı yapısı, onu ekipler tarafından sürdürülen büyük, iç içe geçmiş yapılandırmalar için doğal seçim yapar — Kubernetes manifestlerini ve GitHub Actions iş akışlarını düşünün. TOML'un açık tipleri ve düz bölüm yapısı, onu yanlış okunan bir sürüm dizesinin veya ülke kodunun gerçek bir hataya neden olacağı proje manifestleri ve araç yapılandırması için doğal seçim yapar.
Yanınızda götüreceğiniz tek şey: YAML yazıyorsanız ve boolean, sayı veya null gibi görünebilecek
değerleriniz varsa — tırnak içine alın. Bu, YAML ile ilgili yapılandırma hatalarının çoğunu önleyen
tek alışkanlıktır. Yapılandırma formatınızı özgürce seçebiliyorsanız ve yeni bir proje başlıyorsanız,
TOML'a bir bakın.
TOML GitHub deposu
iyi örnekler içerir ve bir Cargo.toml veya pyproject.toml yazdıktan sonra,
formatın çekiciliği oldukça netleşir.