---
title: 'Bildirimsel ve Buyurgan Yaklaşım'
source: 'https://academia.sh/tr/kurslar/kod-olarak-altyapi/bildirimsel-ve-buyurgan-yaklasim'
course: 'Kod Olarak Altyapı'
language: tr
updated: '2026-08-17T18:09:06+00:00'
license: 'CC BY-SA 4.0'
---

# Bildirimsel ve Buyurgan Yaklaşım

Aynı dokuz kalemlik hedef iki biçimde yazılır — dört satırlık istenen durum tanımı ve dokuz satırlık adım listesi — ve üçüncü adımda hata çıkacak biçimde koşturulur. Kısmi başarısızlıktan sonra hedefe ulaşan kalem, yeniden koşumda üretilen boş iş ile hata, ve hedef değiştiğinde yazılan satır sayılır.

Bir önceki ders kaydı bir kalem listesi olarak yazdı: her satır bir kaynağın ne **olması
gerektiğini** söylüyordu. Aynı ortam bir adım listesi olarak da yazılabilir — önce ağı aç, sonra
depoyu aç, sonra makineyi bağla — ve o liste de bir dosyada durur, sürümlenir, gözden geçirilir.
İki biçim de kayıttır ve ikisi de aynı ek adımları ister.

**Bildirimsel** tarif istenen durumu yazar; **buyurgan** tarif oraya götüren adımları yazar.
M22/K01 **DevOps Kültürü ve Temelleri** kursundaki `Altyapı Sağlama Modelleri` dersi elle, betikle
ve bildirimsel sağlamayı karşılaştırmış, sapmanın neden yalnız bildirimsel modelde sayılabildiğini
göstermişti; o karşılaştırma burada tekrarlanmıyor. Bu ders ölçüyü başka bir eksene taşır:
**kısmi başarısızlık**. Aynı hedef iki biçimde yazılır, üçüncü adımda hata çıkacak biçimde
koşturulur, ve üç şey sayılır — hatadan sonra hedefe ulaşan kalem, aynı tarif yeniden koşturulunca
üretilen iş, ve hedef değiştiğinde yazılan satır.

Ortam yine **bölgesel ölçüm ağı**dır: sayaç okumalarını toplayan, doğrulayan ve faturaya çeviren
**kurgu** yazılım. Altyapı sağlanmaz; ortam, işlemler ve kota `node` ile modellenir. Tarif
dosyaları gerçekten diske yazılır.

**AT7.** Hedef dört kaynak ve dokuz kalemdir; **kaynağın kendisi de bir kalemdir**, nitelikleri de.
**AT8.** Buyurgan tarif dokuz satırlık bir adım listesi, bildirimsel tarif dört satırlık bir
tanımdır; ikisi de aynı dokuz kalemi hedefler.
**AT9.** `yarat` var olan kaynakta hata verir; `ayarla` aynı değere yazıldığında **boş yazma**
sayılır. Etkisizliğin olup olmadığı bu iki kuralda kararlaşır.
**AT10.** İlk koşumda veri deposu kotası sıfırdır ve üçüncü adım düşer; kota ikinci koşumdan önce
bire çıkarılır. Hata önceden yazılıdır, rastgelelik yoktur.
**AT11.** Bildirimsel uygulayıcı kalemleri bağımlılık sırasına göre uygular; bağımlılığı
karşılanmayan kalem **atlanır**, hata sayılmaz.
**AT12.** Buyurgan koşucunun iki modu vardır: ilk hatada durur ya da hatayı atlayarak devam eder.

## Aynı Hedef, İki Biçim

```bash
#!/usr/bin/env bash
# Ayni hedefin iki bicimi: bildirimsel tanim ve buyurgan adim listesi. Ikinci surumler de yazilir.
set -e

cat > hedef.alt <<'SON'
kaynak ag "olcum-agi" { blok = "10.40.0.0/16" }
kaynak veri_deposu "olcum-deposu" { boyut_gb = 200 }
kaynak makine "toplayici" { sayi = 3  bagli = "veri_deposu.olcum-deposu" }
kaynak kuyruk "okuma-kuyrugu" { bolum = 6 }
SON

cat > adimlar.txt <<'SON'
yarat ag.olcum-agi
ayarla ag.olcum-agi.blok 10.40.0.0/16
yarat veri_deposu.olcum-deposu
ayarla veri_deposu.olcum-deposu.boyut_gb 200
yarat makine.toplayici
ayarla makine.toplayici.sayi 3
yarat kuyruk.okuma-kuyrugu
ayarla kuyruk.okuma-kuyrugu.bolum 6
bagla makine.toplayici veri_deposu.olcum-deposu
SON

# Hedef degisir: toplayici 3 -> 5, kuyruk bolumu 6 -> 12, bir nesne deposu eklenir.
cat > hedef-v2.alt <<'SON'
kaynak ag "olcum-agi" { blok = "10.40.0.0/16" }
kaynak veri_deposu "olcum-deposu" { boyut_gb = 200 }
kaynak makine "toplayici" { sayi = 5  bagli = "veri_deposu.olcum-deposu" }
kaynak kuyruk "okuma-kuyrugu" { bolum = 12 }
kaynak nesne_deposu "arsiv" { sinif = "seyrek" }
SON

cat > adimlar-v2.txt <<'SON'
varsa-atla yarat ag.olcum-agi
ayarla ag.olcum-agi.blok 10.40.0.0/16
varsa-atla yarat veri_deposu.olcum-deposu
ayarla veri_deposu.olcum-deposu.boyut_gb 200
varsa-atla yarat makine.toplayici
ayarla makine.toplayici.sayi 5
varsa-atla yarat kuyruk.okuma-kuyrugu
ayarla kuyruk.okuma-kuyrugu.bolum 12
varsa-atla bagla makine.toplayici veri_deposu.olcum-deposu
varsa-atla yarat nesne_deposu.arsiv
ayarla nesne_deposu.arsiv.sinif seyrek
SON
```

Bildirimsel tanım dört satır, adım listesi dokuz satırdır ve ikisi de aynı dokuz kalemi taşır.
Aradaki asıl fark boyut değil: tanımda `bagli` bir niteliktir ve makinenin veri deposuna **bağlı
olduğunu** söyler; listede `bagla` en sondaki bir adımdır ve bağlamanın **ne zaman** yapılacağını
söyler. İlki bir bağımlılık, ikincisi bir sıra bildirir.

```js
// motor.mjs — ortam modeli ve iki kosucu; ikisi de modeldir, gercek altyapi saglanmaz.
import { readFileSync } from "node:fs";

export const yeniDunya = (kota) => ({ kaynak: new Set(), kalem: new Map(), kota,
  denenen: 0, basarili: 0, bos: 0, hata: 0, atlanan: 0 });
export const kopya = (d) => ({ ...d, kaynak: new Set(d.kaynak), kalem: new Map(d.kalem),
  denenen: 0, basarili: 0, bos: 0, hata: 0, atlanan: 0 });

export const islem = (d, ad, hedef, deger) => {           // yarat / ayarla / bagla
  d.denenen++;
  if (ad === "yarat") {
    if (d.kaynak.has(hedef)) return { ok: false, neden: "zaten var" };
    const tur = hedef.split(".")[0];
    const n = [...d.kaynak].filter((k) => k.startsWith(tur + ".")).length;
    if (n >= (d.kota[tur] ?? 9)) return { ok: false, neden: tur + " kotasi dolu" };
    d.kaynak.add(hedef); d.basarili++; return { ok: true };
  }
  const anahtar = ad === "bagla" ? hedef + ".bagli" : hedef;
  const sahip = anahtar.split(".").slice(0, 2).join(".");
  if (!d.kaynak.has(sahip)) return { ok: false, neden: "kaynak yok" };
  if (ad === "bagla" && !d.kaynak.has(deger)) return { ok: false, neden: "hedef kaynak yok" };
  if (d.kalem.get(anahtar) === deger) { d.bos++; return { ok: true, bos: true }; }
  d.kalem.set(anahtar, deger); d.basarili++; return { ok: true };
};

// Buyurgan: adim listesini sirayla kosar. mod "dur" ilk hatada durur, "gecerek" hatayi atlar.
export const buyurgan = (d, satirlar, mod) => {
  const gunluk = [];
  for (const [i, ham] of satirlar.entries()) {
    const koruma = ham.startsWith("varsa-atla ");
    const [ad, hedef, deger] = ham.replace("varsa-atla ", "").split(" ");
    if (koruma && ad === "yarat" && d.kaynak.has(hedef)) { d.atlanan++; continue; }
    if (koruma && ad === "bagla" && d.kalem.get(hedef + ".bagli") === deger) { d.atlanan++; continue; }
    const r = islem(d, ad, hedef, deger);
    if (!r.ok) { d.hata++; gunluk.push(`adim ${i + 1} (${ad} ${hedef}): ${r.neden}`);
      if (mod === "dur") return { gunluk, durulanAdim: i + 1, denenmeyen: satirlar.length - i - 1 }; }
  }
  return { gunluk, durulanAdim: 0, denenmeyen: 0 };
};

const BLOK = /^kaynak\s+(\w+)\s+"([\w-]+)"\s*\{(.*)\}$/;   // 01'deki yapilandirma dilinin ayni
export const hedefiOku = (yol) => {
  const k = new Map();
  for (const s of readFileSync(yol, "utf8").split("\n")) {
    const m = BLOK.exec(s.trim());
    if (!m) continue;
    k.set(`${m[1]}.${m[2]}`, "var");                       // kaynagin kendisi de bir kalemdir
    for (const x of m[3].matchAll(/(\w+)\s*=\s*("[^"]*"|[\w./-]+)/g))
      k.set(`${m[1]}.${m[2]}.${x[1]}`, x[2].replaceAll('"', ""));
  }
  return k;
};

// Bildirimsel: fark hesaplanir, bagimliligi karsilanmayan kalem atlanir, sira derinlige gore.
export const bildirimsel = (d, hedef) => {
  const gunluk = [];
  const fark = [...hedef].filter(([k, v]) => (k.split(".").length === 2
    ? !d.kaynak.has(k) : d.kalem.get(k) !== v));
  for (const [k, v] of fark.sort((a, b) => a[0].split(".").length - b[0].split(".").length)) {
    const gerek = [k.split(".").length > 2 ? k.split(".").slice(0, 2).join(".") : null,
      k.endsWith(".bagli") ? v : null].filter(Boolean);
    if (gerek.some((g) => !d.kaynak.has(g))) { d.atlanan++; gunluk.push(`${k}: bagimlilik yok`); continue; }
    const [ad, hedefAd] = k.split(".").length === 2 ? ["yarat", k]
      : k.endsWith(".bagli") ? ["bagla", k.split(".").slice(0, 2).join(".")] : ["ayarla", k];
    const r = islem(d, ad, hedefAd, v);
    if (!r.ok) { d.hata++; gunluk.push(`${k}: ${r.neden}`); }
  }
  return { gunluk, fark: fark.length };
};

export const rapor = (ad, d, ek = "") =>
  `  ${ad.padEnd(30)} denenen ${d.denenen}  uygulanan ${d.basarili}  bos yazma ${d.bos}` +
  `  hata ${d.hata}  atlanan ${d.atlanan}${ek}`;
```

## Üçüncü Adımda Hata

```js
// senaryo.mjs — ayni hedef iki bicimde: kismi basarisizlik, yeniden kosum, ucuncu kosum.
import { readFileSync } from "node:fs";
import { yeniDunya, kopya, buyurgan, bildirimsel, hedefiOku, rapor } from "./motor.mjs";

const satir = (y) => readFileSync(y, "utf8").trim().split("\n");
const adimlar = satir("adimlar.txt"), hedef = hedefiOku("hedef.alt");
const dar = { veri_deposu: 0 }, genis = { veri_deposu: 1 };   // ucuncu adim dar kotada duser

console.log(`hedef ${hedef.size} kalem   adim listesi ${adimlar.length} satir\n`);
console.log("A. kismi basarisizlik (veri deposu kotasi 0)");
const bA = yeniDunya(dar), sA = buyurgan(bA, adimlar, "dur");
console.log(rapor("buyurgan (ilk hatada durur)", bA,
  `  denenmeyen adim ${sA.denenmeyen}`));
console.log(`     ${sA.gunluk.join("; ")}   nerede kalindigini yazan kayit: 0 dosya`);
const dA = yeniDunya(dar), tA = bildirimsel(dA, hedef);
console.log(rapor("bildirimsel (fark uygular)", dA, `  fark ${tA.fark}`));
console.log(`     ${tA.gunluk.join("; ")}`);
console.log(`  hedefe ulasan kalem   buyurgan ${bA.kaynak.size + bA.kalem.size}/${hedef.size}` +
  `   bildirimsel ${dA.kaynak.size + dA.kalem.size}/${hedef.size}\n`);

console.log("B. ikinci kosum (kota yukseltildi, tarif degismedi)");
const bB = kopya({ ...bA, kota: genis }), sB = buyurgan(bB, adimlar, "dur");
console.log(rapor("buyurgan (ayni liste bastan)", bB, `  denenmeyen adim ${sB.denenmeyen}`));
console.log(`     ${sB.gunluk.join("; ")}`);
const kisa = adimlar.filter((a) => a !== "yarat ag.olcum-agi");   // elle cikarilan 1 satir
const bB2 = kopya({ ...bA, kota: genis });
buyurgan(bB2, kisa, "dur");
console.log(rapor("buyurgan (1 satir cikarildi)", bB2, `  elle duzenleme 1 satir`));
const dB = kopya({ ...dA, kota: genis }), tB = bildirimsel(dB, hedef);
console.log(rapor("bildirimsel (ayni tarif)", dB, `  fark ${tB.fark}, elle duzenleme 0 satir`));
console.log(`  hedefe ulasan kalem   buyurgan ${bB2.kaynak.size + bB2.kalem.size}/${hedef.size}` +
  `   bildirimsel ${dB.kaynak.size + dB.kalem.size}/${hedef.size}\n`);

console.log("C. ucuncu kosum (hedefe ulasildi, tarif yeniden kosuluyor)");
const bC = kopya({ ...bB2, kota: genis });
buyurgan(bC, adimlar, "gecerek");
console.log(rapor("buyurgan (hatayi atlayarak)", bC));
const dC = kopya({ ...dB, kota: genis }), tC = bildirimsel(dC, hedef);
console.log(rapor("bildirimsel", dC, `  fark ${tC.fark}`));

console.log("\nD. hedef degisti (toplayici 3 -> 5, kuyruk bolumu 6 -> 12, nesne deposu eklendi)");
const hedef2 = hedefiOku("hedef-v2.alt"), adimlar2 = satir("adimlar-v2.txt");
const bD = kopya({ ...bC, kota: genis });
buyurgan(bD, adimlar2, "gecerek");
console.log(rapor("buyurgan v2 (korumali liste)", bD, `  liste ${adimlar2.length} satir`));
const dD = kopya({ ...dC, kota: genis }), tD = bildirimsel(dD, hedef2);
console.log(rapor("bildirimsel v2", dD, `  fark ${tD.fark}, tanim ${hedef2.size} kalem`));
```

```
hedef 9 kalem   adim listesi 9 satir

A. kismi basarisizlik (veri deposu kotasi 0)
  buyurgan (ilk hatada durur)    denenen 3  uygulanan 2  bos yazma 0  hata 1  atlanan 0  denenmeyen adim 6
     adim 3 (yarat veri_deposu.olcum-deposu): veri_deposu kotasi dolu   nerede kalindigini yazan kayit: 0 dosya
  bildirimsel (fark uygular)     denenen 7  uygulanan 6  bos yazma 0  hata 1  atlanan 2  fark 9
     veri_deposu.olcum-deposu: veri_deposu kotasi dolu; veri_deposu.olcum-deposu.boyut_gb: bagimlilik yok; makine.toplayici.bagli: bagimlilik yok
  hedefe ulasan kalem   buyurgan 2/9   bildirimsel 6/9

B. ikinci kosum (kota yukseltildi, tarif degismedi)
  buyurgan (ayni liste bastan)   denenen 1  uygulanan 0  bos yazma 0  hata 1  atlanan 0  denenmeyen adim 8
     adim 1 (yarat ag.olcum-agi): zaten var
  buyurgan (1 satir cikarildi)   denenen 8  uygulanan 7  bos yazma 1  hata 0  atlanan 0  elle duzenleme 1 satir
  bildirimsel (ayni tarif)       denenen 3  uygulanan 3  bos yazma 0  hata 0  atlanan 0  fark 3, elle duzenleme 0 satir
  hedefe ulasan kalem   buyurgan 9/9   bildirimsel 9/9

C. ucuncu kosum (hedefe ulasildi, tarif yeniden kosuluyor)
  buyurgan (hatayi atlayarak)    denenen 9  uygulanan 0  bos yazma 5  hata 4  atlanan 0
  bildirimsel                    denenen 0  uygulanan 0  bos yazma 0  hata 0  atlanan 0  fark 0

D. hedef degisti (toplayici 3 -> 5, kuyruk bolumu 6 -> 12, nesne deposu eklendi)
  buyurgan v2 (korumali liste)   denenen 6  uygulanan 4  bos yazma 2  hata 0  atlanan 5  liste 11 satir
  bildirimsel v2                 denenen 4  uygulanan 4  bos yazma 0  hata 0  atlanan 0  fark 4, tanim 11 kalem
```

Üçüncü adımdaki hata iki biçimde çok farklı bir maliyet üretti. Buyurgan liste durduğunda **iki
kalem** yerindeydi ve altı adım hiç denenmemişti — oysa o altı adımın beşinin veri deposuyla hiçbir
ilgisi yok. Liste bir **sıra** bildirdiği için sıradaki hata sonrasını da durdurur; makine ve kuyruk
kotadan etkilenmediği hâlde açılmadan kaldı. Bildirimsel uygulayıcı aynı hatayı aldı ve **altı
kalemi** yerine koydu; yalnız veri deposuna gerçekten bağımlı iki kalemi atladı. Aradaki dört
kalemlik fark bir uygulayıcı hızından değil, tarifin ne bildirdiğinden geliyor: bağımlılık
bildirilirse hata yalnız kendi alt ağacını durdurur, sıra bildirilirse hata kuyruğun tamamını.

Ortada bırakılan durumun **okunabilirliği** de ayrıdır. Buyurgan koşumun geriye bıraktığı tek bilgi
durduğu adım numarasıdır ve ortamın hangi kaleminin yerinde olduğunu ayrıca bakmak gerekir; nerede
kalındığını yazan bir kayıt yoktur. Bildirimsel koşum ise bir sonraki koşumda farkı yeniden
hesaplar — "nerede kalındı" sorusu sorulmaz, çünkü yanıt her koşumda baştan üretilir.

## Yeniden Koşumda Üretilen İş

İkinci koşum aynı ayrımı başka bir yerden gösterir. Kota yükseltildikten sonra buyurgan liste
**baştan koşturulduğunda birinci adımda düşer**: ağ zaten vardır ve `yarat` var olan kaynakta hata
verir. Sekiz adım denenmez. Listeyi ilerletmek için bir satırın elle çıkarılması gerekir; bu
çıkarma ortamın o anki durumuna göre yapılır ve başka bir ortamda başka bir satır olur. Bildirimsel
tarif ise **hiç düzenlenmeden** koşar, farkı üç kalem bulur, üçünü uygular.

Üçüncü koşum etkisizliği doğrudan sayar. Hedefe ulaşılmış bir ortamda buyurgan liste hatayı
atlayarak koşturulduğunda dokuz adımın dördü hata verir ve beşi **boş yazma** üretir: aynı değer
aynı kaleme yeniden yazılır, ortam değişmez, ama dokuz işlem yine de denenmiştir. Bildirimsel tarif
aynı ortamda sıfır fark bulur ve **hiçbir işlem denemez**. Bu ikisi arasındaki fark bir verimlilik
ayrıntısı değil: dokuz denemenin dördü hata olarak görünür ve bir sonraki gerçek hatayı bu dört
hatanın arasından ayırmak gerekir.

## Hedef Değiştiğinde Yazılan Satır

```bash
#!/usr/bin/env bash
# Hedef degistiginde yazilan satir: iki tarifin birinci ve ikinci surumu karsilastirilir.
printf 'tarif buyuklugu (satir)   bildirimsel %s -> %s   buyurgan %s -> %s\n' \
  "$(wc -l < hedef.alt | tr -d ' ')" "$(wc -l < hedef-v2.alt | tr -d ' ')" \
  "$(wc -l < adimlar.txt | tr -d ' ')" "$(wc -l < adimlar-v2.txt | tr -d ' ')"
printf 'hedef degisiminde yazilan satir   bildirimsel %s   buyurgan %s\n' \
  "$(diff hedef.alt hedef-v2.alt | grep -c '^>')" \
  "$(diff adimlar.txt adimlar-v2.txt | grep -c '^>')"
printf 'bunun %s satiri koruma eklemesi, %s satiri deger degisikligi, %s satiri yeni kaynak\n' \
  "$(diff adimlar.txt adimlar-v2.txt | grep '^> varsa-atla' | grep -vc arsiv)" \
  "$(diff adimlar.txt adimlar-v2.txt | grep '^> ayarla' | grep -vc arsiv)" \
  "$(diff adimlar.txt adimlar-v2.txt | grep '^>' | grep -c arsiv)"
```

```
tarif buyuklugu (satir)   bildirimsel 4 -> 5   buyurgan 9 -> 11
hedef degisiminde yazilan satir   bildirimsel 3   buyurgan 9
bunun 5 satiri koruma eklemesi, 2 satiri deger degisikligi, 2 satiri yeni kaynak
```

Aynı hedef değişikliği için bildirimsel tanımda üç, adım listesinde dokuz satır yazıldı. Dokuzun
yalnız dördü hedefin kendisiyle ilgili — iki değer değişikliği ve yeni kaynağın iki satırı. Kalan
**beş satır koruma**dır: her `yarat` adımının önüne "varsa atla" yazılır, yoksa liste ikinci kez
koşamaz. Bu beş satır D bölümünde işini yapıyor: koşum sıfır hatayla biter, beş adım atlanır, dört
kalem uygulanır. Bedeli iki boş yazmadır — koruma kaynağın varlığını okur, niteliğin değerini
okumaz.

Burada görülen şey bir dönüşümdür. Buyurgan listeyi yeniden koşulabilir kılmanın yolu her adımın
önüne bir **durum okuması** koymaktır; bu okumalar tamamlandığında liste artık "ne yapılacağını"
değil, "ne olması gerektiğini" söylemeye başlar. İki biçim arasındaki sınır bu noktada silinir ve
kalan tek fark, o okumaların tarifin içine elle mi yazıldığı yoksa uygulayıcıya mı bırakıldığıdır.
Bildirimsel biçimin kazancı bir üstünlük değil, bir **tekrar etmeme**dir: aynı okuma dokuz satırda
dokuz kez yazılmaz, uygulayıcıda bir kez yazılır.

## Özet

- Üçüncü adımdaki hatadan sonra hedefe ulaşan kalem buyurgan biçimde 2/9, bildirimsel biçimde 6/9
  oldu; buyurgan koşumda denenmeyen 6 adımın 5'i hatayla ilgisizdi.
- Buyurgan koşum geriye adım numarasından başka kayıt bırakmadı; bildirimsel koşum bir sonraki
  koşumda farkı baştan hesapladığı için "nerede kalındı" sorusunu sormadı.
- İkinci koşumda buyurgan liste 1. adımda düştü ve ilerlemesi için 1 satır elle çıkarıldı;
  bildirimsel tarif 0 satır düzenlemeyle koştu ve 3 kalem uyguladı.
- Hedefe ulaşılmış ortamda buyurgan liste 9 işlem denedi (4 hata, 5 boş yazma), bildirimsel tarif
  0 işlem denedi.
- Hedef değişince bildirimsel tanımda 3, adım listesinde 9 satır yazıldı; 9'un 5'i yalnız listeyi
  yeniden koşulabilir kılan koruma satırıydı.

## Sonraki Adım

Buraya kadar iki tarif de aynı şeyi yaptı: var olan bir kaynağı **yerinde** değiştirdi. Kuyruğun
bölüm sayısı altıdan on ikiye çıktığında kuyruk aynı kuyruktu; makinenin sayısı üçten beşe
çıktığında var olan üç makineye dokunulmadı. Bu, altyapıyı değiştirmenin tek yolu değil.

Sonraki ders aynı güncellemeyi iki yolla yapar — yerinde yama ve yeniden oluşturma — ve dört şeyi
sayar: bir dönem sonunda kaç makinenin birbirinden ayrıştığı, güncelleme süresi, geri alma turu, ve
yeniden oluşturmanın **taşıyamadığı** şey. Yeniden oluşturmanın hiçbir şey kazandırmadığı durum da
aynı ölçüyle gösterilir.
