---
title: 'Politika ve Ayrıntı Ayrımı'
source: 'https://academia.sh/tr/kurslar/tasarim-ilkeleri/politika-ve-ayrinti-ayrimi'
course: 'Tasarım İlkeleri'
language: tr
updated: '2026-08-17T18:10:40+00:00'
license: 'CC BY-SA 4.0'
---

# Politika ve Ayrıntı Ayrımı

Kararlı kural ile değişken ayrıntının ayrılması: gönderi ücretlendirme kitaplığının değişiklik günlüğünden karar başına değişim sayısının çıkarılması, tek dosyalı ve ayrılmış düzende dosya dokunuşunun sayılması ve ayrımın davranışı değiştirmediğinin gösterilmesi.

Bağlaşım ve Uyum konusu denetimin ters çevrilmesiyle kapandı: üst düzey parçanın alt düzey
parçayı çağırmak yerine ona çağrılma noktası vermesi. Buraya kadarki bütün ölçüler **modül
çiftleri** üzerindeydi — iki modül arasındaki bağın gücü, bir modülün içindeki adların
ilgililiği, bir çağrının kaç nesne üzerinden geçtiği.

Kod tabanı büyüdüğünde soru biçim değiştirir. Artık hangi modülün hangisine bağlanacağı
değil, sınırın **nereye çizileceği** sorulur. Bu sorunun cevabı, kod parçalarının ne kadar
sık değiştiğinde saklıdır: bir kısım karar yıllarca aynı kalır, bir kısmı ayda bir yenilenir.
Birincisi **politika** (policy), ikincisi **ayrıntı** (detail) adını alır ve sınır ikisinin
arasına çizilir.

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

Politika ile ayrıntının farkı önem değil, **değişim sıklığıdır**. Gönderi ücretlendirme
kitaplığında "ağırlık kademesinin ücreti bölge katsayısıyla çarpılır, sonuç yuvarlanır,
asgari ücretin altına inemez" cümlesi kurumun kuralıdır ve kurum kural değiştirmedikçe
durur. Kademe sınırlarının nerede olduğu, katsayıların kaç olduğu, yuvarlamanın kaç kuruşa
yapıldığı ise fiyat listesi her yenilendiğinde değişir.

Aynı ayrımın bir de yön tarafı vardır: ayrıntı politikayı bilebilir, politika ayrıntıyı
bilemez. Kural hangi kademede hangi ücretin olduğunu bilmeden de yazılabilir; tablo ise
kuralın ondan ne beklediğini bilmek zorundadır.

## Karışık Düzen

Kitaplığın ilk sürümünde iki taraf aynı dosyada duruyor.

```sh
mkdir -p tek-dosya
```

```js
// tek-dosya/ucret.mjs — kural, tarife, bolge ve yuvarlama tek dosyada
const KADEMELER = [
  { ustAgirlik: 1, ucret: 4990 },
  { ustAgirlik: 5, ucret: 8490 },
  { ustAgirlik: 15, ucret: 14990 },
  { ustAgirlik: 30, ucret: 24990 },
];
const ASGARI_UCRET = 3990;
const YUVARLAMA_ADIMI = 50;
const KATSAYI = { yakin: 1, orta: 1.35, uzak: 1.8 };
const POSTA_BOLGE = { 34: "yakin", "06": "orta", 35: "orta", 65: "uzak" };

export function ucretHesapla(gonderi) {
  const kademe = KADEMELER.find((k) => gonderi.agirlik <= k.ustAgirlik);
  if (kademe === undefined) throw new RangeError("agirlik kademesi yok");
  const bolge = POSTA_BOLGE[gonderi.postaKodu.slice(0, 2)] ?? "uzak";
  const ham = kademe.ucret * KATSAYI[bolge];
  return Math.max(Math.round(ham / YUVARLAMA_ADIMI) * YUVARLAMA_ADIMI, ASGARI_UCRET);
}
```

Dosya kısa ve çalışıyor. Sorun onun okunmasında değil, dokunulma sıklığındadır. Bunu iddia
etmek yerine saymak gerekir.

## Değişikliğin Sayılması

Aşağıdaki modül kitaplığın on bir aylık geçmişini bir **değişiklik günlüğü** (change log)
olarak taşıyor: her satır bir değişikliğin tarihi ve o değişikliğin dokunduğu kararlardır.

```js
// degisiklik-gunlugu.mjs — kitapligin 24 degisikligi ve her birinin dokundugu kararlar
export const KARARLAR = ["kural", "kademe-tablosu", "bolge-tablosu", "yuvarlama-adimi", "asgari-tutar"];

export const GUNLUK = [
  ["2024-01-08", ["kademe-tablosu"]],
  ["2024-01-22", ["bolge-tablosu"]],
  ["2024-02-05", ["kademe-tablosu", "asgari-tutar"]],
  ["2024-02-19", ["kademe-tablosu"]],
  ["2024-03-04", ["bolge-tablosu"]],
  ["2024-03-18", ["kademe-tablosu"]],
  ["2024-04-01", ["kural"]],
  ["2024-04-15", ["kademe-tablosu"]],
  ["2024-04-29", ["bolge-tablosu"]],
  ["2024-05-13", ["kademe-tablosu", "asgari-tutar"]],
  ["2024-05-27", ["yuvarlama-adimi", "bolge-tablosu"]],
  ["2024-06-10", ["kademe-tablosu"]],
  ["2024-06-24", ["bolge-tablosu"]],
  ["2024-07-08", ["kademe-tablosu"]],
  ["2024-07-22", ["kural", "kademe-tablosu"]],
  ["2024-08-05", ["bolge-tablosu"]],
  ["2024-08-19", ["kademe-tablosu"]],
  ["2024-09-02", ["kademe-tablosu", "asgari-tutar"]],
  ["2024-09-16", ["kademe-tablosu"]],
  ["2024-09-30", ["bolge-tablosu"]],
  ["2024-10-14", ["kademe-tablosu", "yuvarlama-adimi"]],
  ["2024-10-28", ["bolge-tablosu"]],
  ["2024-11-11", ["kademe-tablosu", "asgari-tutar"]],
  ["2024-11-25", ["kural"]],
];
```

Günlük, kararları dosyalara eşleyen iki düzenle birleştirilir. Birincisi yukarıdaki tek
dosyalı düzen, ikincisi ayrımın uygulandığı düzendir.

```js
// dokunma-say.mjs — karar basina degisiklik sayisi ve iki duzende dosya dokunusu
import { KARARLAR, GUNLUK } from "./degisiklik-gunlugu.mjs";

const TEK_DOSYA = Object.fromEntries(KARARLAR.map((k) => [k, "ucret.mjs"]));
const AYRILMIS = {
  "kural": "politika/ucret-kurali.mjs",
  "kademe-tablosu": "ayrinti/tarife-tablosu.mjs",
  "yuvarlama-adimi": "ayrinti/tarife-tablosu.mjs",
  "asgari-tutar": "ayrinti/tarife-tablosu.mjs",
  "bolge-tablosu": "ayrinti/bolge-tablosu.mjs",
};

function dosyaDokunusu(esleme) {
  const sayac = new Map();
  for (const [, kararlar] of GUNLUK) {
    for (const dosya of new Set(kararlar.map((k) => esleme[k]))) {
      sayac.set(dosya, (sayac.get(dosya) ?? 0) + 1);
    }
  }
  return [...sayac].sort((a, b) => b[1] - a[1]);
}

for (const karar of KARARLAR) {
  const n = GUNLUK.filter(([, k]) => k.includes(karar)).length;
  console.log(`${karar.padEnd(16)} ${String(n).padStart(2)} degisiklik`);
}
console.log(`toplam degisiklik = ${GUNLUK.length}`);

for (const [ad, esleme] of [["tek dosya", TEK_DOSYA], ["ayrilmis", AYRILMIS]]) {
  console.log(`\n${ad} duzeni`);
  for (const [dosya, n] of dosyaDokunusu(esleme)) {
    console.log(`  ${dosya.padEnd(28)} ${String(n).padStart(2)} / ${GUNLUK.length}`);
  }
}
```

```sh
node dokunma-say.mjs
```

```
kural             3 degisiklik
kademe-tablosu   14 degisiklik
bolge-tablosu     8 degisiklik
yuvarlama-adimi   2 degisiklik
asgari-tutar      4 degisiklik
toplam degisiklik = 24

tek dosya duzeni
  ucret.mjs                    24 / 24

ayrilmis duzeni
  ayrinti/tarife-tablosu.mjs   15 / 24
  ayrinti/bolge-tablosu.mjs     8 / 24
  politika/ucret-kurali.mjs     3 / 24
```

İlk beş satır ayrımın ölçütünü veriyor: `kural` yirmi dört değişikliğin üçünde,
`kademe-tablosu` on dördünde dokunulmuş. Aradaki dört katlık fark iki kararın aynı dosyada
durmasının gerekçesini ortadan kaldırıyor.

Alt bölümdeki iki blok sonucu gösteriyor. Tek dosyalı düzende kararlı kuralı içeren dosya
24 değişikliğin 24'ünde açılıyor. Ayrılmış düzende aynı kural 24 değişikliğin 3'ünde
açılıyor; kalan 21 değişiklik ona hiç dokunmuyor.

## Kararlı Kuralın Ayrılması

Ayrım, tabloları başka dosyaya taşımaktan ibaret değildir. Kuralın tabloları **ithal
etmemesi**, ihtiyaç duyduğu işlemleri parametre olarak alması gerekir; aksi hâlde dosya
ayrılır ama bağımlılık yönü aynı kalır.

```sh
mkdir -p ayrilmis/politika ayrilmis/ayrinti
```

```js
// ayrilmis/politika/ucret-kurali.mjs — kararli kural: adimlarin kendisi ve sirasi
export function ucretHesapla(gonderi, tarife, bolgeler) {
  const kademe = tarife.kademeBul(gonderi.agirlik);
  if (kademe === null) throw new RangeError("agirlik kademesi yok");
  const katsayi = bolgeler.katsayi(gonderi.postaKodu);
  const yuvarlanmis = tarife.yuvarla(kademe.ucret * katsayi);
  return Math.max(yuvarlanmis, tarife.asgariUcret());
}
```

Dosyada tek bir sayı yok. Kural yalnız adımların kendisini ve sırasını söylüyor: kademeyi
bul, katsayıyla çarp, yuvarla, asgarinin altına düşürme.

```js
// ayrilmis/ayrinti/tarife-tablosu.mjs — degisken ayrinti: kademeler, adim, asgari tutar
const KADEMELER = [
  { ustAgirlik: 1, ucret: 4990 },
  { ustAgirlik: 5, ucret: 8490 },
  { ustAgirlik: 15, ucret: 14990 },
  { ustAgirlik: 30, ucret: 24990 },
];
const ASGARI_UCRET = 3990;
const YUVARLAMA_ADIMI = 50;

export const tarife = {
  kademeBul: (agirlik) => KADEMELER.find((k) => agirlik <= k.ustAgirlik) ?? null,
  yuvarla: (tutar) => Math.round(tutar / YUVARLAMA_ADIMI) * YUVARLAMA_ADIMI,
  asgariUcret: () => ASGARI_UCRET,
};
```

```js
// ayrilmis/ayrinti/bolge-tablosu.mjs — degisken ayrinti: posta kodu esdegeri ve katsayilar
const KATSAYI = { yakin: 1, orta: 1.35, uzak: 1.8 };
const POSTA_BOLGE = { 34: "yakin", "06": "orta", 35: "orta", 65: "uzak" };

export const bolgeler = {
  bolgeBul: (postaKodu) => POSTA_BOLGE[postaKodu.slice(0, 2)] ?? "uzak",
  katsayi(postaKodu) { return KATSAYI[this.bolgeBul(postaKodu)]; },
};
```

İki ayrıntı dosyası da politikanın beklediği adları karşılıyor. Bu, Bağımlılığın Ters
Çevrilmesi dersindeki yönün bu ölçekteki karşılığıdır: kararsız taraf kararlı tarafa
bakıyor.

## Ayrımın Bedeli Var mı

Bir yeniden düzenlemenin davranışı koruduğu iddia edilmez, sınanır. İki sürüm aynı
gönderilerle çağrılır.

```js
// esdeger-mi.mjs — ayrim davranisi degistirdi mi: iki surumu ayni gonderilerle karsilastirir
import { ucretHesapla as tekDosya } from "./tek-dosya/ucret.mjs";
import { ucretHesapla as ayrilmis } from "./ayrilmis/politika/ucret-kurali.mjs";
import { tarife } from "./ayrilmis/ayrinti/tarife-tablosu.mjs";
import { bolgeler } from "./ayrilmis/ayrinti/bolge-tablosu.mjs";

const GONDERILER = [
  { agirlik: 0.4, postaKodu: "34710" }, { agirlik: 3, postaKodu: "06800" },
  { agirlik: 12, postaKodu: "65100" }, { agirlik: 28, postaKodu: "35400" },
  { agirlik: 0.9, postaKodu: "81600" }, { agirlik: 5, postaKodu: "34100" },
];

let ayrilan = 0;
for (const g of GONDERILER) {
  const a = tekDosya(g), b = ayrilmis(g, tarife, bolgeler);
  if (a !== b) ayrilan += 1;
  console.log(`${String(g.agirlik).padStart(4)} kg  ${g.postaKodu}  ${String(a).padStart(6)}  ${String(b).padStart(6)}`);
}
console.log(`ayrilan sonuc = ${ayrilan} / ${GONDERILER.length}`);
```

```sh
node esdeger-mi.mjs
```

```
 0.4 kg  34710    5000    5000
   3 kg  06800   11450   11450
  12 kg  65100   27000   27000
  28 kg  35400   33750   33750
 0.9 kg  81600    9000    9000
   5 kg  34100    8500    8500
ayrilan sonuc = 0 / 6
```

Altı gönderinin altısında sonuç aynı. Ayrımın getirdiği tek şey dosya sayısının birden üçe
çıkması; buna karşılık kararlı kurala dokunan değişiklik oranı yüzde yüzden yüzde on ikiye
inmiş durumda.

## Politika Düzeyi

Ayrım ikili değildir. Bir kitaplıkta birden çok politika düzeyi bulunur ve düzeyin ölçüsü
karara girdi-çıktıdan olan uzaklıktır. Ücret kuralı en yüksek düzeydedir: hiçbir dış
kaynağa dokunmaz. Tarife tablosu bir düzey aşağıdadır: değerler dışarıdan gelir ama biçim
kitaplığın kendi biçimidir. Posta kodunun ilk iki basamağının bölgeyi verdiği varsayımı en
alt düzeydir; adres biçimi değişirse yalnız o kural değişir.

Kural tek cümleyle yazılır: bağımlılık okları daima daha yüksek politika düzeyine bakar.
Bu ilkenin ihlali, bir sonraki dersin ölçtüğü şeyi bozar — kararlı tarafın karşı taraf
hakkında bilmek zorunda olduğu ayrıntı sayısını artırır.

## Özet

- Politika ile ayrıntının ayrımı önem sırasına göre değil, değişim sıklığına göre yapılır;
  ölçü değişiklik günlüğünden karar başına değişim sayısıdır.
- Kitaplığın yirmi dört değişikliğinde kural üç kez, kademe tablosu on dört kez değişti;
  dört katlık fark ikisinin aynı dosyada durmasını gerekçesiz bıraktı.
- Tek dosyalı düzende kararlı kurala 24 değişikliğin 24'ünde dokunuluyordu; ayrım sonrası
  bu sayı 3'e indi.
- Ayrım, tabloları taşımakla bitmez; kuralın tabloları ithal etmemesi, ihtiyaç duyduğu
  işlemleri parametre olarak alması gerekir.
- Altı gönderide iki sürümün sonucu aynı çıktı: yeniden düzenleme davranışı değiştirmedi,
  yalnız dokunuş dağılımını değiştirdi.

## Sonraki Adım

Ayrılmış düzende kural, tarife nesnesinden üç ad bekliyor: kademe bulma, yuvarlama ve
asgari ücret. Bu üç ad iki modül arasındaki sözleşmedir ve şu ana kadar sayılmadı. Sözleşme
kaç addan oluşuyor, sınırdan kaç tip geçiyor, karşı tarafın bilmek zorunda olduğu alan
sayısı kaç? Sonraki ders sözleşme yüzeyini ölçen bir araç yazar, geniş ve dar iki sınır
tanımını aynı ölçüyle karşılaştırır ve sınır daraltıldığında karşı tarafa sızan ayrıntı
sayısının nasıl düştüğünü gösterir.
