İçeriğe geç
academia.sh

Ders 19 / 19

Araç Zinciri

Tasarım aracıyla kod arasında tek yönlü doğruluk kaynağı, belirteç dışa aktarımının normalleştirilmesi, sahte farkların elenmesi ve kalan gerçek sapmanın sınıflandırılarak eşitleme oranına bağlanması.

İçindekiler

Önceki dersin taraması kod tarafında kaldı: sistem bileşeninin kullanılıp kullanılmadığına bakıldı, ama o bileşenin taşıdığı değerlerin tasarım kitaplığındakiyle aynı olup olmadığına bakılmadı. Bir ekip sistem düğmesini kullanıyor olabilir ve düğmenin dolgu rengi tasarım dosyasındakinden farklı olabilir; kapsam yüzdesi bunu yüzde yüz olarak sayar.

Araç zinciri bu boşluğu kapatır. İşi, tasarım aracındaki değerlerle koddaki değerlerin aynı olduğunu sürekli olarak doğrulamaktır. Bu ders zincirin yönünü tanımlar, fark raporunu üretir ve raporun okunabilir hâle gelmesi için gereken normalleştirmeyi gösterir.

Doğruluğun Yönü

Bir değer iki yerde tutuluyorsa, hangisinin doğru olduğu önceden kararlaştırılmalıdır. Üç düzen vardır ve üçü de tek yönlüdür:

  • Tasarım aracı kaynaktır. Değerler tasarım kitaplığında tanımlanır, dışa aktarılır ve koda üretilir. Kodda elle değişiklik yapılmaz.
  • Kod kaynaktır. Değerler bir belirteç dosyasında tanımlanır ve tasarım aracına aktarılır. Tasarımcı değeri araçta değil dosyada değiştirir.
  • Nötr bir kaynak vardır. Değerler araçtan da koddan da bağımsız bir dosyada — bir JSON belgesinde — tanımlanır; hem tasarım aracı hem kod bu dosyadan beslenir.

Dördüncü bir seçenek olarak görünen iki yönlü eşitleme çalışmaz. İki taraf da yazma yetkisine sahipse, aynı belirtecin iki tarafta birden değişmesi bir çakışma üretir ve çakışmayı çözecek bir kural yoktur: hangi değerin daha yeni olduğu, hangisinin daha doğru olduğunu söylemez. Bu yüzden araç zinciri kurulurken verilen ilk karar, hangi yönde akacağıdır; teknik seçimler bu karardan sonra gelir.

Yön seçildikten sonra zincirin biçimi aynıdır: dışa aktarım → dönüştürme → hedef biçimler. Dönüştürme adımı adları hedefin sözleşmesine çevirir, değerleri hedefin birimlerine getirir ve türetilmiş belirteçleri hesaplar. Hedef biçimler birden çok olabilir — aynı kaynaktan CSS özel özellikleri, mobil biçim dosyaları ve belge sayfaları üretilir.

Fark Raporunun Üretilmesi

Yön ne olursa olsun, iki tarafın aynı olduğunun denetlenmesi gerekir. Denetimin önündeki asıl engel, iki tarafın aynı değeri farklı biçimde yazmasıdır: tasarım aracı rengi büyük harfli onaltılık yazar, kod küçük harfli; tasarım aracı uzunluğu piksel yazar, kod kök boyutuna göre oran yazar.

Aşağıdaki program on sekiz tasarım belirteci ile on sekiz kod belirtecini üç aşamada karşılaştırır: ham hâlde, yalnız adlar normalleştirilerek ve hem adlar hem değerler normalleştirilerek.

// eslestirme.mjs — tasarim aracindan cikan belirtec disa aktarimi ile koddaki
// belirtec tanimi arasinda fark raporu

// Tasarim aracinin disa aktardigi ad-deger cifleri.
const TASARIM = {
  "Renk/Yüzey/Birincil": "#FFFFFF",
  "Renk/Yüzey/İkincil": "#F7F7F8",
  "Renk/Kenarlık/Varsayılan": "#B7BCC2",
  "Renk/Metin/Birincil": "rgb(31, 35, 40)",
  "Renk/Metin/İkincil": "#5A6169",
  "Renk/Eylem/Ana": "#275EA5",
  "Renk/Eylem/Ana Üzeri": "#FFF",
  "Renk/Eylem/İkincil": "#3B7BC8",
  "Aralık/Adım 1": "4px",
  "Aralık/Adım 2": "8px",
  "Aralık/Adım 3": "12px",
  "Aralık/Adım 4": "16px",
  "Tipografi/Gövde/Boyut": "16px",
  "Tipografi/Gövde/Satır Yüksekliği": "1.5",
  "Tipografi/Başlık/Boyut": "24px",
  "Yuvarlaklık/Küçük": "4px",
  "Yuvarlaklık/Orta": "8px",
  "Gölge/Yükselti 1": "0 1px 2px rgba(0, 0, 0, 0.08)",
};

// Kodda tanimli ozel ozellikler.
const KOD = {
  "--renk-yuzey-birincil": "#ffffff",
  "--renk-yuzey-ikincil": "#f7f7f8",
  "--renk-kenarlik-varsayilan": "#b7bcc2",
  "--renk-metin-birincil": "#1f2328",
  "--renk-metin-ikincil": "#5a6169",
  "--renk-eylem-ana": "#275ea5",
  "--renk-eylem-ana-uzeri": "#ffffff",
  "--renk-eylem-ikincil": "#2f6bb5",
  "--aralik-adim-1": "0.25rem",
  "--aralik-adim-2": "0.5rem",
  "--aralik-adim-3": "0.75rem",
  "--aralik-adim-4": "1rem",
  "--tipografi-govde-boyut": "1rem",
  "--tipografi-govde-satir-yuksekligi": "1.5",
  "--tipografi-baslik-boyut": "1.5rem",
  "--yuvarlaklik-kucuk": "0.25rem",
  "--yuvarlaklik-orta": "0.5rem",
  "--renk-eylem-tehlike": "#a12d2d",
};

// Ad normalizasyonu: 02. dersteki cevriyazim kuralinin aynisi.
const CEVRIM = { "ı": "i", "İ": "i", "ş": "s", "Ş": "s", "ç": "c", "Ç": "c", "ğ": "g", "Ğ": "g", "ü": "u", "Ü": "u", "ö": "o", "Ö": "o" };
const cevir = (s) => [...s].map((h) => CEVRIM[h] ?? h).join("");
const adNormal = (tasarimAdi) => "--" + cevir(tasarimAdi).toLowerCase().replace(/[/\s]+/g, "-");

// Deger normalizasyonu: renk -> alti haneli kucuk harfli onaltilik, uzunluk -> piksel.
const KOK_BOYUT = 16;
function degerNormal(deger) {
  const d = deger.trim().replace(/\s+/g, " ");
  const kisaOnaltilik = d.match(/^#([0-9a-fA-F]{3})$/);
  if (kisaOnaltilik) return "#" + [...kisaOnaltilik[1]].map((h) => h + h).join("").toLowerCase();
  if (/^#[0-9a-fA-F]{6}$/.test(d)) return d.toLowerCase();
  const rgb = d.match(/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/);
  if (rgb) return "#" + rgb.slice(1, 4).map((n) => Number(n).toString(16).padStart(2, "0")).join("");
  const rem = d.match(/^(-?[\d.]+)rem$/);
  if (rem) return `${Number(rem[1]) * KOK_BOYUT}px`;
  const px = d.match(/^(-?[\d.]+)px$/);
  if (px) return `${Number(px[1])}px`;
  return d;
}

// Uc asamali karsilastirma: ham, yalniz ad normalizasyonu, tam normalizasyon.
function karsilastir(adDonusum, degerDonusum) {
  const sol = new Map(Object.entries(TASARIM).map(([a, d]) => [adDonusum(a), degerDonusum(d)]));
  const sag = new Map(Object.entries(KOD).map(([a, d]) => [a, degerDonusum(d)]));
  const yalnizTasarim = [...sol.keys()].filter((a) => !sag.has(a));
  const yalnizKod = [...sag.keys()].filter((a) => !sol.has(a));
  const degerFarki = [...sol.entries()].filter(([a, d]) => sag.has(a) && sag.get(a) !== d).map(([a]) => a);
  return { yalnizTasarim, yalnizKod, degerFarki, ortak: sol.size - yalnizTasarim.length };
}

const asamalar = [
  ["ham karşılaştırma", (a) => a, (d) => d],
  ["ad normalizasyonu", adNormal, (d) => d],
  ["ad + değer normalizasyonu", adNormal, degerNormal],
];

console.log("aşama                       ortak ad   yalnız tasarımda   yalnız kodda   değer farkı   toplam fark");
let son = null;
for (const [ad, aD, dD] of asamalar) {
  const s = karsilastir(aD, dD);
  son = s;
  const toplam = s.yalnizTasarim.length + s.yalnizKod.length + s.degerFarki.length;
  console.log(
    `${ad.padEnd(27)} ${String(s.ortak).padStart(8)} ${String(s.yalnizTasarim.length).padStart(18)} ` +
    `${String(s.yalnizKod.length).padStart(14)} ${String(s.degerFarki.length).padStart(13)} ${String(toplam).padStart(13)}`
  );
}

console.log("\n— GERÇEK SAPMALAR —");
for (const a of son.degerFarki) {
  const tasarimAnahtar = Object.keys(TASARIM).find((k) => adNormal(k) === a);
  console.log(`değer farkı: ${a}\n    tasarım: ${TASARIM[tasarimAnahtar]} → ${degerNormal(TASARIM[tasarimAnahtar])}\n    kod    : ${KOD[a]} → ${degerNormal(KOD[a])}`);
}
for (const a of son.yalnizTasarim) console.log(`yalnız tasarımda: ${a} (${TASARIM[Object.keys(TASARIM).find((k) => adNormal(k) === a)]})`);
for (const a of son.yalnizKod) console.log(`yalnız kodda: ${a} (${KOD[a]})`);

// Eslesme orani ve kapi: hangi esikte yayin durdurulur?
const toplamBelirtec = new Set([...Object.keys(TASARIM).map(adNormal), ...Object.keys(KOD)]).size;
const gercekFark = son.yalnizTasarim.length + son.yalnizKod.length + son.degerFarki.length;
console.log(`\ntoplam belirteç (birleşim): ${toplamBelirtec}`);
console.log(`gerçek sapma: ${gercekFark}   eşitleme oranı: %${(((toplamBelirtec - gercekFark) / toplamBelirtec) * 100).toFixed(1)}`);
aşama                       ortak ad   yalnız tasarımda   yalnız kodda   değer farkı   toplam fark
ham karşılaştırma                  0                 18             18             0            36
ad normalizasyonu                 17                  1              1            16            18
ad + değer normalizasyonu         17                  1              1             1             3

— GERÇEK SAPMALAR —
değer farkı: --renk-eylem-ikincil
    tasarım: #3B7BC8 → #3b7bc8
    kod    : #2f6bb5 → #2f6bb5
yalnız tasarımda: --golge-yukselti-1 (0 1px 2px rgba(0, 0, 0, 0.08))
yalnız kodda: --renk-eylem-tehlike (#a12d2d)

toplam belirteç (birleşim): 19
gerçek sapma: 3   eşitleme oranı: %84.2

Sahte Farkın Elenmesi

Üç aşamalı tablo, fark raporunun neden çoğu kuruluşta okunmadığını açıklıyor. Ham karşılaştırmada 36 fark var ve bunların hiçbiri gerçek değil; iki taraf yalnızca farklı yazım sözleşmeleri kullanıyor. Böyle bir rapor bir kez okunur, sonra kapatılır.

Ad normalizasyonu farkı 18’e indiriyor. Kullanılan kural, ikinci derste kurulan çevriyazım kuralının aynısıdır; adlandırma sözleşmesinin bedeli orada ödenmişti, karşılığı burada alınıyor. Sözleşme olmasaydı bu adım için ayrı bir eşleme tablosu tutulması gerekirdi ve tablo, belirteç eklendikçe eskirdi.

Değer normalizasyonu farkı 3’e indiriyor. Elenen 15 fark üç ayrı biçim ayrımından doğuyordu: onaltılık gösterimin harf büyüklüğü, üç haneli kısa gösterim, rgb işlevsel gösterimi ve uzunluk biriminin piksel yerine kök oranı olarak yazılması. Bunların hiçbiri görsel bir sapma üretmez; ikisi de aynı rengi ve aynı uzunluğu anlatır.

Sıralamanın kendisi bir tasarım kararıdır: normalizasyon karşılaştırmadan önce yapılır, sonra değil. Farkı önce hesaplayıp sonra elemeye çalışmak, hangi farkın sahte olduğunu her seferinde yeniden karar vermek demektir.

Kalan Üç Sapmanın Okunması

Geriye kalan üç satırın her biri farklı bir iş üretir.

Değer farkı--renk-eylem-ikincil iki tarafta farklı. Bu, doğruluk kaynağının ihlalidir: taraflardan biri diğerini beklemeden değiştirilmiş. Kaynağın yönü belirlenmiş olsa bile bu satır tek başına hangi tarafın haklı olduğunu söylemez; söylediği şey, akışın bir yerde kırıldığıdır. Bu rengin ikincil eylem rengi olduğu ve tipografi ve renk derslerinde birincil eylem rengiyle arasındaki kontrast oranının hesaplandığı düşünülürse, sapmanın sonucu görsel değil işlevsel olabilir.

Yalnız tasarımda--golge-yukselti-1 tasarım kitaplığında var, kodda yok. Gerçekleştirilmemiş bir tasarım kararıdır ve katkı sürecine bir iş olarak girer. Bu satırın raporda kalması, kararın unutulmasını önler.

Yalnız kodda--renk-eylem-tehlike kodda var, tasarımda yok. Bir ekip yıkıcı bir eylem için renk gerektiğinde belirteci kod tarafında eklemiş. Bu satır iki sonuçtan birine bağlanır: ya belirteç meşrudur ve tasarım kitaplığına eklenir, ya da değildir ve kaldırılır. Kararsız bırakıldığında belirteç kalır, kullanılır ve bir sonraki tema türetiminde karşılığı bulunamaz.

Eşitleme oranı — yüzde 84,2 — bu üç satırın tek sayıya indirilmiş hâlidir ve ikinci derste ad eşleşmesi için kurulan kapı burada da kurulabilir: oran bir alt sınırın altına düştüğünde yayın durdurulur. Sayının kendisinden çok, her yayında ölçülüyor olması önemlidir; sapma bir olay değil, biriken bir niceliktir.

Zincirin Kapsayamadığı Katman

Araç zincirinin yapabildiği ile yapamadığı arasındaki sınır nettir ve bu ders boyunca kurulan yapının neden yalnız araçla kurulamayacağını açıklar.

Zincir değerleri eşitler: renk, aralık, tipografi, yuvarlaklık, gölge. Bunlar ad-değer çiftleridir, makinede karşılaştırılabilir ve otomatik üretilebilir.

Zincir davranışı eşitleyemez. Bir düğmenin hangi durumda hangi rengi aldığı, bir kip pencerenin odağı nereye götürdüğü, bir açılır listenin klavyeyle nasıl gezildiği tasarım aracından dışa aktarılamaz. Bu katman, ikinci derste kurulan adlandırma sözleşmesiyle, üçüncü derste tanımlanan belge bölümleriyle ve beşinci derste kurulan inceleme kapılarıyla eşitlenir. Araç zinciri belirteç katmanının bekçisidir; bileşen katmanının bekçisi yönetişimdir.

Özet

  • Bir değer iki yerde tutuluyorsa doğruluk kaynağının yönü önceden kararlaştırılmalıdır; iki yönlü eşitleme, çözülemeyen çakışmalar ürettiği için bir seçenek değildir. Zincirin biçimi yönden bağımsızdır: dışa aktarım, dönüştürme ve birden çok hedef biçim.
  • Fark raporu normalleştirme olmadan okunmaz hâle gelir; örnekte 36 farkın 33’ü yalnızca yazım sözleşmesi ayrımından doğan sahte farktı.
  • Normalizasyon karşılaştırmadan önce yapılır; ad kuralı adlandırma sözleşmesinden devralınır, değer kuralı renkleri tek gösterime ve uzunlukları tek birime indirir.
  • Kalan sapmalar üç sınıftır: değer farkı akışın kırıldığını, yalnız tasarımda olan gerçekleştirilmemiş bir kararı, yalnız kodda olan kayıtsız eklenmiş bir belirteci gösterir.
  • Eşitleme oranı her yayında ölçülür ve bir alt sınıra bağlanır; sapma bir olay değil, biriken bir niceliktir.
  • Araç zinciri değerleri eşitler, davranışı eşitleyemez; bileşen katmanının eşitliği adlandırma sözleşmesi, belge bölümleri ve inceleme kapılarıyla sağlanır.

Kurs Kapanışı

Bu konu, tasarım sisteminin değerlerden sonra gelen katmanını kurdu. Kataloğa neyin gireceği bir kapsam ölçütüne, giren şeyin ne kadar hazır olduğu olgunluk düzeylerinin çıkış koşullarına bağlandı. Tasarımla kod arasındaki ortak dil bir türetim kuralı hâline getirildi ve eşleşmeyen adlar sayıldı. Belgelendirme yedi zorunlu bölüme ayrıldı ve kapsamı kullanımla ağırlıklandırılarak hesaplandı. Sürüm numarası bir tartışma konusu olmaktan çıkarılıp arayüz farkının sonucuna dönüştürüldü, göç maliyeti çağrı yeriyle ölçüldü. Katkı akışı bir durum makinesi oldu, yönetişim modelleri kuyruk ve sapma sayılarıyla karşılaştırıldı, benimseme depo taramasıyla ölçüldü ve son olarak belirteç katmanının eşitliği bir fark raporuna bağlandı.

Bütün bu yapının ortak yanı, her kararın bir sayıya bağlanmış olmasıdır: kapsam yüzdesi, eksik etkisi, göç maliyeti, kuyruk süresi, sapma sayısı, eşitleme oranı. Bir tasarım sisteminin başarısı bu sayılarla izlenir; izlenmediğinde sistem, kimsenin ne zaman bıraktığını fark etmediği bir kütüphaneye dönüşür.

Katalog kuruldu ve yönetiliyor. Ancak kataloğun her kaydı hâlâ bir soruyu yanıtsız bırakıyor: bu bileşen klavyeyle nasıl kullanılır, odağı nereye götürür, ekran okuyucuya kendini nasıl bildirir? Üçüncü derste “erişilebilirlik notu” bir belge bölümü olarak tanımlandı ve kararlı olgunluk düzeyinin çıkış ölçütlerinden biri sayıldı, ama o notun içine ne yazılacağı söylenmedi. Bir sonraki kurs olan Erişilebilir Bileşen Kalıpları bu boşluğu doldurur: düğmeden açılır listeye, sekmelerden kip pencereye kadar kataloğun her bileşeninin klavye davranışını, odak yönetimini ve ekran okuyucuya bildirdiği bilgiyi tek tek belirtir; karmaşık etkileşim kalıplarının odak tuzaklarını tasarlar ve arayüz metniyle yerelleştirme gereksinimlerini sistemin parçası hâline getirir.

İ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