---
title: 'Anlamlı Adlar'
source: 'https://academia.sh/tr/kurslar/temiz-kod/anlamli-adlar'
course: 'Temiz Kod'
language: tr
updated: '2026-08-17T18:10:37+00:00'
license: 'CC BY-SA 4.0'
---

# Anlamlı Adlar

Adlandırmanın ölçülebilir bir tasarım kararı olarak ele alınması: aynı gönderi ücreti hesabının kısaltılmış ve niyeti açıklayan iki sürümünde çağrı yerindeki opak argümanların sayılması, kısaltmaların kaç aday karşılığa çözümlendiğinin çıkarılması ve ad uzunluğunun kapsamla ilişkisi.

Bir dil müfredatı tamamlandığında elde edilen yetenek şudur: istenen davranışı üreten kod
yazmak. JavaScript ve TypeScript kursları bunu sağladı; testler geçiyorsa program doğrudur.
Bu müfredat farklı bir soruyla başlıyor. Aynı davranışı üreten iki program arasında bir
tercih yapmak gerekirse, tercih neye dayanır?

Soru kaçınılmazdır, çünkü kod bir kez yazılıp bırakılmaz. Bir gönderi ücretlendirme
kitaplığına altı ay sonra yeni bir bölge katsayısı eklenir, bir yıl sonra hacimsel ağırlık
böleni değişir. Bu değişiklikleri yapan kişi, kodu önce **okur**. Okuma maliyeti tasarımın
asıl ölçüsüdür ve "daha okunabilir" gibi bir iddia, sayıya bağlanmadığı sürece tartışmayı
bitirmez. Bu ders adlandırmayı iki sayıya bağlıyor: çağrı yerinde ne söylediği anlaşılmayan
argüman sayısı ve bir kısaltmanın kaç farklı alan sözcüğüne çözümlenebildiği.

Kurs boyunca tek bir kitaplık geliştirilecek: gönderi ücretlendirme ve yönlendirme. İlk
işlevi, bir gönderinin ağırlığından, hacminden ve bölgesinden ücretini hesaplamak.

## Ölçüt: Çağrı Yerinde Cevaplanabilen Soru

Bir adın taşıdığı bilgi, o adın **kullanıldığı yerde** ölçülür. Bir çağrı satırına bakan
kişi şu soruları sorar: bu argüman hangi parametreyi dolduruyor, değeri ne anlama geliyor,
sonuç neyin ücreti? Cevap için başka bir dosyayı açmak gerekiyorsa ad bilgi taşımıyordur.

Bunu mekanik hâle getirmek için bir argümanı **etiketli** sayalım: çağrı metninin kendisi
hangi parametreye karşılık geldiğini söylüyorsa (adlandırılmış bir alan ya da en az üç
harfli bir değişken adı) etiketlidir. Değilse **opak**tır: çıplak bir sayı, bir doğruluk
değeri ya da tek harfli bir ad. Opak argüman sayısı, çağrı yerinde cevaplanamayan soru
sayısının alt sınırıdır.

## Kısaltılmış Sürüm

İlk sürüm çalışıyor ve testleri geçiyor. Hacimsel ağırlığı hesaplar, ücretlendirilen
ağırlığı bulur, kademeyi seçer, bölge katsayısını uygular, indirimi düşer ve asgari ücretin
altına inmez.

```sh
mkdir -p surum-a surum-b
```

```js
// surum-a/veri.mjs — ornek gonderi ve tarife
export const g = { a: 2.4, e: 30, by: 24, y: 18 };
export const t = { k: [{ s: 1, u: 38 }, { s: 5, u: 26 }, { s: 10, u: 21 }, { s: Infinity, u: 17 }],
                   bk: { 1: 1, 2: 1.35, 3: 1.8 }, as: 45 };
```

```js
// surum-a/ucret.mjs — gonderi ucreti, kisaltilmis adlarla
export function hsp(g, t, b, x) {
  const d = (g.e * g.by * g.y) / 3000;
  const a = Math.max(g.a, d);
  const k = t.k.find((i) => a <= i.s);
  const u = k.u * a * t.bk[b];
  return Math.max(u * (1 - x), t.as);
}
```

```js
// surum-a/cagri.mjs — cagri yeri
import { hsp } from "./ucret.mjs";
import { g, t } from "./veri.mjs";
console.log(hsp(g, t, 2, 0.12).toFixed(2));
```

Çağrı satırındaki dört argümandan hiçbiri kendini açıklamıyor. `2` bir bölge kodu mu, bir
kademe indisi mi, bir adet mi? `0.12` bir indirim oranı mı, bir vergi oranı mı? Cevap
`ucret.mjs` dosyasında; okuyan kişi ikinci dosyayı açmak zorunda.

## Adlandırılmış Sürüm

İkinci sürüm aynı aritmetiği yapar. Değişen tek şey adlar, parametre biçimi ve sayıların
nereden geldiği.

```js
// surum-b/veri.mjs — ayni veri, alan adlariyla
export const BOLGE = { AYNI_SEHIR: 1, KOMSU_BOLGE: 2, UZAK_BOLGE: 3 };
export const SOZLESMELI_MUSTERI_INDIRIMI = 0.12;
export const ornekGonderi = { agirlikKg: 2.4, enCm: 30, boyCm: 24, yukseklikCm: 18 };
export const yurticiTarife = {
  agirlikKademeleri: [{ ustSinirKg: 1, kiloBasiUcret: 38 }, { ustSinirKg: 5, kiloBasiUcret: 26 },
                      { ustSinirKg: 10, kiloBasiUcret: 21 }, { ustSinirKg: Infinity, kiloBasiUcret: 17 }],
  bolgeKatsayilari: { 1: 1, 2: 1.35, 3: 1.8 },
  asgariUcret: 45,
};
```

```js
// surum-b/ucret.mjs — ayni hesap, niyeti aciklayan adlarla
const HACIMSEL_BOLEN = 3000;

export function gonderiUcretiHesapla({ gonderi, tarife, bolgeKodu, indirimOrani }) {
  const hacimselAgirlikKg = (gonderi.enCm * gonderi.boyCm * gonderi.yukseklikCm) / HACIMSEL_BOLEN;
  const ucretlendirilenAgirlikKg = Math.max(gonderi.agirlikKg, hacimselAgirlikKg);
  const kademe = tarife.agirlikKademeleri.find((k) => ucretlendirilenAgirlikKg <= k.ustSinirKg);
  const bolgeliUcret = kademe.kiloBasiUcret * ucretlendirilenAgirlikKg * tarife.bolgeKatsayilari[bolgeKodu];
  return Math.max(bolgeliUcret * (1 - indirimOrani), tarife.asgariUcret);
}
```

```js
// surum-b/cagri.mjs — cagri yeri
import { gonderiUcretiHesapla } from "./ucret.mjs";
import { ornekGonderi, yurticiTarife, BOLGE, SOZLESMELI_MUSTERI_INDIRIMI } from "./veri.mjs";
console.log(gonderiUcretiHesapla({ gonderi: ornekGonderi, tarife: yurticiTarife,
  bolgeKodu: BOLGE.KOMSU_BOLGE, indirimOrani: SOZLESMELI_MUSTERI_INDIRIMI }).toFixed(2));
```

İki sürümün aynı sonucu ürettiği doğrulanır.

```sh
node surum-a/cagri.mjs
node surum-b/cagri.mjs
```

```
133.44
133.44
```

Davranış aynı. Fark yalnızca okuma maliyetinde ve bu maliyet sayılabilir.

## Ölçüm

Aşağıdaki araç iki şeyi sayar. Birincisi, verilen çağrı yerindeki opak argümanları.
İkincisi, gerçekleştirimdeki iki harfe kadar kısa adları alıp her birinin alan sözlüğündeki
kaç sözcüğe çözümlenebileceğini — yani kısaltmanın belirsizliğini.

```js
// ad-olcer.mjs — cagri yerindeki opak argumanlari ve kisaltmalarin belirsizligini sayar
import { readFileSync } from "node:fs";

// Kitapligin alan sozlugu: adlarin tasimasi beklenen sozcukler.
const SOZLUK = ["agirlik", "asgari", "bolen", "bolge", "desi", "gonderi", "hacim",
  "indirim", "kademe", "katsayi", "kilo", "oran", "sinir", "tarife", "ucret"];

// Bir arguman, cagri yerinde hangi parametreyi doldurdugunu kendisi soyluyorsa etiketlidir.
const etiketli = (arg) => /^[A-Za-z_$][\w$]{2,}\s*:/.test(arg) || /^[A-Za-z_$][\w$]{2,}$/.test(arg);

function opakSay(dosya, fnAdi) {
  const govde = readFileSync(dosya, "utf8");
  const cagri = govde.match(new RegExp(`\\b${fnAdi}\\(([^()]*)\\)`));
  const args = cagri[1].replace(/[{}]/g, "").split(",").map((s) => s.trim()).filter(Boolean);
  return { toplam: args.length, opak: args.filter((a) => !etiketli(a)).length };
}

function kisaltmalar(dosya) {
  const govde = readFileSync(dosya, "utf8").replace(/^\/\/.*$/gm, "");
  const adlar = [...new Set(govde.match(/[A-Za-z_$][\w$]*/g))].filter((a) => a.length <= 2);
  return adlar.map((ad) => ({
    ad,
    adaylar: SOZLUK.filter((s) => s.startsWith(ad[0].toLowerCase())),
  }));
}

for (const [dosya, fn] of [["surum-a/cagri.mjs", "hsp"], ["surum-b/cagri.mjs", "gonderiUcretiHesapla"]]) {
  const s = opakSay(dosya, fn);
  console.log(`${dosya.padEnd(20)} ${fn.padEnd(21)} arguman=${s.toplam}  opak=${s.opak}`);
}

console.log("\nkisaltma  aday sayisi  adaylar");
const kisa = kisaltmalar("surum-a/ucret.mjs");
for (const k of kisa) console.log(`${k.ad.padEnd(9)} ${String(k.adaylar.length).padEnd(12)} ${k.adaylar.join(", ") || "-"}`);
const tek = kisa.filter((k) => k.adaylar.length === 1).length;
console.log(`\nsurum-a kisa ad sayisi = ${kisa.length}, tek adayla cozumlenen = ${tek}`);
console.log(`surum-b kisa ad sayisi = ${kisaltmalar("surum-b/ucret.mjs").length}`);
```

```sh
node ad-olcer.mjs
```

```
surum-a/cagri.mjs    hsp                   arguman=4  opak=4
surum-b/cagri.mjs    gonderiUcretiHesapla  arguman=4  opak=0

kisaltma  aday sayisi  adaylar
g         1            gonderi
t         1            tarife
b         2            bolen, bolge
x         0            -
d         1            desi
e         0            -
by        2            bolen, bolge
y         0            -
a         2            agirlik, asgari
k         3            kademe, katsayi, kilo
i         1            indirim
s         1            sinir
u         1            ucret
bk        2            bolen, bolge
as        2            agirlik, asgari

surum-a kisa ad sayisi = 15, tek adayla cozumlenen = 6
surum-b kisa ad sayisi = 1
```

Dört opak argüman sıfıra indi. Kısaltma tablosu ikinci sonucu veriyor: on beş kısa addan
yalnız altısı tek bir alan sözcüğüne çözümleniyor. Üçü (`x`, `e`, `y`) hiçbir sözcüğe
karşılık gelmiyor; okuyan kişi bunları ancak kodu izleyerek çözebilir. Beşi birden çok
aday taşıyor: `a` hem ağırlık hem asgari, `k` hem kademe hem katsayı hem kilo olabilir.
Gerçekleştirimde `a` ağırlığı, `as` asgari ücreti tutuyor — iki farklı kavram bir harf
farkıyla ayrılmış.

Adlandırılmış sürümde tek bir kısa ad kaldı: `find` çağrısına verilen `k` parametresi. Bu
kalıntı rastlantı değil; sonraki bölümün konusu.

## Ad Uzunluğu Kapsama Bağlıdır

Kısa ad kendiliğinden kusur değildir. Ölçüt, adın **yaşadığı kapsamdır**. Bir satırlık bir
geri çağırma içindeki `k` ile modül düzeyinde dışa aktarılan `t` arasındaki fark, okuyanın
tanımı bulmak için gezmesi gereken mesafedir. Birincisinde tanım aynı satırda; ikincisinde
tanım başka bir dosyada.

Buradan pratik bir kural çıkar: adın uzunluğu, adın görünür olduğu kod miktarıyla birlikte
artar. Döngü sayacı `i` üç satırlık bir döngüde savunulabilir, dışa aktarılan bir sabit
olarak savunulamaz. Aynı gerekçe tersine de işler: dar kapsamda gereksiz uzun ad
(`gecerliGonderininHacimselAgirligiDegeri`) bilgi eklemeden satırı uzatır.

## Adın Vermesi Gereken Bilgi

Ölçüm ne kadarının eksik olduğunu söyler, hangi bilginin eklenmesi gerektiğini söylemez.
Bunun için dört ölçüt işe yarar.

**Birim ve tür adın içinde durur.** `agirlikKg` ile `agirlik` arasındaki fark, gramla
kilogramı karıştıran bir hatanın derleme öncesinde görünmesidir. `enCm`, `ustSinirKg`,
`indirimOrani` adlarının sonundaki ekler bu işi yapar; `indirimOrani` ile `indirimTutari`
birbirinin yerine geçemez.

**Ad yanlış bilgi vermemelidir.** `bolgeListesi` adlı bir değişkenin gerçekte bir eşleme
tutması, hiç ad vermemekten kötüdür: okuyan kişi yanlış bir varsayımla ilerler. Yanlış
adın maliyeti, hata bulunana kadar yapılan bütün yorumlardır.

**Kavram başına tek sözcük.** Aynı kitaplıkta `getTarife`, `tarifeAl` ve `tarifeGetir`
birlikte bulunuyorsa okuyan kişi üç farklı işlem olduğunu varsayar. Sözlük kurs boyunca
sabittir: bir gönderinin ücretlendirilen ağırlığı her yerde `ucretlendirilenAgirlikKg`
adıyla geçer.

**Aranabilirlik.** `3000` sayısı kod tabanında yüzlerce yerde geçer; `HACIMSEL_BOLEN` bir
kez geçer. Sayının değişmesi gerektiğinde aranacak şey addır. Çıplak sayıların isimsiz
bırakılması bu yüzden yalnız okuma değil, değiştirme maliyetidir.

## Özet

- Adlandırma bir üslup tercihi değil, ölçülebilir bir karardır: ölçüt, çağrı yerinde
  cevaplanamayan soruların alt sınırı olan opak argüman sayısıdır.
- Kısaltılmış sürümde dört argümanın dördü opaktı; adlandırılmış sürümde hiçbiri opak
  değil. İki sürüm aynı sonucu (133.44) üretiyor, fark yalnızca okuma maliyetinde.
- Kısaltma çözümleme tablosu ikinci ölçüyü verdi: on beş kısa addan altısı tek bir alan
  sözcüğüne çözümleniyor, üçü hiçbirine, beşi birden çoğuna.
- Ad uzunluğu adın yaşadığı kapsamla birlikte artar; bir satırlık geri çağırmadaki kısa ad
  ile dışa aktarılan kısa ad aynı şey değildir.
- İyi ad birimi ve türü taşır, yanlış bilgi vermez, kavram başına tek sözcük kullanır ve
  aranabilir; çıplak sayıya ad vermek okuma değil değiştirme maliyetini düşürür.

## Sonraki Adım

Adlandırılmış sürümde bir şey dikkat çekiyor: `HACIMSEL_BOLEN` sabiti bir yorum satırına
ihtiyaç duymadı, çünkü adı ne olduğunu söylüyor. Kısaltılmış sürümde aynı bilgi ancak bir
yorumla verilebilirdi. Bu gözlem genelleşir mi? Bir yorumun varlığı, kodun söyleyemediği
bir şeyi söylemek zorunda kalmasının işareti midir? Sonraki ders bu soruyu ölçerek yanıtlar:
yorumların ne kadarı ada çevrilebilir, çevrilemeyenler hangileridir ve yorumla kodun
birbirinden ayrı düşmesi hangi noktada sessiz bir yanlışa dönüşür.
