---
title: 'Bağımlılık ve Katman Denetimi'
source: 'https://academia.sh/tr/kurslar/mimari-yonetisim/bagimlilik-ve-katman-denetimi'
course: 'Kalite Nitelikleri ve Yönetişim'
language: tr
updated: '2026-08-17T18:10:33+00:00'
license: 'CC BY-SA 4.0'
---

# 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ı.

Ö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.

```js
// 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.

```js
// 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.

```js
// 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.
