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

# Modüler Tek Parça

Sınırların kod içinde korunması: alanlar arası ithal grafiğinin ölçülmesi, bir modülün başkasının içine uzandığı sınır ihlallerinin sayılması, kural konduğunda dokunulan dosyanın ve genişleyen genel yüzün ölçüsü; süreç ve dağıtım birimi hâlâ tek.

Önceki ders tek parçayı ölçtü: yedi modül, on ithal kenarı, tek süreç, tek dağıtım birimi.
Ölçünün açık bıraktığı yer, o on kenarın **hangi kurala göre** çizildiğiydi. Cevap şuydu:
hiçbir kurala göre. Bir modül başka bir modülün herhangi bir dosyasını ithal edebilir; hiçbir
şey engellemez.

Bu ders o boşluğu kapatır. Aynı ödünç iş akışı, alanları dizinlere ayrılmış olarak yeniden
kurulur; önce sınırların kendiliğinden aşındığı hâli ölçülür, sonra sınır bir kuralla
korunur. Sınırların kod içinde korunduğu bu düzene **modüler tek parça (modular monolith)**
denir. Süreç sayısı, dağıtım birimi sayısı ve iş akışının çıktısı **hiç değişmez**; değişen
tek şey ithal grafiğidir. Bu, mimarinin dağıtımdan bağımsız olarak da ölçülebildiği tek
yerdir.

Buradaki `tek parça`, Başarım Karşıt Kalıpları ve İzleme kursundaki **tek parça kalıcılık**
ile aynı sözcüğü taşır ama ayrı şeydir: orada tek olan veri deposu, burada tek olan dağıtım
birimidir.

## Düzenek

**MS3.** Durum, tek koşum içinde çalışıldığı için bellekte tutulur. Birinci dersteki dosya
deposunun yerini alan bu sadeleştirme ölçüyü etkilemez: ölçülen şey ithal grafiğidir.

Beş alanın her biri bir dizin. Her dizinde dışa açılan `index.mjs` ile alanın iç dosyaları
bulunur.

```sh
# kur.sh — 01'deki ayni is akisi, alanlar dizin oldu; durum tek kosumda bellekte tutulur
rm -rf bozulmus && mkdir -p bozulmus/katalog bozulmus/uyelik bozulmus/ucretlendirme \
  bozulmus/bildirim bozulmus/odunc && cd bozulmus
cat > depo.mjs <<'JS'
export const veri = { kitap: { 1: { durum: "rafta" } },
                      uye: { 4: { ad: "Emre", acik: 1, sinir: 3, borc: 0 } } };
JS
cat > katalog/kayit.mjs <<'JS'
import { veri } from "../depo.mjs";
export const kitap = (id) => veri.kitap[id];
JS
cat > katalog/index.mjs <<'JS'
import { kitap } from "./kayit.mjs";
export const durum = (id) => kitap(id).durum;
JS
cat > uyelik/kayit.mjs <<'JS'
import { veri } from "../depo.mjs";
export const uye = (id) => veri.uye[id];
JS
cat > uyelik/index.mjs <<'JS'
import { uye } from "./kayit.mjs";
export const uygunMu = (id) => uye(id).acik < uye(id).sinir;
export const oduncEkle = (id) => { uye(id).acik += 1; };
JS
cat > ucretlendirme/index.mjs <<'JS'
import { uye } from "../uyelik/kayit.mjs";
export const ucret = (gun) => (gun > 0 ? gun * 2 : 0);
export const borcEkle = (id, tutar) => { uye(id).borc += tutar; };
JS
cat > bildirim/index.mjs <<'JS'
import { uye } from "../uyelik/kayit.mjs";
export const gonder = (id, metin) => console.log(`  bildirim -> ${uye(id).ad}: ${metin}`);
JS
cat > odunc/index.mjs <<'JS'
import { kitap } from "../katalog/kayit.mjs";
import * as uyelik from "../uyelik/index.mjs";
import * as ucretlendirme from "../ucretlendirme/index.mjs";
import * as bildirim from "../bildirim/index.mjs";
export function oduncVer(kitapId, uyeId, gecikmeGun = 0) {
  if (uyelik.uygunMu(uyeId) === false) throw new Error("odunc siniri asildi");
  if (kitap(kitapId).durum !== "rafta") throw new Error("kitap rafta degil");
  kitap(kitapId).durum = "odunc";
  uyelik.oduncEkle(uyeId);
  const tutar = ucretlendirme.ucret(gecikmeGun);
  if (tutar > 0) ucretlendirme.borcEkle(uyeId, tutar);
  bildirim.gonder(uyeId, `kitap ${kitapId} odunc verildi`);
  return tutar;
}
JS
cat > uygulama.mjs <<'JS'
import { oduncVer } from "./odunc/index.mjs";
import { durum } from "./katalog/index.mjs";
const tutar = oduncVer(1, 4, 3);
console.log(`odunc verildi: kitap 1 -> uye 4, ucret ${tutar}`);
console.log(`  katalog: kitap 1 = ${durum(1)}`);
JS
find . -name "*.mjs" | sort
node uygulama.mjs
```

```
./bildirim/index.mjs
./depo.mjs
./katalog/index.mjs
./katalog/kayit.mjs
./odunc/index.mjs
./ucretlendirme/index.mjs
./uyelik/index.mjs
./uyelik/kayit.mjs
./uygulama.mjs
  bildirim -> Emre: kitap 1 odunc verildi
odunc verildi: kitap 1 -> uye 4, ucret 6
  katalog: kitap 1 = odunc
```

Listeleme `bozulmus/` dizinine göredir. İş akışı çalışıyor, ücret hesaplanıyor, bildirim
gidiyor. Dizin ayrımı bakıldığında düzenli görünüyor.

## Sınır İhlalinin Ölçüsü

Ölçülecek kural şudur: bir alan, başka bir alandan yalnız `index.mjs` dosyasını ithal
edebilir. Bunun dışındaki her ithal bir **sınır ihlali**dir — bir modülün başkasının içine
uzanması.

```js
// sinir.mjs — alan siniri kurali: baska alandan yalniz index.mjs ithal edilebilir
import { readdirSync, readFileSync, statSync } from "node:fs";
const kok = process.argv[2] ?? ".";
const alanlar = readdirSync(kok).filter((a) => statSync(`${kok}/${a}`).isDirectory()).sort();
let kenar = 0, ihlal = 0, yuz = 0;
for (const alan of alanlar) {
  for (const dosya of readdirSync(`${kok}/${alan}`).sort()) {
    if (dosya.endsWith(".mjs") === false) continue;
    const metin = readFileSync(`${kok}/${alan}/${dosya}`, "utf8");
    if (dosya === "index.mjs") yuz += [...metin.matchAll(/^export /gm)].length;
    for (const [, hedef] of metin.matchAll(/from "(\.[^"]+)"/g)) {
      kenar += 1;
      const p = hedef.split("/");
      if (p[0] === ".." && p.length === 3 && p[2] !== "index.mjs") {
        ihlal += 1;
        console.log(`IHLAL ${alan}/${dosya} -> ${hedef}`);
      }
    }
  }
}
console.log(`alan: ${alanlar.length}  ithal kenari: ${kenar}  genel yuz: ${yuz}  sinir ihlali: ${ihlal}`);
```

```sh
node sinir.mjs bozulmus
```

```
IHLAL bildirim/index.mjs -> ../uyelik/kayit.mjs
IHLAL odunc/index.mjs -> ../katalog/kayit.mjs
IHLAL ucretlendirme/index.mjs -> ../uyelik/kayit.mjs
alan: 5  ithal kenari: 10  genel yuz: 7  sinir ihlali: 3
```

Üç ihlal. Üçü de sonradan eklenmiş, tek satırlık, kimseyi rahatsız etmemiş ithallerdir.
Ücretlendirme üyenin borcunu artırmak için üye kaydına doğrudan uzandı; bildirim üyenin adını
almak için aynısını yaptı; ödünç, kitabın durumunu okumak için katalog kaydını açtı. Hiçbiri
hata üretmedi, çünkü aynı süreçte her şey erişilebilirdir.

Bunun bedeli, ihlal sayısında değil, değişimin yayılmasında görünür. `uyelik/kayit.mjs`
içindeki kayıt biçimi değişirse, üyelik alanının kendi `index.mjs` dosyasıyla birlikte iki
yabancı alan da düzeltilmek zorundadır.

## Kuralın Konması

Düzeltme, dışa uzanan üç ithali alanın genel yüzüne çevirir: eksik olan işlemler ilgili
alanın `index.mjs` dosyasına eklenir, ihlal eden üç dosya bu yeni yüz üzerinden yazılır.

```sh
# duzelt.sh — kural konur: her alan disariya yalniz index.mjs uzerinden acilir
rm -rf moduler && cp -r bozulmus moduler && cd moduler
cat > katalog/index.mjs <<'JS'
import { kitap } from "./kayit.mjs";
export const durum = (id) => kitap(id).durum;
export const raftaMi = (id) => kitap(id).durum === "rafta";
export const oduncIsaretle = (id) => { kitap(id).durum = "odunc"; };
JS
cat > uyelik/index.mjs <<'JS'
import { uye } from "./kayit.mjs";
export const uygunMu = (id) => uye(id).acik < uye(id).sinir;
export const oduncEkle = (id) => { uye(id).acik += 1; };
export const ad = (id) => uye(id).ad;
export const borcEkle = (id, tutar) => { uye(id).borc += tutar; };
JS
cat > ucretlendirme/index.mjs <<'JS'
import { borcEkle as uyeyeBorcEkle } from "../uyelik/index.mjs";
export const ucret = (gun) => (gun > 0 ? gun * 2 : 0);
export const borcEkle = (id, tutar) => uyeyeBorcEkle(id, tutar);
JS
cat > bildirim/index.mjs <<'JS'
import { ad } from "../uyelik/index.mjs";
export const gonder = (id, metin) => console.log(`  bildirim -> ${ad(id)}: ${metin}`);
JS
cat > odunc/index.mjs <<'JS'
import * as katalog from "../katalog/index.mjs";
import * as uyelik from "../uyelik/index.mjs";
import * as ucretlendirme from "../ucretlendirme/index.mjs";
import * as bildirim from "../bildirim/index.mjs";
export function oduncVer(kitapId, uyeId, gecikmeGun = 0) {
  if (uyelik.uygunMu(uyeId) === false) throw new Error("odunc siniri asildi");
  if (katalog.raftaMi(kitapId) === false) throw new Error("kitap rafta degil");
  katalog.oduncIsaretle(kitapId);
  uyelik.oduncEkle(uyeId);
  const tutar = ucretlendirme.ucret(gecikmeGun);
  if (tutar > 0) ucretlendirme.borcEkle(uyeId, tutar);
  bildirim.gonder(uyeId, `kitap ${kitapId} odunc verildi`);
  return tutar;
}
JS
echo "yeniden yazilan dosya: 5"
node uygulama.mjs
```

```
yeniden yazilan dosya: 5
  bildirim -> Emre: kitap 1 odunc verildi
odunc verildi: kitap 1 -> uye 4, ucret 6
  katalog: kitap 1 = odunc
```

Çıktı birinci koşumun aynısı. Kullanıcı tarafında hiçbir şey değişmedi.

```sh
node sinir.mjs moduler
echo "uyelik ic dosyasina uzanan dis dosya -> bozulmus: $(grep -l 'uyelik/kayit.mjs' bozulmus/*/*.mjs | wc -l | tr -d ' ')  moduler: $(grep -l 'uyelik/kayit.mjs' moduler/*/*.mjs | wc -l | tr -d ' ')"
```

```
alan: 5  ithal kenari: 10  genel yuz: 11  sinir ihlali: 0
uyelik ic dosyasina uzanan dis dosya -> bozulmus: 2  moduler: 0
```

Üç sayı okunmalı. İhlal 3'ten 0'a indi. İthal kenarı **10'da kaldı**: kural kenar sayısını
azaltmaz, kenarların ucunu değiştirir; üç kenar bir alanın iç dosyasından o alanın genel
yüzüne kaydı. Genel yüz ise 7'den 11'e çıktı — dört yeni dışa verilen ad.

Son satır asıl kazancı verir. Üyelik alanının iç dosyasına dışarıdan uzanan dosya sayısı
2'den 0'a indi. `uyelik/kayit.mjs` içindeki kayıt biçimi değiştiğinde dokunulacak dosya,
bozulmuş sürümde 3 (kendi `index.mjs` dosyası artı iki yabancı alan), modüler sürümde 1'dir.

Ücretlendirme alanındaki `borcEkle`, üyeliğin aynı adlı işlevini çağıran bir sarmalayıcıya
dönüştü. Bu, kuralın doğrudan bedelidir: alanlar arası her yeni ihtiyaç bir dolaylılık
katmanı ekler ve genel yüzü genişletir.

## Kuralın Ayakta Kalması

Bu düzenin bir zayıflığı var: kural derleyicinin değil, denetleyicinin kuralıdır.

```sh
# kacak.sh — moduler surume tek satirlik bir ithal eklenir; program calismaya devam eder
sed -i.yedek '1i\
import { uye } from "../uyelik/kayit.mjs";
' moduler/bildirim/index.mjs
rm -f moduler/bildirim/index.mjs.yedek
( cd moduler && node uygulama.mjs | head -n 1 )
node sinir.mjs moduler | tail -n 2
```

```
  bildirim -> Emre: kitap 1 odunc verildi
IHLAL bildirim/index.mjs -> ../uyelik/kayit.mjs
alan: 5  ithal kenari: 11  genel yuz: 11  sinir ihlali: 1
```

Program çalışmaya devam etti; hiçbir test kırılmadı. Yalnız denetleyici konuştu. İhlal
sayısı 0'dan 1'e, ithal kenarı 10'dan 11'e çıktı. Sınır ihlali bir çalışma zamanı hatası
değil, bir ölçüdür: ölçülmediği anda serbestçe büyür. Yerinde düzenlemede kullanılan `-i`
seçeneği GNU ve BSD sürümlerinde farklı davrandığı için burada yedek uzantısı verilip yedek
silinmiştir; iki ortamda da aynı sonucu üretir.

## Üç Sütun

| | Modüler tek parça |
|---|---|
| Ucuzlattığı | Bir alanın iç yapısı değiştiğinde dokunulan dosya 3'ten 1'e indi; sınır sayılabilir bir ölçü oldu |
| Pahalılaştırdığı | Genel yüz 7'den 11'e çıktı; alanlar arası her ihtiyaç bir dolaylılık katmanı ekliyor |
| Doğan arıza kipi | Kural yalnız denetleyici koştuğunda geçerli; tek satırlık bir ithal hiçbir şeyi kırmadan sınırı sessizce geri alıyor |

Değişmeyen sayılar da kayda değer: süreç 1, dağıtım birimi 1, ağ atlaması 0. Modüler tek
parça bir dağıtım kararı değil, bir kod düzeni kararıdır. Bütün alanlar hâlâ birlikte yayına
çıkar ve bir alandaki sonsuz döngü hepsini birlikte durdurur.

## Özet

- Alanlar dizinlere ayrıldığında bile ithal grafiği kendiliğinden aşınır: üç alan komşusunun
  iç dosyasına uzanmıştı, hiçbiri hata üretmiyordu.
- Sınır ihlali ölçülebilir bir birimdir: başka bir alandan `index.mjs` dışında bir dosyayı
  ithal eden her satır bir ihlaldir.
- Kural konduğunda 5 dosya yeniden yazıldı, ihlal 3'ten 0'a indi, ithal kenarı 10'da kaldı;
  kural kenarları azaltmaz, uçlarını genel yüze taşır.
- Bedel genel yüzün 7'den 11'e genişlemesi ve alanlar arası her ihtiyaçta bir sarmalayıcı
  eklenmesidir.
- Kural denetleyiciye bağlıdır; tek satırlık bir ithal programı kırmadan ihlali geri getirdi.

## Sonraki Adım

Modüler tek parça sınırı kod içinde korudu, ama bir şeyi hiç sorgulamadı: `depo.mjs` bütün
alanların ortak veri yapısını tutmayı sürdürüyor. Katalog da üyelik de aynı nesnenin farklı
dallarına yazıyor, yani sınır ithal grafiğinde var, veride yok. Sonraki ders bu ortaklığı
büyütür: alanlar ayrı birimler hâline geldiğinde bile paylaşılan bir sözleşme ve ortak bir
veri modeli üzerinden konuşurlarsa ne olur — ortak katmandaki tek bir değişikliğin kaç birimi
dokunulur kıldığını ölçer.
