---
title: 'Tek Parça Uygulama'
source: 'https://academia.sh/tr/kurslar/servis-mimarileri/tek-parca-uygulama'
course: 'Servis Mimarileri'
language: tr
updated: '2026-08-17T18:06:53+00:00'
license: 'CC BY-SA 4.0'
---

# Tek Parça Uygulama

Çalışan bir tek parça ödünç sisteminin kurulması ve ölçülmesi: yedi modül, on ithal kenarı, tek süreç, sıfır ağ atlaması; yerel çağrının ucuzluğu, tek dağıtım biriminin getirdiği değiştirme kolaylığı ve aynı birimin çoğaltılmasıyla ortaya çıkan ölçek sınırı.

Önceki kurs, Eşzamansız İşleme, kapanışında tek bir varsayımı işaret etti: bütün kuyruklar,
teslim garantileri ve geri basınç düzenekleri **tek bir dağıtım biriminin** içinde kuruldu. Bu
kurs o birimi bölmeyi ele alır. Bölmeden önce bölünecek şeyin ne olduğu ortada durmalıdır.

Bu ders, kütüphane ödünç sisteminin çalışan bir **tek parça (monolith)** gerçekleştirmesini
kurar ve ölçer. Kurulan düzenek sonraki beş dersin tabanıdır: her ders onu bir adım böler ya
da bölmenin bedelini bu ölçülerin üzerinden sayar. Mimari biçemlerin tanımı Mimari Biçemler
kursunda yapıldı; buradaki iş tanım değil, gerçekleştirme ve ölçüdür.

## Düzeneğin Sınırı

**MS1.** Durum tek bir JSON dosyasında tutulur. Gerçek bir dağıtımda burada paylaşılan bir
veri deposu olurdu; modelin taşıdığı özellik, durumun **süreç dışında ve tek yerde** olmasıdır.

**MS2.** Modüller aynı süreçte, yerel işlev çağrısıyla konuşur. Ağ gecikmesi, serileştirme ve
kısmi hata bu modelde yoktur; onlar dördüncü derste gerçek süreçlerle ölçülür.

## Düzenek: Tek Parça Ödünç Sistemi

Sistem beş iş alanı taşır: katalog, üyelik, ödünç, bildirim ve ücretlendirme. Durumu tutan
ortak bir modül var.

```js
// depo.mjs — butun modullerin durumu; tek dosya, tek surec
import { existsSync, readFileSync, writeFileSync } from "node:fs";
const YOL = "veri.json";
const BASLANGIC = {
  kitap: { 1: { baslik: "Korluk", durum: "rafta" }, 2: { baslik: "Kum Kitabi", durum: "rafta" } },
  uye: { 4: { ad: "Emre", acik: 1, sinir: 3, borc: 0 },
         5: { ad: "Selin", acik: 3, sinir: 3, borc: 0 } },
  odunc: [],
};
export function oku() {
  if (existsSync(YOL) === false) writeFileSync(YOL, JSON.stringify(BASLANGIC));
  return JSON.parse(readFileSync(YOL, "utf8"));
}
export function yaz(d) { writeFileSync(YOL, JSON.stringify(d)); }
```

Üç iş modülü bu depoyu okur ve yazar; bildirim modülünün durumu yoktur.

```js
// katalog.mjs — kitap kayitlari
import { oku, yaz } from "./depo.mjs";
export function durum(kitapId) { return oku().kitap[kitapId].durum; }
export function oduncIsaretle(kitapId) {
  const d = oku();
  if (d.kitap[kitapId].durum !== "rafta") throw new Error("kitap rafta degil");
  d.kitap[kitapId].durum = "odunc";
  yaz(d);
}
```

```js
// uyelik.mjs — uye kayitlari ve odunc siniri
import { oku, yaz } from "./depo.mjs";
export function uygunMu(uyeId) { const u = oku().uye[uyeId]; return u.acik < u.sinir; }
export function oduncEkle(uyeId) { const d = oku(); d.uye[uyeId].acik += 1; yaz(d); }
```

```js
// ucretlendirme.mjs — gecikme ucreti
import { oku, yaz } from "./depo.mjs";
export const GUNLUK = 2;
export function ucret(gecikmeGun) { return gecikmeGun > 0 ? gecikmeGun * GUNLUK : 0; }
export function borcEkle(uyeId, tutar) { const d = oku(); d.uye[uyeId].borc += tutar; yaz(d); }
```

```js
// bildirim.mjs — uyeye bildirim
export function gonder(uyeId, metin) { console.log(`  bildirim -> uye ${uyeId}: ${metin}`); }
```

İş akışını yürüten modül dördünü de sırayla çağırır.

```js
// odunc.mjs — odunc verme is akisi; dort modulu sirayla cagirir
import { oku, yaz } from "./depo.mjs";
import * as katalog from "./katalog.mjs";
import * as uyelik from "./uyelik.mjs";
import * as ucretlendirme from "./ucretlendirme.mjs";
import * as bildirim from "./bildirim.mjs";

export function oduncVer(kitapId, uyeId, gecikmeGun = 0) {
  if (uyelik.uygunMu(uyeId) === false) throw new Error("odunc siniri asildi");
  katalog.oduncIsaretle(kitapId);
  uyelik.oduncEkle(uyeId);
  const tutar = ucretlendirme.ucret(gecikmeGun);
  if (tutar > 0) ucretlendirme.borcEkle(uyeId, tutar);
  const d = oku();
  d.odunc.push({ kitapId, uyeId });
  yaz(d);
  bildirim.gonder(uyeId, `kitap ${kitapId} odunc verildi`);
  return { kitapId, uyeId, tutar };
}
```

```js
// uygulama.mjs — tek giris noktasi; is akisini bastan sona kosturur
import { oduncVer } from "./odunc.mjs";
import { durum } from "./katalog.mjs";
const [kitapId = 1, uyeId = 4, gecikme = 0] = process.argv.slice(2).map(Number);
try {
  const s = oduncVer(kitapId, uyeId, gecikme);
  console.log(`odunc verildi: kitap ${s.kitapId} -> uye ${s.uyeId}, ucret ${s.tutar}`);
} catch (h) {
  console.log("basarisiz:", h.message);
}
console.log(`  katalog: kitap ${kitapId} = ${durum(kitapId)}`);
```

## İş Akışının Koşumu

Dört istek dört yolu sınar: geçen bir ödünç, ödünçteki bir kitabın ikinci kez istenmesi,
sınırındaki bir üye ve gecikme ücreti çıkaran bir kayıt.

```sh
rm -f veri.json
node uygulama.mjs 1 4
echo "--- ayni kitap ikinci kez ---"
node uygulama.mjs 1 4
echo "--- sinirdaki uye ---"
node uygulama.mjs 2 5
echo "--- gecikmeli kayit ---"
node uygulama.mjs 2 4 3
```

```
  bildirim -> uye 4: kitap 1 odunc verildi
odunc verildi: kitap 1 -> uye 4, ucret 0
  katalog: kitap 1 = odunc
--- ayni kitap ikinci kez ---
basarisiz: kitap rafta degil
  katalog: kitap 1 = odunc
--- sinirdaki uye ---
basarisiz: odunc siniri asildi
  katalog: kitap 2 = rafta
--- gecikmeli kayit ---
  bildirim -> uye 4: kitap 2 odunc verildi
odunc verildi: kitap 2 -> uye 4, ucret 6
  katalog: kitap 2 = odunc
```

Üçüncü koşumda dikkat çeken şey, üyelik denetiminin katalogdan **önce** yapılmış olmasıdır:
sınır aşıldığı için kitap hiç işaretlenmedi. Bu sıralamayı ayakta tutan şey, iki denetimin de
aynı süreçte, aynı `oduncVer` gövdesinde durmasıdır. Beşinci koşumdan sonra bu sıralama bir
sözleşmeye dönüşecek; şimdilik bir `if` satırıdır.

## Ölçü

Mimari tartışmasının taşıyacağı sayılar kaynak dosyalardan okunur.

```js
// olc.mjs — modul, ithal kenari ve is akisindaki modullerarasi cagri sayisi
import { readdirSync, readFileSync } from "node:fs";
const KENAR = /from "\.\/([\w-]+\.mjs)"/g;
const dosyalar = readdirSync(".").filter((a) => a.endsWith(".mjs") && a !== "olc.mjs").sort();
let toplam = 0;
for (const d of dosyalar) {
  const hedef = [...readFileSync(d, "utf8").matchAll(KENAR)].map((m) => m[1].replace(".mjs", ""));
  toplam += hedef.length;
  console.log(`${d.padEnd(18)} -> ${hedef.join(", ") || "(yok)"}`);
}
const akis = [...readFileSync("odunc.mjs", "utf8")
  .matchAll(/\b(katalog|uyelik|ucretlendirme|bildirim)\.\w+\(/g)];
console.log(`modul: ${dosyalar.length}   ithal kenari: ${toplam}`);
console.log(`is akisindaki modullerarasi cagri: ${akis.length}   ag atlamasi: 0`);
console.log(`surec: 1   dagitim birimi: 1   baslatma adimi: 1`);
```

```sh
node olc.mjs
```

```
bildirim.mjs       -> (yok)
depo.mjs           -> (yok)
katalog.mjs        -> depo
odunc.mjs          -> depo, katalog, uyelik, ucretlendirme, bildirim
ucretlendirme.mjs  -> depo
uyelik.mjs         -> depo
uygulama.mjs       -> odunc, katalog
modul: 7   ithal kenari: 10
is akisindaki modullerarasi cagri: 6   ag atlamasi: 0
surec: 1   dagitim birimi: 1   baslatma adimi: 1
```

Yedi modül, on ithal kenarı, altı modüller arası çağrı. Bu altı çağrının hepsi yerel: yığıt
üzerinde parametre geçirir, dönüş değerini doğrudan alır, hata `throw` ile yayılır. Ağ
atlaması sıfırdır. Sistemi ayağa kaldırmak tek adımdır; ödünç iş akışını uçtan uca koşturmak
için başka bir sürecin hazır olmasını beklemek gerekmez.

Bu üç sayı — altı yerel çağrı, sıfır atlama, bir dağıtım birimi — tek parçanın ucuzlattığı
şeyi tek başına anlatır. Bir çağrının yarı yolda kaybolması diye bir durum yoktur; ya işlev
döner ya hata atar. Katalog ile üyelik arasındaki tutarlılık için bir düzen kurmak gerekmez,
çünkü ikisi de aynı `veri.json` dosyasına aynı süreçten yazar. Beş alana yayılan bir
değişiklik tek bir derlemede sınanır ve tek bir dağıtımda yayına çıkar.

## Ölçek Sınırı

Bedel, aynı birimin bölünememesinde görünür. Ödünç yolunun yükü arttığında yapılabilecek tek
şey, birimin tamamını çoğaltmaktır.

```sh
# olcek.sh — ayni tek parcanin uc kopyasi; her kopya butun modulleri tasir
rm -rf kopya1 kopya2 kopya3
for k in kopya1 kopya2 kopya3; do
  mkdir "$k"
  for m in depo katalog uyelik ucretlendirme bildirim odunc uygulama; do cp "$m.mjs" "$k/"; done
  ( cd "$k" && node uygulama.mjs 1 4 | grep '^odunc' | sed "s|^|$k: |" )
done
echo "dagitilan modul dosyasi: $(ls kopya*/*.mjs | wc -l | tr -d ' ')"
```

```
kopya1: odunc verildi: kitap 1 -> uye 4, ucret 0
kopya2: odunc verildi: kitap 1 -> uye 4, ucret 0
kopya3: odunc verildi: kitap 1 -> uye 4, ucret 0
dagitilan modul dosyasi: 21
```

İki sayı okunmalı. Birincisi: yalnız ödünç yoluna kapasite eklemek istenmesine karşın
dağıtılan modül dosyası 7'den 21'e çıktı. Bildirim ve ücretlendirme kodunun üç kopyası,
ihtiyaç duyulmadığı hâlde ayakta duruyor. Ölçekleme birimi **kod tabanının tamamıdır**;
darboğazın hangi modülde olduğu bu birimi küçültmez.

İkincisi, koşumun kendisi: üç kopya da aynı kitabı ödünç verdi. Her kopya kendi
`veri.json` dosyasını taşıdığı için üçü de kitabı rafta gördü. Gerçek bir dağıtımda durum
ortak bir depoya taşınır ve bu üçleme ortadan kalkar — ama o zaman da bütün kopyalar tek bir
depoya yüklenir. Tek parçanın ölçek sınırı buradadır: süreç çoğaltılabilir, durum çoğaltılamaz.

Değiştirme tarafında da bir sınır var. Dağıtım birimi bir tane olduğu için, ücret oranındaki
tek satırlık bir değişiklik de katalog ile üyeliği yeniden yayına çıkarır. Ölçüde bunun
karşılığı şudur: dokunulan dosya bir, yeniden dağıtılan modül yedi.

## Üç Sütun

Bu kursun her dersi aynı işi iki gerçekleştirmede karşılaştırır ve üç sütunu doldurur.

| | Tek parça |
|---|---|
| Ucuzlattığı | Yerel çağrı, ortak işlem sınırı, tek derleme, tek dağıtım adımı |
| Pahalılaştırdığı | Ölçekleme birimi tüm kod tabanı; bir satırlık değişiklik yedi modülü yeniden yayınlar |
| Doğan arıza kipi | Bir modüldeki bellek sızıntısı ya da sonsuz döngü bütün alanları birlikte durdurur |

Üçüncü satır ölçülmedi, çünkü tek süreçte bunu ölçmenin yolu süreci çökertmektir. Kayıt olarak
bırakılıyor: dördüncü derste aynı arıza ayrı süreçlerde denendiğinde karşılaştırılacak.

## Özet

- Kütüphane ödünç sistemi tek parça olarak kuruldu: 7 modül, 10 ithal kenarı, 1 süreç, 1
  dağıtım birimi; ödünç iş akışı uçtan uca koşuyor.
- İş akışındaki 6 modüller arası çağrının hepsi yerel; ağ atlaması sıfır, başlatma adımı bir.
- Tek işlem sınırı ve yerel çağrı, katalog ile üyelik arasındaki tutarlılığı ek bir düzen
  gerektirmeden sağlıyor.
- Ölçek sınırı çoğaltmada görünür: yalnız ödünç yoluna kapasite eklemek 7 modülü 21 dosyaya
  çıkardı, çünkü ölçekleme birimi kod tabanının tamamıdır.
- Tek dağıtım birimi, tek satırlık bir ücret değişikliğinde bile bütün modülleri yeniden
  yayına çıkarır.

## Sonraki Adım

Ölçülen sayılardan biri henüz sorgulanmadı: `odunc.mjs` dört modülü de doğrudan ithal
ediyor, ama bunu engelleyen bir şey yok — `bildirim.mjs` de `katalog.mjs` dosyasını ithal
edebilir, katalog da üyeliğin içine uzanabilir. Tek parçanın kod içinde bir sınırı yoktur;
ithal grafiği kimse bakmazsa tamamlanmış bir grafiğe doğru büyür. Sonraki ders bu grafiği
ölçer, bir modülün başkasının içine uzandığı **sınır ihlallerini** sayar ve sınırın kod
içinde bir kuralla korunduğu düzeni kurar: süreç hâlâ tek, dağıtım birimi hâlâ tek, ama
ithal kenarları artık serbest değil.
