---
title: 'Girinti ve Kod Biçimi'
source: 'https://academia.sh/tr/kurslar/temiz-kod/girinti-ve-kod-bicimi'
course: 'Temiz Kod'
language: tr
updated: '2026-08-17T18:10:37+00:00'
license: 'CC BY-SA 4.0'
---

# Girinti ve Kod Biçimi

Kod biçiminin üslup tercihi olmaktan çıkarılıp fark maliyetiyle ölçülmesi: aynı içeriğin iki girinti düzeninde ürettiği fark satırları, tarife tablosunun hizalanmış ve düz biçimlerine uygulanan aynı revizyonun fark satırı sayıları ve içerik taşımayan fark satırlarının ayıklanması.

Önceki derste her fonksiyon tek soyutlama düzeyine indirildi, ama dosyanın kendisi
hakkında bir şey söylenmedi: satırların nerede biteceği, hangi bildirimlerin yan yana
duracağı, girintinin ne kadar olacağı. Bu kararlar genellikle üslup sayılır ve tartışması
zevke bağlanır.

Biçimin ölçülebilir bir sonucu vardır. Kod tabanına yapılan her değişiklik bir **fark**
üretir; farkı bir başkası okur ve onaylar. Aynı içerik değişikliği, farklı biçimlerde
farklı sayıda fark satırı üretir ve bu satırların bir kısmı hiçbir bilgi taşımaz. Bu ders
biçimi iki sayıya bağlıyor: bir değişikliğin ürettiği fark satırı sayısı ve bunların
içinde içerik taşımayanların sayısı.

## Girinti Yapının Kendisini Gösterir

Girinti, iç içe geçmiş blokların derinliğini göze taşıyan tek işarettir. Yapı ile girinti
ayrı düştüğünde okuyan kişi bloğun nerede bittiğini süslü parantezleri sayarak bulmak
zorunda kalır. Aşağıdaki iki dosya aynı sözcük dizisini taşır; yalnız girintileri farklıdır.

```sh
mkdir -p duzenli karisik duz hizali
```

```js
// duzenli/ucret.mjs — girinti yapisal derinlikle uyusuyor
const ASGARI_UCRET = 52;
const AGIRLIK_KADEMELERI = [
  { ustSinirKg: 5, kiloBasiUcret: 26 },
  { ustSinirKg: 30, kiloBasiUcret: 17 },
];

export function kademeUcreti(agirlikKg, bolgeKatsayisi) {
  const kademe = AGIRLIK_KADEMELERI.find((k) => agirlikKg <= k.ustSinirKg);
  if (kademe === undefined) {
    throw new RangeError("kademe disi agirlik");
  }
  return Math.max(kademe.kiloBasiUcret * agirlikKg * bolgeKatsayisi, ASGARI_UCRET);
}
```

```js
// karisik/ucret.mjs — ayni icerik, girinti yapiyla uyusmuyor
const ASGARI_UCRET = 52;
const AGIRLIK_KADEMELERI = [
    { ustSinirKg: 5, kiloBasiUcret: 26 },
  { ustSinirKg: 30, kiloBasiUcret: 17 },
];

export function kademeUcreti(agirlikKg, bolgeKatsayisi) {
    const kademe = AGIRLIK_KADEMELERI.find((k) => agirlikKg <= k.ustSinirKg);
      if (kademe === undefined) {
    throw new RangeError("kademe disi agirlik");
      }
  return Math.max(kademe.kiloBasiUcret * agirlikKg * bolgeKatsayisi, ASGARI_UCRET);
}
```

İkinci dosyada `throw` satırı, içinde bulunduğu koşuldan daha az girintili. Bir okuyucu
o satıra baktığında koşulun içinde mi dışında mı olduğunu girintiden anlayamaz. Aynı
belirsizlik `AGIRLIK_KADEMELERI` dizisinin ilk ögesinde de var: iki öge aynı düzeyde
olduğu hâlde farklı sütunlarda duruyor.

İki dosya arasındaki fark ölçülebilir. Dosyaların ilk satırı dosya adını taşıyan işaret
olduğu için karşılaştırmaya girmez.

```sh
diff <(tail -n +2 duzenli/ucret.mjs) <(tail -n +2 karisik/ucret.mjs)
```

```
3c3
<   { ustSinirKg: 5, kiloBasiUcret: 26 },
---
>     { ustSinirKg: 5, kiloBasiUcret: 26 },
8,9c8,9
<   const kademe = AGIRLIK_KADEMELERI.find((k) => agirlikKg <= k.ustSinirKg);
<   if (kademe === undefined) {
---
>     const kademe = AGIRLIK_KADEMELERI.find((k) => agirlikKg <= k.ustSinirKg);
>       if (kademe === undefined) {
11c11
<   }
---
>       }
```

Sekiz fark satırı var ve hiçbiri bir davranış değişikliği anlatmıyor. Bu, biçim
uyuşmazlığının ilk maliyetidir: girintiyi düzelten kişi, hiçbir içerik değiştirmediği
hâlde sekiz satırlık bir fark üretir ve o farkı bir başkası okumak zorunda kalır.

## Tarife Tablosunun İki Biçimi

İkinci ölçüm daha somut bir soruyu yanıtlar: aynı **içerik** değişikliği iki farklı
biçimde kaç satır fark üretir? Tarife modülü iki biçimde yazıldı. Birincisinde eşittir
işaretleri hizalanmış ve kademe tablosu satır başına iki öge alacak şekilde
sıkıştırılmış; ikincisinde bildirimler tek boşluklu ve her kademe kendi satırında.

```js
// hizali/tarife.mjs — hizalanmis bildirimler, sikistirilmis kademe tablosu
export const HACIMSEL_BOLEN              = 3000;
export const ASGARI_UCRET                = 52;
export const SOZLESMELI_MUSTERI_INDIRIMI = 0.15;
export const PARA_BIRIMI                 = "TL";

export const AGIRLIK_KADEMELERI = [
  { ustSinirKg:  1, kiloBasiUcret: 38 }, { ustSinirKg:  5, kiloBasiUcret: 26 },
  { ustSinirKg: 10, kiloBasiUcret: 21 }, { ustSinirKg: 30, kiloBasiUcret: 17 },
];
```

```js
// duz/tarife.mjs — tek bosluklu bildirimler, satir basina bir kademe
export const HACIMSEL_BOLEN = 3000;
export const ASGARI_UCRET = 52;
export const SOZLESMELI_MUSTERI_INDIRIMI = 0.15;
export const PARA_BIRIMI = "TL";

export const AGIRLIK_KADEMELERI = [
  { ustSinirKg: 1, kiloBasiUcret: 38 },
  { ustSinirKg: 5, kiloBasiUcret: 26 },
  { ustSinirKg: 10, kiloBasiUcret: 21 },
  { ustSinirKg: 30, kiloBasiUcret: 17 },
];
```

Taşıyıcı tarifeyi gözden geçirdi ve üç şey değişti: beş kilogram kademesinin kilo başı
ücreti 26'dan 25'e indi, elli kilograma kadar yeni bir kademe açıldı,
`SOZLESMELI_MUSTERI_INDIRIMI` sabiti `SOZLESME_INDIRIMI` adına çevrildi. Aynı üç
değişiklik iki dosyaya da uygulanır.

```js
// hizali/tarife-yeni.mjs — ayni revizyon, hizalamasi korunmus hali
export const HACIMSEL_BOLEN    = 3000;
export const ASGARI_UCRET      = 52;
export const SOZLESME_INDIRIMI = 0.15;
export const PARA_BIRIMI       = "TL";

export const AGIRLIK_KADEMELERI = [
  { ustSinirKg:  1, kiloBasiUcret: 38 }, { ustSinirKg:  5, kiloBasiUcret: 25 },
  { ustSinirKg: 10, kiloBasiUcret: 21 }, { ustSinirKg: 30, kiloBasiUcret: 17 },
  { ustSinirKg: 50, kiloBasiUcret: 14 },
];
```

```js
// duz/tarife-yeni.mjs — tarife revizyonu uygulanmis hali
export const HACIMSEL_BOLEN = 3000;
export const ASGARI_UCRET = 52;
export const SOZLESME_INDIRIMI = 0.15;
export const PARA_BIRIMI = "TL";

export const AGIRLIK_KADEMELERI = [
  { ustSinirKg: 1, kiloBasiUcret: 38 },
  { ustSinirKg: 5, kiloBasiUcret: 25 },
  { ustSinirKg: 10, kiloBasiUcret: 21 },
  { ustSinirKg: 30, kiloBasiUcret: 17 },
  { ustSinirKg: 50, kiloBasiUcret: 14 },
];
```

Hizalanmış sürümde ad kısaldığı için hizalama sütunu kaydı ve dört bildirimin dördü de
yeniden yazıldı. Düz sürümde yalnız adı değişen bildirim yeniden yazıldı.

## Fark Ölçer

Aşağıdaki araç her dosya çifti için farkı alır ve fark satırlarını ikiye ayırır. Çıkan bir
satırın boşlukları sadeleştirilmiş hâli giren satırlardan birinde de bulunuyorsa o çift
**yalnız biçim** farkıdır; içerik taşımaz. Kalanlar içerik farkıdır.

```js
// fark-olc.mjs — iki dosya arasindaki fark satirlarinin kaci icerik tasiyor
import { execSync } from "node:child_process";

// Ilk satir dosya adi isaretidir, karsilastirmaya girmez.
const fark = (eski, yeni) =>
  execSync(`diff <(tail -n +2 ${eski}) <(tail -n +2 ${yeni}) || true`, { shell: "/bin/bash" })
    .toString().split("\n");
const icerik = (s) => s.slice(1).replace(/\s+/g, " ").trim();

const CIFTLER = [
  ["duzenli/ucret.mjs", "karisik/ucret.mjs"],
  ["hizali/tarife.mjs", "hizali/tarife-yeni.mjs"],
  ["duz/tarife.mjs", "duz/tarife-yeni.mjs"],
];

for (const [eski, yeni] of CIFTLER) {
  const satirlar = fark(eski, yeni);
  const cikan = satirlar.filter((s) => s.startsWith("< ")).map(icerik);
  const giren = satirlar.filter((s) => s.startsWith("> ")).map(icerik);
  const esli = cikan.filter((s) => giren.includes(s)).length;
  console.log(`${eski.padEnd(18)} -> ${yeni.padEnd(22)} degisen=${cikan.length + giren.length}` +
    `  yalniz bicim=${esli * 2}  icerik=${cikan.length + giren.length - esli * 2}`);
}
```

```
duzenli/ucret.mjs  -> karisik/ucret.mjs      degisen=8  yalniz bicim=8  icerik=0
hizali/tarife.mjs  -> hizali/tarife-yeni.mjs degisen=11  yalniz bicim=6  icerik=5
duz/tarife.mjs     -> duz/tarife-yeni.mjs    degisen=5  yalniz bicim=0  icerik=5
```

Üç satırın anlattığı şey şu. Girinti düzeltmesi sekiz satır fark üretiyor ve sekizi de
biçim; içerik farkı sıfır. Tarife revizyonunun içerik farkı iki biçimde de aynı: beş
satır. Hizalanmış biçimde bu beş satırın yanına altı satır daha ekleniyor. Aynı bilgi,
iki katından fazla fark satırıyla anlatılıyor.

## Farkı Okuyan Kişi

Sayıların anlamı, farkı okuyan kişinin işidir. On bir satırlık farkta beş satır bir karar
taşır, altı satır taşımaz; okuyan kişi hangisinin hangisi olduğunu önceden bilmez ve
hepsini karşılaştırmak zorundadır. Beş satırlık farkta böyle bir ayıklama yoktur.

Sıkıştırılmış tablonun ikinci bir etkisi de var. Hizalanmış sürümün fark çıktısında
değişen tablo satırı iki kademe taşıyor: biri değişti, biri değişmedi. Okuyan kişi
satırın hangi yerinde değişiklik olduğunu karakter karakter aramak zorunda. Düz sürümde
değişen satır tek kademe taşıdığı için karşılaştırma satırın kendisiyle biter.

Buradan biçim kararının ölçütü çıkar: **bir satır tek bir bilgi taşımalı ve bir bilginin
biçimi komşusuna bağlı olmamalı.** Hizalama bu ikinci koşulu bozar; bir adın uzunluğu
komşu satırların boşluk sayısını belirlediği için, adı değişen bir bildirim komşularını
da değiştirir. Satır başına birden çok öge yerleştirmek birinci koşulu bozar.

## Biçim Kararı Bir Kez Verilir

Ölçüm hangi biçimin seçileceğini tam olarak söylemez; girintinin iki mi dört boşluk
olduğu bu sayılara yansımaz. Söylediği şey, kararın **proje düzeyinde bir kez verilmesi**
ve dosya dosya yeniden tartışılmamasıdır. Aynı projede iki girinti alışkanlığı bir arada
yaşadığında her dosya, üzerinde en son çalışan kişinin alışkanlığına dönüşür ve her
dönüşüm içerik taşımayan fark satırı üretir.

Bu yüzden biçim kararı bir tartışma konusu değil, bir yapılandırma dosyası konusudur.
Biçimlendirici sınıfından bir araç kuralları kaynağa mekanik olarak uygular; karar bir
kez verilir, uygulama kişiye bırakılmaz. Aracın seçtiği biçim kimsenin tercihiyle birebir
uyuşmayabilir; ölçülen maliyet, tercih uyuşmazlığının maliyetinden büyüktür.

## Özet

- Biçim kararının ölçüsü, ürettiği fark satırı sayısıdır: her değişiklik bir fark üretir
  ve farkı bir başkası okur.
- Yalnız girintisi bozulmuş bir dosya sekiz fark satırı üretti ve sekizinin de içerik
  farkı sıfırdı; biçim uyuşmazlığı içerik değişmeden maliyet doğurur.
- Aynı tarife revizyonu düz biçimde beş, hizalanmış biçimde on bir fark satırı üretti;
  içerik farkı ikisinde de beş satır, aradaki altı satır yalnız hizalamadan geliyor.
- Bir satır tek bilgi taşımalı ve bir bilginin biçimi komşu satırlara bağlı olmamalı;
  hizalama ikinci koşulu, satır başına çok öge birinci koşulu bozar.
- Biçim kararı proje düzeyinde bir kez verilir ve mekanik olarak uygulanır; dosya başına
  yeniden verilen karar her seferinde içerik taşımayan fark üretir.

## Sonraki Adım

Biçim, kodun göze nasıl göründüğünü belirliyor; yapının kendisini değil. Düzgün
girintilenmiş bir fonksiyon da okunması güç olabilir: iç içe geçmiş koşullar, birden çok
çıkış noktası ve birleşik mantıksal ifadeler girintiyle düzelmez. Bu güçlüğün de bir
sayısı var. Sonraki ders bir fonksiyonun karar noktalarını sayan bir ölçer yazar,
ücretlendirme fonksiyonunun iki sürümünde çevrimsel karmaşıklığı ve bağımsız yol sayısını
karşılaştırır, ardından sayıyı düşüren dönüşümleri uygular.
