---
title: 'Görsel Denetim'
source: 'https://academia.sh/tr/kurslar/tasarim-sistemleri/gorsel-denetim'
course: 'Tasarım Sistemleri'
language: tr
updated: '2026-08-17T18:09:34+00:00'
license: 'CC BY-SA 4.0'
---

# Görsel Denetim

Var olan arayüzlerin biçem kaynağından değer envanterinin makineyle çıkarılması, yakın-yinelemelerin eşiklerle kümelemesi, bağlama kuralının sayıya etkisi ve ürün bazında sapma haritası.

Önceki ders sistemin ne zaman kendini ödediğini hesapladı ve kapsamın en belirleyici karar
olduğunu gösterdi. Kapsam, hangi kararların sisteme gireceğini söyler; bunu bilmek için de
hangi kararların fiilen tekrarlandığını bilmek gerekir. Tahminle çizilen bir kapsam ya
kullanılmayan belirteçler üretir ya da en sık kullanılan kararı dışarıda bırakır.

**Görsel denetim (visual audit)**, var olan arayüzlerin fiilen kullandığı değerlerin
sayılmasıdır. Denetimin ayırt edici özelliği, kaynağının bellek değil **eser** olmasıdır:
kimseye "kart iç boşluğu kaç piksel" diye sorulmaz, biçem kaynağından okunur. Bu ders o
okumayı yapan hesabı kurar ve envanterin hangi bölümünün gerçek karar, hangi bölümünün
karşılıksız çeşitlilik olduğunu ayırır.

## Denetim Eserden Okunur

Katalog kurumunun dört ürünü var: katalog arayüzü, yönetim paneli, üye profili ve raf
yerleşim ekranı. Dördü ayrı zamanlarda, kısmen ayrı ekiplerce yazıldı. Yinelenme ve
Tutarlılık dersinde katalog arayüzünün dört ekranı elle sayılmıştı; burada sayım dört ürünün
tamamına genişler ve elle değil, kaynağı ayrıştırarak yapılır.

Elle sayımla makine sayımı arasındaki fark yalnız hız değildir. Elle sayım, sayanın gözüne
çarpan değerleri bulur; makine sayımı, kimsenin bakmadığı bildirimleri de bulur. Denetimin
değeri tam buradadır: aranan şey zaten bilinen tutarsızlık değil, bilinmeyen tutarsızlıktır.

Sayım beş özellik sınıfı üzerinde yapılır: aralık, yazı boyutu, köşe yarıçapı, kenar
kalınlığı ve renk. İlk dördünde yakınlık ölçütü piksel farkıdır ve eşikler Yinelenme ve
Tutarlılık dersindeki ayırt edilebilirlik eşikleridir. Renkte ölçüt iki parçalıdır: iki renk
hem birbirine karşı kontrast oranı 1.10'un altındaysa hem de en büyük kanal farkı 16'nın
altındaysa aynı kararı taşıyor sayılır. Tek başına kontrast oranı yetmez, çünkü farklı
tonlardaki iki renk aynı bağıl parlaklığa sahip olabilir.

```js
// denetim.mjs — dort katalog urununun bicem kaynagindan envanter cikarma ve yakin-yineleme kumeleme

// Dort urunun bicem kaynagindan alinmis bildirimler. Her satirin onunde urun kodu var:
// K katalog, Y yonetim paneli, U uye profili, R raf yerlesim ekrani.
const KAYNAK = `
K .arama-alani { padding: 8px 12px; font-size: 14px; border-radius: 4px; border: 1px solid #b7bcc2; color: #212327; }
K .arama-dugmesi { padding: 8px 16px; font-size: 14px; border-radius: 4px; background: #275ea5; color: #ffffff; }
K .kayit-karti { padding: 16px; border-radius: 8px; border: 1px solid #d3d6d9; background: #ffffff; }
K .kayit-basligi { font-size: 20px; color: #212327; margin-bottom: 4px; }
K .kayit-yazari { font-size: 16px; color: #5e656e; margin-bottom: 8px; }
K .kayit-ustverisi { font-size: 13px; color: #757e8a; }
K .kayit-etiketi { padding: 2px 8px; font-size: 12px; border-radius: 12px; background: #dee9f7; color: #15335b; }
K .sonuc-listesi { gap: 24px; padding: 32px 24px; }
K .sayfalama { gap: 8px; font-size: 14px; padding: 24px 0; }
K .onay-katmani { padding: 24px; border-radius: 8px; background: #ffffff; border: 1px solid #d3d6d9; }
K .onay-uyarisi { font-size: 14px; color: #ab3321; margin-top: 8px; }
Y .panel-baslik { font-size: 24px; color: #1f2226; margin-bottom: 16px; }
Y .panel-kart { padding: 14px; border-radius: 6px; border: 1px solid #d5d8db; background: #fdfdfd; }
Y .panel-tablo { font-size: 13px; color: #333333; }
Y .panel-tablo-basligi { font-size: 12px; color: #6b7280; padding: 6px 10px; }
Y .panel-satiri { padding: 10px 12px; border-bottom: 1px solid #e9eaec; }
Y .panel-dugmesi { padding: 6px 14px; font-size: 13px; border-radius: 3px; background: #2a5fa8; color: #ffffff; }
Y .panel-ikincil-dugme { padding: 6px 14px; font-size: 13px; border-radius: 3px; border: 1px solid #b7bcc2; color: #275ea5; }
Y .panel-uyari { font-size: 12px; color: #a83224; padding: 10px; border-radius: 3px; }
Y .panel-bolum { gap: 20px; padding: 20px; }
U .profil-basligi { font-size: 22px; color: #212327; margin-bottom: 12px; }
U .profil-karti { padding: 20px; border-radius: 8px; border: 1px solid #d3d6d9; background: #ffffff; }
U .odunc-satiri { padding: 12px 16px; font-size: 15px; color: #22252a; border-bottom: 1px solid #e9eaec; }
U .odunc-tarihi { font-size: 13px; color: #5e656e; }
U .gecikme-uyarisi { font-size: 13px; color: #ab3321; padding: 8px 12px; border-radius: 4px; background: #fbeae7; }
U .profil-dugmesi { padding: 10px 18px; font-size: 15px; border-radius: 6px; background: #275ea5; color: #ffffff; }
U .profil-bolumu { gap: 16px; padding: 28px 24px; }
R .raf-basligi { font-size: 18px; color: #212327; margin-bottom: 8px; }
R .raf-hucresi { padding: 12px; border-radius: 4px; border: 2px solid #b7bcc2; }
R .raf-kodu { font-size: 12px; color: #757e8a; }
R .raf-dolu { background: #e9eaec; border: 2px solid #969da6; }
R .raf-secili { border: 2px solid #3075cf; background: #dee9f7; }
R .raf-izgarasi { gap: 6px; padding: 18px; }
R .raf-uyarisi { font-size: 13px; color: #b03526; padding: 8px; border-radius: 4px; }
`;

// --- cikarma -----------------------------------------------------------------
const UZUNLUK_OZELLIK = {
  aralik: /^(padding|margin-top|margin-bottom|gap)$/,
  "yazi boyutu": /^font-size$/,
  "kose yaricapi": /^border-radius$/,
};
const SINIFLAR = ["aralik", "yazi boyutu", "kose yaricapi", "kenar kalinligi", "renk"];
const envanter = Object.fromEntries(SINIFLAR.map((s) => [s, []]));

for (const satir of KAYNAK.trim().split("\n")) {
  const urun = satir[0];
  const govde = satir.slice(satir.indexOf("{") + 1, satir.lastIndexOf("}"));
  for (const bildirim of govde.split(";")) {
    const i = bildirim.indexOf(":");
    if (i < 0) continue;
    const ozellik = bildirim.slice(0, i).trim();
    const deger = bildirim.slice(i + 1).trim();

    for (const [sinif, kalip] of Object.entries(UZUNLUK_OZELLIK)) {
      if (!kalip.test(ozellik)) continue;
      for (const p of deger.split(/\s+/)) {
        const m = p.match(/^(\d+(?:\.\d+)?)px$/);
        if (m) envanter[sinif].push({ deger: Number(m[1]), urun });
      }
    }
    if (/^border(-bottom)?$/.test(ozellik)) {
      const m = deger.match(/^(\d+(?:\.\d+)?)px/);
      if (m) envanter["kenar kalinligi"].push({ deger: Number(m[1]), urun });
    }
    for (const m of deger.matchAll(/#([0-9a-f]{6})/g)) {
      envanter.renk.push({ deger: "#" + m[1], urun });
    }
  }
}

// --- yakinlik olcutleri -------------------------------------------------------
const ESIK = { aralik: 2, "yazi boyutu": 1, "kose yaricapi": 2, "kenar kalinligi": 0.5 };
const cz = (h) => [1, 3, 5].map((i) => parseInt(h.slice(i, i + 2), 16));
function kanal(v) {
  const s = v / 255;
  return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
}
const parlaklik = ([r, g, b]) => 0.2126 * kanal(r) + 0.7152 * kanal(g) + 0.0722 * kanal(b);
function kontrast(a, b) {
  const [x, y] = [parlaklik(a), parlaklik(b)].sort((p, q) => q - p);
  return (x + 0.05) / (y + 0.05);
}
const kanalFarki = (a, b) => Math.max(...a.map((v, i) => Math.abs(v - b[i])));

// Iki deger ayni karari tasiyor mu? Renkte olcut hem kontrast orani hem kanal farkidir.
function yakin(sinif, a, b) {
  if (sinif !== "renk") return Math.abs(a - b) <= ESIK[sinif];
  return kontrast(cz(a), cz(b)) < 1.1 && kanalFarki(cz(a), cz(b)) < 16;
}
function sirala(sinif, degerler) {
  const tekil = [...new Set(degerler)];
  return sinif === "renk"
    ? tekil.sort((a, b) => parlaklik(cz(b)) - parlaklik(cz(a)))
    : tekil.sort((a, b) => a - b);
}

// Zincirleme baglama: bir degere yakin tek bir uye bulmak kumeye katilmaya yeter.
function zincirleme(sinif, degerler) {
  const kumeler = [];
  for (const d of sirala(sinif, degerler)) {
    const k = kumeler.find((k) => k.some((o) => yakin(sinif, d, o)));
    if (k) k.push(d);
    else kumeler.push([d]);
  }
  return kumeler;
}

// Cap sinirli baglama: kumeye katilmak icin kumedeki HER uyeye yakin olmak gerekir.
function capSinirli(sinif, degerler) {
  const kumeler = [];
  for (const d of sirala(sinif, degerler)) {
    const k = kumeler.find((k) => k.every((o) => yakin(sinif, d, o)));
    if (k) k.push(d);
    else kumeler.push([d]);
  }
  return kumeler;
}

console.log("ozellik          kullanim  ayri deger  zincirleme kume  cap sinirli kume");
let toplamKullanim = 0;
let toplamAyri = 0;
let toplamZincir = 0;
let toplamCap = 0;
const capKumeleri = {};
for (const sinif of SINIFLAR) {
  const degerler = envanter[sinif].map((k) => k.deger);
  const z = zincirleme(sinif, degerler);
  const c = capSinirli(sinif, degerler);
  capKumeleri[sinif] = c;
  const ayri = new Set(degerler).size;
  toplamKullanim += degerler.length;
  toplamAyri += ayri;
  toplamZincir += z.length;
  toplamCap += c.length;
  console.log(
    `${sinif.padEnd(15)} ${String(degerler.length).padStart(9)} ${String(ayri).padStart(11)} ` +
      `${String(z.length).padStart(16)} ${String(c.length).padStart(17)}`
  );
}
console.log(
  `${"toplam".padEnd(15)} ${String(toplamKullanim).padStart(9)} ${String(toplamAyri).padStart(11)} ` +
    `${String(toplamZincir).padStart(16)} ${String(toplamCap).padStart(17)}`
);
console.log(
  `karsiliksiz cesitlilik (cap sinirli): ${toplamAyri - toplamCap} deger, ` +
    `${((100 * (toplamAyri - toplamCap)) / toplamAyri).toFixed(1)}%`
);

console.log("\ncap sinirli kumeler (ayni karar, farkli yazim)");
for (const sinif of SINIFLAR) {
  for (const k of capKumeleri[sinif]) {
    if (k.length > 1) console.log(`  ${sinif.padEnd(15)} ${k.join(", ")}`);
  }
}

// --- urun bazinda sapma -------------------------------------------------------
// Bir kumenin en cok kullanilan uyesi "ana yazim"; digerleri sapma sayilir.
const sayac = {};
for (const sinif of SINIFLAR) {
  for (const kayit of envanter[sinif]) {
    const a = `${sinif}:${kayit.deger}`;
    sayac[a] = (sayac[a] || 0) + 1;
  }
}
const anaYazim = new Map();
for (const sinif of SINIFLAR) {
  for (const k of capKumeleri[sinif]) {
    const en = k.reduce((a, b) => ((sayac[`${sinif}:${b}`] || 0) > (sayac[`${sinif}:${a}`] || 0) ? b : a));
    for (const uye of k) anaYazim.set(`${sinif}:${uye}`, en);
  }
}
console.log("\nurun  kullanim  ana yazimdan sapan  sapma orani");
for (const urun of ["K", "Y", "U", "R"]) {
  let toplam = 0;
  let sapan = 0;
  for (const sinif of SINIFLAR) {
    for (const kayit of envanter[sinif].filter((k) => k.urun === urun)) {
      toplam++;
      if (anaYazim.get(`${sinif}:${kayit.deger}`) !== kayit.deger) sapan++;
    }
  }
  console.log(
    `${urun.padStart(4)} ${String(toplam).padStart(9)} ${String(sapan).padStart(19)} ${((100 * sapan) / toplam).toFixed(1).padStart(12)}%`
  );
}
```

```
ozellik          kullanim  ayri deger  zincirleme kume  cap sinirli kume
aralik                 45          13                4                 8
yazi boyutu            22           9                5                 7
kose yaricapi          14           5                2                 3
kenar kalinligi        11           2                2                 2
renk                   43          23               15                15
toplam                135          52               28                35
karsiliksiz cesitlilik (cap sinirli): 17 deger, 32.7%

cap sinirli kumeler (ayni karar, farkli yazim)
  aralik          2, 4
  aralik          6, 8
  aralik          10, 12
  aralik          14, 16
  aralik          18, 20
  yazi boyutu     12, 13
  yazi boyutu     14, 15
  kose yaricapi   3, 4
  kose yaricapi   6, 8
  renk            #ffffff, #fdfdfd
  renk            #e9eaec, #dee9f7
  renk            #d5d8db, #d3d6d9
  renk            #b03526, #ab3321, #a83224
  renk            #2a5fa8, #275ea5
  renk            #22252a, #212327, #1f2226

urun  kullanim  ana yazimdan sapan  sapma orani
   K        46                   3          6.5%
   Y        37                  20         54.1%
   U        31                   6         19.4%
   R        21                   5         23.8%
```

## Bağlama Kuralı Sayıyı Belirler

Birinci tablonun iki küme sütunu aynı veriden iki farklı sonuç üretiyor: 28 ve 35. Fark
küçük görünüyor ama tek bir satırda toplanıyor. Aralık sınıfında zincirleme bağlama 4 küme,
çap sınırlı bağlama 8 küme buluyor.

Nedeni, **zincirleme bağlama**nın kümeye katılmak için tek bir yakın üye aramasıdır. Aralık
değerleri 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 biçiminde ikişer ikişer ilerlediği için her
değer bir öncekine yakındır ve zincir kopmaz. Sonuçta 2 ile 20 aynı kümeye düşer; oysa 2
piksellik bir boşlukla 20 piksellik bir boşluk aynı karar değildir.

**Çap sınırlı bağlama** kümeye katılmak için kümedeki her üyeye yakın olmayı şart koşar.
Bu, kümenin genişliğini eşikle sınırlar ve zinciri kırar. Aynı veride 2 ile 4 aynı kümede
kalır, 6 yeni bir küme açar.

Bu ayrım denetim raporunun güvenilirliğini doğrudan etkiler. Zincirleme sayı, yakın-yineleme
sorununu olduğundan büyük gösterir: "on üç aralık değeri aslında dört karar" cümlesi
denetimden çıkan en çarpıcı ama en yanlış cümledir. Doğru sayı sekizdir ve karşılıksız
çeşitlilik toplamda 52 değerden 17'sidir, yani yüzde 32.7.

## Kümeleme Öneri Üretir, Karar Vermez

İkinci blok kümelerin içeriğini gösteriyor ve burada ölçütün sınırı görünür hâle geliyor.

Renk kümelerinin çoğu doğru: `#22252a`, `#212327` ve `#1f2226` üç ürünün üç ayrı koyu metin
rengidir ve birbirinden ayırt edilemez. `#b03526`, `#ab3321`, `#a83224` üçlüsü aynı biçimde
üç ayrı hata kırmızısıdır. `#2a5fa8` ile `#275ea5` iki ayrı birincil eylem mavisidir.
Bunların hepsi tek bir karar olmalıydı ve üç kez verildi.

Bir küme ise yanlış: `#e9eaec` ile `#dee9f7`. Birincisi nötr bir gri, ikincisi soluk bir
mavi zemin. Bağıl parlaklıkları birbirine yakın olduğu ve kanal farkı eşiğin altında kaldığı
için ölçüt bunları aynı sayıyor; oysa ikisi ayrı işler yapıyor — biri dolu raf hücresinin
zemini, diğeri seçili kaydın vurgusu. Ölçüt bunu bilemez, çünkü ölçüt yalnızca değere bakar,
değerin taşıdığı role bakmaz.

Buradan çıkan kural denetimin tamamı için geçerlidir: **kümeleme bir öneri listesidir, bir
karar listesi değil.** Her küme insan tarafından okunur ve iki soru sorulur: bu değerler aynı
işi mi yapıyor, ve birleştirilirlerse kaybolan bir ayrım var mı. Birinci soruya hayır yanıtı
gelen küme bölünür; ikinci soruya evet yanıtı gelen küme kayda geçirilir.

## Sapma Tek Yerde Toplanır

Üçüncü tablo denetimin en doğrudan eyleme dönüşen çıktısı. Her kümenin en çok kullanılan
üyesi **ana yazım** kabul ediliyor; diğer üyeler sapma sayılıyor.

Sonuç eşit dağılmıyor. Katalog arayüzünün 46 kullanımından yalnız 3'ü sapma: yüzde 6.5.
Yönetim panelinin 37 kullanımından 20'si sapma: yüzde 54.1. Üye profili yüzde 19.4, raf
ekranı yüzde 23.8.

Bu dağılım kapsam ve sıralama kararını birlikte veriyor. Yönetim paneli tek başına toplam
sapmanın büyük bölümünü taşıyor; sisteme geçişte önce onun düzeltilmesi, diğer üç üründen
daha fazla kazanç sağlar. Aynı zamanda bir soru açıyor: yönetim paneli neden bu kadar
uzakta? Yanıt genellikle ya ayrı bir ekipte yazılmış olmasıdır ya da başka bir zamanda —
iki durumda da düzeltme yalnız değerleri değiştirmekle bitmez, o ekibin ya da o dönemin
kararlarının neden farklılaştığının anlaşılmasını gerektirir.

Katalog arayüzünün düşük sapma oranı da ayrıca okunur: ana yazımlar zaten büyük ölçüde onun
değerleridir, çünkü en çok kullanım oradadır. Bu, "en sık kullanılan değer doğrudur"
varsayımının denetime gizlice girdiği yerdir. Varsayım her zaman doğru değildir; en sık
kullanılan değer, en çok ekran yazılmış ürünün değeridir — kalitesinin değil, hacminin
sonucudur.

## Denetimin Teslim Ettiği Şey

Bir görsel denetim üç belge üretir ve üçü de sonraki adımların girdisidir.

**Değer envanteri**: her özellik sınıfı için kullanılan değerler, kullanım sayılarıyla
birlikte. Ölçek kurulurken hangi değerin korunacağını bu sayılar belirler.

**Küme raporu**: yakın-yineleme kümeleri ve her küme için verilmiş insan kararı —
birleştirilecek mi, bölünecek mi, kayda geçirilecek mi.

**Sapma haritası**: hangi ürünün ana yazımdan ne kadar uzakta olduğu. Geçiş sırasını ve
maliyet tahminini bu harita verir.

Denetimin teslim etmediği şey ise ölçeğin kendisidir. Envanter neyin kullanıldığını söyler,
neyin kullanılması gerektiğini söylemez. İkisi arasındaki geçiş ayrı bir karardır ve iki
farklı yoldan yapılabilir.

## Özet

- Görsel denetim, arayüzün fiilen kullandığı değerlerin biçem kaynağından makineyle
  sayılmasıdır; kaynağı bellek değil eserdir ve aradığı şey bilinmeyen tutarsızlıktır.
- Yakın-yineleme ölçütü sınıfa göre değişir: uzunluklarda piksel farkı, renkte hem kontrast
  oranı hem en büyük kanal farkı birlikte kullanılır.
- Bağlama kuralı sonucu belirler: zincirleme bağlama 13 aralık değerini 4 kümede toplar ve
  yakın-yinelemeyi abartır; çap sınırlı bağlama 8 küme bulur.
- Ölçülen dört üründe 52 ayrı değerin 17'si karşılıksız çeşitliliktir; yüzde 32.7'lik bu pay
  bedelsiz kapatılabilir.
- Kümeleme öneri üretir; her küme rolüyle birlikte okunur, çünkü ölçüt değere bakar, değerin
  işine bakmaz.
- Sapma haritası geçiş sırasını verir: dört üründen biri toplam sapmanın büyük bölümünü
  taşıyorsa geçiş oradan başlar.

## Sonraki Adım

Envanter elde olduğunda iki yol açılır. Birinci yol, ölçeği ilkelerden kurup mevcut değerleri
ona oturtmaktır; ikinci yol, mevcut değerlerin en sık kullanılanlarını ölçek ilan edip
oradan devam etmektir. İki yolun geçiş maliyeti de, ürettiği ölçeğin kalitesi de farklıdır ve
ikisi de hesaplanabilir. Sonraki ders bu iki stratejiyi aynı envanter üzerinde uygular; kaç
değerin gözle görülür biçimde değişeceğini, kaç bileşenin dokunulacağını ve türetilen
ölçeklerin Aralık Ölçeği dersindeki ölçütleri geçip geçmediğini karşılaştırır.
