---
title: 'Tam Kapsamlı Çerçeveler'
source: 'https://academia.sh/tr/kurslar/bilesen-tabanli-gelistirme/tam-kapsamli-cerceveler'
course: 'Bileşen Tabanlı Arayüz Geliştirme'
language: tr
updated: '2026-08-17T18:09:13+00:00'
license: 'CC BY-SA 4.0'
---

# Tam Kapsamlı Çerçeveler

Yönlendirmeyi, form modelini ve bağımlılık çözümünü tek sözleşmede toplayan çerçeveler; kapsamlı bağımlılık çözümünün çalışması, tekil örnek tuzağı, karar yüzeyinin sayılması ve sözleşme birliğinin bedeli.

Önceki üç aile de aynı soruya yanıt veriyordu: durum değiştiğinde belgenin neresi
yazılacak. Bir uygulamanın bileşen katmanının üstünde ise başka sorular var. Kuzey Yamaç
Ölçüm İstasyonu sayfası büyüdüğünde adresin hangi görünüme karşılık geldiği, süzgeç
panelinin doğrulama kurallarını nereden aldığı ve ölçüm servisinin bileşene nasıl ulaştığı
kararlaştırılmak zorundadır.

İlk üç ailede bu kararlar çerçevenin dışındadır; her ekip kendi birleşimini kurar. Dördüncü
yaklaşım, yanıtları çerçevenin kendisiyle birlikte vermektir.

## Çatının Kapsadığı Roller

**Tam kapsamlı çerçeve**, görünüm katmanının yanında yönlendirmeyi, form modelini, veri
getirmeyi, bağımlılık çözümünü, sunucuda oluşturmayı ve sınama araçlarını da tek bir
sözleşme altında sunar. Parçalar ayrı ayrı seçilmez; birlikte gelir, birlikte sürümlenir ve
birbirini tanıyacak biçimde tasarlanır.

Bu ailenin en ayırt edici parçası **bağımlılık enjeksiyonudur (dependency injection)**.
Bileşen, ihtiyaç duyduğu servisi kendisi kurmaz; bir anahtarla ister ve çerçeve o anahtara
kayıtlı sağlayıcıyı bulup örneği verir. Programlama Temelleri kursundaki arayüz–gerçekleştirim
ayrımı burada çalışma zamanına taşınmış olur.

## Kapsamlı Bağımlılık Çözümü

Düzenek üç parçadan oluşur: sağlayıcı kaydı, kapsam zinciri ve örneklerin nerede yaşadığını
belirleyen kural.

```js
// enjeksiyon.mjs — kapsamli bagimlilik cozumu: kayit, kapsam zinciri ve degistirme
const kapsamAc = (ad, ust = null) => ({ ad, ust, saglayicilar: new Map(), ornekler: new Map() });
const kaydet = (kapsam, anahtar, uret, { kapsamBasina = false } = {}) =>
  kapsam.saglayicilar.set(anahtar, { uret, kapsamBasina });

const iz = [];
function coz(kapsam, anahtar, zincir = []) {
  if (zincir.includes(anahtar)) throw new Error(`döngüsel bağımlılık: ${[...zincir, anahtar].join(" → ")}`);
  let sahip = kapsam;
  while (sahip && !sahip.saglayicilar.has(anahtar)) sahip = sahip.ust;
  if (!sahip) throw new Error(`kayıtlı sağlayıcı yok: ${anahtar} (istek: ${kapsam.ad})`);
  const kayit = sahip.saglayicilar.get(anahtar);
  const barinak = kayit.kapsamBasina ? kapsam : sahip;      // ornek nerede yasayacak
  if (barinak.ornekler.has(anahtar)) {
    iz.push(`${kapsam.ad}: ${anahtar} ← ${barinak.ad} (var olan örnek)`);
    return barinak.ornekler.get(anahtar);
  }
  iz.push(`${kapsam.ad}: ${anahtar} ← ${sahip.ad} (yeni örnek, ${kayit.kapsamBasina ? "kapsam başına" : "tekil"})`);
  const ornek = kayit.uret((a) => coz(kapsam, a, [...zincir, anahtar]));
  barinak.ornekler.set(anahtar, ornek);
  return ornek;
}

// --- Uygulama kaydi ---
const kok = kapsamAc("kök");
let sayac = 0;
kaydet(kok, "OlcumKaynagi", () => ({ kimlik: ++sayac, getir: () => [{ ad: "Üst yamaç", deger: -4.2 }] }));
kaydet(kok, "BirimBicimleyici", () => ({ bicimle: (c) => `${c.toFixed(1)} °C` }));
kaydet(kok, "OlcumServisi", (c) => {
  const kaynak = c("OlcumKaynagi"), bicimleyici = c("BirimBicimleyici");
  return { kimlik: ++sayac, satirlar: () => kaynak.getir().map((o) => `${o.ad}: ${bicimleyici.bicimle(o.deger)}`) };
});
kaydet(kok, "SuzgecDurumu", () => ({ kimlik: ++sayac, esik: -5 }), { kapsamBasina: true });

const tabloKapsami = kapsamAc("ölçüm tablosu", kok);
const panelKapsami = kapsamAc("süzgeç paneli", kok);

console.log("--- cozum izi ---");
const t = coz(tabloKapsami, "OlcumServisi");
const p = coz(panelKapsami, "OlcumServisi");
const ts = coz(tabloKapsami, "SuzgecDurumu");
const ps = coz(panelKapsami, "SuzgecDurumu");
for (const s of iz) console.log(" ", s);
console.log("\nölçüm servisi aynı örnek mi:", t === p);
console.log("süzgeç durumu aynı örnek mi:", ts === ps, `(kimlikler: ${ts.kimlik}, ${ps.kimlik})`);
console.log("tablonun satırları:", JSON.stringify(t.satirlar()));

// --- Sinamada degistirme: (a) var olan kokun altinda, (b) taze kokle ---
const altKapsam = kapsamAc("sınama (kök altında)", kok);
kaydet(altKapsam, "OlcumKaynagi", () => ({ kimlik: 0, getir: () => [{ ad: "Sahte", deger: 0 }] }));
iz.length = 0;
const altServis = coz(altKapsam, "OlcumServisi");
console.log("\n--- (a) var olan kokun altinda degistirme ---");
for (const s of iz) console.log(" ", s);
console.log("satırlar:", JSON.stringify(altServis.satirlar()), "| kök örneğiyle aynı mı:", altServis === t);

const tazeKok = kapsamAc("taze kök");
for (const [anahtar, kayit] of kok.saglayicilar) tazeKok.saglayicilar.set(anahtar, kayit);
kaydet(tazeKok, "OlcumKaynagi", () => ({ kimlik: 0, getir: () => [{ ad: "Sahte", deger: 0 }] }));
iz.length = 0;
const tazeServis = coz(kapsamAc("sınama (taze kök)", tazeKok), "OlcumServisi");
console.log("\n--- (b) taze kokle degistirme ---");
for (const s of iz) console.log(" ", s);
console.log("satırlar:", JSON.stringify(tazeServis.satirlar()), "| kök örneğiyle aynı mı:", tazeServis === t);

// --- Hatalar acik bildirilir ---
console.log("\n--- hatalar ---");
kaydet(kok, "A", (c) => ({ b: c("B") }));
kaydet(kok, "B", (c) => ({ a: c("A") }));
for (const deneme of [() => coz(tabloKapsami, "Kutuk"), () => coz(kok, "A")]) {
  try { deneme(); } catch (h) { console.log(" ", h.message); }
}
```

```
--- cozum izi ---
  ölçüm tablosu: OlcumServisi ← kök (yeni örnek, tekil)
  ölçüm tablosu: OlcumKaynagi ← kök (yeni örnek, tekil)
  ölçüm tablosu: BirimBicimleyici ← kök (yeni örnek, tekil)
  süzgeç paneli: OlcumServisi ← kök (var olan örnek)
  ölçüm tablosu: SuzgecDurumu ← kök (yeni örnek, kapsam başına)
  süzgeç paneli: SuzgecDurumu ← kök (yeni örnek, kapsam başına)

ölçüm servisi aynı örnek mi: true
süzgeç durumu aynı örnek mi: false (kimlikler: 3, 4)
tablonun satırları: ["Üst yamaç: -4.2 °C"]

--- (a) var olan kokun altinda degistirme ---
  sınama (kök altında): OlcumServisi ← kök (var olan örnek)
satırlar: ["Üst yamaç: -4.2 °C"] | kök örneğiyle aynı mı: true

--- (b) taze kokle degistirme ---
  sınama (taze kök): OlcumServisi ← taze kök (yeni örnek, tekil)
  sınama (taze kök): OlcumKaynagi ← taze kök (yeni örnek, tekil)
  sınama (taze kök): BirimBicimleyici ← taze kök (yeni örnek, tekil)
satırlar: ["Sahte: 0.0 °C"] | kök örneğiyle aynı mı: false

--- hatalar ---
  kayıtlı sağlayıcı yok: Kutuk (istek: ölçüm tablosu)
  döngüsel bağımlılık: A → B → A
```

İzin ilk üç satırı çözümün nasıl indiğini gösteriyor. Ölçüm servisi istendiğinde, sağlayıcısı
kök kapsamda bulunuyor; servis kurulurken kendi bağımlılıkları aynı yolla çözülüyor. Bileşen
hiçbirinin nasıl kurulduğunu bilmiyor; yalnızca anahtarları biliyor.

Dördüncü satır tekil davranışı gösteriyor: süzgeç paneli aynı servisi istediğinde yeni örnek
üretilmiyor, kök kapsamdaki örnek dönüyor. Beşinci ve altıncı satırlarda ise sağlayıcı
kapsam başına kayıtlı olduğu için iki kapsam iki ayrı örnek alıyor. Kayıt kökte, örnek
isteyen kapsamda yaşıyor.

Bu ayrım tasarım kararıdır ve doğrudan doğruluğu etkiler. Ölçüm kaynağı paylaşılmalıdır —
iki bileşenin ayrı bağlantı açması gereksizdir. Süzgeç durumu paylaşılmamalıdır — tablonun
süzgeci panelin süzgeciyle aynı olsaydı, iki bileşen birbirinin durumunu ezerdi.

## Tekil Örnek Tuzağı

(a) ve (b) bölümleri, bütün kapsamlı çözüm düzeneklerinin ortak tuzağını gösteriyor.

Sınama kapsamında ölçüm kaynağı sahtesiyle değiştirilmiş, ama sonuç değişmemiş. Nedeni
izde yazılı: ölçüm servisi zaten kök kapsamda kurulmuş ve örneği orada duruyor. Yeni kapsam
servisi istediğinde var olan örnek dönüyor; o örnek gerçek kaynağı kurulum sırasında almış
ve bir daha sormuyor.

Doğru yol (b) bölümündedir: sınama için taze bir kök kurulur, sağlayıcı kayıtları oraya
kopyalanır ve değiştirilecek anahtar taze kökte yeniden kaydedilir. Hiçbir örnek henüz
kurulmadığı için çözüm baştan yapılır ve sahte kaynak zincire girer.

Kural şudur: **değiştirme, örnek kurulmadan önce yapılmalıdır.** Tekil kapsamdaki bir
bağımlılığın değiştirilmesi, o kapsamın tümüyle yeniden kurulmasını gerektirir.

Hata iletileri de bu ailenin bir özelliğidir. Kayıtsız bir anahtar istendiğinde hangi
kapsamın ne istediği, döngüsel bağımlılıkta ise zincirin tamamı bildirilir. Dolaylılık
arttıkça hatanın kendini açıklaması zorunlu hâle gelir.

## Karar Yüzeyi

Bütünleşikliğin kazancı, tek tek özelliklerde değil karar sayısındadır. Bu sayılabilir.

```js
// karar-yuzeyi.mjs — butunlesikligin karar ve uyum yuzeyine etkisi
const ROLLER = [
  "görünüm katmanı", "yönlendirme", "form modeli", "veri getirme",
  "bağımlılık çözümü", "paylaşılan durum", "sunucuda oluşturma", "sınama araçları",
];

// Bir profil: her rolu hangi paketin karsiladigi.
const profiller = {
  "kitaplık toplama": ROLLER.map((r) => r),                       // her rol ayri paket
  "çekirdek + eklenti": ROLLER.map((r, i) => (i < 3 ? "çekirdek" : r)),
  "tam kapsamlı": ROLLER.map(() => "çatı"),
};

const ikili = (m) => (m * (m - 1)) / 2;

console.log("profil               bağımsız paket  sürüm akışı  ikili uyum  kırıcı değişiklikte  tek seferde");
console.log("                                                    ilişkisi   gözden geçirilecek  değişecek rol");
for (const [ad, atama] of Object.entries(profiller)) {
  const paketler = [...new Set(atama)];
  const m = paketler.length;
  // En cok rol tasiyan paket birakilirsa kac rol birden degisir?
  const enBuyuk = Math.max(...paketler.map((p) => atama.filter((a) => a === p).length));
  console.log(
    `${ad.padEnd(20)} ${String(m).padStart(14)} ${String(m).padStart(12)} ${String(ikili(m)).padStart(11)} ` +
    `${String(Math.max(m - 1, 0)).padStart(20)} ${String(enBuyuk).padStart(14)}`
  );
}

// Ayni hesap, rol sayisi degistikce: uyum yuzeyi kare buyur.
console.log("\nayrı paket sayısı  ikili uyum ilişkisi");
for (const m of [1, 2, 4, 6, 8, 12]) console.log(`${String(m).padStart(17)} ${String(ikili(m)).padStart(20)}`);

// Bir rolun catidan cikarilabilirligi: catinin o rolu ne kadar sikica bagladigi.
const BAGLILIK = { "sözleşme yok": 0, "arayüz üzerinden": 1, "doğrudan tip bağımlılığı": 2, "kod üretimi": 3 };
const ornek = [
  ["yönlendirme", "kod üretimi"],
  ["form modeli", "doğrudan tip bağımlılığı"],
  ["veri getirme", "arayüz üzerinden"],
  ["paylaşılan durum", "sözleşme yok"],
];
console.log("\nrol                bağlılık biçimi            değiştirme puanı");
let toplam = 0;
for (const [rol, bicim] of ornek) {
  toplam += BAGLILIK[bicim];
  console.log(`${rol.padEnd(18)} ${bicim.padEnd(26)} ${String(BAGLILIK[bicim]).padStart(17)}`);
}
console.log(`toplam çıkış maliyeti (0 = serbest, ${ornek.length * 3} = tümüyle bağlı): ${toplam}`);
```

```
profil               bağımsız paket  sürüm akışı  ikili uyum  kırıcı değişiklikte  tek seferde
                                                    ilişkisi   gözden geçirilecek  değişecek rol
kitaplık toplama                  8            8          28                    7              1
çekirdek + eklenti                6            6          15                    5              3
tam kapsamlı                      1            1           0                    0              8

ayrı paket sayısı  ikili uyum ilişkisi
                1                    0
                2                    1
                4                    6
                6                   15
                8                   28
               12                   66

rol                bağlılık biçimi            değiştirme puanı
yönlendirme        kod üretimi                                3
form modeli        doğrudan tip bağımlılığı                   2
veri getirme       arayüz üzerinden                           1
paylaşılan durum   sözleşme yok                               0
toplam çıkış maliyeti (0 = serbest, 12 = tümüyle bağlı): 6
```

Sekiz rolü ayrı paketlerle karşılamak sekiz karar, sekiz bağımsız sürüm akışı ve 28 ikili
uyum ilişkisi demektir. İlişki sayısı paket sayısının karesiyle büyür: on iki pakette 66
olur. Bu ilişkilerin her biri, iki paketin belirli sürümlerinin birlikte çalıştığı iddiasıdır
ve bu iddiayı doğrulayan taraf ekiptir.

Tam kapsamlı profilde bu sayı sıfırdır. Parçaların uyumu çatının sorumluluğudur; ekip tek
bir sürüm akışı izler. Yeni bir ekip üyesinin öğreneceği şey sekiz kitaplığın birleşimi
değil, bir sözleşmedir.

Son sütun bedeli gösteriyor. Kitaplık toplama profilinde bir paket bırakıldığında yalnızca
bir rol değişir; roller ayrı ayrı, ayrı zamanlarda göç edebilir. Tam kapsamlı profilde çatı
bırakılırsa sekiz rol aynı anda değişir. Karar geri alınabilir olmaktan çıkar.

## Sözleşme Birliğinin Bedeli

Son tablo bu bedelin nasıl ölçüleceğini gösteriyor. Bir rolün çatıdan çıkarılabilirliği,
çatının o rolü hangi biçimde bağladığına göre değişir. Yalnızca bir arayüz üzerinden
bağlanan bir rol, aynı arayüzü karşılayan başka bir gerçekleştirimle değiştirilebilir.
Kod üretimiyle bağlanan bir rol, kaynak metnin biçimine kadar çatıya yaslanır.

Uygulamanın çıkış maliyetini ölçmek, çatı seçimini bir tercih olmaktan çıkarıp bir yatırım
kararına dönüştürür. Ölçü, uygulamanın hangi bölümlerinin çatıdan bağımsız yazılabildiğidir:
doğrulama kuralları, biçimlendirme, başsız bileşenlerdeki durum makineleri ve saf sunum
bileşenleri çatı bilmez ve göçte olduğu gibi taşınır.

İkinci bedel sürüm yönetimidir. Tek bir sürüm akışı, çatının bir sürüm yükseltmesinin
uygulamanın **her** katmanını aynı anda ilgilendirmesi demektir. Kırıcı bir değişiklik
yönlendirmeyi de, formu da, bağımlılık çözümünü de kapsayabilir; yükseltme küçük adımlara
bölünemez. Ayrı paketlerde ise yükseltmeler sıraya konabilir, ama karşılığında 28 uyum
ilişkisi taşınır.

Üçüncü bedel esnekliktir. Bir rolde çatının verdiği yanıt uygulamanın ihtiyacına uymuyorsa,
o rolü değiştirmek çatının varsayımlarına karşı çalışmak anlamına gelir. Bütünleşik bir
çerçevede alışılmışın dışına çıkmak, alışılmışın içinde kalmaktan belirgin biçimde pahalıdır.

## Ailenin Profili

Bu aile bir güncelleme modeli değil, bir **kapsam** kararıdır; içinde sanal ağaç da,
çalışma zamanı bağımlılık takibi de, derleme zamanı çözümleme de bulunabilir. Ayırt edici
özelliği, bileşen katmanının üstündeki rollerin çatının parçası olmasıdır.

Kazanç, kararların ve uyum ilişkilerinin sayıca azalması, ekip içinde tek bir sözleşmenin
paylaşılması ve yeni bir üyenin öğreneceği yüzeyin daralmasıdır. Bedel, sürüm akışının
tekleşmesi, yükseltmelerin bölünememesi ve çıkış maliyetinin tek seferde ödenmesidir.

## Özet

- Tam kapsamlı çerçeve, görünüm katmanının yanında yönlendirme, form, veri getirme, bağımlılık
  çözümü ve sınama gibi rolleri tek sözleşmede toplar.
- Bağımlılık enjeksiyonunda bileşen servisi kurmaz, anahtarla ister; kapsam zinciri
  sağlayıcıyı bulur, kayıt biçimi örneğin nerede yaşayacağını belirler.
- Tekil kayıtlı bir bağımlılığı değiştirmek, örnek kurulduktan sonra etkisizdir; sınama için
  kapsam baştan kurulur.
- Karar yüzeyi sayılabilir: sekiz rol ayrı paketlerde sekiz sürüm akışı ve 28 ikili uyum
  ilişkisi üretir, bütünleşik çatıda bu sayı sıfıra iner.
- Karşılığında çıkış maliyeti tek seferde ödenir: çatı bırakıldığında sekiz rol aynı anda
  değişir.
- Bir rolün çıkarılabilirliği bağlılık biçimine bağlıdır; arayüz üzerinden bağlanan rol
  değiştirilebilir, kod üretimiyle bağlanan rol kaynak metne kadar yaslanır.

## Sonraki Adım

Dört ailenin de özellikleri, maliyetleri ve bedelleri ortaya kondu. Geriye tek bir soru
kalıyor ve bu sorunun yanıtı ailelerin özelliklerinde değil, projenin kendisindedir: bu
uygulama için hangi özellikler gerçekten gerekli? Sonraki ders bir karşılaştırma tablosu
değil, bir karar çerçevesi kurar — ekibin büyüklüğü ve deneyimi, uygulamanın etkileşim
yoğunluğu, oluşturma stratejisi gereksinimi, ekosistem derinliği ve bakım maliyeti gibi
ölçütleri açık ağırlıklara bağlar; kararın hangi ölçüt değiştiğinde döndüğünü hesaplar ve
kararın ne kadarının geri alınabilir kaldığını ölçer.
