İçeriğe geç
academia.sh

Ders 18 / 19

Bileşen Bağlaşım İlkeleri

Bileşenler arası bağın yönünün ölçülmesi: gelen ve giden bağ sayısından kararsızlık ölçüsünün hesaplanması, kararlı yöne akmayan kenarların sayılması, topolojik sıralamayla yayın sırasının çıkarılması ve kararlı çekirdeğe eklenen tek bir ithalin sıralamayı nasıl olanaksız kıldığının gösterilmesi.

İçindekiler

Bir önceki ders bileşen sınırını birlikte değişen dosyalardan çıkardı ve iki bölünmeyi yeniden yayın sayısıyla karşılaştırdı. O ölçüler bileşenlerin içine bakıyordu: hangi dosyalar birlikte durmalı. Bileşenler arası kenarlar sayıldı, ama yönleri sorgulanmadı.

Bileşenler arası kenar, Bağlaşım ve Uyum konusunda modül çiftleri için ölçülen bağlaşımın bileşen ölçeğindeki karşılığıdır. Aradaki fark yöndür: orada bağın gücü sayılıyordu, burada bağın hangi yöne baktığı sayılacak. Bir kenarın hangi yöne bakması gerektiğinin bir ölçütü vardır ve ölçüt yine değişimle ilgilidir. Sık değişen bir bileşene bağlanan bir bileşen, kendisi hiç değişmese bile o değişikliklerin peşinden sürüklenir. Bu ders her bileşen için bir kararlılık ölçüsü hesaplar, bağların doğru yöne akıp akmadığını sayar ve kararlılığın karşılığını yayın sırasında gösterir.

Kararlılık Ölçülebilir Bir Şeydir

Bir bileşenin kararlılığı, değişmemesi değil, değişmesinin zor olmasıdır. İki sayı bunu belirler: kaç bileşen ona bağlı (gelen bağ sayısı) ve o kaç bileşene bağlı (giden bağ sayısı). Gelen bağı çok olan bir bileşen kolay değiştirilemez, çünkü değişimi başkalarını kırar. Giden bağı çok olan bir bileşen kolay değiştirilir, çünkü değişimi kimseyi kırmaz — ama aynı bileşen başkalarının değişiminden etkilenmeye açıktır.

İkisi tek bir orana indirgenir. Kararsızlık ölçüsü, giden bağ sayısının toplam bağ sayısına oranıdır:

I=gidengelen+gidenI = \frac{\text{giden}}{\text{gelen} + \text{giden}}

I=0I = 0 olan bileşen en kararlıdır: ona bağlanan vardır, o kimseye bağlanmaz. I=1I = 1 olan bileşen en kararsızdır: hiçbir şey ona bağlı değildir, kendisi başkalarına bağlıdır. Ölçü kalite değil konum bildirir; bir kitaplıkta her iki uçtan da bileşenlere ihtiyaç vardır.

Kararlı bağımlılıklar ilkesi (stable dependencies principle) bu ölçünün üzerine kurulur: bir kenar, II’nin düştüğü yöne akmalıdır. Kararlı bir bileşenin kararsız bir bileşene bağlanması, kararlılığını bir kurgu hâline getirir — bileşen değişmeye kapalı görünür ama bağlandığı taraf her değiştiğinde yeniden yayınlanır.

Ölçülecek Üç Çizge

Bir önceki dersteki iki bölünme aynı kitaplığın iki bileşen çizgesini verir. Üçüncü çizge, ikincisine tek bir ithal eklenerek üretiliyor: para bileşeni tutarları bölgeye göre biçimlendirmeye başlıyor ve tarife bileşenini ithal ediyor.

// bilesen-cizgesi.mjs — ayni kitapligin uc bilesen cizgesi
export const DIZIN = {
  bilesenler: ["ucret", "bolge", "tasiyici", "rota", "teslimat", "ortak"],
  kenarlar: [["ucret", "bolge"], ["ucret", "ortak"], ["tasiyici", "ucret"],
    ["rota", "tasiyici"], ["teslimat", "rota"]],
};

export const BIRLIKTE = {
  bilesenler: ["tarife", "ticari-kural", "ag", "izleme", "para"],
  kenarlar: [["ticari-kural", "tarife"], ["ticari-kural", "para"], ["ticari-kural", "ag"],
    ["tarife", "para"], ["izleme", "ag"]],
};

export const BOZUK = {
  bilesenler: BIRLIKTE.bilesenler,
  kenarlar: [...BIRLIKTE.kenarlar, ["para", "tarife"]],
};

Ölçüm aracı iki şey hesaplar. Birincisi kararsızlık ölçüsü ve kararlı yöne akmayan kenarlar. İkincisi yayın sırası: bir bileşen, bağlandığı bileşenlerin hepsi yayınlandıktan sonra yayınlanabilir. Bu, Veri Yapıları kursunda kurulan topolojik sıralamanın bileşenler üzerindeki karşılığıdır; sıralanamayan bileşen kalırsa çizgede döngü var demektir.

// kararlilik.mjs — kararsizlik olcusu, kararli yon ihlali ve yayin sirasi
export function olcu(bilesenler, kenarlar) {
  const gelen = Object.fromEntries(bilesenler.map((b) => [b, 0]));
  const giden = Object.fromEntries(bilesenler.map((b) => [b, 0]));
  for (const [a, b] of kenarlar) { giden[a] += 1; gelen[b] += 1; }
  const I = Object.fromEntries(bilesenler.map((b) => {
    const toplam = gelen[b] + giden[b];
    return [b, toplam === 0 ? 0 : giden[b] / toplam];
  }));
  return { gelen, giden, I, ihlal: kenarlar.filter(([a, b]) => I[a] < I[b]) };
}

export function yayinSirasi(bilesenler, kenarlar) {
  const kalan = new Set(bilesenler);
  const sira = [];
  for (;;) {
    const hazir = [...kalan]
      .filter((b) => kenarlar.every(([a, h]) => a !== b || !kalan.has(h))).sort();
    if (hazir.length === 0) return { sira, kalan: [...kalan].sort() };
    for (const b of hazir) { sira.push(b); kalan.delete(b); }
    if (kalan.size === 0) return { sira, kalan: [] };
  }
}
// kararlilik-raporu.mjs — uc cizgeyi ayni olculerle raporlar
import { DIZIN, BIRLIKTE, BOZUK } from "./bilesen-cizgesi.mjs";
import { olcu, yayinSirasi } from "./kararlilik.mjs";

for (const [ad, cizge] of [["dizin", DIZIN], ["birlikte", BIRLIKTE], ["bozuk", BOZUK]]) {
  const { gelen, giden, I, ihlal } = olcu(cizge.bilesenler, cizge.kenarlar);
  console.log(`${ad} cizgesi — ${cizge.bilesenler.length} bilesen, ${cizge.kenarlar.length} kenar`);
  for (const b of [...cizge.bilesenler].sort((x, y) => I[x] - I[y] || x.localeCompare(y))) {
    console.log(`  ${b.padEnd(13)} gelen ${gelen[b]}  giden ${giden[b]}  I = ${I[b].toFixed(2)}`);
  }
  console.log(`  kararli yon ihlali = ${ihlal.length} / ${cizge.kenarlar.length}` +
    (ihlal.length ? `  ${ihlal.map(([a, b]) => `${a} -> ${b}`).join(", ")}` : ""));
  const { sira, kalan } = yayinSirasi(cizge.bilesenler, cizge.kenarlar);
  console.log(`  yayin sirasi: ${sira.join(" -> ")}` +
    (kalan.length ? `  || siralanamayan: ${kalan.join(", ")}` : ""));
}
dizin cizgesi — 6 bilesen, 5 kenar
  bolge         gelen 1  giden 0  I = 0.00
  ortak         gelen 1  giden 0  I = 0.00
  rota          gelen 1  giden 1  I = 0.50
  tasiyici      gelen 1  giden 1  I = 0.50
  ucret         gelen 1  giden 2  I = 0.67
  teslimat      gelen 0  giden 1  I = 1.00
  kararli yon ihlali = 1 / 5  tasiyici -> ucret
  yayin sirasi: bolge -> ortak -> ucret -> tasiyici -> rota -> teslimat
birlikte cizgesi — 5 bilesen, 5 kenar
  ag            gelen 2  giden 0  I = 0.00
  para          gelen 2  giden 0  I = 0.00
  tarife        gelen 1  giden 1  I = 0.50
  izleme        gelen 0  giden 1  I = 1.00
  ticari-kural  gelen 0  giden 3  I = 1.00
  kararli yon ihlali = 0 / 5
  yayin sirasi: ag -> para -> izleme -> tarife -> ticari-kural
bozuk cizgesi — 5 bilesen, 6 kenar
  ag            gelen 2  giden 0  I = 0.00
  para          gelen 2  giden 1  I = 0.33
  tarife        gelen 2  giden 1  I = 0.33
  izleme        gelen 0  giden 1  I = 1.00
  ticari-kural  gelen 0  giden 3  I = 1.00
  kararli yon ihlali = 0 / 6
  yayin sirasi: ag -> izleme  || siralanamayan: para, tarife, ticari-kural

Yönün Yanlış Olduğu Yer

Dizin çizgesinde beş kenarın biri kararlı yöne akmıyor: tasiyici -> ucret. Taşıyıcı bileşeninin kararsızlığı 0.50, ücret bileşeninin 0.67. Bağ, daha kararsız olana doğru gidiyor.

Bunun somut anlamı şudur: rota bileşeni taşıyıcıya, taşıyıcı da ücrete bağlı olduğu için, ücret bileşenine gelen her ticari kural değişikliği rota bileşenine kadar yürür. Ücret bileşeni bir önceki dersin günlüğünde en sık dokunulan yerdi; en sık değişen bileşen, zincirin ortasına yerleşmiş durumda.

Birlikte değişim çizgesinde aynı sayı sıfır. Beş kenarın beşi de kararsızdan kararlıya akıyor: en kararsız iki bileşen (ticari-kural ve izleme) hiçbir bileşene girdi vermiyor, en kararlı iki bileşen (ag ve para) hiçbir şeye bağlanmıyor. Ölçü, bir önceki dersin bölünmesini bağımsız bir ölçütle daha doğruluyor.

Kararlılığın Karşılığı

Kararlı yön yalnız bir estetik tercih olsaydı ölçmeye değmezdi. Karşılığı yayın sırasında görünür: birlikte çizgesinde beş bileşen ag -> para -> izleme -> tarife -> ticari-kural sırasıyla yayınlanabilir. Bu sıra, her bileşenin bağlandığı her şeyin ondan önce yayınlandığını garanti eder. Bir bileşenin yeni sürümü çıktığında hangi bileşenlerin yeniden sınanacağı da aynı sıradan okunur.

Sıranın var olabilmesinin koşulu döngüsüz bağımlılıklar ilkesidir (acyclic dependencies principle): bileşen çizgesinde döngü bulunmamalıdır. Döngü varsa yayın sırası yoktur, çünkü döngüdeki her bileşen bir diğerinin önce yayınlanmasını bekler.

Kararlı Çekirdeğe Tek Bir İthal

Bozuk çizge tam olarak bunu gösteriyor. Eklenen tek kenar para -> tarife. Sonuçlar:

Para bileşeninin kararsızlığı 0.00’dan 0.33’e çıktı. Kitaplığın en kararlı parçası artık tarife tablosuna bağlı; fiyat listesi her yenilendiğinde para bileşeni de yeniden yayınlanacak. Tarife bileşeni de simetrik olarak 0.50’den 0.33’e indi — sayı düştüğü hâlde durum iyileşmedi, çünkü iki bileşen artık birbirinin içine geçmiş durumda.

Kararlı yön ihlali sıfır çıktı. İki bileşenin kararsızlığı eşit olduğu için hiçbir kenar “kararsızdan kararlıya akmıyor” ölçütüne takılmıyor. Bu, kararsızlık ölçüsünün tek başına yetmediğinin kanıtıdır: döngü, ölçüyü ihlal etmez, ölçüyü anlamsızlaştırır.

Yayın sırası ise durumu saklamıyor. Beş bileşenin yalnız ikisi sıralanabildi; para, tarife ve ticari-kural sıralanamayan olarak kaldı. ticari-kural döngünün içinde olmadığı hâlde listede: döngüye bağlanan her bileşen de sıralanamaz hâle gelir. Bir bileşenin tek bir ithal satırı, ona uzaktan bağlı üçüncü bileşeni yayınlanamaz yapıyor.

Döngünün Kırılması

Döngüyü kaldırmanın iki bilinen yolu vardır ve ikisi de daha önce kurulmuş hareketlerdir.

Birincisi yönü çevirmektir: para bileşeni tarifeyi ithal etmek yerine, biçimlendirme için ihtiyaç duyduğu bilgiyi parametre olarak alır. Bu, birinci dersteki hareketin bileşen ölçeğindeki karşılığıdır — kural tabloyu ithal etmez, tablo kurala verilir. SOLID’in bağımlılığın ters çevrilmesi maddesi ile M16/K04’teki katman kuralı aynı hareketi tarif eder.

İkincisi araya bir bileşen koymaktır: iki bileşenin ortak ihtiyacı üçüncü bir bileşene ayrılır ve ikisi de ona bağlanır. Döngü, iki kenarın da aynı yöne bakmasıyla kırılır.

Birinci yol uygulandığında çizge yeniden birlikte değişim çizgesi olur: para yeniden I=0I = 0 değerine döner, kenar sayısı altıdan beşe iner ve beş bileşenin tamamı sıralanır. Ölçülerin üçü de aynı anda düzelir.

Özet

  • Bir bileşenin kararsızlığı I=giden/(gelen+giden)I = \text{giden} / (\text{gelen} + \text{giden}) ile hesaplanır; 0 en kararlı, 1 en kararsız konumu gösterir.
  • Kararlı bağımlılıklar ilkesi kenarların II’nin düştüğü yöne akmasını ister; dizin bölünmesinde 5 kenarın 1’i bu yöne akmıyordu, birlikte değişim bölünmesinde 0’ı.
  • Kararlılığın karşılığı yayın sırasıdır: birlikte çizgesinde beş bileşen tek bir sırayla yayınlanabiliyor ve bir sürüm çıktığında yeniden sınanacaklar aynı sıradan okunuyor.
  • Kararlı çekirdeğe eklenen tek bir ithal (para -> tarife) para bileşeninin kararsızlığını 0.00’dan 0.33’e çıkardı ve beş bileşenin üçünü sıralanamaz yaptı.
  • Aynı bozuk çizgede kararlı yön ihlali 0 çıktı; kararsızlık ölçüsü döngüyü yakalamaz, döngü ölçünün kendisini anlamsızlaştırır.

Sonraki Adım

Yayın sırası döngünün var olduğunu söyledi ama nerede olduğunu söylemedi: sıralanamayan üç bileşenin hangisi döngünün içinde, hangisi ona bağlı olduğu için listede, çıktıdan okunamıyor. Ayrıca bu bölümün bütün ölçüleri elle yazılmış bir bileşen çizgesi üzerindeydi; gerçek bir kod tabanında çizge ithal satırlarından çıkarılır. Sonraki ders ithal grafiğini kaynak dosyalardan okuyan, döngüleri derine aramayla adlarıyla listeleyen ve katman kuralına aykırı ithalleri sayan bir araç yazar; aracı önce bozuk bir sürümde koşturur, sonra düzeltilmiş sürümde iki sayının da sıfıra indiğini gösterir.

İ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