İçeriğe geç
academia.sh

Ders 12 / 15

Mobil Otomasyonu

Aygıt ve sürüm eksenlerinin çarpımıyla büyüyen koşum matrisinin ölçülmesi; kullanıcı payına göre ve kapsamaya göre seçilen alt kümelerin kapsadığı pay ile yakaladıkları kusur sınıflarının karşılaştırılması ve emülatörün taşıdığı boyutun sınırı.

İçindekiler

Önceki dersin bütün ölçümleri tek bir sayfa modeli üzerindeydi: tek ağaç, tek zaman çizelgesi. Ödünç akışının mobil arayüzü ise tek bir yerde koşmaz. Aynı ekran bir avuç aygıt sınıfında ve birden çok işletim sistemi sürümünde açılır, ve testin sorusu artık “hangi seçici dayanıklı” değil, “hangi aygıtlarda koşacağım” olur.

Bu ders gerçek aygıt ya da emülatör kurmaz. Ölçülen şey aygıtın kendisi değil seçim kararıdır: matrisin ne kadar hızlı büyüdüğü, seçilen alt kümenin kaç kullanıcıyı temsil ettiği ve kapsam dışında kalan kusur sınıfının ne olduğu. Üçü de sayılabilir.

Matris ve İki Seçim Ölçütü

Model girdisi açıkça yazılır. MB1 — altı aygıt sınıfı ve beş işletim sistemi sürümü; paylar üye oturumlarından ölçülmüş kabul edilir ve her eksende toplamları yüzdür; iki eksen bağımsız varsayılır. Bağımsızlık varsayımı gerçek kurulumlarda geçerli değildir (eski sürümler eski aygıtlarda yoğunlaşır); orada hücre payı doğrudan ölçülür ve aşağıdaki hesap aynı biçimde çalışır.

// matris.mjs — aygit-surum matrisi ve iki alt kume secimi
export const aygitlar = [
  ['kucuk', 22], ['orta', 26], ['buyuk', 18], ['katlanir', 6], ['tablet', 12], ['eski', 16],
];
export const surumler = [['S-6', 4], ['S-7', 9], ['S-8', 17], ['S-9', 31], ['S-10', 39]];

export const hucreler = aygitlar.flatMap(([aygit, ap]) =>
  surumler.map(([surum, sp]) => ({ aygit, surum, pay: (ap * sp) / 100 })));

export const payaGore = (k) => [...hucreler].sort((a, b) => b.pay - a.pay).slice(0, k);

export function kapsamayaGore(k) {
  const secilen = [];
  const gorulen = { aygit: new Set(), surum: new Set() };
  while (secilen.length < k) {
    const kalan = hucreler.filter((h) => secilen.includes(h) === false);
    const kazanc = (h) => (gorulen.aygit.has(h.aygit) ? 0 : 1) + (gorulen.surum.has(h.surum) ? 0 : 1);
    kalan.sort((a, b) => kazanc(b) - kazanc(a) || b.pay - a.pay);
    const secim = kalan[0];
    gorulen.aygit.add(secim.aygit);
    gorulen.surum.add(secim.surum);
    secilen.push(secim);
  }
  return secilen;
}

export const altKumeler = { paya: payaGore(6), kapsamaya: kapsamayaGore(6) };

İki ölçüt farklı şeyi eniyiler. Paya göre seçim en çok kullanıcının bulunduğu hücreleri alır. Kapsamaya göre seçim her adımda henüz görülmemiş bir aygıt sınıfı ya da sürüm kazandıran hücreyi tercih eder, eşitlikte paya bakar. Altışar hücre seçilir ve üç kusur sınıfı için yakalama sayılır: sürüme bağlı kusur alt kümede o sürüm varsa, aygıt sınıfına bağlı kusur o sınıf varsa, tek hücreye özgü kusur ise yalnız o hücre seçildiyse yakalanır.

// kapsama.mjs — iki secimin kullanici payi ve kusur yakalama orani
import { aygitlar, surumler, hucreler, altKumeler } from './matris.mjs';

const oran = (secilen) => {
  const aygit = new Set(secilen.map((h) => h.aygit));
  const surum = new Set(secilen.map((h) => h.surum));
  return {
    pay: secilen.reduce((t, h) => t + h.pay, 0),
    surumKusuru: `${surum.size}/${surumler.length}`,
    aygitKusuru: `${aygit.size}/${aygitlar.length}`,
    hucreKusuru: `${secilen.length}/${hucreler.length}`,
  };
};

const s = (n, g) => String(n).padStart(g);
console.log(`${'secim'.padEnd(16)}${s('hucre', 6)}${s('kullanici payi', 16)}${s('surum kusuru', 14)}${s('aygit kusuru', 14)}${s('hucre kusuru', 14)}`);
for (const [ad, secilen] of [['paya gore', altKumeler.paya], ['kapsamaya gore', altKumeler.kapsamaya]]) {
  const o = oran(secilen);
  console.log(`${ad.padEnd(16)}${s(secilen.length, 6)}${s(`%${o.pay.toFixed(1)}`, 16)}${s(o.surumKusuru, 14)}${s(o.aygitKusuru, 14)}${s(o.hucreKusuru, 14)}`);
}
console.log(`matris ${aygitlar.length} aygit x ${surumler.length} surum = ${hucreler.length} hucre;`
  + ` bir surum eklenirse ${hucreler.length + aygitlar.length}, bir aygit eklenirse ${hucreler.length + surumler.length}`);
console.log('paya gore secilen:', altKumeler.paya.map((h) => `${h.aygit}/${h.surum}`).join(' '));
console.log('kapsamaya gore secilen:', altKumeler.kapsamaya.map((h) => `${h.aygit}/${h.surum}`).join(' '));
secim            hucre  kullanici payi  surum kusuru  aygit kusuru  hucre kusuru
paya gore            6           %46.9           2/5           4/6          6/30
kapsamaya gore       6           %24.3           5/5           6/6          6/30
matris 6 aygit x 5 surum = 30 hucre; bir surum eklenirse 36, bir aygit eklenirse 35
paya gore secilen: orta/S-10 kucuk/S-10 orta/S-9 buyuk/S-10 kucuk/S-9 eski/S-10
kapsamaya gore secilen: orta/S-10 kucuk/S-9 buyuk/S-8 eski/S-7 tablet/S-6 katlanir/S-10

Sayılar takası açık ediyor. Paya göre seçim kullanıcıların yüzde kırk altı virgül dokuzunu temsil ediyor, ama beş sürümün yalnız ikisine ve altı aygıt sınıfının dördüne dokunuyor; seçtiği altı hücrenin üçü aynı sürümde. Kapsamaya göre seçim temsil ettiği payı yarıya indiriyor, buna karşılık her sürüme ve her aygıt sınıfına bir kez giriyor. Hücreye özgü kusurda ikisi eşit ve ikisi de zayıftır: otuz hücrenin altısı, yani beşte biri.

Matrisin büyümesi bu kararı her yıl yeniden açar. Yeni bir sürüm çıktığında matris otuzdan otuz altıya, yeni bir aygıt sınıfı girdiğinde otuz beşe gider; alt küme altı hücrede kalırsa hücre kapsaması beşte birden altıda bire düşer. Koşum bütçesi doğrusal artarken matris çarpımsal büyür, ve bu yüzden mobil koşumun sorusu hiçbir zaman “hepsini koşalım” olamaz.

Emülatörün Taşıdığı Boyut

Kapsama tablosu bir varsayım taşıyor: seçilen hücrenin gerçekten o aygıt sınıfında koştuğu. Emülatör (emulator) bu varsayımı yalnız yarısında karşılar. Emülatör işletim sistemi sürümünü gerçekten çalıştırır — sürüme bağlı kusurları taşır. Aygıt sınıfına bağlı olan şeyi ise taşımaz: dokunma yüzeyinin gerçek boyutu, bellek sınırı, ağ kesintisi, kamera ve sensör, üreticinin arayüz katmanı.

Bunun aritmetiği doğrudan tabloya işler. Kapsamaya göre seçilen altı hücrenin tamamı emülatörde koşulursa aygıt sınıfına bağlı kusur yakalaması altıda altıdan sıfıra iner; sürüme bağlı yakalama beşte beş kalır. İki hücre bir aygıt havuzunda (device farm) gerçek donanıma ayrılırsa aygıt yakalaması altıda ikiye çıkar. Karar bu yüzden “emülatör mü gerçek aygıt mı” değildir; hangi kusur sınıfının hangi hücrede aranacağıdır.

Yakaladığı Kusur: Sürüme Bağlı Ayrıştırma

Ödünç akışının sonunda üyeye bir iade tarihi gösterilir. Tarih metnini üreten taraf uygulamadır, okuyan taraf ise platformun tarih ayrıştırıcısıdır ve bu ayrıştırıcının davranışı sürüme göre değişir: eski sürümler yalnız sıralı biçimi kabul eder.

// platform.mjs — tarih ayristirmanin surume gore degisen davranisi
const AYRISTIRICI_GENIS = new Set(['S-9', 'S-10']);

export function tarihAyristir(surum, metin) {
  if (/^\d{4}-\d{2}-\d{2}$/.test(metin)) return metin;
  if (AYRISTIRICI_GENIS.has(surum) && /^\d{2}\.\d{2}\.\d{4}$/.test(metin)) {
    const [gun, ay, yil] = metin.split('.');
    return `${yil}-${ay}-${gun}`;
  }
  return null;
}
// iade.mjs — surum 1: iade tarihi yerel bicimde uretiliyor
export function iadeTarihi(oduncTarihi, gun = 14) {
  const t = new Date(`${oduncTarihi}T00:00:00Z`);
  t.setUTCDate(t.getUTCDate() + gun);
  const iki = (n) => String(n).padStart(2, '0');
  return `${iki(t.getUTCDate())}.${iki(t.getUTCMonth() + 1)}.${t.getUTCFullYear()}`;
}

Aynı akış iki alt kümede de koşturulur; her hücre için üretilen tarihin o sürümde okunup okunmadığı sınanır.

// aygit.test.mjs — iade tarihi akisi secilen alt kumelerde kosar
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { altKumeler } from './matris.mjs';
import { tarihAyristir } from './platform.mjs';
import { iadeTarihi } from './iade.mjs';

const kos = (secilen) => {
  for (const hucre of secilen) {
    const metin = iadeTarihi('2026-03-04');
    assert.equal(tarihAyristir(hucre.surum, metin), '2026-03-18',
      `${hucre.aygit}/${hucre.surum} iade tarihini okuyamadi: ${metin}`);
  }
};

test('paya gore secilen alt kumede iade tarihi okunur', () => kos(altKumeler.paya));

test('kapsamaya gore secilen alt kumede iade tarihi okunur', () => kos(altKumeler.kapsamaya));
node --test --test-reporter=tap aygit.test.mjs | grep -E '^ *(ok|not ok|# (tests|pass|fail))'
ok 1 - paya gore secilen alt kumede iade tarihi okunur
not ok 2 - kapsamaya gore secilen alt kumede iade tarihi okunur
# tests 2
# pass 1
# fail 1

Kusur birdir, alt küme ikidir ve sonuç ikiye ayrılır. Kapsamaya göre seçilen alt küme S-6, S-7 ve S-8 hücrelerini taşıdığı için kırmızıya döndü. Paya göre seçilen alt küme aynı kusurla yeşil kaldı: içinde yalnız S-9 ve S-10 var, ikisi de yerel biçimi kabul ediyor. Kaçan sınıf burada bir test biçiminin değil, bir seçimin kaçırdığı sınıftır ve kaçırılan kullanıcılar da sayılabilir: S-6 ile S-8 arası üç sürüm, sürüm ekseninin yüzde otuzudur.

Düzeltme, tarih metnini platformdan bağımsız biçimde üretmektir.

// iade.mjs — surum 2: iade tarihi platformdan bagimsiz bicimde uretiliyor
export function iadeTarihi(oduncTarihi, gun = 14) {
  const t = new Date(`${oduncTarihi}T00:00:00Z`);
  t.setUTCDate(t.getUTCDate() + gun);
  return t.toISOString().slice(0, 10);
}
node --test --test-reporter=tap aygit.test.mjs | grep -E '^ *(ok|not ok|# (tests|pass|fail))'
ok 1 - paya gore secilen alt kumede iade tarihi okunur
ok 2 - kapsamaya gore secilen alt kumede iade tarihi okunur
# tests 2
# pass 2
# fail 0

İki alt kümenin de kaçırdığı bir sınıf da vardır: yalnız tek bir hücrede görülen kusur — belirli bir aygıt sınıfının belirli bir sürümdeki arayüz katmanı. Tabloda karşılığı otuzda altıdır; hücreye özgü kusurların beşte dördü her iki seçimde de kapsam dışındadır ve bu oran alt küme büyütülmeden düzelmez.

Bedelin koşuma bağlı yanı bu koşumda küçüktür — iki test 31,1 milisaniye sürdü, çünkü burada koşan şey model. Gerçek koşumda bedeli belirleyen sayı tablodadır: on iki hücre koşumu, yani iki alt küme için altışar aygıt oturumu. Her oturum bir kurulum, bir uygulama yüklemesi ve bir yıkım demektir; alt küme otuz hücrenin tamamına çıkarıldığında bu sayı beş katına çıkar, süre de aynı oranda artar.

Özet

  • Aygıt ve sürüm eksenleri çarpılır: altı aygıt ve beş sürüm otuz hücre eder, yeni bir sürüm altı, yeni bir aygıt sınıfı beş hücre ekler.
  • Paya göre seçilen altı hücre kullanıcıların yüzde kırk altı virgül dokuzunu temsil etti ama beş sürümün ikisine, altı aygıt sınıfının dördüne dokundu.
  • Kapsamaya göre seçilen altı hücre payı yüzde yirmi dört virgül üçe indirdi, buna karşılık her sürüme ve her aygıt sınıfına girdi.
  • Sürüme bağlı tarih ayrıştırma kusurunu yalnız kapsamaya göre seçilen alt küme yakaladı; aynı kusurla paya göre seçilen alt küme yeşil kaldı.
  • Emülatör sürüm boyutunu taşır, aygıt sınıfı boyutunu taşımaz; altı hücrenin tamamı emülatörde koşulursa aygıt kusuru yakalaması altıda altıdan sıfıra iner.

Sonraki Adım

Buraya kadar bütün iddialar bir değer üzerineydi: bir durum kodu, bir metin, bir tarih. Arayüzün asıl çıktısı ise bir görüntüdür ve onun hakkında “eşit mi” diye sorulduğunda soru birdenbire zorlaşır — iki ekran görüntüsü hiçbir zaman tam olarak aynı piksellerden oluşmaz. Sonraki ders bu karşılaştırmayı bir eşiğe bağlar ve eşiği tarayarak ölçer: eşik düştükçe kaç yanlış alarm üretiliyor, eşik yükseldikçe kaç gerçek gerileme kaçıyor.

İ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