Ders 11 / 11
Tahmin ve Değerlendirme
İş büyüklüğü tahmininin ölçülmesi: aynı iş kümesinin tek sayı ve belirsizlik bandı olarak tahmin edilip gerçekleşmeyle karşılaştırılması, sapma dağılımının yüzdelikleri, bandın gerçek kapsama oranı ve tahmini parçalara bölmenin hem sapmayı hem yayılımı nasıl değiştirdiği.
İçindekiler
Önceki ders belgedeki iddianın kodla eşitlenmesini ölçtü. Buraya kadar ölçülen her şeyin ortak yanı, olmuş bir şeyi anlatmasıydı: verilen karar, çizilen sınır, koşan kod. Mimarın yazılı olarak verdiği bir şey daha var ve tek başına geleceğe bakıyor — bu iş ne kadar sürer.
Tahmin de bir belgedir ve bu kursun ölçüsü ona da uygulanır: hangi soruyu yanıtlıyor, hangi soruyu yanıtlayamıyor, sapması ne. Kabaca büyüklük hesabı Sistem Tasarımına Giriş kursunda kurulmuştu; orada hesaplanan büyüklük veri ve istek hacmiydi. Buradaki büyüklük iş büyüklüğüdür, birimi adam-gün, ve doğrulaması hacim hesabından farklıdır — hacim hesabı yaklaşık doğrulanır, iş tahmini gerçekleşmeyle tek tek karşılaştırılır.
İki Biçimde Tahmin
Aşağıdaki blok bir çeyreğin iş listesini, tahminlerin band biçimini ve gerçekleşme modelini modelleyerek tanımlar, sonra tek bir gerçekleşme koşturur. Gerçekleşme modeli iki sayıdan oluşur ve ikisi de görünürdür: sistematik iyimserlik ile kaleme özgü değişkenlik.
// tahmin.mjs — is kalemlerini, band kuralini ve gerceklesme modelini tanimlar; dogrudan // calistirildiginda tek bir gerceklesmeyi olcer. Sonraki iki blok bu dosyayi ithal eder. // GR21: bolgesel kutuphane agi sisteminin sonraki ceyrek is listesi; tahminler adam-gun. export const IS = [ ["sube tanim akisi", 5], ["katalog sarmalayici ucu", 8], ["odunc kayit gecisi", 13], ["uyelik dogrulama", 5], ["bildirim kanali", 3], ["ucret hesap kurallari", 8], ["rezervasyon sirasi", 13], ["rapor ekrani", 5], ["yedege gecis provasi", 8], ["toplu yukleme penceresi", 3], ["denetim betigi", 2], ["gorunum belgesi", 5], ]; // Band tek sayidan turetilir: alt sinir dortte uc, ust sinir bir buçuk kat. Tahmini veren, // bandin gerceklesmelerin onda dokuzunu kapsayacagini soyluyor. export const band = (t) => [Math.round(t * 0.75), Math.round(t * 1.5)]; // GR22: gerceklesme modeli. Gerceklesme = tahmin x 1.25 x exp(N(0, 0.45)). 1.25 sistematik // iyimserligi (tahminde gorunmeyen is), exp(N(0, 0.45)) kaleme ozgu bagimsiz degiskenligi // temsil eder. Iki sayi da modelin girdisidir; asagidaki butun sonuclar bunlara baglidir. export const IYIMSERLIK = 1.25; export const YAYILIM = 0.45; export const uretec = (tohum) => () => { // uretec kendi yazilmistir, tohum gorunur tohum = (tohum + 0x6d2b79f5) | 0; let t = Math.imul(tohum ^ (tohum >>> 15), 1 | tohum); t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; export const normal = (r) => { // Box-Muller: iki duzgun sayidan bir normal const u = Math.max(r(), 1e-12); return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * r()); }; export const carpan = (r) => IYIMSERLIK * Math.exp(YAYILIM * normal(r)); if (process.argv[1]?.endsWith("tahmin.mjs")) { const TOHUM = 60406; const r = uretec(TOHUM); console.log(`tohum ${TOHUM}; iyimserlik ${IYIMSERLIK}, yayilim ${YAYILIM}`); console.log(`${"is kalemi".padEnd(26)}${"tahmin".padStart(7)}${"band".padStart(10)}` + `${"gerceklesme".padStart(12)}${"oran".padStart(7)}${"band ici".padStart(10)}`); let toplamT = 0, toplamG = 0, ici = 0; for (const [ad, t] of IS) { const [alt, ust] = band(t); const g = Math.round(t * carpan(r) * 10) / 10; const icinde = g >= alt && g <= ust; toplamT += t; toplamG += g; ici += icinde ? 1 : 0; console.log(`${ad.padEnd(26)}${String(t).padStart(7)}${`${alt}-${ust}`.padStart(10)}` + `${g.toFixed(1).padStart(12)}${(g / t).toFixed(2).padStart(7)}` + `${(icinde ? "evet" : "hayir").padStart(10)}`); } const [pAlt, pUst] = band(toplamT); console.log(`toplam tahmin ${toplamT} gun, gerceklesme ${toplamG.toFixed(1)} gun, ` + `oran ${(toplamG / toplamT).toFixed(2)}`); console.log(`band ${IS.length} kalemin ${ici} tanesini kapsadi; proje toplami icin band ` + `${pAlt}-${pUst} gun ve gerceklesme ${toplamG >= pAlt && toplamG <= pUst ? "band ici" : "band disi"}`); }
tohum 60406; iyimserlik 1.25, yayilim 0.45 is kalemi tahmin band gerceklesme oran band ici sube tanim akisi 5 4-8 8.6 1.72 hayir katalog sarmalayici ucu 8 6-12 8.0 1.00 evet odunc kayit gecisi 13 10-20 12.2 0.94 evet uyelik dogrulama 5 4-8 5.6 1.12 evet bildirim kanali 3 2-5 1.5 0.50 hayir ucret hesap kurallari 8 6-12 8.3 1.04 evet rezervasyon sirasi 13 10-20 17.6 1.35 evet rapor ekrani 5 4-8 10.1 2.02 hayir yedege gecis provasi 8 6-12 5.0 0.63 hayir toplu yukleme penceresi 3 2-5 2.0 0.67 evet denetim betigi 2 2-3 3.9 1.95 hayir gorunum belgesi 5 4-8 1.2 0.24 hayir toplam tahmin 78 gun, gerceklesme 84.0 gun, oran 1.08 band 12 kalemin 6 tanesini kapsadi; proje toplami icin band 59-117 gun ve gerceklesme band ici
Tek koşumda proje toplamı 78 güne karşı 84 gün: yüzde sekiz sapma, band içinde. Kalem düzeyinde aynı tahmin çok daha kötü — on iki kalemin altısı bandın dışında ve iki kalemde oran 1,95 ile 2,02. Toplamdaki iyi görüntü kalem sapmalarının birbirini götürmesinden geliyor. Tek koşum kanıt değildir; aynı liste çok kez koşturulmalıdır.
Sapma Nasıl Dağılır
// dagilim.mjs — tahmin.mjs'i ithal eder; sapma dagilimini ve bandin kapsama oranini olcer import { IS, band, uretec, carpan } from "./tahmin.mjs"; const TOHUM = 31517; const KOSUM = 500; const r = uretec(TOHUM); const toplamT = IS.reduce((s, [, t]) => s + t, 0); const kalemOran = [], projeOran = []; let kalemIci = 0, projeIci = 0, altinda = 0; for (let k = 0; k < KOSUM; k += 1) { let toplamG = 0; for (const [, t] of IS) { const g = t * carpan(r); const [alt, ust] = band(t); kalemOran.push(g / t); if (g >= alt && g <= ust) kalemIci += 1; if (g < t) altinda += 1; toplamG += g; } projeOran.push(toplamG / toplamT); const [pAlt, pUst] = band(toplamT); if (toplamG >= pAlt && toplamG <= pUst) projeIci += 1; } const yuzdelik = (d, p) => [...d].sort((a, b) => a - b)[Math.floor((d.length - 1) * p)]; const satir = (ad, d) => `${ad.padEnd(16)}` + [0.1, 0.25, 0.5, 0.75, 0.9].map((p) => yuzdelik(d, p).toFixed(2).padStart(8)).join("") + `${(d.reduce((s, x) => s + x, 0) / d.length).toFixed(2).padStart(10)}`; console.log(`tohum ${TOHUM}, ${KOSUM} kosum; ${kalemOran.length} kalem gerceklesmesi`); console.log(`${"gerceklesme/tahmin".padEnd(16)}${"p10".padStart(8)}${"p25".padStart(8)}` + `${"medyan".padStart(8)}${"p75".padStart(8)}${"p90".padStart(8)}${"ortalama".padStart(10)}`); console.log(satir("kalem basina", kalemOran)); console.log(satir("proje toplami", projeOran)); console.log(`\nband kapsamasi: kalem basina ${((kalemIci / kalemOran.length) * 100).toFixed(0)}%, ` + `proje toplaminda ${((projeIci / KOSUM) * 100).toFixed(0)}% ` + `(tahmini veren onda dokuz, yani 90% demisti)`); console.log(`tahminin altinda kalan kalem: ${((altinda / kalemOran.length) * 100).toFixed(0)}%; ` + `ustunde kalan: ${(100 - (altinda / kalemOran.length) * 100).toFixed(0)}%`);
tohum 31517, 500 kosum; 6000 kalem gerceklesmesi gerceklesme/tahmin p10 p25 medyan p75 p90 ortalama kalem basina 0.71 0.92 1.25 1.68 2.23 1.38 proje toplami 1.13 1.23 1.36 1.51 1.67 1.38 band kapsamasi: kalem basina 54%, proje toplaminda 72% (tahmini veren onda dokuz, yani 90% demisti) tahminin altinda kalan kalem: 31%; ustunde kalan: 69%
Üç sonuç ayrı ayrı okunur. Birincisi, sapma dağılımı geniştir ve simetrik değildir: kalem başına p10 ile p90 arasında 0,71’den 2,23’e uzanan bir aralık var, yani onda birlik uçlar arasında üç kattan fazla fark. Kalemlerin yüzde 69’u tahmini aşıyor.
İkincisi, kalem medyanı ile proje toplamının merkezi aynı sayı değildir. Kalem başına medyan 1,25 iken proje toplamının medyanı 1,36, ortalaması 1,38. Neden farklı olduğu dağılımın biçiminden gelir: çarpan sağa çarpık olduğu için ortalaması medyanının üstündedir, ve on iki kalem toplandığında toplam ortalamaya yakınsar. Toplama, medyanı değil ortalamayı görünür kılar. Tek kaleme bakarak “genelde tahmini tutuyor” diyen biri, proje toplamında sistematik bir aşımla karşılaşır.
Üçüncüsü, bandın kapsama oranı, iddia edilenin çok altındadır. Tahmini veren bandın onda dokuz kapsayacağını söylemişti; ölçülen kapsama kalem başına yüzde 54, proje toplamında yüzde 72. Band yanlış değil, iddiası yanlış: bir aralık vermek onu bir güven düzeyine bağlamaz. Bandın kapsaması ancak gerçekleşmeyle karşılaştırılarak bilinir; bu yapılmadıkça band tek sayıdan yalnızca biçimce farklıdır.
Tahmini Bölmek
// bolme.mjs — tahmin.mjs'i ithal eder; tahmini parcalara bolmenin sapmaya etkisini olcer import { IS, band, uretec, normal, IYIMSERLIK, YAYILIM } from "./tahmin.mjs"; // GR23: bir kalem k parcaya bolununce iki sey degisir. Bir, gorunmeyen isin (1 - 1/k) payi // gorunur hale gelir ve tahmine eklenir. Iki, her parcanin degiskenligi bagimsiz cekilir, // yani k parcanin gerceklesmesi ortalamada birbirini dengeler. Gercek is her iki durumda ayni // modelden gelir: tahmin x 1.25 x degiskenlik. const bolunmusTahmin = (t, k) => t * (1 + (IYIMSERLIK - 1) * (1 - 1 / k)); const bolunmusGerceklesme = (t, k, r) => { let toplam = 0; for (let i = 0; i < k; i += 1) toplam += (t * IYIMSERLIK / k) * Math.exp(YAYILIM * normal(r)); return toplam; }; const TOHUM = 74113; const KOSUM = 500; const toplamT = IS.reduce((s, [, t]) => s + t, 0); const yuzdelik = (d, p) => [...d].sort((a, b) => a - b)[Math.floor((d.length - 1) * p)]; console.log(`tohum ${TOHUM}, ${KOSUM} kosum, ${IS.length} kalem`); console.log(`${"parca".padStart(6)}${"kalem tahmini".padStart(14)}${"p10".padStart(7)}` + `${"medyan".padStart(8)}${"p90".padStart(7)}${"p90/p10".padStart(9)}` + `${"band ici".padStart(10)}${"proje medyani".padStart(15)}`); for (const k of [1, 2, 4, 8]) { const r = uretec(TOHUM); const oran = [], projeOran = []; let ici = 0; for (let n = 0; n < KOSUM; n += 1) { let toplamG = 0, toplamE = 0; for (const [, t] of IS) { const e = bolunmusTahmin(t, k); const g = bolunmusGerceklesme(t, k, r); const [alt, ust] = band(e); oran.push(g / e); if (g >= alt && g <= ust) ici += 1; toplamG += g; toplamE += e; } projeOran.push(toplamG / toplamE); } const p10 = yuzdelik(oran, 0.1), p90 = yuzdelik(oran, 0.9); console.log(`${String(k).padStart(6)}` + `${(bolunmusTahmin(toplamT, k) / toplamT).toFixed(3).padStart(14)}` + `${p10.toFixed(2).padStart(7)}${yuzdelik(oran, 0.5).toFixed(2).padStart(8)}` + `${p90.toFixed(2).padStart(7)}${(p90 / p10).toFixed(2).padStart(9)}` + `${`${((ici / oran.length) * 100).toFixed(0)}%`.padStart(10)}` + `${yuzdelik(projeOran, 0.5).toFixed(2).padStart(15)}`); } console.log(`\nbolme iki sayiyi ayri yonde oynatir: gorunur hale gelen is tahmini`); console.log(`buyutur (kalem tahmini sutunu), bagimsiz parcalarin ortalamasi yayilimi`); console.log(`daraltir (p90/p10 sutunu).`);
tohum 74113, 500 kosum, 12 kalem
parca kalem tahmini p10 medyan p90 p90/p10 band ici proje medyani
1 1.000 0.70 1.24 2.19 3.14 54% 1.35
2 1.125 0.77 1.16 1.76 2.29 65% 1.21
4 1.188 0.83 1.13 1.52 1.82 84% 1.16
8 1.219 0.90 1.12 1.38 1.52 93% 1.13
bolme iki sayiyi ayri yonde oynatir: gorunur hale gelen is tahmini
buyutur (kalem tahmini sutunu), bagimsiz parcalarin ortalamasi yayilimi
daraltir (p90/p10 sutunu).
Bölmenin etkisi iki ayrı kanaldan geliyor ve ikisi de ölçülebiliyor. Birinci kanal tahmini büyütüyor: sekiz parçaya bölünen bir kalemin tahmini bölünmemiş hâlinin 1,219 katı, çünkü parça parça bakınca daha önce görünmeyen işin bir bölümü listeye giriyor. İkinci kanal yayılımı daraltıyor: bağımsız parçaların gerçekleşmeleri ortalamada birbirini dengeliyor, p90/p10 oranı 3,14’ten 1,52’ye iniyor.
İki kanal birlikte medyan sapmayı 1,24’ten 1,12’ye, proje medyanını 1,35’ten 1,13’e çekiyor ve bandın kapsamasını yüzde 54’ten yüzde 93’e çıkarıyor. Kazancın büyük bölümü ilk bölmelerde: bir parçadan dörde geçmek kapsamayı 30 puan artırıyor, dörtten sekize geçmek 9 puan. Bölmenin getirisi azalarak artar ve karşılığında her parça ayrıca tahmin edilmek zorundadır.
Bu ders üç soruluk bir kümeye yanıt arıyordu. “Bu iş ne kadar sürer” sorusunu tek sayı yanıtlıyor. “Ne kadar emin” sorusunu yalnız band yanıtlıyor, ama ancak kapsama oranı ölçülmüşse — ölçülmemiş bir band bu soruyu yanıtlıyor gibi görünüp yanıtlamaz. Üçüncü soru olan “bu tahmin neye dayanıyor” ikisinde de yanıtsız kalıyor. Bu, dördüncü dersteki eşiğin kaynağı boşluğunun aynısıdır: sayı yazılıyor, sayının nereden geldiği yazılmıyor.
Özet
- İş büyüklüğü tahmininin sapması gerçekleşmeyle tek tek karşılaştırılarak ölçülür; modelde kalem başına p10–p90 aralığı 0,71–2,23 ve kalemlerin yüzde 69’u tahmini aşıyor.
- Kalem medyanı ile proje toplamının merkezi ayrı sayılardır: kalem medyanı 1,25 iken proje toplamının medyanı 1,36 ve ortalaması 1,38 — toplama, medyanı değil ortalamayı görünür kılar.
- Bandın kapsama oranı iddia edilenden bağımsızdır: onda dokuz kapsayacağı söylenen band kalem başına yüzde 54, proje toplamında yüzde 72 kapsıyor; ölçülmemiş band tek sayıdan biçimce farklıdır.
- Bölme iki kanaldan çalışır: görünmeyen işin bir bölümünü tahmine ekleyerek tahmini 1,219 katına çıkarır, bağımsız parçaları ortalayarak p90/p10 oranını 3,14’ten 1,52’ye indirir.
- Sekize bölme medyan sapmayı 1,24’ten 1,12’ye, proje medyanını 1,35’ten 1,13’e çeker ve kapsamayı yüzde 93’e taşır; getiri azalarak artar, bire dörtten sonraki kazanç 9 puandır.
Kurs Kapanışı
Bu kurs bir kuralla yürüdü: bir belgenin değeri, sonradan gelen birinin sorduğu soruların kaçını yanıtladığıyla ölçülür. On bir dersin her biri kendi soru kümesini kurdu, o kümeyi bir kayıt, görünüm, diyagram, senaryo ya da tahmin üzerinde koşturdu ve yanıtlananla birlikte yanıtlanamayanı da saydı.
| Ders | Soru kümesi | Yanıtlanan / yanıtlanamayan | Bakım maliyeti ya da sapma |
|---|---|---|---|
| Mimari Karar Kayıtları | 4 karara sorulan 39 soru | kayıtsız 18/39, yapılandırılmış kayıtla 39/39 | 4 kayıt 101 satır, 170 dakika; sürenin %15’i hiçbir soruya yanıt vermeyen bölüme gitti |
| Öneri ve Değerlendirme Süreci | 8 karara sorulan küme | doğru yanıt 13, 32 ve 40; sözlü onayda 12 yanlış ve 15 eksik yanıt | çevrilen karar başına 440 ve 420 kişi-dakika; tek turlu düzen 900 kişi-dakikayı yön değiştirmeden harcadı |
| Ödünleşim Çözümlemesi | 5 çözümlemeye sorulan küme | kayıttaki hâliyle 2/5 yeniden üretilebildi, eksikler giderilince 5/5; doğrulanabilen 1 | tamamlama 110 dakika, kazanılan çözümleme başına 36,7 dakika |
| Risk Kaydı | gerçekleşen 2.348 risk | kayıtta hiç olmayan 808 risk (%34,4); doğru yanıt 16’dan 40,9’a, yanlış yanıt 6’dan 0,4’e | yıllık gözden geçirme dönem başına 1,26 risk; aylığa çıkınca yakalanan risk başına 602 kişi-dakika |
| Teknik Borç Yönetimi | 9 borç kalemi ve yıllık değişiklik kümesi | bilinçsiz 5 kalem 6.820, bilinçli 4 kalem 3.640 dakika; 48 tekrar eşiğinde bir yılda hiç fark edilmiyor | borçlu modülde aynı iş %63,7 fazla sürüyor; fark edilme gecikmesi 2,5 aydan 7,4 aya |
| Mimari Görünümler | 24 soru | 18 yanıtlanan / 6 yanıtlanamayan | 200 değişiklikte 279 yazım, 79’u yineleme; yanıt başına 15,50 yazım |
| Katmanlı Diyagram Yaklaşımı | 14 soru | kendi düzeyinde 14 yanıt / bağlam düzeyinde D03 ve ilk üç düzeyde D11 yanıtsız | 112 düğüm bakımda; 62 düğüm okuma yerine tek düzeyde 278, fark 4,24 turda geri ödeniyor |
| Diyagram Türünün Soruya Göre Seçilmesi | 18 soru | 16 yanıtlanan / 2 yanıtlanamayan | 150 değişiklikte 241 öge güncellemesi; yanıt başına bakım 2,8 ile 24,3 arasında |
| Kalite Nitelik Senaryoları | 12 gereksinime 5 soru, toplam 60 | 29 yanıtlanan / 31 yanıtlanamayan | yazım 1,85 kat; eşiği yazılmamış 9 gereksinim teslim başına 5,31 anlaşmazlık |
| Belgenin Güncel Kalması | 7 soru | üretilen denetimde 6 doğru / elle güncellemede 4 doğru ve 2 yanlış | sapma 2’den 10’a; denetim 10 güncelleme ve 6 yanlış alarm ödetiyor |
| Tahmin ve Değerlendirme | 3 soru | 2 yanıtlanan / 1 yanıtlanamayan (“bu tahmin neye dayanıyor”) | kalem medyanı 1,25 sapma; band kapsaması %54, bölmeyle %93 |
Tablo bir örüntü gösteriyor. Hiçbir ders soru kümesini tamamen kapatamadı ve bu bir kusur değil: yanıtlanamayan sorular her seferinde aynı iki sınıftan çıktı — ya iki ayrı görünümün bilgisini birleştirmeyi istediler, ya da bir sayının nereden geldiğini sordular. İkinci sınıf kursun başından sonuna kadar sürdü; karar kaydında “bu sayı nereden geldi”, nitelik senaryosunda “eşiğin kaynağı”, tahminde “bu tahmin neye dayanıyor” aynı boşluğun üç adıdır.
İkinci örüntü bakım maliyetinde: her ders bir belge biçiminin bedelini saydı, hiçbirinde bedel sıfır çıkmadı. Bir belgeyi güncel tutmanın maliyeti yazım anında değil, ondan sonraki her değişiklikte ödenir; bu yüzden bir belgenin değeri yalnız yanıtladığı soru sayısıyla değil, o sayının bakım maliyetine oranıyla anlamlıdır.
Bütün bu kayıtlar, görünümler, senaryolar ve tahminler tek bir sistemin içinde kaldı: bölgesel kütüphane ağının yazılım sistemi, kendi modülleri, kendi sınırları ve kendi belgesiyle. Oysa hiçbir sistem yalnız durmaz. Sistem bir kurumun içinde duruyor, yanında başka sistemler var ve onlarla veri alışverişi yapıyor. Sonraki kurs — Kurumsal Bağlam ve Tümleştirme — bu soruyla açılır: bir sistemin sınırı, o sistemin dışında kalanlarla kurduğu bağlar hesaba katıldığında nereden geçer.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.