İçeriğe geç
academia.sh

Ders 04 / 11

Kabul Ölçütleri

Tamamlanma tanımının bir veri yapısı olarak yazılması: kabul ölçütünün özne, ölçü ve sınır yuvaları, yuvayı kimin ne zaman doldurduğuna göre değişen geri dönüş sayısı ve keşif aşaması, ürün tarafının dikkatinin sınırlı bir bütçe olması ve kapanışta yazılan ölçütün gözlenen davranışı onaylaması.

İçindekiler

Önceki dersin keşifsel oturumu anlam-sapmasi sınıfında bulgular üretti, ama bu bulguların kusur olup olmadığı bir ölçüm sorusu değildi: sınayan kusur sayar, geliştiren beklenen davranış sayar, ürün tarafı ikisine de katılmaz. Böyle bir durumda kaçan hata sayısı bir ölçü değil bir anlaşmazlıktır.

Anlaşmazlığı ölçüye çeviren şey kabul ölçütüdür (acceptance criteria): bir iş kaleminin ne zaman bittiğini söyleyen, önceden yazılmış koşul. Kabul ölçütünün otomatik teste çevrilmesi Birim Testi ve Test Odaklı Geliştirme kursunda kurulmuştu; buradaki soru başkadır — ölçütü kim yazar ve ne zaman kapanır. Bu ders o iki soruyu bir bütçe dağıtımı olarak kurar; dağıtılan kaynak ürün tarafının dikkatidir ve ölçüsü geri dönüş, yani yeniden açılan iştir. (Dayanıklılık ve Güvenilirlik kursundaki geri dönüş bir devralmadan sonra asıl düğüme dönmektir; burada kastedilen, kapanmış sayılan bir işin yeniden açılmasıdır.)

Ölçütün Üç Yuvası

Bir kabul ölçütü üç yuva doldurur: özne neyin gözleneceğini, ölçü nasıl gözleneceğini, sınır hangi değerin kabul edildiğini söyler. Bir tamamlanma tanımı (definition of done) bu ölçütlerin tümünün karşılandığı durumdur. Üç yuvanın hepsi her ölçüt için gerekmez ve gerekliliği ölçütün türünden gelir: varlık ölçütü özne ile ölçü ister (“gecikme bildirimi gönderilir”), sayısal ölçüt sınırı da ister (“iade tarihinden beş gün sonra”), anlamsal ölçüt sınırı ister ve o sınırın gözlemden türetilmiş olmamasını ister (“bildirim ödüncü alan üyeye gider”).

Son madde bu dersin en keskin noktasıdır. Bir ölçüt kapanışta, sistemin gözlenen davranışına bakılarak yazılırsa sınır o davranışa eşitlenir; ölçüt hiçbir zaman kırmızı vermez, çünkü sınadığı şey kendi kaynağıdır.

TS15 (varsayım) — 20 iş kalemi, kalem başına 4 kabul ölçütü, toplam 80 ölçüt; tür dağılımı tohum 6060’tan gelir. Kusur kümesinin 60 kusuru kalemlere üçer üçer dağılır. TS16 (varsayım) — ürün tarafının ölçüt yazımına ayırabildiği süre ufuk boyunca 300 dakikadır; bir ölçüte bakması 12 dakika sürer. Bu, dağıtılan kaynaktır ve duyarlılığı taranır. TS17 (varsayım) — bir geri dönüşün bedeli açığa çıktığı aşamaya bağlıdır: yazım anında 5, geliştirme sırasında 20, kabul incelemesinde 60, sürümden sonra 180 dakika.

// kutuphane/kusurlar.mjs — birinci dersin kusur kumesi, aynen (tohum 20260731, 60 kusur,
// 14 sinif). Bu ders envanterin bedel sutunlarini kullanmaz, yalniz kusur kumesini kullanir.
const AGIRLIK = [["kural-siniri", 9], ["sema-uyusmazligi", 6], ["goc-veri-kaybi", 4],
  ["sozlesme-alani", 5], ["arayuz-durumu", 8], ["gorsel-sapma", 3], ["veri-buyumesi", 4],
  ["sql-birlestirme", 3], ["bilinen-acik", 3], ["erisilebilirlik", 4], ["bozulmus-yanit", 3],
  ["kurtarma-eksigi", 2], ["senaryo-disi", 5], ["anlam-sapmasi", 4]];
export function kusurlar(tohum, n) {
  let x = tohum;
  const rast = () => { x = (1103515245 * x + 12345) % 2147483648; return x / 2147483648; };
  const toplam = AGIRLIK.reduce((a, [, w]) => a + w, 0);
  const liste = [];
  for (let i = 1; i <= n; i += 1) {
    let p = rast() * toplam, sinif = AGIRLIK[AGIRLIK.length - 1][0];
    for (const [s, w] of AGIRLIK) { p -= w; if (p < 0) { sinif = s; break; } }
    liste.push({ no: i, sinif, olasilik: 1 + Math.floor(rast() * 5),
      etki: 1 + Math.floor(rast() * 5), duzeltme: 15 + 15 * Math.floor(rast() * 8) });
  }
  return liste;
}

Beş Politika

Beş politika ölçütü farklı ellere ve farklı anlara dağıtır. Eksik kalan bir yuva, onu dolduracak tarafın ölçüte ilk baktığı aşamada açığa çıkar: eksik sınırı ürün tarafı, eksik ölçüyü sınayan doldurur.

// kutuphane/olcut.mjs — kabul olcutunu uc yuvali bir veri yapisi olarak kurar ve olcutu
// kimin ne zaman yazdiginin geri donusunu olcer. Girdi: kutuphane/kusurlar.mjs
import { kusurlar } from "./kusurlar.mjs";

const IS = 20, BASINA = 4, TOHUM = 20260731, N = 60, URUNDK = 12, URUNBUTCE = 300;
const BEDEL = [5, 20, 60, 180];        // TS17: geri donusun asama basina dakikasi
const ASAMA = ["yazim ani", "gelistirme", "kabul incelemesi", "surumden sonra"];
let KAT = 6;                           // TS5: kacan hatanin duzeltme kati
const g = (x, n) => String(x).padStart(n);

// TS15: 20 is kalemi x 4 kabul olcutu = 80 olcut. Olcut turu gereken yuvalari belirler:
// varlik (ozne+olcu), sayisal (ozne+olcu+sinir), anlamsal (ucu de; sinir gozlemden turetilemez).
let x = 6060;
const r = () => { x = (1103515245 * x + 12345) % 2147483648; return x / 2147483648; };
const TUR = ["varlik", "sayisal", "anlamsal"];
const OLCUTLER = Array.from({ length: IS * BASINA }, (_, i) => { const p = r();
  return { no: i, kalem: Math.floor(i / BASINA), tur: TUR[p < 0.45 ? 0 : p < 0.8 ? 1 : 2] }; });
const GEREK = { varlik: ["ozne", "olcu"], sayisal: ["ozne", "olcu", "sinir"],
  anlamsal: ["ozne", "olcu", "sinir"] };

// Kusurlar kalemlere ucer ucer dagilir. Anlam sapmasi kusuru taniminca anlamsal bir olcutun
// altinda durur — onu kusur yapan sey koddaki bir kural degil, olcutun ne dedigidir; kalemde
// anlamsal olcut yoksa kalemin bir olcutu anlamsal olarak isaretlenir.
const KUSUR = kusurlar(TOHUM, N).map((k, i) => ({ ...k, kalem: Math.floor(i / (N / IS)) }));
const ANLAM = KUSUR.filter((k) => k.sinif === "anlam-sapmasi");
for (const k of ANLAM) {
  const kalemin = OLCUTLER.filter((o) => o.kalem === k.kalem);
  k.olcut = kalemin.find((o) => o.tur === "anlamsal")
    || Object.assign(kalemin[Math.floor(r() * kalemin.length)], { tur: "anlamsal" });
}

// Politika: her olcutte hangi yuvalarin doldugu, sinir yuvasini dolduran urun mu, sinirin
// gozlemden turetilip turetilmedigi ve eksigi kapatacak tarafin olcutu ilk okudugu asama.
function olc(ad, yuva, urunMu, gozlemden, urunOkuma, sinayanOkuma, yazim) {
  const durum = OLCUTLER.map((o) => {
    const dolu = yuva(o);
    const eksik = GEREK[o.tur].filter((y) => dolu.includes(y) === false);
    const yargilar = eksik.length === 0 && (o.tur !== "anlamsal" || gozlemden === false);
    return { ...o, yargilar, sinirli: dolu.includes("sinir"),
      asama: eksik.length ? urunOkuma : yargilar ? -1 : sinayanOkuma };
  });
  const acik = durum.filter((o) => o.yargilar === false);
  const kacan = ANLAM.filter((k) => durum[k.olcut.no].yargilar === false);
  const urunSaat = urunMu ? URUNDK * durum.filter((o) => o.sinirli).length : 0;
  return { ad, urunSaat, yazimDk: yazim * OLCUTLER.length + urunSaat,
    geri: acik.length, kalem: new Set(acik.map((o) => o.kalem)).size,
    donusDk: acik.reduce((a, o) => a + BEDEL[o.asama], 0),
    dagilim: [0, 1, 2, 3].map((s) => acik.filter((o) => o.asama === s).length),
    kacan: kacan.length, risk: kacan.reduce((a, k) => a + k.olasilik * k.etki, 0),
    duz: KAT * kacan.reduce((a, k) => a + k.duzeltme, 0) };
}
const IKI = ["ozne", "olcu"], UC = ["ozne", "olcu", "sinir"];
const P = () => [olc("Y1 gelistiren yazar, urun bakmaz", () => IKI, false, false, 2, 2, 5),
  olc("Y2 urun her olcute bakar, basta", () => UC, true, false, 0, 1, 5),
  olc("Y3 sinayan kapanista yazar", () => UC, false, true, 3, 2, 8),
  olc("Y4 olcut yok, tek satirlik tanim", () => [], false, false, 3, 3, 1),
  olc("Y5 urun yalniz anlamsal olcute bakar", (o) => (o.tur === "anlamsal" ? UC : IKI),
    true, false, 2, 2, 5)];
const toplam = (o) => o.yazimDk + o.donusDk + o.duz;
const sigan = (t) => { const u = P().map((o, i) => [t[i], o.urunSaat <= URUNBUTCE, i])
  .filter(([, s]) => s); return "Y" + (u.sort((a, b) => a[0] - b[0])[0][2] + 1); };

console.log(`${IS} is kalemi x ${BASINA} kabul olcutu = ${OLCUTLER.length} olcut (tohum 6060); tur: ` +
  TUR.map((t) => `${t} ${OLCUTLER.filter((o) => o.tur === t).length}`).join(", "));
console.log(`kusur kumesi tohum ${TOHUM}, ${N} kusur; ${ANLAM.length} anlam sapmasi, ` +
  `${ANLAM.reduce((a, k) => a + k.olasilik * k.etki, 0)} risk puani; ` +
  `${new Set(ANLAM.map((k) => k.kalem)).size} ayri is kaleminde`);
console.log(`TS16 urun butcesi ${URUNBUTCE} dk (olcut basina ${URUNDK} dk); ` +
  `TS17 geri donus: ` + ASAMA.map((a, i) => `${a} ${BEDEL[i]} dk`).join(", "));

console.log("\npolitika                               urun dk  butce  geri donus  kalem  kesif asamasi");
for (const o of P()) console.log(o.ad.padEnd(38) + g(o.urunSaat, 7) +
  g(o.urunSaat <= URUNBUTCE ? "sigar" : "asiyor", 7) + g(o.geri, 12) + g(o.kalem, 7) +
  "  " + (o.geri ? ASAMA[o.dagilim.indexOf(Math.max(...o.dagilim))] : "-"));

console.log("\nayni kusur kumesinde bedel");
console.log("politika                                yazim dk   donus dk   kacan  kacan risk   duzeltme dk   toplam dk");
for (const o of P()) console.log(o.ad.padEnd(38) + g(o.yazimDk, 9) + g(o.donusDk, 11) +
  g(o.kacan, 8) + g(o.risk, 12) + g(o.duz, 14) + g(toplam(o), 12));

console.log("\nurun butcesi TS16'nin duyarliligi — urun once anlamsal, sonra sayisal olcute bakar");
console.log("urun dk   bakilan olcut   geri donus   kacan   toplam dk");
const sira = [...OLCUTLER].sort((a, b) => TUR.indexOf(b.tur) - TUR.indexOf(a.tur));
for (const b of [0, 204, 300, 960]) {
  const kume = new Set(sira.slice(0, Math.floor(b / URUNDK)).map((o) => o.no));
  const o = olc("", (t) => (kume.has(t.no) ? UC : IKI), true, false, 2, 2, 5);
  console.log(g(b, 7) + g(kume.size, 16) + g(o.geri, 13) + g(o.kacan, 8) + g(toplam(o), 12));
}

console.log("\nTS5'in duyarliligi: kacan hatanin kati degisirse hangi politika en ucuz");
console.log("kat   " + ["Y1", "Y2", "Y3", "Y4", "Y5"].map((a) => g(a, 8)).join("") +
  "   en ucuz   butceye sigan en ucuz");
for (const kat of [1, 6, 20]) {
  KAT = kat;
  const t = P().map(toplam);
  console.log(g(kat, 3) + t.map((n) => g(n, 8)).join("") +
    g("Y" + (t.indexOf(Math.min(...t)) + 1), 10) + g(sigan(t), 22));
}
20 is kalemi x 4 kabul olcutu = 80 olcut (tohum 6060); tur: varlik 34, sayisal 29, anlamsal 17
kusur kumesi tohum 20260731, 60 kusur; 6 anlam sapmasi, 60 risk puani; 5 ayri is kaleminde
TS16 urun butcesi 300 dk (olcut basina 12 dk); TS17 geri donus: yazim ani 5 dk, gelistirme 20 dk, kabul incelemesi 60 dk, surumden sonra 180 dk

politika                               urun dk  butce  geri donus  kalem  kesif asamasi
Y1 gelistiren yazar, urun bakmaz            0  sigar          46     20  kabul incelemesi
Y2 urun her olcute bakar, basta           960 asiyor           0      0  -
Y3 sinayan kapanista yazar                  0  sigar          17     14  kabul incelemesi
Y4 olcut yok, tek satirlik tanim            0  sigar          80     20  surumden sonra
Y5 urun yalniz anlamsal olcute bakar      204  sigar          29     19  kabul incelemesi

ayni kusur kumesinde bedel
politika                                yazim dk   donus dk   kacan  kacan risk   duzeltme dk   toplam dk
Y1 gelistiren yazar, urun bakmaz            400       2760       6          60          2970        6130
Y2 urun her olcute bakar, basta            1360          0       0           0             0        1360
Y3 sinayan kapanista yazar                  640       1020       6          60          2970        4630
Y4 olcut yok, tek satirlik tanim             80      14400       6          60          2970       17450
Y5 urun yalniz anlamsal olcute bakar        604       1740       0           0             0        2344

urun butcesi TS16'nin duyarliligi — urun once anlamsal, sonra sayisal olcute bakar
urun dk   bakilan olcut   geri donus   kacan   toplam dk
      0               0           46       6        6130
    204              17           29       0        2344
    300              25           21       0        1960
    960              80            0       0        1360

TS5'in duyarliligi: kacan hatanin kati degisirse hangi politika en ucuz
kat         Y1      Y2      Y3      Y4      Y5   en ucuz   butceye sigan en ucuz
  1    3655    1360    2155   14975    2344        Y2                    Y3
  6    6130    1360    4630   17450    2344        Y2                    Y5
 20   13060    1360   11560   24380    2344        Y2                    Y5

Kâğıt Üzerindeki En Ucuz Politika Bütçede Yok

Y2 her ölçütü ürün tarafıyla birlikte yazar ve tabloda hiçbir geri dönüş üretmez: 1.360 dakikayla beş politikanın en ucuzudur. Ama ürün sütunu 960 dakika der, TS16’nın bütçesi 300 — politika uygulanamaz. Beş satırın en iyisi bir seçenek değildir; bir üst sınırdır.

Bütçeye sığanlar arasında Y5 öne çıkar: ürün tarafı yalnız on yedi anlamsal ölçüte bakar, 204 dakika harcar ve kaçan hatayı sıfıra indirir. Y1 aynı bütçeyi hiç kullanmaz ve altı kusuru sürüme geçirir; toplam bedeli 6.130 dakika, Y5’in 2,6 katı. Aradaki fark 204 dakikalık bir dikkatin nereye konduğudur.

Ürün bütçesi taraması bu dağıtımın biçimini verir. İlk 204 dakika kaçan hatanın tamamını kaldırır (6 → 0), çünkü o dakikalar anlamsal ölçütlere gider. Kalan 756 dakika bir kusur daha kurtarmaz; yalnız geri dönüşü 29’dan 0’a indirir ve toplamı 2.344’ten 1.360’a çeker. Aynı kaynağın ilk parçası ile son parçası farklı şeyler satın alır: ilk parça kaçan hatayı, son parça geri dönüşü.

Kapanışta Yazılan Ölçüt

Y3 tabloda makul görünür: ürün bütçesi harcamaz, yalnız on yedi geri dönüş üretir, 4.630 dakikayla Y1’den ucuzdur. Yine de altı kusuru sürüme geçirir. Nedeni ölçütün eksik olması değil — üç yuvası da doludur. Nedeni sınırın gözlemden türetilmiş olmasıdır: sınayan kapanışta, çalışan sistemi izleyerek ölçüt yazar ve sistemin yaptığını kabul edilebilir olarak kaydeder. Ölçüt kırmızı vermez, çünkü sınadığı davranışın kendisinden türemiştir. Yazılmış ölçüt sayısı bir kalite göstergesi değildir; ölçütün kaynağı göstergedir.

Y4 ölçütü hiç yazmaz ve seksen ölçütün seksenini sürümden sonra tartışmaya bırakır: 14.400 dakikalık geri dönüş, yirmi kalemin yirmisi yeniden açılır. Keşif aşaması sütunu bu politikayı ötekilerden ayıran tek şeydir — sayı değil, an. Aynı anlaşmazlık kabul incelemesinde 60, sürümden sonra 180 dakikaya mal olur.

Kararın Geri Dönüşü

Bu derste kararın geri dönüşü doğrudan ölçülen niceliktir. Y1 yirmi kalemin yirmisini yeniden açar, Y5 on dokuzunu, Y3 on dördünü, Y2 hiçbirini. Yeniden açılan kalem sayısı politikalar arasında az değişir; değişen, açılmanın hangi aşamada olduğu ve kaç kusurun sürüme geçtiğidir.

TS5 taraması kararı bir bağlama bağlar. Kaçan hatanın düzeltmesi yakalanmışla eşitse (kat 1) bütçeye sığan en ucuz politika Y3’tür — kapanışta yazılan ölçüt, kusur ucuzken savunulabilir. Kat 6 ve 20’de Y5 kazanır ve arayı açar. Yani ölçütü kimin yazacağı sorusunun cevabı, kaçan bir kusurun ekibe neye mal olduğuna bağlıdır; o sayı bilinmeden politika seçilemez.

Özet

  • Kabul ölçütü üç yuvadır: özne, ölçü, sınır. Ölçütün türü hangi yuvaların gerekli olduğunu belirler; anlamsal ölçüt ayrıca sınırın gözlemden türetilmemiş olmasını ister.
  • Ürün tarafının dikkati sınırlı bir kaynaktır (TS16, 300 dakika); her ölçüte bakan politika 960 dakika ister ve bütçeye sığmaz — tablodaki en ucuz satır bir seçenek değil, üst sınırdır.
  • Aynı bütçenin ilk 204 dakikası kaçan hatanın tamamını kaldırır, kalan 756 dakika yalnız geri dönüşü azaltır; bir kaynağın ilk ve son parçası farklı şeyler satın alır.
  • Kapanışta yazılan ölçüt üç yuvasını doldurur ama sınırı gözlenen davranıştan aldığı için kırmızı vermez ve altı kusuru sürüme geçirir.
  • Ölçüt hiç yazılmadığında anlaşmazlık kaybolmaz, yalnız aşaması kayar: aynı geri dönüş kabul incelemesinde 60, sürümden sonra 180 dakikadır.
  • Politika seçimi kaçan hatanın katına bağlıdır: kat 1’de kapanışta yazım, kat 6 ve 20’de hedefli ürün dikkati bütçeye sığan en ucuz seçenektir.

Sonraki Adım

Buradaki bütün ölçütleri ekibin içindeki taraflar yazdı: geliştiren, sınayan, ürün. Üçü de sistemi tasarlayan tarafta duruyor ve üçü de aynı sözlüğü kullanıyor. Oysa ölçütün sonunda karşılanması gereken beklenti ekibin dışındadır ve o beklenti hiçbir yuvaya yazılmadı — kütüphane görevlisinin bir ödünç işlemini kaç adımda bitirmeyi beklediği, bir üyenin gecikme bildirimini ne zaman anlamlı bulduğu. Sonraki ders bu doğrulamayı yönetir: kabul kapsamının kullanıcı görevlerine nasıl dağıtılacağı, dönen geri bildirimin kusur ile istek ile yanlış anlama arasında nasıl ayrılacağı ve her sınıfın ekibe neye mal olduğu.

İ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