İçeriğe geç
academia.sh

Ders 08 / 11

Karar Verme

Geri döndürülebilir ve geri döndürülemez kararların ayrı yöntemle verilmesi: geri alma maliyetinin bir bağımlılık kümesinden hesaplanması, aynı karar kümesinin bu maliyete göre iki sınıfa ayrılması, hızlı deneme ile uzun değerlendirme yöntemlerinin her iki sınıfta koşturulması ve bekleme süresi ile yanlış karar maliyetinin dört politika üzerinde karşılaştırılması.

İçindekiler

Önceki ders bir sadeleştirmenin fiyatını hesapladı ama bir soruyu açıkta bıraktı: kaldırılan sarmalayıcı geri getirilebilir mi? Altı modüle dağılmış ayar okumasını yeniden tek noktada toplamak, sarmalayıcıyı kaldırmakla aynı büyüklükte bir iş değildir. Kararların bir kısmı böyledir; geri alınması, verilmesinden kat kat pahalıdır.

Bu fark pratikte çoğu zaman görülmez, çünkü bütün kararlar aynı yerde ve aynı hızda verilir. Sonuç iki yönlü bir israftır: geri alınabilir kararlar için haftalarca toplantı yapılır, geri alınamaz kararlar bir öğleden sonra kapatılır. Bu dersin ölçtüğü şey, bu iki hatanın kaç adam-güne mal olduğudur.

Geri Alma Maliyeti Bir Bağımlılık Kümesinden Okunur

Bir kararın ne kadar geri döndürülebilir olduğu bir his değil, bir hesaptır. Karar bir bileşene iner; geri almak o bileşeni ve ona bağlı olan her bileşeni dolaşmayı gerektirir. Model kütüphane ağının yazılım sistemidir; kurgudur, gerçek bir kurum anlatılmaz.

// karar/maliyet.mjs — geri alma maliyeti bir bagimlilik kumesinden okunur; kurgu bir modeldir
// BAGIMLILIK[x] = x'in kullandigi bilesenler. Geri alma, degisen bileseni ve ona bagli
// olan her bileseni dolasmayi gerektirir (MP7).
export const BAGIMLILIK = {
  "veri-deposu": [],
  "odunc-cekirdegi": ["veri-deposu"],
  "uyelik": ["veri-deposu"],
  "katalog-kapisi": ["veri-deposu"],
  "ayirtma": ["odunc-cekirdegi"],
  "raporlama": ["veri-deposu", "odunc-cekirdegi"],
  "odeme-kapisi": ["odunc-cekirdegi"],
  "bildirim": ["ayirtma"],
  "eslesme-hatti": ["katalog-kapisi", "veri-deposu"],
  "sube-istemcisi": ["odunc-cekirdegi", "ayirtma", "katalog-kapisi"],
};

// MP7 katsayilari (adam-gun). Bilesen basina dolasma 2; yazilmis kayitlarin bicimi degistiyse
// goc 15; disa acilmis bir arayuz surumlenmisse esgudum 20.
export const KATSAYI = { bilesen: 2, goc: 15, sozlesme: 20 };

export const KARAR = [
  { ad: "odunc-kaydi-bicimi", bilesen: "veri-deposu", bicim: true, disa: false },
  { ad: "sube-istemcisi-onbellegi", bilesen: "sube-istemcisi", bicim: false, disa: false },
  { ad: "katalog-kapisi-surumu", bilesen: "katalog-kapisi", bicim: false, disa: true },
  { ad: "bildirim-metni-sablonu", bilesen: "bildirim", bicim: false, disa: false },
  { ad: "raporlama-sorgu-plani", bilesen: "raporlama", bicim: false, disa: false },
  { ad: "odunc-kural-motoru", bilesen: "odunc-cekirdegi", bicim: false, disa: false },
  { ad: "ayirtma-siralama-kurali", bilesen: "ayirtma", bicim: false, disa: false },
  { ad: "odeme-arayuzu-surumu", bilesen: "odeme-kapisi", bicim: false, disa: true },
];

export function dolasilan(bilesen) {
  const kume = new Set([bilesen]);
  let buyudu = true;
  while (buyudu) {
    buyudu = false;
    for (const [x, kullandiklari] of Object.entries(BAGIMLILIK))
      if (!kume.has(x) && kullandiklari.some((y) => kume.has(y))) { kume.add(x); buyudu = true; }
  }
  return kume;
}

export const geriAlma = (k) => dolasilan(k.bilesen).size * KATSAYI.bilesen +
  (k.bicim ? KATSAYI.goc : 0) + (k.disa ? KATSAYI.sozlesme : 0);

Hesabın üç bileşeni var ve üçü de farklı bir olguyu sayıyor. Dolaşılan bileşen sayısı grafikten okunur ve kararın nereye indiğine bağlıdır. Kayıt biçimi değiştiyse geri alma yalnız kodu değil, yazılmış kayıtları da ilgilendirir; bu pay koda dokunmadan da orada durur. Dışa açılmış bir arayüz sürümlendiyse geri alma tek taraflı yapılamaz, karşı tarafla eşgüdüm gerekir.

İki Sınıf

// karar/sinifla.mjs — geri alma maliyeti hesaplanir, kararlar iki sinifa ayrilir
import { KARAR, dolasilan, geriAlma } from "./maliyet.mjs";

// MP8: esik, bir surum dongusunde geri alma icin ayrilabilen kapasitedir: 10 adam-gun.
const ESIK = 10;
console.log("karar                     | bilesen          | dolasilan | goc | disa | geri alma");
console.log("--------------------------|------------------|-----------|-----|------|----------");
for (const k of KARAR)
  console.log(`${k.ad.padEnd(25)} | ${k.bilesen.padEnd(16)} | ` +
    `${String(dolasilan(k.bilesen).size).padStart(9)} | ${(k.bicim ? "var" : "  -").padStart(3)} | ` +
    `${(k.disa ? "var" : "  -").padStart(4)} | ${String(geriAlma(k)).padStart(9)}`);

const sinif = (k) => (geriAlma(k) <= ESIK ? "dondurulebilir" : "dondurulemez");
const grup = { dondurulebilir: [], dondurulemez: [] };
for (const k of KARAR) grup[sinif(k)].push(k);
console.log(`\nesik ${ESIK} adam-gun (MP8)`);
for (const [ad, liste] of Object.entries(grup))
  console.log(`  geri ${ad.padEnd(15)}: ${liste.length} karar, maliyetler ` +
    `${liste.map(geriAlma).join(", ")} (toplam ${liste.reduce((t, k) => t + geriAlma(k), 0)})`);
karar                     | bilesen          | dolasilan | goc | disa | geri alma
--------------------------|------------------|-----------|-----|------|----------
odunc-kaydi-bicimi        | veri-deposu      |        10 | var |    - |        35
sube-istemcisi-onbellegi  | sube-istemcisi   |         1 |   - |    - |         2
katalog-kapisi-surumu     | katalog-kapisi   |         3 |   - |  var |        26
bildirim-metni-sablonu    | bildirim         |         1 |   - |    - |         2
raporlama-sorgu-plani     | raporlama        |         1 |   - |    - |         2
odunc-kural-motoru        | odunc-cekirdegi  |         6 |   - |    - |        12
ayirtma-siralama-kurali   | ayirtma          |         3 |   - |    - |         6
odeme-arayuzu-surumu      | odeme-kapisi     |         1 |   - |  var |        22

esik 10 adam-gun (MP8)
  geri dondurulebilir : 4 karar, maliyetler 2, 2, 2, 6 (toplam 12)
  geri dondurulemez   : 4 karar, maliyetler 35, 26, 12, 22 (toplam 95)

Sekiz kararın dördü geri döndürülebilir karar, dördü geri döndürülemez karardır ve toplam geri alma maliyetinin 95’i, yani yüzde 88,8’i dört kararda toplanmış. Sayıların dağılımı da öğreticidir: odeme-arayuzu-surumu yalnız tek bir bileşene iniyor, dolaşılan bileşen sayısı 1, ama dışa açılmış bir arayüz sürümlendiği için maliyeti 22. odunc-kural-motoru altı bileşene yayılıyor ama geri alması 12. Yani “kaç yere dokunuyor” tek başına sınıfı belirlemiyor; kararı geri döndürülemez yapan şey çoğu zaman dokunduğu yer sayısı değil, dışarıya verdiği söz ya da yazdığı kayıttır.

İki Yöntem, İki Sınıf

Karşılaştırma iki karar yöntemini aynı karar kümesinde koşturur. Hızlı deneme kararı iki günde verir ve yanlış çıkma oranı yüksektir; uzun değerlendirme on beş gün bekletir ve yanlış çıkma oranı düşüktür. İki yöntem iki ayrı maliyeti üretir: bekleyen her gün gecikme bedeli yazar, yanlış çıkan her karar geri alma maliyetini yazar.

// karar/yontem.mjs — iki karar yontemi iki sinifta: bekleme suresi ve yanlis karar maliyeti
import { KARAR, geriAlma } from "./maliyet.mjs";

// MP9: hizli deneme 2 gun bekletir ve kararlarin %35'i geri alinir; uzun degerlendirme
// 15 gun bekletir ve %10'u geri alinir. Bekleyen her gun 0.4 adam-gun gecikme bedeli yazar.
const YONTEM = {
  "hizli-deneme": { bekleme: 2, yanlis: 0.35 },
  "uzun-degerlendirme": { bekleme: 15, yanlis: 0.10 },
};
const GUNLUK = 0.4, ESIK = 10;
const beklenen = (y, toplamGeriAlma, adet) =>
  y.bekleme * adet * GUNLUK + y.yanlis * toplamGeriAlma;

const grup = { dondurulebilir: [], dondurulemez: [] };
for (const k of KARAR) grup[geriAlma(k) <= ESIK ? "dondurulebilir" : "dondurulemez"].push(k);

console.log("sinif           | karar | geri alma | hizli-deneme | uzun-degerlendirme | kazanan");
console.log("----------------|-------|-----------|--------------|--------------------|--------");
for (const [ad, liste] of Object.entries(grup)) {
  const t = liste.reduce((s, k) => s + geriAlma(k), 0);
  const h = beklenen(YONTEM["hizli-deneme"], t, liste.length);
  const u = beklenen(YONTEM["uzun-degerlendirme"], t, liste.length);
  console.log(`${ad.padEnd(15)} | ${String(liste.length).padStart(5)} | ${String(t).padStart(9)} | ` +
    `${h.toFixed(2).padStart(12)} | ${u.toFixed(2).padStart(18)} | ${h < u ? "hizli" : "uzun"} (fark ${Math.abs(h - u).toFixed(2)})`);
}

const a = YONTEM["hizli-deneme"], b = YONTEM["uzun-degerlendirme"];
const kirilma = (b.bekleme - a.bekleme) * GUNLUK / (a.yanlis - b.yanlis);
console.log(`\nyontem kirilma noktasi: geri alma maliyeti ${kirilma.toFixed(1)} adam-gunu asinca` +
  ` uzun degerlendirme ucuzlar`);
console.log(`sinif esigi (MP8) ${ESIK}, kirilma noktasi ${kirilma.toFixed(1)}: iki sayi ayni degil`);

const politika = {
  "hepsine-hizli": () => "hizli-deneme",
  "hepsine-uzun": () => "uzun-degerlendirme",
  "esige-gore": (k) => (geriAlma(k) <= ESIK ? "hizli-deneme" : "uzun-degerlendirme"),
  "kirilmaya-gore": (k) => (geriAlma(k) <= kirilma ? "hizli-deneme" : "uzun-degerlendirme"),
};
console.log("\npolitika        | bekleme (gun) | beklenen maliyet (adam-gun)");
console.log("----------------|---------------|----------------------------");
for (const [ad, sec] of Object.entries(politika)) {
  let gun = 0, maliyet = 0;
  for (const k of KARAR) {
    const y = YONTEM[sec(k)];
    gun += y.bekleme;
    maliyet += y.bekleme * GUNLUK + y.yanlis * geriAlma(k);
  }
  console.log(`${ad.padEnd(15)} | ${String(gun).padStart(13)} | ${maliyet.toFixed(2).padStart(27)}`);
}
sinif           | karar | geri alma | hizli-deneme | uzun-degerlendirme | kazanan
----------------|-------|-----------|--------------|--------------------|--------
dondurulebilir  |     4 |        12 |         7.40 |              25.20 | hizli (fark 17.80)
dondurulemez    |     4 |        95 |        36.45 |              33.50 | uzun (fark 2.95)

yontem kirilma noktasi: geri alma maliyeti 20.8 adam-gunu asinca uzun degerlendirme ucuzlar
sinif esigi (MP8) 10, kirilma noktasi 20.8: iki sayi ayni degil

politika        | bekleme (gun) | beklenen maliyet (adam-gun)
----------------|---------------|----------------------------
hepsine-hizli   |            16 |                       43.85
hepsine-uzun    |           120 |                       58.70
esige-gore      |            68 |                       40.90
kirilmaya-gore  |            55 |                       38.70

İlk tablo dersin çekirdeğidir. Aynı iki yöntem, aynı ölçütle, iki sınıfta ters sonuç veriyor. Geri döndürülebilir sınıfta hızlı deneme 17,80 adam-gün daha ucuz; geri döndürülemez sınıfta uzun değerlendirme 2,95 adam-gün daha ucuz. Yöntemlerden biri ötekinden iyi değildir; sınıfa yanlış eşleştirilen yöntem kötüdür.

İki farkın büyüklüğü de eşit değil. Geri döndürülebilir kararlarda yanlış yöntemin cezası 17,80, geri döndürülemez kararlarda 2,95. Yani geri alınabilir bir karar için uzun değerlendirme yapmanın bedeli, geri alınamaz bir karar için hızlı denemenin bedelinden bu modelde daha büyüktür — çünkü uzun değerlendirmenin gecikme bedeli her karar için ödenir, geri alma maliyeti ise ancak karar yanlış çıkarsa.

Eşiğin Kaynağı Yeniden

Alt tablo dört politikayı aynı sekiz karar üzerinde koşturuyor. hepsine-uzun politikası hem en pahalı hem en yavaş: 58,70 adam-gün ve 120 gün bekleme. hepsine-hizli en hızlısı, 16 gün, ama maliyeti sınıfa göre ayıran politikalardan yüksek. İki sınıfı ayırmak, bekleme süresini hepsine-uzun politikasına göre 52 gün kısaltırken maliyeti de 17,80 adam-gün düşürüyor.

Ama iki eşik arasında bir uyuşmazlık var ve bu, ilk dersteki eşiğin kaynağı ölçüsünün burada karşımıza çıkışıdır. Sınıf eşiği 10 adam-gün olarak alındı; kaynağı bir sürüm döngüsünde geri alma için ayrılabilen kapasiteydi. Yöntem kırılma noktası ise 20,8 adam-gün: bu sayı seçilmedi, yöntemlerin bekleme süresi ve yanlışlık oranından türetildi. İkisi aynı olmadığı için esige-gore politikası odunc-kural-motoru kararını (geri alma 12) uzun değerlendirmeye gönderiyor, oysa o karar kırılma noktasının altında. kirilmaya-gore politikası aynı kararı hızlı denemeye gönderiyor ve hem 13 gün hem 2,20 adam-gün kazanıyor.

Buradan çıkan kural, sınıflandırmanın kendisinden daha dar ve daha kullanışlıdır: sınıf eşiği yöntemden türetilir, seçilmez. İki karar yönteminin bekleme süresi ve yanlışlık oranı yazıldığı anda eşik hesaplanabilir hale gelir. Kapasite gibi başka bir yerden gelen sayı eşik olarak kullanıldığında sınıflandırma yine bir şey kazandırır, ama kazandırabileceğinin altında kalır.

Özet

  • Bir kararın geri alma maliyeti histen değil bağımlılık kümesinden okunur: dolaşılan bileşen sayısı, yazılmış kayıtların göçü ve dışa açılmış arayüzün eşgüdümü.
  • Sekiz kararlık kümede toplam geri alma maliyetinin yüzde 88,8’i dört geri döndürülemez kararda toplandı; dolaşılan bileşen sayısı tek başına sınıfı belirlemiyor.
  • Aynı iki yöntem iki sınıfta ters sonuç verdi: geri döndürülebilir sınıfta hızlı deneme 17,80, geri döndürülemez sınıfta uzun değerlendirme 2,95 adam-gün daha ucuz.
  • Dört politika aynı küme üzerinde koşturulunca hepsine-uzun hem en pahalı hem en yavaş çıktı (58,70 adam-gün, 120 gün); sınıfa göre ayıran politika 40,90 adam-gün ve 68 güne indi.
  • Sınıf eşiği 10, yöntem kırılma noktası 20,8 idi; eşiği kırılma noktasından türeten politika 38,70 adam-gün ve 55 gün ile dördünün en iyisi oldu.
  • Eşik seçilmez, iki yöntemin bekleme süresi ve yanlışlık oranından hesaplanır.

Sonraki Adım

Buraya kadar ölçülen her şey mimarın masasında bitiyor: ağırlık, karmaşıklık payı, geri alma maliyeti, eşik. Sekiz kararın hiçbiri o masada uygulanmıyor. odunc-kaydi-bicimi kararının geri alma maliyeti 35 adam-gün olarak hesaplandı, ama bu sayının anlamı bütçeyi tutan birimde farklıdır, kayıt göçünü yapacak ekipte farklıdır, şubede iş yapan görevlide bambaşkadır. Hesap aynı kalır, karşı tarafın onu okuma biçimi değişir. Sonraki ders teknik olmayan muhataplarla kurulan iletişimi bir veri yapısına çevirir: aynı karar iki ayrı anlatımla aynı paydaşlara sunulduğunda sorulan soru ve onay için gereken tur sayı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