Ders 10 / 15
Erişilebilirlik Testi
Otomatik denetimin kapsama payının ölçülmesi: ölçütlerin karar kaynağına göre ayrılması, küçük bir öge ağacı üzerinde gerçekten koşan bir denetçinin yanlış alarm ve kaçırma sayıları ve eşiği yükseltmenin hiçbir kazanç getirmediği bir denetimde elle doğrulamanın zorunlu alanı.
İçindekiler
Dört ders sistemi kötüye kullanan bir istemciyi varsaydı. Aynı sorunun bir başka yüzü, sistemi kullanamayan bir okuyucudur: ekranı görmeyen, fareyi kullanmayan ya da metni büyüterek okuyan biri için ödünç ekranı çalışıyor mu?
Bu sorunun ölçütleri, arayüz tarafındaki karşılıkları ve otomatik denetleyicinin kural sınıfları Frontend Kalitesi kursunda kuruldu; burada tekrarlanmaz. Bu dersin sorusu bir test sorusudur ve erişilebilirlik denetiminin kendisini ölçer: kapsama payı. Ölçüt kümesinin kaçı bir programa yaptırılabilir, kaçı elle doğrulanmak zorundadır ve otomatik denetimin kendi yanlış alarm ile kaçırma oranı nedir? Ölçüm, tarayıcı çıktısı üzerinden değil, küçük bir belge modeli üzerinde yapılacak.
Belge Modeli ve Bilinen Kusurlar
Ödünç ekranının öge ağacı sekiz kusur taşıyor; kusurların yeri elle doğrulanmıştır.
// belge.mjs — odunc ekraninin oge agaci ve elle dogrulanmis kusur listesi export const BELGE = { tur: "sayfa", baslik: "Odunc Islemleri", dil: null, cocuk: [ { tur: "bolum", ad: "gezinme", cocuk: [ { tur: "baglanti", hedef: "/katalog", metin: "Katalog" }, { tur: "baglanti", hedef: "/odunc", metin: "Odunc" }, ] }, { tur: "bolum", ad: "ana", cocuk: [ { tur: "baslik", duzey: 1, metin: "Odunc Islemleri" }, { tur: "baslik", duzey: 3, metin: "Rafta Bekleyenler" }, { tur: "liste", cocuk: [ { tur: "satir", cocuk: [ { tur: "metin", metin: "Kum Saati" }, { tur: "eylem", kimlik: "al-1", metin: "", simge: "sepet", boyut: 40, odaklanabilir: true }, ] }, { tur: "satir", cocuk: [ { tur: "metin", metin: "Rafta Kalan" }, { tur: "eylem", kimlik: "al-2", metin: "Al", boyut: 40, odaklanabilir: true }, ] }, ] }, { tur: "alan", kimlik: "uye-no", tip: "metin", etiket: null }, { tur: "metin", metin: "Ceza: 30", renk: "#8a8a8a", zemin: "#ffffff" }, { tur: "eylem", kimlik: "gecmis", metin: "Gecmis", boyut: 40, odaklanabilir: true, edilgen: true, renk: "#9b9b9b", zemin: "#ffffff" }, ] }, ], }; // Elle dogrulanmis kusurlar: olcut kodu, yer ve kisa gerekce. // Edilgen "gecmis" eylemi karsitlik esiginden muaftir; listede yoktur. export const GERCEK = [ ["D1", "al-1", "sepet simgeli eylemin adi bos"], ["D2", "uye-no", "uye numarasi alaninin etiketi yok"], ["D3", "baslik 3", "birinci duzeyden ucuncu duzeye atlaniyor"], ["D5", "sayfa", "belge dil bildirimi tasimiyor"], ["D7", "Ceza: 30", "ceza metninin karsitligi esigin altinda"], ["D9", "-", "gecikme yalniz renk degisimiyle bildiriliyor"], ["D10", "-", "iki ayri islemi yapan eylem ayni adi tasiyor"], ["D11", "-", "odak sirasi gorsel sirayla uyusmuyor"], ]; export function* gez(d = BELGE) { yield d; for (const c of d.cocuk ?? []) yield* gez(c); }
Ölçütlerin Karar Kaynağı
Bir ölçütün otomatikleştirilip otomatikleştirilemeyeceğini belirleyen şey ölçütün önemi değil, kararın nereden okunduğudur. Dört kaynak var: ağaçtan doğrudan okunan bir bildirim, bildirilen değerlerden hesaplanan bir sayı, içeriğin ne anlattığına bağlı bir niyet ve zaman içindeki bir etkileşim dizisi. İlk ikisi bir programa yaptırılabilir, son ikisi yaptırılamaz.
// denetci.mjs — olcut kumesi, karar kaynaklari ve agactan karar verilebilen denetimler import { gez } from "./belge.mjs"; // karar kaynagi: agac | hesap (ikisi otomatik) | niyet | dizi (ikisi elle) export const OLCUT = [ ["D1", "eylem adi bos", "agac", 90], ["D2", "alan etiketsiz", "agac", 90], ["D3", "baslik duzeyi atlanmis", "agac", 70], ["D4", "kimlik yineleniyor", "agac", 90], ["D5", "dil bildirimi yok", "agac", 90], ["D6", "eylem odak almiyor", "agac", 90], ["D7", "karsitlik esigin altinda", "hesap", 60], ["D8", "dokunma hedefi kucuk", "hesap", 50], ["D9", "bildirim yalniz renkle", "niyet", 0], ["D10", "eylem adi anlamsiz", "niyet", 0], ["D11", "odak sirasi gorsel siraya uymuyor", "niyet", 0], ["D12", "pencereden klavyeyle cikilamiyor", "dizi", 0], ["D13", "degisim duyurusunun zamanlamasi", "dizi", 0], ["D14", "buyutulmus metinde icerik kaybi", "dizi", 0], ]; const kanal = (c) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4); const isik = (h) => { const [r, g, b] = [1, 3, 5].map((i) => kanal(parseInt(h.slice(i, i + 2), 16) / 255)); return 0.2126 * r + 0.7152 * g + 0.0722 * b; }; export const karsitlik = (on, arka) => { const [a, b] = [isik(on), isik(arka)].sort((x, y) => y - x); return (a + 0.05) / (b + 0.05); }; export function denetle(belge) { const bulgu = [], kimlikler = []; let onceki = 0; for (const d of gez(belge)) { if (d.tur === "sayfa" && !d.dil) bulgu.push({ olcut: "D5", yer: "sayfa" }); if (d.kimlik) kimlikler.push(d.kimlik); if (d.tur === "baslik") { if (onceki && d.duzey > onceki + 1) bulgu.push({ olcut: "D3", yer: `baslik ${d.duzey}` }); onceki = d.duzey; } if (d.tur === "eylem") { if (!d.metin) bulgu.push({ olcut: "D1", yer: d.kimlik }); if (!d.odaklanabilir) bulgu.push({ olcut: "D6", yer: d.kimlik }); if (d.boyut < 24) bulgu.push({ olcut: "D8", yer: d.kimlik }); } if (d.tur === "alan" && !d.etiket) bulgu.push({ olcut: "D2", yer: d.kimlik }); if (d.renk && d.zemin && karsitlik(d.renk, d.zemin) < 4.5) bulgu.push({ olcut: "D7", yer: d.kimlik ?? d.metin, oran: karsitlik(d.renk, d.zemin).toFixed(2) }); } const yineleyen = kimlikler.filter((k, i) => kimlikler.indexOf(k) !== i); for (const k of new Set(yineleyen)) bulgu.push({ olcut: "D4", yer: k }); return bulgu; }
IO13 (varsayım): karar kaynağı sınıflandırması ve elle doğrulanmış kusur listesi doğrudur. Kapsama payı bu iki listeye görelidir; ölçüt kümesi genişletildiğinde pay değişir.
Kapsama Payı ve Bulgular
// olcum.mjs — kapsama payi, bulgular ve esik taramasi import { BELGE, GERCEK } from "./belge.mjs"; import { OLCUT, denetle } from "./denetci.mjs"; const OTOMATIK = ["agac", "hesap"]; const oto = OLCUT.filter(([, , k]) => OTOMATIK.includes(k)); console.log(`${OLCUT.length} olcut; karar kaynagina gore dagilim:`); for (const k of ["agac", "hesap", "niyet", "dizi"]) { const n = OLCUT.filter(([, , x]) => x === k).length; console.log(` ${k.padEnd(7)}${String(n).padStart(3)} %${((100 * n) / OLCUT.length).toFixed(0)}`); } console.log(`kapsama payi: ${oto.length}/${OLCUT.length} = %${((100 * oto.length) / OLCUT.length).toFixed(0)}`); const puan = Object.fromEntries(OLCUT.map(([k, , , p]) => [k, p])); const ad = Object.fromEntries(OLCUT.map(([k, a]) => [k, a])); const gercekKume = new Set(GERCEK.map(([k, y]) => `${k}|${y}`)); const anahtar = (b) => `${b.olcut}|${b.yer}`; const bulgu = denetle(BELGE); const dogru = bulgu.filter((b) => gercekKume.has(anahtar(b))).length; console.log(`\n${bulgu.length} bulgu, ${GERCEK.length} elle dogrulanmis kusur, otomatik bulunan ${dogru}` + ` = %${((100 * dogru) / GERCEK.length).toFixed(0)}`); for (const b of bulgu) { console.log(` ${b.olcut} ${ad[b.olcut].padEnd(26)}${String(b.yer).padEnd(11)}` + `${String(puan[b.olcut]).padStart(3)} gercek: ${gercekKume.has(anahtar(b)) ? "evet" : "hayir"}` + `${b.oran ? ` (oran ${b.oran})` : ""}`); } console.log(`\n${"esik".padStart(4)}${"kalan".padStart(7)}${"yanlis alarm".padStart(14)}${"kacirma".padStart(9)}${"maliyet w=5".padStart(12)}`); for (const e of [50, 60, 70, 90]) { const k = bulgu.filter((b) => puan[b.olcut] >= e); const ya = k.filter((b) => !gercekKume.has(anahtar(b))).length; const kac = GERCEK.length - k.filter((b) => gercekKume.has(anahtar(b))).length; console.log(`${String(e).padStart(4)}${String(k.length).padStart(7)}${String(ya).padStart(14)}${String(kac).padStart(9)}${String(ya + 5 * kac).padStart(12)}`); } const otomatikKod = oto.map(([k]) => k); const elle = GERCEK.filter(([k]) => !otomatikKod.includes(k)); console.log(`\nhicbir esikte gorunmeyen ${elle.length} kusur (elle dogrulama alani):`); for (const [k, , g] of elle) console.log(` ${k} ${g}`);
14 olcut; karar kaynagina gore dagilim: agac 6 %43 hesap 2 %14 niyet 3 %21 dizi 3 %21 kapsama payi: 8/14 = %57 6 bulgu, 8 elle dogrulanmis kusur, otomatik bulunan 5 = %63 D5 dil bildirimi yok sayfa 90 gercek: evet D3 baslik duzeyi atlanmis baslik 3 70 gercek: evet D1 eylem adi bos al-1 90 gercek: evet D2 alan etiketsiz uye-no 90 gercek: evet D7 karsitlik esigin altinda Ceza: 30 60 gercek: evet (oran 3.45) D7 karsitlik esigin altinda gecmis 60 gercek: hayir (oran 2.78) esik kalan yanlis alarm kacirma maliyet w=5 50 6 1 3 16 60 6 1 3 16 70 4 0 4 20 90 3 0 5 25 hicbir esikte gorunmeyen 3 kusur (elle dogrulama alani): D9 gecikme yalniz renk degisimiyle bildiriliyor D10 iki ayri islemi yapan eylem ayni adi tasiyor D11 odak sirasi gorsel sirayla uyusmuyor
İki oran ayrı şeyleri söylüyor. Kapsama payı %57, ölçüt kümesinin bir programa yaptırılabilen bölümüdür ve belgeden bağımsızdır. Bulunan kusur oranı %63, bu belgedeki sekiz kusurun beşinin otomatik denetimle yakalandığını söyler ve belgeye bağlıdır: kusurlar başka bir dağılıma düşseydi bu oran değişirdi. İkinci sayı birinciden türetilemez.
Tek yanlış alarm karşıtlık hesabından geldi. Edilgen bir eylemin metin karşıtlığı eşiğin altında, ama edilgen denetimler bu eşikten muaftır ve denetçi bunu bilmiyor. Hesaplanan ölçütlerin ortak sorunu budur: sayı doğru, kural doğru, bağlam eksik.
Eşiği Yükseltmek Neden İşe Yaramıyor
Eşik taraması önceki üç dersten farklı bir sonuç veriyor. Orada eşiği yükseltmek yanlış alarmları düşürürken bazı gerçek kusurları kaçırıyordu ve arada bir en uygun nokta vardı. Burada eşiği yükseltmek tek bir yanlış alarmı düşürüyor, karşılığında iki gerçek kusuru kaçırıyor; maliyet monoton olarak artıyor. En düşük maliyet, taramanın en alt ucundadır.
Tablonun yanlış alarm sütunu yanlış kalma, kaçırma sütunu yanlış geçme sayısıdır; burada yanlış geçme hiçbir eşikte üçün altına inmiyor. Nedeni tablonun son üç satırındadır: kaçırılan üç kusur hiçbir eşikte görünmüyor, çünkü onlara karşılık gelen ölçütlerin puanı yok — programa yaptırılamıyorlar. Kaçırma burada eşik seçiminin sonucu değil, yöntemin yapısal sınırıdır. Bir gecikmenin yalnız renk değişimiyle bildirilmesi, aynı adı taşıyan iki eylemin ayrı işler yapması ve odak sırasının görsel sırayla uyuşmaması: üçü de ağaçta hiçbir bildirim eksikliği bırakmaz.
Bu yüzden bu denetimin eşiği bir puan değildir. Eşik ve kaynağı şöyle yazılır: yayın, otomatik denetimden sıfır bulgu ve elle doğrulama listesindeki altı ölçütün işaretlenmiş olması koşuluna bağlanır. Eşiğin kaynağı bu ölçümdür — sekiz kusurdan üçünün otomatik denetimde hiç görünmemesi, yalnız otomatik denetime dayanan bir kapının üç gerçek kusurla yeşil döneceğini gösterir.
Denetimin Bedeli
Koşumdan bağımsız bedel üç yerdedir. Otomatik yan ucuzdur: bir ağaç dolaşımı, on dört öge, sıfır süreç, sıfır istek; her değişiklikte koşturulabilir.
Elle doğrulama yanı ucuz değildir ve bedeli ekran başına ölçüt sayısıyla ölçülür: altı ölçüt, her ekran için ayrı ayrı. Ödünç sisteminin ekran sayısı arttıkça bu sayı doğrusal büyür ve otomatik denetimin aksine sürüm başına yeniden ödenir.
Üçüncü bedel sınıflandırmanın bakımıdır. Ölçütün karar kaynağı değişebilir: bugün niyet gerektiren bir kontrol, belge modeline yeni bir bildirim eklendiğinde ağaçtan okunabilir hâle gelir. Sınıflandırma güncellenmezse kapsama payı olduğundan düşük görünür ve elle doğrulama listesi gereğinden uzun kalır.
Kararın sahibi: otomatik bulgu yayımı durdurur; elle doğrulama listesi bir kontrol kaydıdır ve işaretlenmemiş bir ölçüt yayını durdurmaz, yalnız yayının hangi ölçütler sınanmadan çıktığını kayda geçirir.
Özet
- Bir ölçütün otomatikleştirilebilirliğini belirleyen şey kararın kaynağıdır: ağaçtan okunan bildirim ve hesaplanan değer otomatiktir, niyet ve etkileşim dizisi değildir.
- On dört ölçütün sekizi otomatik denetlenebilir (kapsama payı %57); bu belgedeki sekiz kusurun beşi otomatik bulundu (%63). İki oran ayrı şeyleri ölçer ve biri diğerinden türetilemez.
- Tek yanlış alarm hesaplanan bir ölçütten geldi: edilgen bir denetimin karşıtlığı eşiğin altındaydı ama o denetim eşikten muaftı — sayı doğru, bağlam eksikti.
- Kaçan üç kusur hiçbir eşikte görünmedi; kaçırma burada eşik seçiminin değil yöntemin sonucudur ve eşiği yükseltmek maliyeti tek yönde artırır.
- Eşik bir puan değil bir koşuldur: sıfır otomatik bulgu ve altı elle doğrulama ölçütünün işaretlenmesi. Kaynağı, yalnız otomatik denetime dayanan bir kapının üç gerçek kusurla yeşil döneceği ölçümüdür.
- Bedel: otomatik yan bir ağaç dolaşımı kadar ucuz, elle yan ekran başına altı ölçüt kadar pahalı ve her sürümde yeniden ödeniyor.
Sonraki Adım
Bu denetim tek bir belge modeli üzerinde koştu ve tek bir sonuç verdi. Oysa aynı ödünç ekranı her okuyucuda aynı ağacı üretmez: farklı oluşturma motorları aynı bildirimi farklı yorumlar, farklı ekran genişlikleri farklı düzen kurar, farklı giriş biçimleri farklı etkileşim sırası dayatır. Buraya kadarki bütün ölçümler tek bir ortamda yapıldı ve o ortamın temsil ettiği kullanıcı payı hiç sorulmadı. Sonraki ders ortam eksenlerini bir matrise açar, matrisin hangi alt kümesinin koşulacağını iki ayrı ölçütle seçer ve seçimin kapsadığı payı sayar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.