İçeriğe geç
academia.sh

Ders 08 / 10

Bağımlılık ve Katman Denetimi

Yapısal mimari kuralların gerçek bir ithal grafiği üzerinde sınanması: aynı katman kuralının izin listesi ve yasak listesi biçiminde yazılması, beş kural biçiminin bilinen ihlal kümesinde yakalanan, kaçan ve yanlış alarm sayılarının karşılaştırılması, süreli istisnaların yaşlanması ve yeni bir modül eklendiğinde kuralın kaç yerde güncellendiğinin sayılması.

İçindekiler

Önceki dersin uygunluk işlevi tek bir modülün dosyasına baktı. Mimari kuralların bir bölümü ise tek dosyada görünmez: hangi modülün hangi modülü ithal edebileceği ancak grafiğin tamamı okunarak denetlenir. Katman denetimi ve bağımlılık denetimi bu tür kuralların adıdır ve ikisi de aynı veriyi okur — kod tabanının ithal grafiği.

Bu grafiğin kendisi daha önce ölçüldü: servis sınırları kursu aynı türden bir ithal grafiğinden sınır ihlallerini saymıştı. Buradaki soru o sayım değildir. Buradaki soru kuralın kendisidir. Aynı katman kuralı en az iki biçimde yazılabilir — izin listesi (“şu kenar türleri serbesttir”) ve yasak listesi (“şu kenar türleri yasaktır”) — ve iki biçim aynı grafikte farklı sonuç verir. Ders bu farkı üç sayıyla ölçer: hangisi daha az yanlış alarm veriyor, hangisi kaç ihlali kaçırıyor, kod tabanına yeni bir modül girdiğinde kural kaç yerde güncelleniyor. Through-line bölgesel kütüphane ağıdır ve kurgudur.

Denetlenecek İthal Grafiği

YN9 — kod tabanı on üç modülden oluşur, her modül kendi katmanını kaynağında bildirir ve katmanlar giriş, uygulama, alan, altyapı ve ortak olmak üzere beştir. Gerekçe: katman denetimi ancak her modülün bir katmana atanmış olduğu bir kod tabanında koşabilir; katman bildiriminin kaynakta durması, denetleyicinin dışarıdan bir haritaya bağlı kalmamasını sağlar.

// kur.mjs — bolgesel kutuphane agi kod tabanini katmanlariyla diske yazar
import { mkdirSync, writeFileSync } from "node:fs";

const KATMAN = {
  subeUcu: "giris", personelUcu: "giris",
  oduncAkisi: "uygulama", ucretAkisi: "uygulama", uyelikAkisi: "uygulama",
  oduncKurali: "alan", ucretKurali: "alan", katalogKurali: "alan",
  depoErisimi: "altyapi", katalogKoprusu: "altyapi", kimlikKoprusu: "altyapi",
  olayGunlugu: "altyapi", ortakBicim: "ortak",
};

const KENAR = [
  "subeUcu->oduncAkisi", "subeUcu->ucretAkisi", "subeUcu->ortakBicim",
  "personelUcu->uyelikAkisi", "personelUcu->oduncAkisi", "personelUcu->ortakBicim",
  "oduncAkisi->oduncKurali", "oduncAkisi->katalogKurali", "oduncAkisi->depoErisimi",
  "oduncAkisi->katalogKoprusu", "oduncAkisi->ortakBicim",
  "ucretAkisi->ucretKurali", "ucretAkisi->depoErisimi", "ucretAkisi->ortakBicim",
  "uyelikAkisi->kimlikKoprusu", "uyelikAkisi->ortakBicim",
  "oduncKurali->ortakBicim", "ucretKurali->ortakBicim", "katalogKurali->ortakBicim",
  "depoErisimi->ortakBicim", "olayGunlugu->ortakBicim", "katalogKoprusu->ortakBicim",
  "katalogKoprusu->katalogKurali", "kimlikKoprusu->ortakBicim",
  "subeUcu->katalogKoprusu", "ucretAkisi->oduncAkisi",          // istisna kaydi olan iki kenar
  "oduncKurali->depoErisimi", "ucretKurali->katalogKoprusu", "depoErisimi->oduncAkisi",
  "subeUcu->depoErisimi", "subeUcu->katalogKurali", "ortakBicim->olayGunlugu",
  "oduncAkisi->kimlikKoprusu", "ucretAkisi->katalogKoprusu",
];

mkdirSync("kod", { recursive: true });
for (const ad of Object.keys(KATMAN)) {
  const ithal = KENAR.filter((k) => k.split("->")[0] === ad)
    .map((k) => `import { ${k.split("->")[1]}Islem } from "./${k.split("->")[1]}.mjs";`);
  writeFileSync(`kod/${ad}.mjs`, `// katman: ${KATMAN[ad]}\n${ithal.join("\n")}\n` +
    `export const ${ad}Islem = (x) => x;\n`);
}

const K = ["giris", "uygulama", "alan", "altyapi", "ortak"];
const sayi = {};
for (const k of KENAR) {
  const [a, b] = k.split("->");
  sayi[`${KATMAN[a]}->${KATMAN[b]}`] = (sayi[`${KATMAN[a]}->${KATMAN[b]}`] ?? 0) + 1;
}
console.log(`${Object.keys(KATMAN).length} modul dosyasi, ${KENAR.length} ithal kenari`);
console.log(`\nkatmandan katmana kenar sayisi (satir: ithal eden, sutun: ithal edilen)`);
console.log(`${"".padEnd(10)}${K.map((k) => k.padStart(9)).join("")}`);
for (const a of K) {
  console.log(`${a.padEnd(10)}${K.map((b) => String(sayi[`${a}->${b}`] ?? 0).padStart(9)).join("")}`);
}
13 modul dosyasi, 34 ithal kenari

katmandan katmana kenar sayisi (satir: ithal eden, sutun: ithal edilen)
              giris uygulama     alan  altyapi    ortak
giris             0        4        1        2        2
uygulama          0        1        3        6        3
alan              0        0        0        2        3
altyapi           0        1        1        0        4
ortak             0        0        0        1        0

Matris kuralın hangi hücrelerde çiğnendiğini daha kural yazılmadan gösterir: alan satırında altyapıya iki kenar, giriş satırında alana bir ve altyapıya iki kenar, ortak satırında altyapıya bir kenar vardır. Kuralı yazmak bu hücreleri adlandırmaktır — ve adlandırmanın iki ayrı yolu vardır.

Aynı Kuralın Beş Biçimi

Denetleyici dosyaları okur, // katman: satırından katmanı ve from "./..." satırlarından kenarı çıkarır. Aynı kural beş biçimde yazılır: katman granülerliğinde izin listesi, buna eklenen istisna listesi (süresi denetlenen ve denetlenmeyen), modül granülerliğinde izin listesi ve katman granülerliğinde yasak listesi.

YN10 — mimar otuz dört kenarı elle okudu ve dokuzunu gerçek ihlal olarak işaretledi; iki kenarın süreli istisna kaydı vardır ve birinin süresi dolmuştur. Gerekçe: yakalama, kaçırma ve yanlış alarm ancak elle etiketlenmiş bir kümeye karşı sayılabilir; istisna kayıtları da bu kümenin parçasıdır, çünkü onaylanmış bir kenarı ihlal saymak yanlış alarmdır.

// katman.mjs — kod/ dizinindeki gercek ithal grafigini okur; ayni kural bes bicimde kosturulur
import { readFileSync, readdirSync, writeFileSync } from "node:fs";

function grafik(dizin = "kod") {
  const katman = {}, kenar = [];
  for (const d of readdirSync(dizin)) {
    const ad = d.replace(".mjs", "");
    const t = readFileSync(`${dizin}/${d}`, "utf8");
    katman[ad] = t.match(/^\/\/ katman: (\w+)$/m)[1];
    for (const m of t.matchAll(/from "\.\/(\w+)\.mjs"/g)) kenar.push(`${ad}->${m[1]}`);
  }
  return { katman, kenar };
}
const { katman, kenar } = grafik();
const kat = (k) => `${katman[k.split("->")[0]]}->${katman[k.split("->")[1]]}`;

// YN10: mimar otuz dort kenari elle okudu; asagidaki dokuzu gercek ihlaldir. Istisna kaydi olan
// subeUcu->katalogKoprusu gecerlidir; ucretAkisi->oduncAkisi istisnasinin suresi dolmustur.
const IHLAL = new Set([
  "ucretAkisi->oduncAkisi",
  "oduncKurali->depoErisimi", "ucretKurali->katalogKoprusu", "depoErisimi->oduncAkisi",
  "subeUcu->depoErisimi", "subeUcu->katalogKurali", "ortakBicim->olayGunlugu",
  "oduncAkisi->kimlikKoprusu", "ucretAkisi->katalogKoprusu",
]);
const CEYREK = 4;
const ISTISNA = [                                   // kenar | biten ceyrek | gerekce
  ["subeUcu->katalogKoprusu", 5, "goc donemi: sube ucu eski katalog koprusunu okuyor"],
  ["ucretAkisi->oduncAkisi", 2, "gecici: ucret akisi odunc akisindan okuyor"],
];

const IZIN_KATMAN = ["giris->uygulama", "giris->ortak", "uygulama->alan", "uygulama->altyapi",
  "uygulama->ortak", "alan->ortak", "altyapi->alan", "altyapi->ortak"];
const YASAK_KATMAN = ["alan->altyapi", "alan->uygulama", "alan->giris",
  "altyapi->uygulama", "altyapi->giris", "uygulama->giris"];
const IZIN_MODUL = [
  "subeUcu->oduncAkisi", "subeUcu->ucretAkisi", "subeUcu->ortakBicim",
  "personelUcu->uyelikAkisi", "personelUcu->oduncAkisi", "personelUcu->ortakBicim",
  "oduncAkisi->oduncKurali", "oduncAkisi->katalogKurali", "oduncAkisi->depoErisimi",
  "oduncAkisi->katalogKoprusu", "oduncAkisi->ortakBicim",
  "ucretAkisi->ucretKurali", "ucretAkisi->depoErisimi", "ucretAkisi->ortakBicim",
  "uyelikAkisi->kimlikKoprusu", "uyelikAkisi->ortakBicim",
  "oduncKurali->ortakBicim", "ucretKurali->ortakBicim", "katalogKurali->ortakBicim",
  "depoErisimi->ortakBicim", "olayGunlugu->ortakBicim", "katalogKoprusu->ortakBicim",
  "katalogKoprusu->katalogKurali", "kimlikKoprusu->ortakBicim",
  "subeUcu->katalogKoprusu",
];

writeFileSync("izin_modul.json", JSON.stringify(IZIN_MODUL));

const izinliKenar = (sureDenetle) => new Set(ISTISNA
  .filter(([, bitis]) => !sureDenetle || bitis >= CEYREK).map(([k]) => k));
const BICIM = {
  "izin-katman":               { n: IZIN_KATMAN.length, f: (k) => !IZIN_KATMAN.includes(kat(k)) },
  "izin-katman + istisna":     { n: IZIN_KATMAN.length + ISTISNA.length,
    f: (k) => !IZIN_KATMAN.includes(kat(k)) && !izinliKenar(false).has(k) },
  "izin-katman + sureli ist.": { n: IZIN_KATMAN.length + ISTISNA.length,
    f: (k) => !IZIN_KATMAN.includes(kat(k)) && !izinliKenar(true).has(k) },
  "izin-modul":                { n: IZIN_MODUL.length, f: (k) => !IZIN_MODUL.includes(k) },
  "yasak-katman":              { n: YASAK_KATMAN.length, f: (k) => YASAK_KATMAN.includes(kat(k)) },
};

console.log(`${kenar.length} kenar okundu; bilinen ihlal ${IHLAL.size}, istisna kaydi ${ISTISNA.length} ` +
  `(${ISTISNA.filter(([, b]) => b < CEYREK).length} tanesinin suresi dolmus)`);
console.log(`\n${"kural bicimi".padEnd(27)}${"kural satiri".padStart(13)}${"isaretlenen".padStart(13)}` +
  `${"yakalanan".padStart(11)}${"kacan".padStart(7)}${"yanlis alarm".padStart(14)}`);
for (const [ad, b] of Object.entries(BICIM)) {
  const isaret = kenar.filter(b.f);
  const y = isaret.filter((k) => IHLAL.has(k)).length;
  console.log(`${ad.padEnd(27)}${String(b.n).padStart(13)}${String(isaret.length).padStart(13)}` +
    `${`${y}/${IHLAL.size}`.padStart(11)}${String(IHLAL.size - y).padStart(7)}` +
    `${String(isaret.length - y).padStart(14)}`);
}

console.log(`\nkacan ihlaller (kural bicimi basina):`);
for (const [ad, b] of Object.entries(BICIM)) {
  const kacan = [...IHLAL].filter((k) => !b.f(k));
  console.log(`  ${ad.padEnd(27)}${kacan.length ? kacan.map((k) => `${k} (${kat(k)})`).join("; ") : "-"}`);
}
34 kenar okundu; bilinen ihlal 9, istisna kaydi 2 (1 tanesinin suresi dolmus)

kural bicimi                kural satiri  isaretlenen  yakalanan  kacan  yanlis alarm
izin-katman                            8            8        7/9      2             1
izin-katman + istisna                 10            6        6/9      3             0
izin-katman + sureli ist.             10            7        7/9      2             0
izin-modul                            25            9        9/9      0             0
yasak-katman                           6            3        3/9      6             0

kacan ihlaller (kural bicimi basina):
  izin-katman                oduncAkisi->kimlikKoprusu (uygulama->altyapi); ucretAkisi->katalogKoprusu (uygulama->altyapi)
  izin-katman + istisna      ucretAkisi->oduncAkisi (uygulama->uygulama); oduncAkisi->kimlikKoprusu (uygulama->altyapi); ucretAkisi->katalogKoprusu (uygulama->altyapi)
  izin-katman + sureli ist.  oduncAkisi->kimlikKoprusu (uygulama->altyapi); ucretAkisi->katalogKoprusu (uygulama->altyapi)
  izin-modul                 -
  yasak-katman               ucretAkisi->oduncAkisi (uygulama->uygulama); subeUcu->depoErisimi (giris->altyapi); subeUcu->katalogKurali (giris->alan); ortakBicim->olayGunlugu (ortak->altyapi); oduncAkisi->kimlikKoprusu (uygulama->altyapi); ucretAkisi->katalogKoprusu (uygulama->altyapi)

İzin Listesi ile Yasak Listesinin Ayrımı

Tablo yaygın bir beklentiyi bozar. Yasak listesi sıfır yanlış alarm verir ve dokuz ihlalin altısını kaçırır. Nedeni biçimin kendisindedir: yasak listesi yalnız sayılan kenar türlerini görür. Listede alan->altyapi ve altyapi->uygulama yazılıdır, bu yüzden üç ihlal yakalanır; ama giris->altyapi, giris->alan, ortak->altyapi ve aynı katman içindeki uygulama->uygulama listede yoktur ve o kenarlar hiç görülmez. Yasak listesi ne kadar eksikse o kadar sessizdir ve eksik olduğu hiçbir yerde belli olmaz.

İzin listesi ters çalışır: listede olmayan her şey ihlaldir. Katman granülerliğindeki izin listesi sekiz satırla dokuz ihlalin yedisini yakalar. Kaçırdığı ikisi kuralın ifade gücünün sınırıdır: oduncAkisi->kimlikKoprusu ve ucretAkisi->katalogKoprusu kenarları katman düzeyinde serbest olan uygulama->altyapi çiftine düşer; ikisinin de yasak olduğunu söyleyen kural katmanla değil modül adıyla yazılır. Buna karşılık izin listesinin bir yanlış alarmı vardır ve o alarm onaylanmış bir göç kenarını işaretler.

İstisna listesi bu yanlış alarmı kaldırır ama kendi kusurunu getirir. Süresi denetlenmeyen istisna listesinde yakalama 7’den 6’ya düşer: süresi iki çeyrek önce dolmuş bir istisna hâlâ bir gerçek ihlali gizlemektedir. Süre denetlendiğinde yakalama 7’ye döner ve yanlış alarm sıfırda kalır. Bir istisna listesi, süresi denetlenmediği sürece kuralın kendisini aşındırır — ve aşınmanın büyüklüğü tam olarak süresi dolmuş istisna sayısı kadardır.

Modül granülerliğindeki izin listesi tabloda kusursuzdur: dokuz ihlalin dokuzu yakalanır, hiç kaçan ve hiç yanlış alarm yoktur. Bedeli satır sayısında görünür — sekiz satır yerine yirmi beş satır, yani kural artık mimarinin bir özeti değil, grafiğin tam kopyasıdır. Asıl bedel ise bu tabloda hiç görünmez; sonraki koşum onu ölçer.

Yeni Modül Girdiğinde

Kuralın bakım maliyeti kod tabanı durduğu sürece sıfırdır. Aşağıdaki blok kod tabanına yeni bir modül ekler ve aynı kuralları güncellenmemiş hâlleriyle koşturur.

// yeni.mjs — kod tabanina yeni bir modul eklenir; her kural bicimi kac yerde guncelleniyor
import { readFileSync, readdirSync, writeFileSync } from "node:fs";

// YN11: sonraki ceyrekte kod tabanina tek bir yeni modul girer ve alti yeni ithal kenari acar
const YENI = "rezervasyonAkisi";
const YENI_KENAR = [                                            // besi kurala uygun, biri ihlal
  `subeUcu->${YENI}`, `personelUcu->${YENI}`, `${YENI}->oduncKurali`,
  `${YENI}->depoErisimi`, `${YENI}->ortakBicim`, `${YENI}->personelUcu`,
];
writeFileSync(`kod/${YENI}.mjs`, `// katman: uygulama\n` +
  YENI_KENAR.filter((k) => k.startsWith(`${YENI}->`))
    .map((k) => `import { ${k.split("->")[1]}Islem } from "./${k.split("->")[1]}.mjs";`).join("\n") +
  `\nexport const ${YENI}Islem = (x) => x;\n`);
for (const k of YENI_KENAR.filter((k) => k.endsWith(`->${YENI}`))) {
  const a = k.split("->")[0];
  const t = readFileSync(`kod/${a}.mjs`, "utf8");
  writeFileSync(`kod/${a}.mjs`, t.replace(/\n/, `\nimport { ${YENI}Islem } from "./${YENI}.mjs";\n`));
}

const katman = {}, kenar = [];
for (const d of readdirSync("kod")) {
  const ad = d.replace(".mjs", "");
  const t = readFileSync(`kod/${d}`, "utf8");
  katman[ad] = t.match(/^\/\/ katman: (\w+)$/m)[1];
  for (const m of t.matchAll(/from "\.\/(\w+)\.mjs"/g)) kenar.push(`${ad}->${m[1]}`);
}
const kat = (k) => `${katman[k.split("->")[0]]}->${katman[k.split("->")[1]]}`;

const IZIN_KATMAN = ["giris->uygulama", "giris->ortak", "uygulama->alan", "uygulama->altyapi",
  "uygulama->ortak", "alan->ortak", "altyapi->alan", "altyapi->ortak"];
const YASAK_KATMAN = ["alan->altyapi", "alan->uygulama", "alan->giris",
  "altyapi->uygulama", "altyapi->giris", "uygulama->giris"];
const IZIN_MODUL_ESKI = JSON.parse(readFileSync("izin_modul.json", "utf8"));
const uygunYeni = YENI_KENAR.filter((k) => IZIN_KATMAN.includes(kat(k)));
const IZIN_MODUL_YENI = [...IZIN_MODUL_ESKI, ...uygunYeni];

const BICIM = {
  "izin-katman":         { veri: IZIN_KATMAN, f: (k) => !IZIN_KATMAN.includes(kat(k)) },
  "yasak-katman":        { veri: YASAK_KATMAN, f: (k) => YASAK_KATMAN.includes(kat(k)) },
  "izin-modul (eski)":   { veri: IZIN_MODUL_ESKI, f: (k) => !IZIN_MODUL_ESKI.includes(k) },
  "izin-modul (guncel)": { veri: IZIN_MODUL_YENI, f: (k) => !IZIN_MODUL_YENI.includes(k) },
};
const YENI_IHLAL = new Set([`${YENI}->personelUcu`]);

console.log(`yeni modul: ${YENI} (katman: uygulama), ${YENI_KENAR.length} yeni kenar; ` +
  `${uygunYeni.length} tanesi katman kuralina uygun, ${YENI_KENAR.length - uygunYeni.length} tanesi ihlal`);
console.log(`grafik simdi ${Object.keys(katman).length} modul ve ${kenar.length} kenar`);
console.log(`\n${"kural bicimi".padEnd(22)}${"kural satiri".padStart(13)}${"guncellenen satir".padStart(19)}` +
  `${"yeni ihlal yakalandi".padStart(22)}${"yeni yanlis alarm".padStart(19)}`);
for (const [ad, b] of Object.entries(BICIM)) {
  const isaret = YENI_KENAR.filter(b.f);
  const y = isaret.filter((k) => YENI_IHLAL.has(k)).length;
  const guncel = ad === "izin-modul (guncel)" ? uygunYeni.length : 0;
  console.log(`${ad.padEnd(22)}${String(b.veri.length).padStart(13)}${String(guncel).padStart(19)}` +
    `${`${y}/${YENI_IHLAL.size}`.padStart(22)}${String(isaret.length - y).padStart(19)}`);
}
console.log(`\nyeni modulun kendi dosyasinda her bicim icin ayni tek satir var: "// katman: uygulama"`);
yeni modul: rezervasyonAkisi (katman: uygulama), 6 yeni kenar; 5 tanesi katman kuralina uygun, 1 tanesi ihlal
grafik simdi 14 modul ve 40 kenar

kural bicimi           kural satiri  guncellenen satir  yeni ihlal yakalandi  yeni yanlis alarm
izin-katman                       8                  0                   1/1                  0
yasak-katman                      6                  0                   1/1                  0
izin-modul (eski)                25                  0                   1/1                  5
izin-modul (guncel)              30                  5                   1/1                  0

yeni modulun kendi dosyasinda her bicim icin ayni tek satir var: "// katman: uygulama"

Modül granülerliğindeki izin listesinin gizli bedeli budur. Yeni modül tek satırlık bir katman bildirimiyle gelir; katman granülerliğindeki iki biçim hiçbir yerde güncellenmez ve yeni ihlali yakalar. Modül granülerliğindeki izin listesi ise güncellenmediğinde beş yanlış alarm üretir ve bu beş alarmın hepsi kurala tümüyle uygun kenarlar üzerinedir; güncellendiğinde alarm sıfırlanır ve kural yirmi beş satırdan otuza çıkar. Her yeni modül kuralı beş satır büyütür.

Bu, önceki dersin devre dışı bırakma koşumuyla aynı olgudur. Kurala uygun bir değişikliği engelleyen bir denetim, birkaç yayımdan sonra ya kapatılır ya da kural kendiliğinden onaylanan bir listeye dönüşür. Modül granülerliğindeki izin listesi tabloda kusursuz görünürken pratikte en kırılgan biçimdir, çünkü doğruluğu her yeni kenarda elle güncellenmesine bağlıdır.

Ölçülen üç biçim arasındaki seçim şu üç sayının bileşimidir: yasak listesi hiç bakım istemez ve altı ihlal kaçırır; katman izin listesi hiç bakım istemez, iki ihlal kaçırır ve ihlalleri yakalamak için istisna listesinin süre denetimine muhtaçtır; modül izin listesi hiçbir şey kaçırmaz ve her modülde beş satır bakım ister. Kuralın granülerliği yükseldikçe yakalama artar ve bakım maliyeti onunla birlikte artar; hiçbir biçim ikisini birden ucuzlatmaz.

Özet

  • Katman denetimi gerçek dosyalardan okunan bir ithal grafiği üzerinde koşturuldu: 13 modül, 34 kenar, 9 elle etiketlenmiş ihlal ve süreli 2 istisna kaydı.
  • Yasak listesi biçimi 6 satırla hiç yanlış alarm vermez ama 9 ihlalin 6’sını kaçırır; kaçırdığı kenar türleri listede sayılmadığı için sessizce geçer.
  • Katman granülerliğindeki izin listesi 8 satırla 7 ihlal yakalar, 2 kaçırır ve onaylanmış bir göç kenarına 1 yanlış alarm verir; kaçırdığı ikisi katmanla değil modül adıyla yazılabilen kurallardır.
  • Süresi denetlenmeyen istisna listesi yakalamayı 7’den 6’ya düşürür; süresi dolmuş tek bir istisna bir gerçek ihlali gizler, süre denetimi eklendiğinde yakalama 7’ye döner ve yanlış alarm sıfırdır.
  • Modül granülerliğindeki izin listesi 25 satırla 9/9 yakalar ve hiç yanlış alarm vermez; bedeli yeni modülde ortaya çıkar — güncellenmediğinde kurala uygun 5 kenara yanlış alarm verir, güncellendiğinde 5 satır büyür.
  • Kuralın granülerliği yükseldikçe yakalama artar ve bakım maliyeti onunla birlikte artar; katman bildirimi kaynakta durduğu için katman biçimleri yeni modülde 0 satır güncelleme ister.

Sonraki Adım

Bu üç derste kurallar yazıldı, denetime çevrildi ve denetimin yakaladığı ile kaçırdığı sayıldı. Hepsinin ortak varsayımı şudur: mimari sabittir ve kural onu korur. Oysa bu dersin son koşumu tam tersini gösterdi — kod tabanına bir modül girdiği anda kuralın kendisi de değişmek zorunda kaldı. Bir mimarinin ölçülmesi gereken niteliği yalnız bugün kurala uyup uymadığı değil, değişimi ne kadar ucuza kabul ettiğidir. Sonraki ders bu niteliği ele alır: değişimi ucuzlatan yapı kararlarının kendisi bir denetime çevrilebilir mi, çevrilebiliyorsa hangi sayı ölçülür ve çevrilemeyen kısmın yerine ne konur.

İ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