İçeriğe geç
academia.sh

Ders 03 / 19

Varlıklar

Kimlikle tanımlanan nesnelerin seçim ölçütü: on iki gönderinin değer eşitliğiyle kaç ayrı örneğe indiğinin sayılması, fatura okumasının kaçının doğru çıktığının ölçülmesi, tartım düzeltmesinden sonra aynı kimliği gösteren anahtar sayısının çıkarılması ve iki eşitlik tanımının alanın iki sorusuna verdiği yanıtların karşılaştırılması.

İçindekiler

Önceki dersin birleşik sürümünde gönderi üç alan taşıyan düz bir kayıttı ve iki gönderi ancak alanları eşitse aynı sayılabiliyordu. Alanda bu doğru değildir. Aynı gönderinin ağırlığı tartım düzeltmesiyle değişir ve gönderi hâlâ aynı gönderidir; iki ayrı gönderinin bütün alanları eşit olabilir ve ikisi hâlâ iki gönderidir.

Bu ayrımı taşıyan nesneye varlık nesnesi (entity) denir: alanları değişse bile aynı kalan, dolayısıyla eşitliği alanlarıyla değil bir kimlikle tanımlanan nesne. Tanım Nesneye Dayalı Programlamaya Giriş kursunda verilmişti; buradaki iş tanım değil seçim ölçütüdür — hangi alan kavramına kimlik verilir, verilmediğinde ne kaybedilir.

İki Soru

Ölçüt iki soruya indirgenir. Birincisi: bu şey, alanları değiştikten sonra da aynı şey midir? İkincisi: bütün alanları eşit olan iki tanesi ayrı ayrı izlenmek zorunda mıdır?

Gönderi ücretlendirme kitaplığında ikisinin de yanıtı evettir. Bir müşteri aynı gün aynı bölgeye aynı ağırlıkta beş koli gönderir; beşine beş ayrı fatura kesilir. Aynı koli tartıldığında beyan ağırlığı düzeltilir; fatura o koliye kesilmeye devam eder.

İki Model

Birinci sürüm gönderiyi alanlarıyla tanımlar. Eşitlik, alanların birleşiminden üretilen bir anahtardır.

mkdir -p degerle kimlikle
// degerle/gonderi.mjs — kimliksiz gonderi: esitlik alanlarin esitligidir
export const gonderi = (musteri, agirlik, bolge) => ({ musteri, agirlik, bolge });
export const anahtar = (g) => `${g.musteri}|${g.agirlik}|${g.bolge}`;
export const esitMi = (a, b) => anahtar(a) === anahtar(b);
export const agirligiDuzelt = (g, yeniAgirlik) => ({ ...g, agirlik: yeniAgirlik });

İkinci sürüm gönderiye bir numara verir. Eşitlik yalnız o numaraya bakar; ağırlık düzeltmesi nesneyi değiştirir ama kimliğine dokunmaz.

// kimlikle/gonderi.mjs — varlik nesnesi: esitlik gonderi numarasinin esitligidir
export class Gonderi {
  constructor(gonderiNo, musteri, agirlik, bolge) {
    this.gonderiNo = gonderiNo;
    this.musteri = musteri;
    this.agirlik = agirlik;
    this.bolge = bolge;
  }
  anahtar() { return this.gonderiNo; }
  aynisiMi(o) { return o instanceof Gonderi && o.gonderiNo === this.gonderiNo; }
  agirligiDuzelt(yeniAgirlik) { this.agirlik = yeniAgirlik; return this; }
}

Ölçüm

Ölçünün girdisi on iki gönderi ve her birine kesilmiş bir faturadır. Beş gönderi aynı müşteriye, aynı ağırlığa ve aynı bölgeye aittir; iki tanesi başka bir müşteride, iki tanesi üçüncü müşterinin ağır kolilerinde tekrarlanır.

// kayitlar.mjs — ucretlendirme baglaminda 12 gonderi ve her birine kesilen fatura
export const KAYITLAR = [
  ["G-1041", "ARC", 2.4, "34", "F-9001"],
  ["G-1042", "ARC", 2.4, "34", "F-9002"],
  ["G-1043", "ARC", 2.4, "34", "F-9003"],
  ["G-1044", "ARC", 2.4, "34", "F-9004"],
  ["G-1045", "ARC", 2.4, "34", "F-9005"],
  ["G-1046", "ARC", 5, "34", "F-9006"],
  ["G-1047", "BKM", 0.8, "06", "F-9007"],
  ["G-1048", "BKM", 0.8, "06", "F-9008"],
  ["G-1049", "BKM", 12, "65", "F-9009"],
  ["G-1050", "CTS", 0.8, "06", "F-9010"],
  ["G-1051", "CTS", 18, "65", "F-9011"],
  ["G-1052", "CTS", 18, "65", "F-9012"],
];

Her sürümde fatura tablosu, gönderinin o sürümdeki anahtarıyla kurulur. Sonra ilk gönderinin ağırlığı 2,4’ten 3,1 kilograma düzeltilir ve tablo yeniden okunur.

// kimlik-olc.mjs — 12 gonderi kac ornekle temsil ediliyor, fatura okumasi kaci dogru
import { KAYITLAR } from "./kayitlar.mjs";
import * as deger from "./degerle/gonderi.mjs";
import { Gonderi } from "./kimlikle/gonderi.mjs";

function olc(ad, kur, anahtar, duzelt) {
  const nesneler = KAYITLAR.map(([no, m, a, b]) => kur(no, m, a, b));
  const tablo = new Map();
  nesneler.forEach((n, i) => tablo.set(anahtar(n), KAYITLAR[i][4]));
  const dogru = nesneler.filter((n, i) => tablo.get(anahtar(n)) === KAYITLAR[i][4]).length;
  console.log(`${ad}: 12 gonderi -> ${tablo.size} ayri ornek`);
  console.log(`  fatura okumasi dogru ${dogru}/12`);

  const eski = anahtar(nesneler[0]);
  const yeni = duzelt(nesneler[0], 3.1);
  tablo.set(anahtar(yeni), tablo.get(eski));
  nesneler[0] = yeni;
  const dogru2 = nesneler.filter((n, i) => tablo.get(anahtar(n)) === KAYITLAR[i][4]).length;
  const isaret = [...tablo.keys()].filter((k) => k === eski || k === anahtar(yeni)).length;
  console.log(`  tartim duzeltmesi sonrasi: tablo girdisi ${tablo.size}, ` +
    `G-1041'i gosteren anahtar ${isaret}`);
  console.log(`  duzeltme sonrasi fatura okumasi dogru ${dogru2}/12`);
}

olc("degerle", (no, m, a, b) => deger.gonderi(m, a, b), deger.anahtar,
  (g, a) => deger.agirligiDuzelt(g, a));
olc("kimlikle", (no, m, a, b) => new Gonderi(no, m, a, b), (g) => g.anahtar(),
  (g, a) => g.agirligiDuzelt(a));

const [ilk, ikinci] = [deger.gonderi("ARC", 2.4, "34"), deger.gonderi("ARC", 2.4, "34")];
const [v1, v2] = [new Gonderi("G-1041", "ARC", 2.4, "34"), new Gonderi("G-1042", "ARC", 2.4, "34")];
console.log(`iki ayri gonderi esit mi -> degerle ${deger.esitMi(ilk, ikinci)}, ` +
  `kimlikle ${v1.aynisiMi(v2)}`);
const v1b = new Gonderi("G-1041", "ARC", 3.1, "34");
console.log(`duzeltilmis gonderi ayni mi -> degerle ` +
  `${deger.esitMi(ilk, deger.agirligiDuzelt(ilk, 3.1))}, kimlikle ${v1.aynisiMi(v1b)}`);
node kimlik-olc.mjs
degerle: 12 gonderi -> 6 ayri ornek
  fatura okumasi dogru 6/12
  tartim duzeltmesi sonrasi: tablo girdisi 7, G-1041'i gosteren anahtar 2
  duzeltme sonrasi fatura okumasi dogru 6/12
kimlikle: 12 gonderi -> 12 ayri ornek
  fatura okumasi dogru 12/12
  tartim duzeltmesi sonrasi: tablo girdisi 12, G-1041'i gosteren anahtar 1
  duzeltme sonrasi fatura okumasi dogru 12/12
iki ayri gonderi esit mi -> degerle true, kimlikle false
duzeltilmis gonderi ayni mi -> degerle false, kimlikle true

İlk sayı kaybın büyüklüğünü veriyor: değer eşitliğiyle on iki gönderi altı örneğe iniyor. Altı gönderi bir başkasının anahtarına çöktüğü için fatura okumasının yarısı yanlış çıkıyor — altı gönderi kendisine kesilmeyen faturayı gösteriyor.

İkinci sayı ters yönde bozulmayı gösteriyor. Ağırlık düzeltmesi değer sürümünde yeni bir anahtar üretiyor; eski anahtar silinemez, çünkü ona bağlı başka gönderiler var. Sonuçta tablo yedi girdiye çıkıyor ve tek bir gönderi iki anahtarla gösterilir hâle geliyor. Kimlik sürümünde aynı düzeltme tablo boyunu değiştirmiyor: anahtar G-1041 kalıyor, on iki okumanın on ikisi doğru.

Son iki satır ölçütü tek cümleye indiriyor. Alanın birinci sorusu “bu iki gönderi aynı mı” sorusudur ve yanıtı hayırdır; değer eşitliği evet der. İkinci soru “düzeltilmiş gönderi aynı gönderi mi” sorusudur ve yanıtı evettir; değer eşitliği hayır der. İki tanımdan biri alanın iki sorusuna da yanlış, öteki ikisine de doğru yanıt veriyor.

Kimlik Nereden Gelir

Kimliğin taşıdığı tek şart, nesnenin yaşamı boyunca değişmemesi ve başka hiçbir nesnede tekrarlanmamasıdır. Alanda hazır bir kimlik varsa o kullanılır: gönderi numarası, sözleşme numarası, vergi kimlik numarası. Yoksa bir tane üretilir ve üretim kuralı alanın değil uygulamanın kararıdır.

Alandan gelen bir alan kimlik gibi kullanıldığında ölçü bozulur. Ücretlendirme bağlamında müşteri ile bölgenin birleşimi çoğu zaman tek bir gönderiyi verir; “çoğu zaman” bir kimlik ölçütü değildir ve yukarıdaki ölçüm o varsayımın bedelini gösteriyor. Aynı sebeple ağırlık, posta kodu ve beyan değeri gibi düzeltilebilen alanlar kimliğin parçası olamaz.

Kimliğin ikinci sonucu tekilliktir: aynı kimliğe sahip iki örnek bellekte aynı anda bulunuyorsa hangisinin doğru olduğu belirsizleşir. Bu sorun Tasarım Kalıpları kursundaki Kimlik Haritası dersinde ele alınmıştı; varlık nesnesi kararı o kalıbın önkoşuludur, çünkü tekilliği koruyacak bir kimlik olmadan haritanın anahtarı da yoktur.

Ne Zaman Kimlik Gerekmez

Ölçütün iki sorusu da hayırsa nesne varlık nesnesi değildir. Kitaplıkta bunun açık bir örneği bölge katsayısıdır: 1,35 katsayısı ile bir başka 1,35 katsayısı arasında ayrım yoktur ve katsayının bir yaşam öyküsü de yoktur. Aynı şey ağırlık, para tutarı ve indirim oranı için de geçerlidir.

Bu kavramlara kimlik verilmesi ölçüyü ters yönde bozar. Bir katsayıya numara verildiğinde eşitlik karşılaştırması kimliğe bakar ve alanda eşit olan iki değer kodda eşit çıkmaz. Kimlik, taşıdığı yerde kazanç üretir; taşımadığı yerde her karşılaştırmaya bir kural ekler.

Özet

  • Varlık nesnesi, alanları değiştiği hâlde aynı kalan ve eşitliği bir kimlikle tanımlanan nesnedir; seçim ölçütü iki sorudur — alanları değişince aynı mı kalıyor, alanları eşit olan ikisi ayrı ayrı izleniyor mu.
  • Değer eşitliğiyle on iki gönderi altı örneğe indi; fatura okumasının 6’sı yanlış çıktı.
  • Tartım düzeltmesi değer sürümünde tabloyu yedi girdiye çıkardı ve tek gönderiyi iki anahtarla gösterdi; kimlik sürümünde tablo on iki girdide kaldı, on iki okuma doğru çıktı.
  • Değer eşitliği alanın iki sorusuna da yanlış, kimlik eşitliği ikisine de doğru yanıt verdi.
  • Kimlik yaşam boyunca değişmeyen ve tekrarlanmayan bir ad olmalıdır; düzeltilebilen alanlar kimliğin parçası olamaz.
  • İki sorunun ikisi de hayırsa kimlik gerekmez; katsayı, ağırlık ve oran gibi kavramlara kimlik vermek her karşılaştırmaya gereksiz bir kural ekler.

Sonraki Adım

Bu dersin son bölümü kimlik gerektirmeyen kavramları saydı ama onları hâlâ çıplak sayı ve katar olarak tuttu: ağırlık bir number, bölge bir string. O zaman ağırlıkla hacmi toplamak, kilogramla gramı karşılaştırmak ve kuruşla lirayı çarpmak kodun izin verdiği işlemler olur. Sonraki ders bu kavramları kendi tipleri hâline getirir, değerle karşılaştırmanın kaç yerde elle yazıldığını sayar ve birim karışmasının kaç durumda sessizce yanlış tutar ürettiğini ölçer.

İ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