---
title: 'Sınır Çizme Ölçütleri'
source: 'https://academia.sh/tr/kurslar/servis-mimarileri/sinir-cizme-olcutleri'
course: 'Servis Mimarileri'
language: tr
updated: '2026-08-17T18:06:53+00:00'
license: 'CC BY-SA 4.0'
---

# Sınır Çizme Ölçütleri

Sınırın nereden geçeceğinin koddan ölçülmesi: modüller arası ithal kenarının bağlaşım ölçüsü olarak sayılması, her tablonun sahibinin belirlenip sahibi olmayan yazmaların bulunması, değişiklik kaydından çıkarılan değişim birlikteliği ve üç aday sınır çiziminin aynı ölçütlerle karşılaştırılması.

Önceki konu tek parçadan sunucusuza kadar uzanan seçenekleri kurdu ve her birinin bedelini
dağıtım birimi, süreç ve dağıtım adımı cinsinden saydı. Seçeneklerin hepsinin ortak bir varsayımı
vardı: sınırın nereden geçtiği verili kabul edildi. Oysa bu listede en pahalı karar mimari
seçeneğin adı değil, sınırın yeridir. Yanlış yerden geçen bir sınır, seçilen mimari ne olursa
olsun her değişikliği iki tarafa birden dokundurur.

Bu ders sınırın yerini bir ölçüte bağlar ve ölçüt kodun içindedir. Alan modelleme, sınırlı bağlam
ve bağlam haritası Alan Odaklı Tasarım kursunda kuruldu; burada alan modeli öğretilmez. Buradaki
soru daha dar: elde çalışan bir modüler tek parça varken, hangi sayıya bakılarak sınır çizilir.
Through-line kütüphane ödünç sistemidir ve beş alan modülüne sahiptir: katalog, üyelik, ödünç,
bildirim, ücretlendirme.

## Ölçülecek Uygulama

Aşağıdaki blok uygulamayı diske yazar ve bir kitabın ödünç verilmesi iş akışını koşturur. Modül
dosyaları bir haritadan üretilir; her modül hangi modülleri ithal ettiğini, hangi tablolara
yazdığını ve hangi tablonun sahibi olduğunu kendi kaynağında taşır.

```js
// kur.mjs — kutuphane odunc uygulamasini modul dosyalari olarak yazar ve is akisini kosturur
import { mkdirSync, writeFileSync } from "node:fs";

const MODUL = {                       // ithal: alan modulleri | yazar: tablolar | sahip: tablolar
  katalog:       { ithal: [],                    yazar: ["kitap", "nusha"], sahip: ["kitap", "nusha"] },
  uyelik:        { ithal: [],                    yazar: ["uye"],            sahip: ["uye"] },
  odunc:         { ithal: ["katalog", "uyelik"], yazar: ["odunc", "nusha"], sahip: ["odunc"] },
  ucretlendirme: { ithal: ["odunc"],             yazar: ["ucret", "odunc"], sahip: ["ucret"] },
  bildirim:      { ithal: ["uyelik", "odunc"],   yazar: ["bildirim"],       sahip: ["bildirim"] },
};

mkdirSync("uygulama", { recursive: true });
writeFileSync("uygulama/depo.mjs",
  "export const kayit = [];\n" +
  "export const yaz = (tablo, satir) => kayit.push({ tablo, ...satir });\n");

for (const [ad, m] of Object.entries(MODUL)) {
  writeFileSync(`uygulama/${ad}.mjs`,
    `// sahip: ${m.sahip.join(", ")}\n` +
    'import { yaz, kayit } from "./depo.mjs";\n' +
    m.ithal.map((i) => `import { ${i}Oku } from "./${i}.mjs";\n`).join("") +
    `export const ${ad}Oku = () => kayit.filter((k) => k.tablo === "${m.sahip[0]}");\n` +
    `export function ${ad}Islem(veri) {\n` +
    m.ithal.map((i) => `  ${i}Oku();\n`).join("") +
    m.yazar.map((t) => `  yaz("${t}", { adim: "${ad}", ...veri });\n`).join("") +
    "}\n");
}
writeFileSync("uygulama/uygulama.mjs",
  'import { kayit } from "./depo.mjs";\n' +
  'import { uyelikIslem } from "./uyelik.mjs";\n' +
  'import { katalogIslem } from "./katalog.mjs";\n' +
  'import { oduncIslem } from "./odunc.mjs";\n' +
  'import { bildirimIslem } from "./bildirim.mjs";\n' +
  'import { ucretlendirmeIslem } from "./ucretlendirme.mjs";\n' +
  'const istek = { uye: 7, kitap: 412 };\n' +
  "uyelikIslem(istek); katalogIslem(istek); oduncIslem(istek);\n" +
  "bildirimIslem(istek); ucretlendirmeIslem(istek);\n" +
  'export const yazilan = kayit.map((k) => `${k.adim}->${k.tablo}`);\n');

const { yazilan } = await import("./uygulama/uygulama.mjs");
console.log(`modul dosyasi: ${Object.keys(MODUL).length} alan modulu + depo + uygulama girisi`);
console.log(`is akisi (bir kitabin odunc verilmesi) ${yazilan.length} yazma uretti:`);
console.log(yazilan.join("  "));
```

```
modul dosyasi: 5 alan modulu + depo + uygulama girisi
is akisi (bir kitabin odunc verilmesi) 8 yazma uretti:
uyelik->uye  katalog->kitap  katalog->nusha  odunc->odunc  odunc->nusha  bildirim->bildirim  ucretlendirme->ucret  ucretlendirme->odunc
```

Başlangıç noktası budur: tek dağıtım birimi, tek süreç, sekiz yazma. Bu hâliyle sistem çalışıyor
ve hiçbir sınır yok. Sınır çizme kararı bundan sonra verilecek.

## Koddan Okunan İki Ölçüt

İlk iki ölçüt kaynak dosyalardan doğrudan çıkarılır. **Bağlaşım** (coupling) burada bir sayıya
indirgenir: bir modülün başka bir alan modülünden yaptığı ithal, bir kenardır. **Veri sahipliği**
ikinci ölçüttür: her tablonun tek bir sahip modülü vardır ve sahibi olmayan bir modülün o tabloya
yazması ayrı sayılır.

```js
// olc.mjs — kur.mjs'in yazdigi uygulama/ dizinini okur; olcu koddan cikarilir
import { readFileSync, readdirSync } from "node:fs";

const dosya = readdirSync("uygulama").filter((d) => d !== "depo.mjs" && d !== "uygulama.mjs");
const M = {};
for (const d of dosya) {
  const t = readFileSync(`uygulama/${d}`, "utf8");
  M[d.replace(".mjs", "")] = {
    ithal: [...t.matchAll(/from "\.\/(\w+)\.mjs"/g)].map((m) => m[1]).filter((a) => a !== "depo"),
    yazar: [...t.matchAll(/yaz\("(\w+)"/g)].map((m) => m[1]),
    sahip: t.match(/^\/\/ sahip: (.+)$/m)[1].split(", "),
  };
}
const ad = Object.keys(M);
const sahibi = (tablo) => ad.find((a) => M[a].sahip.includes(tablo));
const kenar = ad.flatMap((a) => M[a].ithal.map((b) => [a, b]));
const disYazma = ad.flatMap((a) => M[a].yazar.filter((t) => sahibi(t) !== a).map((t) => [a, t]));

console.log(`${"modul".padEnd(15)}${"ithal ettigi".padEnd(18)}${"yazdigi".padEnd(15)}sahibi oldugu`);
for (const a of ad) {
  console.log(`${a.padEnd(15)}${(M[a].ithal.join(",") || "-").padEnd(18)}` +
    `${M[a].yazar.join(",").padEnd(15)}${M[a].sahip.join(",")}`);
}
console.log(`toplam: ${ad.length} modul, ${kenar.length} ithal kenari, ` +
  `${ad.reduce((s, a) => s + M[a].yazar.length, 0)} yazma, ` +
  `${disYazma.length} sahibi olmayan yazma (${disYazma.map(([a, t]) => `${a}->${t}`).join(", ")})`);
```

```
modul          ithal ettigi      yazdigi        sahibi oldugu
bildirim       uyelik,odunc      bildirim       bildirim
katalog        -                 kitap,nusha    kitap,nusha
odunc          katalog,uyelik    odunc,nusha    odunc
ucretlendirme  odunc             ucret,odunc    ucret
uyelik         -                 uye            uye
toplam: 5 modul, 5 ithal kenari, 8 yazma, 2 sahibi olmayan yazma (odunc->nusha, ucretlendirme->odunc)
```

Beş kenar ve iki sahibi olmayan yazma. Bu iki yazma tek dağıtım birimi içinde yalnızca bir düzen
kusurudur: ödünç modülü nüsha durumunu doğrudan değiştiriyor, ücretlendirme modülü ödünç kaydına
gecikme işareti koyuyor. İkisi de aynı süreçte, aynı işlemin içinde olduğu için bugün bir bedel
ödetmiyor. Sınır çizildiği anda bunlar **sınır ihlaline** dönüşür: bir servisin başka bir servisin
tablosuna yazması artık ya bir uca ya da paylaşılan bir tabloya bağımlılık demektir.

## Üçüncü Ölçüt: Değişim Birlikteliği

Üçüncü ölçüt kaynak dosyalarda görünmez, kod tabanının geçmişinde durur. **Değişim birlikteliği**
(change coupling), iki modülün aynı değişiklikte birlikte değişme sıklığıdır. Ölçüt şudur: sık
birlikte değişen iki modülü ayıran bir sınır, her değişikliği iki dağıtım birimine yayar.

**SS1 — son çeyreğin değişiklik kaydı yirmi satırdır ve her satır bir değişikliğin dokunduğu
modülleri verir.** Gerekçe: sürüm geçmişindeki her değişiklik, dokunduğu dosyalardan modül kümesine
indirgenebilir; bu ders o indirgemenin sonucunu girdi olarak sabitler. Sayı ve dağılım değişirse
aşağıdaki sıralama da değişir; ölçütün kendisi değişmez.

```js
// aday.mjs — ayni dizini okur, uc aday sinir cizimini ayni olcutlerle karsilastirir
import { readFileSync, readdirSync } from "node:fs";

const M = {};
for (const d of readdirSync("uygulama").filter((x) => x !== "depo.mjs" && x !== "uygulama.mjs")) {
  const t = readFileSync(`uygulama/${d}`, "utf8");
  M[d.replace(".mjs", "")] = {
    ithal: [...t.matchAll(/from "\.\/(\w+)\.mjs"/g)].map((m) => m[1]).filter((a) => a !== "depo"),
    yazar: [...t.matchAll(/yaz\("(\w+)"/g)].map((m) => m[1]),
    sahip: t.match(/^\/\/ sahip: (.+)$/m)[1].split(", "),
  };
}
const ad = Object.keys(M);
const sahibi = (tablo) => ad.find((a) => M[a].sahip.includes(tablo));
const kenar = ad.flatMap((a) => M[a].ithal.map((b) => [a, b]));
const disYazma = ad.flatMap((a) => M[a].yazar.filter((t) => sahibi(t) !== a).map((t) => [a, t]));

// SS1: son ceyregin degisiklik kaydi — her satir bir degisiklik ve dokundugu moduller
const DEGISIM = [
  "gecikme ucreti orani: odunc ucretlendirme", "odunc suresini uzatma: odunc ucretlendirme",
  "ucret muafiyeti: ucretlendirme", "hatirlatma metni: bildirim",
  "iletisim tercihi: uyelik bildirim", "uyelik dondurma: uyelik odunc",
  "tur etiketi: katalog", "arama alani: katalog",
  "nusha durumu: katalog odunc", "rezervasyon sirasi: katalog odunc",
  "ceza esigi: odunc ucretlendirme", "uye adres alani: uyelik",
  "bildirim kanali: bildirim", "yenileme hatirlatmasi: uyelik bildirim",
  "gecikme gunu hesabi: odunc ucretlendirme", "nusha kaybi: katalog odunc ucretlendirme",
  "kapak gorseli: katalog", "kimlik dogrulama: uyelik",
  "iade akisi: odunc", "ucret iadesi: ucretlendirme",
].map((s) => [s.split(": ")[0], s.split(": ")[1].split(" ")]);

const cift = {};
for (const [, ms] of DEGISIM) {
  for (let i = 0; i < ms.length; i += 1) {
    for (let j = i + 1; j < ms.length; j += 1) {
      const c = [ms[i], ms[j]].sort().join(" + ");
      cift[c] = (cift[c] ?? 0) + 1;
    }
  }
}
console.log(`${DEGISIM.length} degisiklikte birlikte degisen ciftler (SS1):`);
for (const [c, n] of Object.entries(cift).sort((a, b) => b[1] - a[1])) {
  console.log(`  ${c.padEnd(30)}${n}`);
}

const ADAY = {
  "A referans/islem": [["katalog", "uyelik"], ["odunc", "ucretlendirme", "bildirim"]],
  "B varlik basina": [["katalog"], ["uyelik"], ["odunc"], ["ucretlendirme"], ["bildirim"]],
  "C degisim birlikteligi": [["odunc", "ucretlendirme"], ["katalog"], ["uyelik", "bildirim"]],
};
console.log(`\n${"aday".padEnd(24)}${"birim".padStart(6)}${"sinir gecen ithal".padStart(19)}` +
  `${"sahiplik ihlali".padStart(17)}${"tek birimde kalan".padStart(19)}${"dagitim".padStart(9)}`);
for (const [a, bolum] of Object.entries(ADAY)) {
  const birim = (m) => bolum.findIndex((b) => b.includes(m));
  const dokunulan = DEGISIM.map(([, ms]) => new Set(ms.map(birim)).size);
  const toplam = dokunulan.reduce((s, n) => s + n, 0);
  console.log(`${a.padEnd(24)}${String(bolum.length).padStart(6)}` +
    `${String(kenar.filter(([x, y]) => birim(x) !== birim(y)).length).padStart(19)}` +
    `${String(disYazma.filter(([x, t]) => birim(x) !== birim(sahibi(t))).length).padStart(17)}` +
    `${`${dokunulan.filter((n) => n === 1).length}/${DEGISIM.length}`.padStart(19)}` +
    `${String(toplam).padStart(9)}`);
}

// Ayni degisiklik, dort gerceklestirim: SS1'in ilk satiri
const [dad, dmod] = DEGISIM[0];
console.log(`\n"${dad}" degisikligi (${dmod.join(", ")}) dort gerceklestirimde:`);
console.log(`${"gerceklestirim".padEnd(24)}${"dokunulan dosya".padStart(16)}${"dagitim birimi".padStart(16)}` +
  `${"aga donusen ithal".padStart(19)}${"sinir gecen yazma".padStart(19)}`);
for (const [g, bolum] of Object.entries({ "moduler tek parca": [ad], ...ADAY })) {
  const birim = (m) => bolum.findIndex((b) => b.includes(m));
  console.log(`${g.padEnd(24)}${String(dmod.length).padStart(16)}` +
    `${String(new Set(dmod.map(birim)).size).padStart(16)}` +
    `${String(kenar.filter(([x, y]) => dmod.includes(x) && dmod.includes(y) && birim(x) !== birim(y)).length).padStart(19)}` +
    `${String(disYazma.filter(([x, t]) => dmod.includes(x) && birim(x) !== birim(sahibi(t))).length).padStart(19)}`);
}
```

```
20 degisiklikte birlikte degisen ciftler (SS1):
  odunc + ucretlendirme         5
  katalog + odunc               3
  bildirim + uyelik             2
  odunc + uyelik                1
  katalog + ucretlendirme       1

aday                     birim  sinir gecen ithal  sahiplik ihlali  tek birimde kalan  dagitim
A referans/islem             2                  3                1              14/20       26
B varlik basina              5                  5                2              10/20       31
C degisim birlikteligi       3                  3                1              16/20       24

"gecikme ucreti orani" degisikligi (odunc, ucretlendirme) dort gerceklestirimde:
gerceklestirim           dokunulan dosya  dagitim birimi  aga donusen ithal  sinir gecen yazma
moduler tek parca                      2               1                  0                  0
A referans/islem                       2               1                  0                  1
B varlik basina                        2               2                  1                  2
C degisim birlikteligi                 2               1                  0                  1
```

## Üç Adayın Okunması

En sık birlikte değişen çift ödünç ile ücretlendirmedir: yirmi değişikliğin beşi ikisine birden
dokunuyor. Katalog ile ödünç üç kez, üyelik ile bildirim iki kez birlikte değişiyor.

**Aday B, her varlığa bir servis, en temiz görünen çizimdir ve ölçüde en pahalısıdır.** Beş ithal
kenarının beşi de sınırı geçiyor, iki sahiplik ihlalinin ikisi de sınır ihlaline dönüşüyor ve
yirmi değişikliğin yalnız onu tek birimde kalıyor. Yirmi değişikliğin toplam dağıtım sayısı 31.

**Aday A ile aday C bağlaşımda eşittir**, ikisi de üç kenar ve bir ihlal veriyor. Ayrım üçüncü
ölçütte çıkıyor: A değişikliklerin on dördünü, C on altısını tek birimde tutuyor; dağıtım toplamı
26'ya karşı 24. Fark, A'nın üyelik ile bildirimi ayırmasından geliyor — o çift iki kez birlikte
değişiyor ve A her seferinde iki birime dokunuyor.

Buradan çıkan kural şudur: **bağlaşım ve sahiplik ölçütleri aday sayısını daraltır, kararı değişim
birlikteliği verir.** İlk iki ölçüt kodun bugünkü hâlini, üçüncüsü kodun nasıl değiştiğini
ölçer; sınır ikincisine göre çizilir çünkü sınırın bedeli her değişiklikte ödenir.

## Aynı Değişiklik, Dört Gerçekleştirim

Son tablo tek bir değişikliği izliyor: gecikme ücreti oranı, ödünç ile ücretlendirmeye dokunuyor.
Dokunulan dosya sayısı dört gerçekleştirimde de ikidir; sınır çizmek bir değişikliğin kod
hacmini azaltmaz. Değişen şey o iki dosyanın nereye ait olduğudur.

**Neyi ucuzlattı.** Modüler tek parçada ve C çiziminde değişiklik tek dağıtım biriminde kalıyor:
tek doğrulama, tek dağıtım, tek geri alma. C bunu tek parçadan farkı olmadan yaparken sistemi üç
bağımsız birime bölmüş oluyor; katalog değişiklikleri ödünç birimine hiç dokunmuyor.

**Neyi pahalılaştırdı.** B çiziminde aynı değişiklik iki dağıtım birimine dokunuyor, bir ithal
kenarı ağ çağrısına dönüşüyor ve iki yazma sınırı geçiyor. Ücretlendirmenin ödünç tablosuna
yazması artık kendi verisine yazma değil, başka bir birimin verisine yazmadır; ya o birimde bir uç
açılır ya da tablo iki birim tarafından paylaşılır. İkisi de yeni sözleşme demektir.

**Hangi yeni arıza kipi doğdu.** Tek parçada iki dosya birlikte yayımlanır ve arada tutarsız bir
an olmaz. İki dağıtım birimine bölündüğünde iki yayım arasında bir pencere açılır: yeni oran
ücretlendirmede yürürlüktedir ama ödünç eski alanı gönderiyordur. Bu, tek parçada bulunmayan bir
arıza kipidir ve sınırın kendisinden doğar. A ile C'de kalan tek sahiplik ihlali de aynı sınıfa
girer: ödünç modülünün nüsha durumunu yazması, katalog ayrı bir birime taşındığı anda ya bir
çağrıya dönüşecek ya da iki birimin aynı satırı yazmasına yol açacaktır.

## Özet

- Sınırın yeri üç ölçüyle sınanır ve üçü de koddan okunur: ithal kenarı (bağlaşım), tablo başına
  sahip modül (veri sahipliği), değişikliklerin modül kümesi (değişim birlikteliği).
- Ölçülen uygulamada 5 alan modülü, 5 ithal kenarı ve 8 yazma var; yazmaların ikisi sahibi olmayan
  modülden geliyor ve tek dağıtım biriminde bedelsizken sınır çizilince sınır ihlaline dönüşüyor.
- Her varlığa bir servis çizimi üç ölçütte de en kötüsüdür: 5 kenarın 5'i sınırı geçiyor, 2
  ihlalin 2'si kalıyor, 20 değişikliğin yalnız 10'u tek birimde kalıyor ve dağıtım toplamı 31.
- Bağlaşımda eşit iki aday değişim birlikteliğiyle ayrılır: 14/20'ye karşı 16/20 ve 26'ya karşı 24
  dağıtım; sık birlikte değişen çifti ayıran sınır her değişiklikte iki birime dokunur.
- Aynı değişiklik dört gerçekleştirimde de 2 dosyaya dokunuyor; sınır dosya sayısını değil dağıtım
  birimi, ağ çağrısı ve sınırı geçen yazma sayısını değiştiriyor.

## Sonraki Adım

Sınır bir ölçüte bağlandı, ama sınırın çizilmesiyle birlikte tabloda sessizce duran bir sayı
işlemeye başlıyor: ağa dönüşen ithal. Modüller arasında bir ithal kenarı, aynı süreçte bir işlev
çağrısıdır ve maliyeti yığıt üzerinde ölçülür. İki dağıtım birimi arasında aynı kenar bir ağ
çağrısıdır ve maliyeti tur cinsinden ölçülür. Sonraki ders bu dönüşümü gerçek süreçlerle kurar:
aynı ödünç verme iş akışı önce tek süreçte, sonra ayrı süreçlerde koşturulur ve zincirin uzunluğu
arttıkça uçtan uca turun nasıl büyüdüğü ölçülür. Aynı koşumda ikinci bir soru daha sorulur — bu
süreçlerden biri ayakta değilken gelen isteklerin hangi payı yanıtsız kalır.
