İçeriğe geç
academia.sh

Ders 02 / 16

Yorum Yerine Ad

Yorumun derlenmeyen ve sınanmayan bir metin olmasından doğan uyumsuzluğun ölçülmesi: gönderi ücreti modülünde yorumdaki sayı iddialarının koddaki karşılığının denetlenmesi, iddiaları ada çeviren yeniden düzenleme ve ada çevrilemeyen yorum türleri.

İçindekiler

Önceki derste adlandırılmış sürüm bir gözlem bıraktı: HACIMSEL_BOLEN sabiti hiçbir açıklama satırına ihtiyaç duymadı, çünkü adı ne olduğunu söylüyordu. Aynı bilgi kısaltılmış sürümde ancak bir yorumla verilebilirdi. Bu gözlem genelleşiyor mu? Bir yorumun varlığı, kodun söyleyemediği bir şeyi söylemek zorunda kalmasının işareti midir?

Soruyu sayıya bağlamak için yorumun teknik özelliğinden başlamak gerekir. Yorum derlenmez, çalıştırılmaz, sınanmaz. Kod her değişiklikte davranışıyla kendini savunur; yorum hiçbir şey yapmadan yerinde durur. Bu asimetri zamanla bir ayrışma üretir: kod bir yöne, yorum başka bir yöne gider ve okuyan kişi yorumu okur.

Altı Ay Sonraki Dosya

Ücretlendirme kitaplığının ücret modülü bir süre yaşadı. Bu arada tarife değişti: dördüncü bir ağırlık kademesi eklendi, asgari ücret yükseldi, sözleşmeli müşteri indirimi yeniden görüşüldü. Değişiklikleri yapan kişi kodu güncelledi.

mkdir -p yorumlu adli
// yorumlu/ucret.mjs
// Ucret hesabi.
// Hacimsel bolen 3000'dir.
// Uc agirlik kademesi vardir: 1, 5, 10 kg.
// Asgari ucret 45'tir.
// Sozlesmeli musteri indirimi %12'dir.
const B = 3000;
const A = 52;
const S = 0.15;
const K = [1, 5, 10, 30];
const U = [38, 26, 21, 17];

export function hesapla(gonderi, bolgeKatsayisi) {
  // hacimsel agirlik
  const d = (gonderi.enCm * gonderi.boyCm * gonderi.yukseklikCm) / B;
  // buyuk olani ucretlendirilir
  const a = Math.max(gonderi.agirlikKg, d);
  // kademeyi bul
  let i = 0;
  while (i < K.length - 1 && a > K[i]) i += 1;
  // indirim asgariden once uygulanir
  return Math.max(U[i] * a * bolgeKatsayisi * (1 - S), A);
}

Yorumlar iki işi birden yapıyor. Bir kısmı kodun ne yaptığını tekrar ediyor (// hacimsel agirlik, // kademeyi bul); bunlar adın taşıması gereken bilgiyi yorum satırına taşımış. Bir kısmı da alan bilgisi iddia ediyor: kademe sayısı, asgari ücret, indirim oranı. İkinci grup denetlenebilir.

Uyumsuzluğun Ölçülmesi

Aşağıdaki araç bir dosyanın yorumlarını ayırır, yorumlardaki sayıları çıkarır ve her birinin kodun sayısal değişmezleri arasında bulunup bulunmadığına bakar. Kodda karşılığı olmayan bir sayı, yorumun kodla ayrı düştüğünün kanıtıdır. Dosyanın ilk satırı dosya adını taşıyan işaret olduğu için sayıma girmez.

// yorum-denetle.mjs — yorum sayisini ve yorumdaki sayi iddialarinin koddaki karsiligini denetler
import { readFileSync } from "node:fs";

const sayilar = (metin) => metin.match(/\d+(?:\.\d+)?/g) ?? [];

function denetle(dosya) {
  // Ilk satir dosya adi isaretidir, yorum sayilmaz.
  const satirlar = readFileSync(dosya, "utf8").split("\n").slice(1);
  const yorumlar = satirlar.map((s) => s.match(/\/\/(.*)$/)?.[1]).filter((s) => s !== undefined);
  const kod = satirlar.map((s) => s.replace(/\/\/.*$/, "")).join("\n");
  const koddakiler = new Set(sayilar(kod));
  const iddialar = yorumlar.flatMap(sayilar);
  return { yorum: yorumlar.length, iddia: iddialar.length,
           uyumsuz: iddialar.filter((s) => !koddakiler.has(s)) };
}

for (const dosya of process.argv.slice(2)) {
  const r = denetle(dosya);
  console.log(`${dosya.padEnd(18)} yorum=${r.yorum}  sayi iddiasi=${r.iddia}  kodda yok=[${r.uyumsuz.join(", ")}]`);
}
node yorum-denetle.mjs yorumlu/ucret.mjs
yorumlu/ucret.mjs  yorum=9  sayi iddiasi=6  kodda yok=[45, 12]

Dokuz yorum satırı, altı sayı iddiası, iki tanesi kodda yok. Yorum “asgari ücret 45” diyor, kod 52 uyguluyor. Yorum “indirim %12” diyor, kod 0.15 uyguluyor. Kademe sayısını sayıyla yazmadığı için “üç kademe” iddiası bu araçla yakalanmıyor; kod dört kademe taşıyor. Denetimin sınırı da böylece görünüyor: araç yalnız sayısal iddiaları karşılaştırır, düz sözcükle yazılmış iddiaları karşılaştıramaz.

Sapmanın Bedeli

İki uyumsuz sayı soyut bir kusur değil. Yorumu okuyan bir kişi, bir gönderinin ücretini elle doğrulamak istediğinde yorumun verdiği değerleri kullanır.

// sapmayi-goster.mjs — yorumun anlattigi hesap ile kodun yaptigi hesap
import { hesapla as yorumlu } from "./yorumlu/ucret.mjs";

const gonderi = { agirlikKg: 2.4, enCm: 30, boyCm: 24, yukseklikCm: 18 };
const BOLGE_KATSAYISI = 1.35;

// Yorumun soyledigi degerlerle elle yapilan hesap: asgari 45, indirim %12.
const yorumaGore = Math.max(26 * 4.32 * BOLGE_KATSAYISI * (1 - 0.12), 45);

console.log(`yoruma gore = ${yorumaGore.toFixed(2)}`);
console.log(`kodun sonucu = ${yorumlu(gonderi, BOLGE_KATSAYISI).toFixed(2)}`);
node sapmayi-goster.mjs
yoruma gore = 133.44
kodun sonucu = 128.89

Aradaki 4,55’lik fark bir hata mesajı üretmez. Program doğru çalışıyor, testler geçiyor; yanlış olan tek şey belgedir ve belge kodun içinde durduğu için doğru sanılır. Yanlış yorumun maliyeti, yorumsuz kodun maliyetinden büyüktür.

Yorumu Ada Çevirmek

Yeniden düzenlemenin adımları mekaniktir. Kodun ne yaptığını anlatan her yorum, o işi yapan parçanın adına dönüşür: // hacimsel agirlik yorumu hacimselAgirlikKg adlı bir fonksiyon olur. Alan bilgisi iddia eden her yorum, o bilgiyi tutan sabitin adına dönüşür: // asgari ucret yorumu ASGARI_UCRET sabiti olur. Böylece iddia ile değer aynı satırda durur ve ayrı düşmeleri olanaksız hâle gelir.

// adli/ucret.mjs — yorumlarin ada cevrilmis hali
const HACIMSEL_BOLEN = 3000; // tasiyici sozlesmesinden gelir, burada karar verilmez
const ASGARI_UCRET = 52;
const SOZLESMELI_MUSTERI_INDIRIMI = 0.15;
const AGIRLIK_KADEMELERI = [
  { ustSinirKg: 1, kiloBasiUcret: 38 },
  { ustSinirKg: 5, kiloBasiUcret: 26 },
  { ustSinirKg: 10, kiloBasiUcret: 21 },
  { ustSinirKg: 30, kiloBasiUcret: 17 },
];

const hacimselAgirlikKg = (g) => (g.enCm * g.boyCm * g.yukseklikCm) / HACIMSEL_BOLEN;
const ucretlendirilenAgirlikKg = (g) => Math.max(g.agirlikKg, hacimselAgirlikKg(g));
const kademeSec = (agirlikKg) =>
  AGIRLIK_KADEMELERI.find((k) => agirlikKg <= k.ustSinirKg) ?? AGIRLIK_KADEMELERI.at(-1);
const indirimiAsgariUcretOncesindeUygula = (ucret) =>
  Math.max(ucret * (1 - SOZLESMELI_MUSTERI_INDIRIMI), ASGARI_UCRET);

export function hesapla(gonderi, bolgeKatsayisi) {
  const agirlikKg = ucretlendirilenAgirlikKg(gonderi);
  return indirimiAsgariUcretOncesindeUygula(
    kademeSec(agirlikKg).kiloBasiUcret * agirlikKg * bolgeKatsayisi);
}

Kademe sınırı ile o kademenin kilo başına ücreti artık aynı nesnenin içinde. Önceki sürümde bunlar iki ayrı dizide, indis eşleşmesiyle tutuluyordu; bir kademe eklendiğinde iki diziyi birden güncellemeyi unutmak sessiz bir yanlış üretiyordu. Ad değişikliği yapıyı da düzeltti.

node yorum-denetle.mjs yorumlu/ucret.mjs adli/ucret.mjs
yorumlu/ucret.mjs  yorum=9  sayi iddiasi=6  kodda yok=[45, 12]
adli/ucret.mjs     yorum=1  sayi iddiasi=0  kodda yok=[]

Dokuz yorum bire indi, altı sayı iddiası sıfıra. Sıfır iddia, uyumsuzluk olasılığının da sıfır olması demektir: ada çevrilen bir iddia kodla birlikte değişir.

Kalan Yorum

Bir yorum kaldı ve kalması gerekiyor:

const HACIMSEL_BOLEN = 3000; // tasiyici sozlesmesinden gelir, burada karar verilmez

Bu yorum kodun ne yaptığını değil, neden öyle olduğunu söylüyor. Sayının nereden geldiğini hiçbir ad taşıyamaz, çünkü bilgi kodun dışındadır. Yorumu silen kişi 3000’i iyileştirilebilir bir seçim sanır ve değiştirmeye kalkışır.

Ada çevrilemeyen yorum türleri sınırlıdır ve hepsi kodun dışına işaret eder:

  • Gerekçe: bir değerin ya da kararın kaynağı, kod tabanının dışındaki bir sözleşme, standart ya da kurum kararıdır.
  • Uyarı: bir işlemin ilk bakışta görünmeyen bir sonucu vardır; bir çağrının sırası önemlidir ya da bir sınırın aşılması pahalıdır.
  • Bilinçli sapma: kod bir yerde beklenenden farklı davranıyordur ve bu bilerek yapılmıştır; yorum sapmayı ve nedenini kaydeder.
  • Yasal ve lisans metni: dosyanın başında bulunması zorunlu olan metinler.

Bu dört türün dışında kalan her yorum bir adaydır: ya bir ada, ya bir fonksiyona, ya da bir teste çevrilebilir. “Bu fonksiyon negatif ağırlık kabul etmez” yorumu bir teste ya da bir koruma cümlesine çevrildiğinde iddia denetlenir hâle gelir; yorum olarak kaldığında denetlenmez.

Özet

  • Yorum derlenmez ve sınanmaz; kod değişirken yorumun yerinde kalması sessiz bir yanlış üretir. Uyumsuzluk, yorumdaki sayı iddialarının kodla karşılaştırılmasıyla ölçülür.
  • Ücret modülünün yorumlu sürümünde dokuz yorum, altı sayı iddiası ve kodda karşılığı olmayan iki iddia vardı; yoruma göre yapılan hesap 133,44, kodun sonucu 128,89.
  • Yorumu ada çeviren yeniden düzenlemeden sonra yorum sayısı bire, sayı iddiası sıfıra indi; ada çevrilen iddia kodla birlikte değiştiği için ayrı düşemez.
  • Ad değişikliği yapıyı da düzeltti: indis eşleşmesiyle tutulan iki dizi tek bir kademe nesnesine dönüştü.
  • Ada çevrilemeyen yorumlar kodun dışına işaret edenlerdir: gerekçe, uyarı, bilinçli sapma ve yasal metin. Kalan her yorum bir ada, bir fonksiyona ya da bir teste adaydır.

Sonraki Adım

Yorumları ada çevirirken tek bir fonksiyon dört parçaya bölündü: hacimsel ağırlık, ücretlendirilen ağırlık, kademe seçimi ve indirim uygulaması. Bölme işini yorumların yerleri belirledi; bu rastlantısal bir ölçüttür. Fonksiyon ne zaman bölünmelidir? Satır sayısı bir ölçüt müdür, yoksa on satırlık bir fonksiyon da bölünmesi gereken bir şey içerebilir mi? Sonraki ders ölçütü satır sayısından çıkarıp tek soyutlama düzeyi kuralına bağlar: bir fonksiyonun çağırdığı adların düzeylerini sayan bir çözümleyici yazılır ve ücret hesabının iki sürümü bu sayıyla karşılaştırılır.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat