Ders 11 / 15
Uyumluluk Testi
Oluşturma motoru, platform ve ekran eksenlerinin çarpımıyla büyüyen matrisin ölçülmesi: özellik destek profillerinin ayrık sınıflara indirgenmesi, paya göre ve profile göre seçimlerin yakaladığı kusur farkı ve seçim ölçütünün eşikten daha belirleyici olması.
İçindekiler
Önceki 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ı destekler, farklı ekran genişlikleri farklı düzen kurar. Buraya kadarki bütün ölçümler tek bir ortamda yapıldı ve o ortamın temsil ettiği kullanıcı payı hiç sorulmadı.
Uyumluluk testi bu eksenlerin çarpımını bir matrise açar ve tek bir soruyu sorar: bu matrisin hangi alt kümesi koşulacak? Tümleşim, Sözleşme ve Uçtan Uca Test kursundaki aygıt–sürüm matrisi aynı aritmetiği aygıt ve işletim sürümü üzerinden kurmuştu; buradaki matrisin ekseni aygıt değil özellik destek profilidir ve seçim ölçütü kullanıcı payından değil profillerin ayrıklığından türer.
Matris ve Destek Profilleri
Üç oluşturma motoru, iki platform ve iki ekran sınıfı on iki ortam veriyor. Altı özelliğin her ortamdaki desteği bir vektördür; aynı vektörü taşıyan ortamlar özellik açısından ayırt edilemez.
IO14 (varsayım): ortam payları ölçülmüştür ve matris eksiksizdir. Listede olmayan bir ortam yoktur sayılır; bütün kapsama oranları bu on iki satıra görelidir.
// matris.mjs — uyumluluk matrisi, ozellik destek profilleri ve bilinen kusurlar export const OZELLIK = ["kalici depo", "gecis animasyonu", "izgara duzeni", "tarih bicimleyici", "gozlemci", "girdi onerisi"]; const MOTOR = { a: [1, 1, 1, 1, 1, 1], b: [1, 0, 0, 1, 1, 0], c: [1, 1, 1, 1, 0, 1] }; // Mobil platformda tarih bicimleyici (3. ozellik) hicbir motorda yok. export const profil = (o) => MOTOR[o.motor].map((v, i) => (i === 3 && o.platform === "mobil" ? 0 : v)).join(""); // Kullanici payi olculmus on iki ortam. export const ORTAM = [ { motor: "a", platform: "masaustu", ekran: "genis", pay: 42 }, { motor: "a", platform: "mobil", ekran: "dar", pay: 26 }, { motor: "b", platform: "masaustu", ekran: "genis", pay: 14 }, { motor: "c", platform: "mobil", ekran: "dar", pay: 9 }, { motor: "b", platform: "mobil", ekran: "dar", pay: 3 }, { motor: "c", platform: "masaustu", ekran: "genis", pay: 2 }, { motor: "a", platform: "masaustu", ekran: "dar", pay: 1.5 }, { motor: "a", platform: "mobil", ekran: "genis", pay: 1 }, { motor: "b", platform: "masaustu", ekran: "dar", pay: 0.7 }, { motor: "c", platform: "masaustu", ekran: "dar", pay: 0.4 }, { motor: "b", platform: "mobil", ekran: "genis", pay: 0.3 }, { motor: "c", platform: "mobil", ekran: "genis", pay: 0.1 }, ].map((o) => ({ ...o, ad: `${o.motor}-${o.platform}-${o.ekran}` })); // Elle dogrulanmis kusurlar ve gorunduklari ortam kosulu. export const KUSUR = [ ["K1 izgara duzeni cizilmiyor", (o) => o.motor === "b"], ["K2 tarih bicimi bos donuyor", (o) => o.platform === "mobil"], ["K3 gozlemci olmadan liste yenilenmiyor", (o) => o.motor === "c"], ["K4 masaustu duzeni dar ekranda tasiyor", (o) => o.platform === "masaustu" && o.ekran === "dar"], ["K5 kuyruk istemcisi mobilde baglanti kuramiyor", (o) => o.motor === "b" && o.platform === "mobil"], ["K6 mobil duzen genis ekranda dagiliyor", (o) => o.platform === "mobil" && o.ekran === "genis"], ]; // Saglam davranislar; kati dogrulama bunlari da kirmiziya cevirir. export const SAGLAM = [ ["Y1 gecis animasyonu atlaniyor", (o) => o.motor === "b"], ["Y2 menu dar ekranda katlaniyor", (o) => o.ekran === "dar"], ]; export const bulunan = (secim, liste) => liste.filter(([, k]) => secim.some(k)).length; export const kirmizi = (secim, liste) => secim.filter((o) => liste.some(([, k]) => k(o))).length;
Üç Seçim Ölçütü
// secim.mjs — matrisin buyuklugu, ayirt edici profiller ve uc secim olcutu import { ORTAM, OZELLIK, KUSUR, SAGLAM, profil, bulunan, kirmizi } from "./matris.mjs"; const profiller = [...new Set(ORTAM.map(profil))]; console.log(`${ORTAM.length} ortam, ${OZELLIK.length} ozellik, ${profiller.length} ayirt edici destek profili`); for (const p of profiller) { const uyan = ORTAM.filter((o) => profil(o) === p); console.log(` ${p} ${String(uyan.reduce((t, o) => t + o.pay, 0).toFixed(1)).padStart(5)}% ${uyan.map((o) => o.ad).join(", ")}`); } // (a) Paya gore: paydan buyukten kucuge, birikimli pay esige ulasana kadar. const payaGore = (esik) => { const s = []; for (const o of ORTAM) { if (s.reduce((t, x) => t + x.pay, 0) >= esik) break; s.push(o); } return s; }; // (b) Profile gore: her destek profilinden payi en buyuk ortam. const profileGore = profiller.map((p) => ORTAM.filter((o) => profil(o) === p)[0]); // (c) Profil ve duzen: (b) uzerine eksik kalan platform-ekran ciftleri eklenir. const cift = (o) => `${o.platform}-${o.ekran}`; const profilVeDuzen = [...profileGore]; for (const o of ORTAM) if (!profilVeDuzen.some((x) => cift(x) === cift(o))) profilVeDuzen.push(o); console.log(`\n${"secim".padEnd(18)}${"kosum".padStart(6)}${"pay".padStart(7)}${"profil".padStart(8)}${"kusur".padStart(7)}${"kirmizi kosum".padStart(15)}`); for (const [ad, s] of [["paya gore %90", payaGore(90)], ["profile gore", profileGore], ["profil ve duzen", profilVeDuzen], ["tam matris", ORTAM]]) { console.log(`${ad.padEnd(18)}${String(s.length).padStart(6)}${`${s.reduce((t, o) => t + o.pay, 0).toFixed(1)}%`.padStart(7)}` + `${`${new Set(s.map(profil)).size}/${profiller.length}`.padStart(8)}${`${bulunan(s, KUSUR)}/${KUSUR.length}`.padStart(7)}` + `${String(kirmizi(s, SAGLAM)).padStart(15)}`); } const kacan = KUSUR.filter(([, k]) => !payaGore(90).some(k)); console.log(`\npaya gore secimin kacirdiklari:`); for (const [ad] of kacan) console.log(` ${ad}`);
12 ortam, 6 ozellik, 6 ayirt edici destek profili 111111 43.5% a-masaustu-genis, a-masaustu-dar 111011 27.0% a-mobil-dar, a-mobil-genis 100110 14.7% b-masaustu-genis, b-masaustu-dar 111001 9.1% c-mobil-dar, c-mobil-genis 100010 3.3% b-mobil-dar, b-mobil-genis 111101 2.4% c-masaustu-genis, c-masaustu-dar secim kosum pay profil kusur kirmizi kosum paya gore %90 4 91.0% 4/6 3/6 3 profile gore 6 96.0% 6/6 4/6 4 profil ve duzen 8 98.5% 6/6 6/6 5 tam matris 12 100.0% 6/6 6/6 8 paya gore secimin kacirdiklari: K4 masaustu duzeni dar ekranda tasiyor K5 kuyruk istemcisi mobilde baglanti kuramiyor K6 mobil duzen genis ekranda dagiliyor
On iki ortam altı profile iniyor: özellik desteği açısından matris yarı yarıya küçük. Paya göre seçim dört koşumla kullanıcıların %91’ini kapsıyor ama altı profilin dördünü görüyor ve altı kusurun üçünü kaçırıyor. Kaçırdıklarının ortak özelliği ise ilginçtir: üçü de eksenlerin birleşiminden doğuyor. Masaüstü düzeninin dar ekranda taşması hiçbir motorun desteğiyle ilgili değil; iki eksenin birlikte aldığı bir değerle ilgili.
Profile göre seçim bu yüzden yeterli değil: altı koşumla bütün destek profillerini kapsıyor ama düzen kusurlarını hâlâ göremiyor, çünkü destek vektörü ekran sınıfını hiç taşımıyor. Sekiz koşumluk üçüncü seçim, eksik kalan platform–ekran çiftlerini ekleyerek altı kusurun altısını da buluyor — tam matrisin üçte ikisi kadar koşumla.
Eşik Taraması
Yaygın kural “kullanıcıların şu kadarını kapsa” biçiminde yazılır. Bu eşiğin ne kazandırdığı taranabilir.
// esik.mjs — kapsanan pay esigi taranir; yanlis gecme ve yanlis kalma sayilir import { ORTAM, KUSUR, SAGLAM, profil, bulunan, kirmizi } from "./matris.mjs"; const payaGore = (esik) => { const s = []; for (const o of ORTAM) { if (s.reduce((t, x) => t + x.pay, 0) >= esik) break; s.push(o); } return s; }; const profiller = new Set(ORTAM.map(profil)).size; console.log(`${"pay esigi".padEnd(10)}${"kosum".padStart(6)}${"kapsanan".padStart(10)}${"profil".padStart(8)}` + `${"yanlis gecme".padStart(14)}${"yanlis kalma".padStart(14)}${"maliyet w=5".padStart(12)}`); for (const e of [80, 90, 95, 99, 100]) { const s = payaGore(e); const gecme = KUSUR.length - bulunan(s, KUSUR), kalma = kirmizi(s, SAGLAM); console.log(`%${String(e).padEnd(9)}${String(s.length).padStart(6)}${`${s.reduce((t, o) => t + o.pay, 0).toFixed(1)}%`.padStart(10)}` + `${`${new Set(s.map(profil)).size}/${profiller}`.padStart(8)}${String(gecme).padStart(14)}${String(kalma).padStart(14)}` + `${String(kalma + 5 * gecme).padStart(12)}`); } // Profil ve duzen olcutuyle secilen kume ayni tabloya konur. const cift = (o) => `${o.platform}-${o.ekran}`; const s = [...new Set(ORTAM.map(profil))].map((p) => ORTAM.filter((o) => profil(o) === p)[0]); for (const o of ORTAM) if (!s.some((x) => cift(x) === cift(o))) s.push(o); const gecme = KUSUR.length - bulunan(s, KUSUR), kalma = kirmizi(s, SAGLAM); console.log(`\nprofil ve duzen olcutu: ${s.length} kosum, yanlis gecme ${gecme}, yanlis kalma ${kalma},` + ` maliyet ${kalma + 5 * gecme}`); console.log(`ayni maliyeti paya gore yakalamak icin gereken kosum: ${payaGore(99).length}`);
pay esigi kosum kapsanan profil yanlis gecme yanlis kalma maliyet w=5 %80 3 82.0% 3/6 4 2 22 %90 4 91.0% 4/6 3 3 18 %95 6 96.0% 6/6 2 4 14 %99 9 99.2% 6/6 0 6 6 %100 12 100.0% 6/6 0 8 8 profil ve duzen olcutu: 8 kosum, yanlis gecme 0, yanlis kalma 5, maliyet 5 ayni maliyeti paya gore yakalamak icin gereken kosum: 9
Yanlış geçme, seçimin dışında kalan ortamda duran gerçek kusurdur; yanlış kalma, sağlam ama farklı davranan bir ortamda katı doğrulamanın kırmızıya dönmesidir. İkisi ters yönde hareket ediyor: ortam ekledikçe kaçan kusur azalıyor, boşa kırmızı dönen koşum artıyor. Tam matris bile en iyi seçenek değil — sekiz kırmızı koşumun ikisi zaten kaçınılmaz gürültü.
Asıl sonuç son iki satırdadır. Paya göre seçim bütün kusurları ancak dokuz koşumla bulabiliyor; profil ve düzen ölçütü aynı sonucu sekiz koşumla veriyor ve maliyeti daha düşük. Eşiğin kaynağı burada bir ölçüm değil bir yanılgıdır: kapsanan kullanıcı payı sezgisel bir sayıdır ama kusurların dağılımıyla ilgisi yoktur. Kusur, kullanıcı payına göre değil ortam sınıfına göre dağılır ve seçim ölçütü eşikten daha belirleyicidir.
Kararın sahibi: matris dışında kalan her ortam bilinen bir boşluktur. Yayım kararı “tüm koşumlar yeşil” cümlesine değil, “şu kadar profil ve şu kadar düzen çifti koşuldu” cümlesine bağlanır; koşulmayan sınıflar kayda geçer.
Testin Bedeli
Koşumdan bağımsız bedel üç sayıdadır. Birincisi koşum sayısı: sekiz ortam, her biri kendi kurulumunu, kendi verisini ve kendi zamanını ister; bu sayı eksen eklendikçe çarpımsal büyür — bir eksene bir değer eklemek matrisi bir katına değil, bir çarpanına taşır.
İkincisi matrisin bakımı: destek vektörleri elle yazılmıştır ve bir motor bir özelliği desteklemeye başladığında profil sayısı değişir. Güncellenmeyen bir destek tablosu, ayırt edici saydığı iki ortamı boşuna koşturur ya da ayrı saymadığı iki ortamdan birini hiç koşturmaz.
Üçüncüsü kırmızı koşumların elenmesi: sekiz koşumun beşi kırmızı döndü ve bunların ikisi gerçek kusur değildi. Uyumluluk testinin kalıcı yükü budur — her ortam farkı kusur değildir ve farkı kusurdan ayıran şey kural değil karardır.
Özet
- Uyumluluk matrisi eksenlerin çarpımıdır; on iki ortam altı özellik üzerinden altı ayırt edici destek profiline indi ve matris özellik açısından yarıya küçüldü.
- Paya göre seçim dört koşumla kullanıcıların %91’ini kapsadı ama altı kusurun üçünü kaçırdı; kaçanların üçü de tek bir eksenden değil eksenlerin birleşiminden doğuyordu.
- Destek profili ekran sınıfını taşımadığı için profile göre seçim de yetmedi; profil ve düzen ölçütü sekiz koşumla altı kusurun altısını buldu — tam matrisin üçte ikisi kadar.
- Eşik taraması iki sütunu ters yönde hareket ettirdi: ortam eklendikçe yanlış geçme azaldı, yanlış kalma arttı. Tam matris bile en düşük maliyetli seçenek değildi.
- Kusurlar kullanıcı payına göre değil ortam sınıfına göre dağılır; seçim ölçütü kapsanan pay eşiğinden daha belirleyicidir.
- Bedel çarpımsaldır: her yeni eksen değeri matrisi bir çarpanla büyütür, destek tablosu elle bakım ister ve kırmızı koşumların bir bölümü her koşumda yeniden elenir.
Sonraki Adım
Bu konunun altı dersi aynı sistemi altı ayrı yöntemle sınadı ve altısı da ortak bir varsayımı paylaştı: sistemin parçaları çalışıyor. Statik tarama kodun metnine baktı, dinamik test koşan servise istek gönderdi, bağımlılık taraması kurulu sürümleri kayıtlarla eşleştirdi, sızma testi kuralların birleşimini sorguladı, erişilebilirlik denetimi çizilen ağacı okudu, uyumluluk testi aynı ekranı farklı ortamlarda koşturdu. Yük de saldırı da dışarıdan gelen bir baskıydı ve her ikisinde de sistemin kendisi ayaktaydı. Oysa ödünç servisinin bağlı olduğu veritabanı yanıt vermeyi bıraktığında, kuyruk istemcisi mesajı kaybettiğinde ya da katalog servisi yarım yanıt döndürdüğünde ne olacağı hiçbir derste sınanmadı. Sonraki konu baskıyı dışarıdan içeriye taşır: arıza sistemin kendi parçalarından birinde başlatılır ve sistemin bu arızayı nasıl karşıladığı ölçülür.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.