---
title: Basitleştirmek
source: 'https://academia.sh/tr/kurslar/mimarin-rolu/basitlestirmek'
course: 'Mimarın Rolü'
language: tr
updated: '2026-08-17T18:10:32+00:00'
license: 'CC BY-SA 4.0'
---

# Basitleştirmek

Karmaşıklığın bilinçli azaltılması: arızi ile özsel karmaşıklığın ayrılması, bir çözümün modül grafiğindeki toplam karmaşıklığın gereksinim grafiğinden okunan özsel tabana göre iki bileşene bölünmesi, sadeleştirmenin kaldırdığı arızi payın ve kaldıramadığı payın sayılması ve aynı değişiklik kümesi iki grafikte koşturularak sadeleştirmenin karşılığında büyüyen şeyin ölçülmesi.

Önceki ders kararın hangi alternatife gittiğini ölçtü. Seçilen alternatif ortaya bir parça kümesi
çıkarır: bir önbellek katmanı, bir eşitleme yolu, bir geçersizleştirme kuralı. Zamanla bu parçalar
birikir ve sistem "karmaşık" diye anılmaya başlar. Karmaşıklık bir sıfat olarak kullanıldığı sürece
üzerine karar verilemez, çünkü azaltma isteği ile azaltma imkânı arasındaki farkı göstermez.

Bu dersin sorusu şudur: bir çözümdeki karmaşıklığın ne kadarı kaldırılabilir, ne kadarı işin
kendisinden gelir? Ayrım yapılmadan girişilen sadeleştirme iki biçimde başarısız olur — ya gereken
bir şeyi siler, ya da hiçbir şeyi silmez ve yalnızca yeniden düzenler. Bağlaşım ve bütünlük
ölçüleri önkoşul tasarım kurslarında kuruldu; burada tekrarlanmaz. Ölçülecek olan, karmaşıklığın
iki bileşene bölünmesidir.

## Arızi ve Özsel Karmaşıklık

**Özsel karmaşıklık** (essential complexity), çözülen işin kendisinden gelen ve hiçbir
gerçekleştirimde ortadan kalkmayan paydır. Ödünç verilen bir kitabın iade tarihinin olması,
gecikmenin bir bedele dönüşmesi, uzatmanın hem ödünç kaydına hem bedele bağlı olması — bunlar
kütüphane ağının kurallarından gelir. Kod nasıl yazılırsa yazılsın bu bağlar durur.

**Arızi karmaşıklık** (accidental complexity), çözümün kurulma biçiminden gelen paydır. Aynı işi
karşılayan ikinci bir modül, hiçbir davranışı karşılamadığı halde araya girmiş bir sarmalayıcı,
tek bir ayarı okumak için kurulmuş bir katman. Bunlar işin değil, çözümün özellikleridir.

Ayrım kulağa açık gelir ama pratikte tartışmaya açıktır, çünkü herkes kendi eklediği katmanı özsel
sayar. Tartışmayı kapatan tek şey ayrımı bir ölçüye bağlamaktır: **özsel pay çözümden değil,
gereksinimden okunur.** Aynı davranış kümesini karşılayan herhangi bir çözümün inebileceği en alt
sınır, gereksinimlerin kendi grafiğidir.

## İki Grafik: Çözüm ve Gereksinim

Model iki grafik tutar. Birincisi kütüphane ağı kurallarının dayattığı davranışlar ve aralarındaki
zorunlu bağlardır. İkincisi içeride yazılmış ödünç servislerinin bugünkü modül grafiğidir. Kurgu
bir modeldir; gerçek bir kurum ya da ürün anlatılmaz.

```js
// sade/grafik.mjs — odunc servislerinin modul grafigi ve gereksinim grafigi; kurgu bir modeldir
// GEREKSINIM: kutuphane agi kurallarinin dayattigi davranislar ve aralarindaki zorunlu bag (MP4)
export const GEREKSINIM = {
  r1: { ad: "odunc-ver", baglar: ["r7"] },
  r2: { ad: "iade-al", baglar: ["r4"] },
  r3: { ad: "uzatma", baglar: ["r1", "r4"] },
  r4: { ad: "gecikme-bedeli", baglar: [] },
  r5: { ad: "ayirtma", baglar: [] },
  r6: { ad: "subeler-arasi-istek", baglar: ["r5"] },
  r7: { ad: "uyelik-dogrulama", baglar: [] },
  r8: { ad: "ceza-affi", baglar: ["r4"] },
  r9: { ad: "raf-durumu-bildirimi", baglar: [] },
};

// MODUL: cozumun bugunku hali. ayarOkur = sube basina degisen ayari dogrudan okuyan modul (MP5)
export const MODUL = [
  { ad: "odunc-akisi", ihtiyac: ["r1"], ayarOkur: false },
  { ad: "iade-akisi", ihtiyac: ["r2"], ayarOkur: false },
  { ad: "uzatma-akisi", ihtiyac: ["r3"], ayarOkur: false },
  { ad: "bedel-hesabi", ihtiyac: ["r4"], ayarOkur: false },
  { ad: "ayirtma-akisi", ihtiyac: ["r5"], ayarOkur: false },
  { ad: "subeler-arasi", ihtiyac: ["r6"], ayarOkur: false },
  { ad: "uyelik-kapisi", ihtiyac: ["r7"], ayarOkur: false },
  { ad: "af-akisi", ihtiyac: ["r8"], ayarOkur: false },
  { ad: "raf-bildirimi", ihtiyac: ["r9"], ayarOkur: false },
  { ad: "odunc-yardimcisi", ihtiyac: ["r1"], ayarOkur: false },
  { ad: "iade-yardimcisi", ihtiyac: ["r2"], ayarOkur: false },
  { ad: "kayit-koprusu", ihtiyac: [], ayarOkur: false },
  { ad: "olay-koprusu", ihtiyac: [], ayarOkur: false },
  { ad: "ayar-sarmalayici", ihtiyac: [], ayarOkur: true },
];

export const BAG = [
  ["odunc-akisi", "odunc-yardimcisi"], ["odunc-akisi", "uyelik-kapisi"],
  ["odunc-akisi", "kayit-koprusu"], ["odunc-akisi", "ayar-sarmalayici"],
  ["iade-akisi", "iade-yardimcisi"], ["iade-akisi", "bedel-hesabi"],
  ["iade-akisi", "kayit-koprusu"], ["iade-akisi", "ayar-sarmalayici"],
  ["uzatma-akisi", "odunc-yardimcisi"], ["uzatma-akisi", "bedel-hesabi"],
  ["uzatma-akisi", "ayar-sarmalayici"], ["bedel-hesabi", "kayit-koprusu"],
  ["bedel-hesabi", "ayar-sarmalayici"], ["ayirtma-akisi", "kayit-koprusu"],
  ["ayirtma-akisi", "olay-koprusu"], ["ayirtma-akisi", "ayar-sarmalayici"],
  ["subeler-arasi", "ayirtma-akisi"], ["subeler-arasi", "olay-koprusu"],
  ["subeler-arasi", "ayar-sarmalayici"], ["af-akisi", "bedel-hesabi"],
  ["af-akisi", "kayit-koprusu"], ["raf-bildirimi", "olay-koprusu"],
  ["uyelik-kapisi", "kayit-koprusu"],
];

export const kopya = () => ({
  modul: MODUL.map((m) => ({ ...m, ihtiyac: [...m.ihtiyac] })),
  bag: BAG.map((b) => [...b]),
});

export const olcu = (g) => g.modul.length + g.bag.length;
```

Karmaşıklık ölçüsü kasten kaba tutuldu: modül sayısı artı bağ sayısı. Ölçünün inceliği burada
önemli değildir, çünkü ölçülen şey mutlak bir büyüklük değil, iki grafik arasındaki farktır.

Sadeleştirme iki adımdan oluşur ve ikisi de tek bir kurala dayanır: bir modül ancak hiçbir
davranışı ayırt etmiyorsa kaldırılabilir.

```js
// sade/sadelestir.mjs — iki sadelestirme adimi: ayni gereksinimi karsilayan modulu birlestir,
// hicbir gereksinimi karsilamayan sarmalayiciyi kaldir (isi cagiranlarina gecer)
function birlestir(g, at, kalan) {
  g.bag = g.bag.map(([a, b]) => [a === at ? kalan : a, b === at ? kalan : b])
    .filter(([a, b]) => a !== b);
  const k = g.modul.find((m) => m.ad === kalan);
  k.ayarOkur ||= g.modul.find((m) => m.ad === at).ayarOkur;
  g.modul = g.modul.filter((m) => m.ad !== at);
}

function kaldir(g, at) {
  const onceki = g.bag.filter(([, b]) => b === at).map(([a]) => a);
  const sonraki = g.bag.filter(([a]) => a === at).map(([, b]) => b);
  const okur = g.modul.find((m) => m.ad === at).ayarOkur;
  g.bag = g.bag.filter(([a, b]) => a !== at && b !== at);
  for (const o of onceki) {
    if (okur) g.modul.find((m) => m.ad === o).ayarOkur = true;
    for (const s of sonraki) if (o !== s && !g.bag.some(([a, b]) => a === o && b === s)) g.bag.push([o, s]);
  }
  g.modul = g.modul.filter((m) => m.ad !== at);
}

export function sadelestir(g) {
  birlestir(g, "odunc-yardimcisi", "odunc-akisi");
  birlestir(g, "iade-yardimcisi", "iade-akisi");
  kaldir(g, "ayar-sarmalayici");
  return g;
}
```

`kaldir` işlevindeki tek satır dersin yarısını taşıyor: kaldırılan modül `ayarOkur` ise, bu
nitelik onu çağıran modüllere geçer. Sarmalayıcı kaldırıldığında yaptığı iş yok olmaz, dağılır.

## Ayrımın Ölçülmesi

```js
// sade/ayir.mjs — toplam karmasikligi ozsel ve arizi bilesene ayirir, sonra sadelestirmeyi kosturur
import { GEREKSINIM, kopya, olcu } from "./grafik.mjs";
import { sadelestir } from "./sadelestir.mjs";

const g = kopya();
const toplam = olcu(g);
const ozselModul = Object.keys(GEREKSINIM).length;
const ozselBag = Object.values(GEREKSINIM).reduce((t, r) => t + r.baglar.length, 0);
const ozsel = ozselModul + ozselBag;

console.log(`modul grafigi     : ${g.modul.length} modul + ${g.bag.length} bag = ${toplam}`);
console.log(`gereksinim grafigi: ${ozselModul} davranis + ${ozselBag} zorunlu bag = ${ozsel}`);
console.log(`ozsel = ${ozsel}, arizi = ${toplam - ozsel} (%${(100 * (toplam - ozsel) / toplam).toFixed(1)})`);

sadelestir(g);
const sade = olcu(g);
console.log(`\nsadelestirmeden sonra: ${g.modul.length} modul + ${g.bag.length} bag = ${sade}`);
console.log(`kaldirilan arizi pay : ${toplam - sade}`);
console.log(`kalan arizi pay      : ${sade - ozsel}`);
console.log(`inilemeyen taban     : ${ozsel} (ozsel)`);
console.log(`ayari dogrudan okuyan modul: once 1, sonra ${g.modul.filter((m) => m.ayarOkur).length}`);
```

```
modul grafigi     : 14 modul + 23 bag = 37
gereksinim grafigi: 9 davranis + 6 zorunlu bag = 15
ozsel = 15, arizi = 22 (%59.5)

sadelestirmeden sonra: 11 modul + 15 bag = 26
kaldirilan arizi pay : 11
kalan arizi pay      : 11
inilemeyen taban     : 15 (ozsel)
ayari dogrudan okuyan modul: once 1, sonra 6
```

Toplam karmaşıklık 37; bunun 15'i özsel, 22'si arızidir. Yani çözümün yarısından fazlası
gereksinimden değil, çözümün kurulma biçiminden geliyor. Bu oran tek başına bir eylem çağrısı
değildir; ayrımın ne işe yaradığını gösteren şey sonraki satırlardır.

Sadeleştirme 37'yi 26'ya indirdi, yani 22'lik arızi paydan 11'ini kaldırdı. Kalan 11 de arızidir
ama kaldırılamadı: `kayit-koprusu` ve `olay-koprusu` hiçbir davranışı karşılamıyor, buna karşılık
gerçek iş yapıyorlar — biri kayıt yazımını, öteki olay yayımını tek yerde topluyor. Onları
kaldırmak işi ortadan kaldırmaz, altı ayrı modüle kopyalar. Arızi olmak kaldırılabilir olmakla
aynı şey değildir.

Son satır ise sadeleştirmenin bedelidir. Şube başına değişen ayarı önce tek bir modül okuyordu;
sarmalayıcı kaldırıldıktan sonra altı modül okuyor. Karmaşıklık ölçüsü 11 azaldı, ama bir
niteliğin dağıldığı yer altı katına çıktı. Ölçü bunu görmez; bir sonraki koşum görür.

## Sadeleştirmenin Karşılığı

Karşılaştırma aynı değişiklik kümesini iki grafikte koşturur. Değişiklikler önümüzdeki on iki ayda
beklenenlerdir (**MP6**) ve iki türdür: bir davranışın kuralını değiştirenler, ve bir kuralı şube
başına farklılaştıran yayılan değişiklik.

```js
// sade/degisiklik.mjs — ayni degisiklik kumesi iki grafikte: dokunulan modul sayisi
import { kopya } from "./grafik.mjs";
import { sadelestir } from "./sadelestir.mjs";

// MP6: on iki ayda beklenen degisiklikler. "yayilan" = sube basina farklilasan kural.
const DEGISIKLIK = [
  { ad: "gecikme bedeli orani", tur: "gereksinim", hedef: "r4" },
  { ad: "uzatma hakki sayisi", tur: "gereksinim", hedef: "r3" },
  { ad: "ayirtma suresi", tur: "gereksinim", hedef: "r5" },
  { ad: "odunc verme kurali", tur: "gereksinim", hedef: "r1" },
  { ad: "iade akisina yeni adim", tur: "gereksinim", hedef: "r2" },
  { ad: "sube basina gecikme bedeli", tur: "yayilan", hedef: null },
];

function dokunulan(g, d) {
  if (d.tur === "yayilan") return g.modul.filter((m) => m.ayarOkur).map((m) => m.ad);
  const tasiyan = g.modul.filter((m) => m.ihtiyac.includes(d.hedef)).map((m) => m.ad);
  const cagiran = g.bag.filter(([, b]) => tasiyan.includes(b)).map(([a]) => a);
  return [...new Set([...tasiyan, ...cagiran])];
}

const grafik = { ozgun: kopya(), sade: sadelestir(kopya()) };
console.log("degisiklik                  | ozgun | sade | fark");
console.log("----------------------------|-------|------|-----");
const toplam = { ozgun: 0, sade: 0 };
for (const d of DEGISIKLIK) {
  const o = dokunulan(grafik.ozgun, d).length, s = dokunulan(grafik.sade, d).length;
  toplam.ozgun += o; toplam.sade += s;
  const fark = s - o;
  console.log(`${d.ad.padEnd(27)} | ${String(o).padStart(5)} | ${String(s).padStart(4)} | ` +
    `${fark > 0 ? "+" : ""}${fark}`);
}
console.log("----------------------------|-------|------|-----");
console.log(`${"toplam dokunulan modul".padEnd(27)} | ${String(toplam.ozgun).padStart(5)} | ` +
  `${String(toplam.sade).padStart(4)} | ${toplam.sade - toplam.ozgun}`);
const y = DEGISIKLIK.filter((d) => d.tur === "yayilan");
console.log(`bilinen ${DEGISIKLIK.length - y.length} degisiklikte sade grafik ` +
  `${toplam.ozgun - dokunulan(grafik.ozgun, y[0]).length - (toplam.sade - dokunulan(grafik.sade, y[0]).length)} modul daha az dokundu`);
console.log(`yayilan 1 degisiklikte sade grafik ` +
  `${dokunulan(grafik.sade, y[0]).length - dokunulan(grafik.ozgun, y[0]).length} modul daha fazla dokundu`);
```

```
degisiklik                  | ozgun | sade | fark
----------------------------|-------|------|-----
gecikme bedeli orani        |     4 |    4 | 0
uzatma hakki sayisi         |     1 |    1 | 0
ayirtma suresi              |     2 |    2 | 0
odunc verme kurali          |     3 |    2 | -1
iade akisina yeni adim      |     2 |    1 | -1
sube basina gecikme bedeli  |     1 |    6 | +5
----------------------------|-------|------|-----
toplam dokunulan modul      |    13 |   16 | 3
bilinen 5 degisiklikte sade grafik 2 modul daha az dokundu
yayilan 1 degisiklikte sade grafik 5 modul daha fazla dokundu
```

Sadeleştirme bilinen beş değişiklikte 2 modül kazandırdı; ikinci modülü kaldırılan iki davranışta
değişiklik tek yere düştü, geri kalan üçünde hiçbir şey değişmedi. Yayılan tek değişiklikte ise 5
modül kaybettirdi. Toplamda dokunulan modül sayısı 13'ten 16'ya çıktı.

Bu, sadeleştirmenin yanlış olduğu anlamına gelmez; sadeleştirmenin bir **fiyatı** olduğu anlamına
gelir. Kaldırılan sarmalayıcı gerçekten arızi bir katmandı — hiçbir davranışı ayırt etmiyordu — ama
bir esneklik noktası tutuyordu. O nokta silindiğinde esneklik yok olmadı, altı modüle dağıldı.
Sadeleştirmenin karşılığında büyüyen şey budur: bir değişikliğin geçmesi gereken yer sayısı.

Karar bu yüzden ölçüye değil, ölçülerin karşılaştırılmasına dayanır. Yayılan değişikliğin gerçekten
geleceğine inanılıyorsa sarmalayıcı arızi olmasına rağmen tutulur; gelmeyeceğine inanılıyorsa
kaldırılır ve geldiği gün 6 modüle dokunma maliyeti kabul edilmiş olur. İkisi de savunulabilir;
savunulamayan tek şey bu sayıyı hiç hesaplamadan katman eklemek ya da silmektir.

## Özet

- Özsel karmaşıklık işin kendisinden gelir ve gereksinim grafiğinden okunur; arızi karmaşıklık
  çözümün kurulma biçiminden gelir ve toplamdan özsel payın çıkarılmasıyla bulunur.
- Modelde toplam karmaşıklık 37 (14 modül + 23 bağ), özsel taban 15 (9 davranış + 6 zorunlu bağ),
  arızi pay 22 — yani toplamın yüzde 59,5'i.
- Sadeleştirme arızi paydan 11'ini kaldırdı ve toplamı 26'ya indirdi; kalan 11 de arızidir ama
  kaldırılamaz, çünkü iki köprü modülü hiçbir davranışı karşılamadan gerçek iş yapıyor.
- Arızi olmak kaldırılabilir olmakla aynı şey değildir; 15'lik özsel taban hiçbir sadeleştirmenin
  altına inemeyeceği sınırdır.
- Aynı altı değişiklik iki grafikte koşturulunca sade grafik bilinen beş değişiklikte 2 modül
  kazandırdı, yayılan tek değişiklikte 5 modül kaybettirdi; toplam 13'ten 16'ya çıktı.
- Sadeleştirmenin karşılığında büyüyen şey, bir değişikliğin geçmesi gereken yer sayısıdır.

## Sonraki Adım

Sadeleştirme kararının fiyatı hesaplandı, ama bir şey hesaplanmadı: sarmalayıcı kaldırıldıktan
sonra geri getirilebilir mi? Altı modüle dağılmış ayar okumasını tek noktaya toplamak, sarmalayıcıyı
kaldırmakla aynı büyüklükte bir iş değildir. Kararların bir kısmı böyledir — verildikten sonra geri
alınması, verilmesinden kat kat pahalıdır; bir kısmı ise ertesi gün geri alınabilir. İki sınıf aynı
yöntemle ele alındığında iki hata birden yapılır: geri alınabilir kararlar için haftalar harcanır,
geri alınamaz kararlar bir toplantıda verilir. Sonraki ders aynı karar kümesinde geri alma
maliyetini hesaplar, kararları iki sınıfa ayırır ve iki karar yöntemini her iki sınıfta koşturarak
bekleme süresi ile yanlış karar maliyetini karşılaştırır.
