---
title: 'Bağlantı Noktaları ve Bağdaştırıcılar'
source: 'https://academia.sh/tr/kurslar/alan-odakli-tasarim/baglanti-noktalari-ve-bagdastiricilar'
course: 'Alan Odaklı Tasarım'
language: tr
updated: '2026-08-17T18:10:41+00:00'
license: 'CC BY-SA 4.0'
---

# Bağlantı Noktaları ve Bağdaştırıcılar

Altıgen mimarinin bir düzenleniş olarak sunulması: alanın dışa açıldığı yerlerin adlandırılmış bağlantı noktalarına dönüştürülmesi, alan modülünün ithal kapanışının ve dış dünyaya giden doğrudan bağ sayısının iki düzende sayılması, aynı alan dosyasının iki bağdaştırıcı takımıyla koşturulması ve karşılanmayan noktanın koşum anında bildirilmesi.

Önceki dersin senaryosu kararları toplama köküne indirdi, ama adımlarından biri hâlâ bir dış
dünya adı taşıyordu. Varış kaydının gerçek hâli tek bir depoyla da yetinmez: taşıyıcının kendi
nokta kodu okunur, bir varış numarası üretilir, aktarma merkezine duyuru gönderilir. Bu üç ad
alan modülünün içine doğrudan bir bağ olarak girerse alan modeli dışarıyı bilmeye başlar.

Bu dersin ölçtüğü şey o bağların sayısıdır. Ölçüyü kurmak için önce dışarının ne olduğunu
adlandırmak gerekir. **Bağlantı noktası** (port) alanın dışa açıldığı bir yerin adı ve
beklediği işlem kümesidir; **bağdaştırıcı** (adapter) o kümeyi karşılayan gerçekleştirimdir.
Aynı noktayı birden fazla bağdaştırıcı karşılayabilir. Bu ad, Bilgisayar Ağları'ndaki taşıma
katmanı bağlantı noktasıyla aynı sözcüktür ama akraba değildir: orada bir sayı, burada bir
işlem kümesi sözleşmesidir.

## Yeni Olan Ne

Sınırın nereye çizileceği, kararlı kural ile değişken ayrıntının ayrımı ve bağımlılık okunun
yönü Tasarım İlkeleri kursundaki Politika ve Ayrıntı Ayrımı ile Sınırların Çizilmesi
derslerinde, katmanların sorumlulukları Veri Erişim Katmanı ve İş Mantığı kursundaki Katman
Sorumlulukları dersinde kurulmuş ve ölçülmüştü. Bağdaştırıcı kalıbının kendisi de Tasarım
Kalıpları kursunda ele alındı. Burada hiçbiri yeniden kurulmuyor.

Yeni olan tek şey bir **düzenlemedir**: aynı ilkeler, alanı merkeze koyup dışa açılan her yeri
adlandırılmış bir nokta hâline getirecek biçimde yerleştirildiğinde ortaya çıkan yerleşim
**altıgen mimari** (hexagonal architecture) adını alır. Altı sayısının bir anlamı yoktur;
şeklin yalnız iki yüzü olmadığını, yani girdi ve çıktı diye iki taraf bulunmadığını söylemek
için seçilmiştir. Nokta sayısı üç de olabilir, dokuz da.

## Dışarısı

Üç dış modül, alanın konuşmak zorunda olduğu üç ayrı dünyayı temsil eder.

```sh
mkdir -p dis kapali/alan kapali/uygulama
```

```js
// dis/kayit-tablosu.mjs — teslimat kayitlarini tutan dis tablo
const TABLO = new Map();

export const kayitTablosu = {
  oku: (id) => structuredClone(TABLO.get(id) ?? null),
  yaz: (kayit) => { TABLO.set(kayit.id, structuredClone(kayit)); },
  tohum: (id) => { TABLO.set(id, { id, durum: "kabul-edildi", rota: ["34", "06", "35"], gecilen: [] }); },
};
```

```js
// dis/takip-servisi.mjs — tasiyicinin nokta kodlarini ve varis numarasini veren dis sistem
const KOD = { "34": "IST-A1", "06": "ANK-T2", "35": "IZM-D7" };
let sayac = 0;

export const takipServisi = {
  nokta: (n) => KOD[n] ?? "BILINMEYEN",
  numara: () => `V${String((sayac += 1)).padStart(4, "0")}`,
};
```

```js
// dis/bildirim-kanali.mjs — aktarma merkezine duyuru gonderen dis kanal
const GIDEN = [];

export const bildirimKanali = { gonder: (m) => GIDEN.push(m), sayi: () => GIDEN.length };
```

## Bağı Doğrudan Kuran Düzen

İlk düzende toplama kökü üç modülü kendisi ithal eder. Kararlar yine onun içindedir; değişen
tek şey dışarıyla nasıl konuştuğudur.

```js
// kapali/alan/teslimat.mjs — toplama koku uc dis modulu dogrudan ithal ediyor
import { kayitTablosu } from "../../dis/kayit-tablosu.mjs";
import { takipServisi } from "../../dis/takip-servisi.mjs";
import { bildirimKanali } from "../../dis/bildirim-kanali.mjs";

export class Teslimat {
  #kayit;

  static yukle(id) {
    const kayit = kayitTablosu.oku(id);
    if (kayit === null) throw new RangeError(`teslimat yok: ${id}`);
    return new Teslimat(kayit);
  }

  constructor(kayit) { this.#kayit = kayit; }

  varisKaydet(nokta) {
    const k = this.#kayit;
    if (k.durum === "teslim-edildi") throw new Error("kapali teslimata varis islenemez");
    if (!k.rota.includes(nokta)) throw new Error(`nokta rotada yok: ${nokta}`);
    const sira = k.rota.indexOf(nokta);
    if (sira !== k.gecilen.length) throw new Error("rota sirasi bozuk");
    k.gecilen.push(nokta);
    k.durum = sira === k.rota.length - 1 ? "dagitimda" : "aktarmada";
    const numara = takipServisi.numara(), kod = takipServisi.nokta(nokta);
    kayitTablosu.yaz(k);
    bildirimKanali.gonder({ numara, id: k.id, kod, durum: k.durum });
    return { kimlik: k.id, numara, kod, durum: k.durum, gecilen: k.gecilen.length };
  }
}
```

```js
// kapali/uygulama/varis-kaydet.mjs — senaryonun disariya verecek bir seyi yok
import { Teslimat } from "../alan/teslimat.mjs";

export const varisKaydet = (id, nokta) => Teslimat.yukle(id).varisKaydet(nokta);
```

Senaryo bir satıra indi, çünkü verecek bir şeyi kalmadı. Bağların hepsi bir basamak aşağıda
kuruldu.

## Noktaların Adlandırılması

İkinci düzende alan tarafı beklediği adları bir dosyada yazılı hâle getirir. Bu dosya alanın
içindedir: sözleşmeyi kararlı taraf yazar, karşılayan taraf ona uyar.

```sh
mkdir -p acik/alan acik/uygulama acik/bagdastiricilar
```

```js
// acik/alan/baglanti-noktalari.mjs — alanin disa acildigi uc nokta ve bekledigi bes ad
export const BAGLANTI_NOKTALARI = {
  kayitlar: ["oku", "yaz"],
  takip: ["noktaKodu", "varisNumarasi"],
  duyurular: ["gonder"],
};

export function cevreyiDogrula(cevre) {
  const eksik = [];
  for (const [nokta, adlar] of Object.entries(BAGLANTI_NOKTALARI)) {
    for (const ad of adlar) if (typeof cevre?.[nokta]?.[ad] !== "function") eksik.push(`${nokta}.${ad}`);
  }
  if (eksik.length > 0) throw new TypeError(`karsilanmayan baglanti noktasi: ${eksik.join(", ")}`);
}
```

```js
// acik/alan/teslimat.mjs — ayni bes karar; dis modul adi yok, cevre parametre olarak geliyor
import { cevreyiDogrula } from "./baglanti-noktalari.mjs";

export class Teslimat {
  #kayit; #cevre;

  static yukle(id, cevre) {
    cevreyiDogrula(cevre);
    const kayit = cevre.kayitlar.oku(id);
    if (kayit === null) throw new RangeError(`teslimat yok: ${id}`);
    return new Teslimat(kayit, cevre);
  }

  constructor(kayit, cevre) { this.#kayit = kayit; this.#cevre = cevre; }

  varisKaydet(nokta) {
    const k = this.#kayit, c = this.#cevre;
    if (k.durum === "teslim-edildi") throw new Error("kapali teslimata varis islenemez");
    if (!k.rota.includes(nokta)) throw new Error(`nokta rotada yok: ${nokta}`);
    const sira = k.rota.indexOf(nokta);
    if (sira !== k.gecilen.length) throw new Error("rota sirasi bozuk");
    k.gecilen.push(nokta);
    k.durum = sira === k.rota.length - 1 ? "dagitimda" : "aktarmada";
    const numara = c.takip.varisNumarasi(), kod = c.takip.noktaKodu(nokta);
    c.kayitlar.yaz(k);
    c.duyurular.gonder({ numara, id: k.id, kod, durum: k.durum });
    return { kimlik: k.id, numara, kod, durum: k.durum, gecilen: k.gecilen.length };
  }
}
```

```js
// acik/uygulama/varis-kaydet.mjs — cevreyi disaridan alip alan modeline veren senaryo
import { Teslimat } from "../alan/teslimat.mjs";

export const varisKaydet = (id, nokta, cevre) => Teslimat.yukle(id, cevre).varisKaydet(nokta);
```

## İki Bağdaştırıcı Takımı

Aynı üç nokta iki ayrı biçimde karşılanır. Biri dış modüllere bağlanır, öbürü bellek içinde
kalır.

```js
// acik/bagdastiricilar/uretim.mjs — uc noktayi dis modullere baglayan bagdastiricilar
import { kayitTablosu } from "../../dis/kayit-tablosu.mjs";
import { takipServisi } from "../../dis/takip-servisi.mjs";
import { bildirimKanali } from "../../dis/bildirim-kanali.mjs";

export const uretimCevresi = {
  kayitlar: { oku: (id) => kayitTablosu.oku(id), yaz: (k) => kayitTablosu.yaz(k) },
  takip: { noktaKodu: (n) => takipServisi.nokta(n), varisNumarasi: () => takipServisi.numara() },
  duyurular: { gonder: (m) => bildirimKanali.gonder(m) },
};
```

```js
// acik/bagdastiricilar/sinama.mjs — ayni uc noktayi bellek icinde karsilayan bagdastiricilar
const TABLO = new Map();
let sayac = 0;
export const GIDEN = [];

export const sinamaCevresi = {
  kayitlar: {
    oku: (id) => structuredClone(TABLO.get(id) ?? null),
    yaz: (k) => { TABLO.set(k.id, structuredClone(k)); },
  },
  takip: { noktaKodu: (n) => `SINAMA-${n}`, varisNumarasi: () => `S${String((sayac += 1)).padStart(4, "0")}` },
  duyurular: { gonder: (m) => GIDEN.push(m) },
};

export const tohum = (id) => TABLO.set(id, { id, durum: "kabul-edildi", rota: ["34", "06", "35"], gecilen: [] });
```

## Ölçüm

Ölçüm alan modülünün kökünden başlayıp ithal bağlarını yürür: kapanışa kaç dosya giriyor,
kaç bağ `dis/` dizinine iniyor. Ardından aynı alan dosyası iki bağdaştırıcı takımıyla
koşturulur ve karşılanmayan bir nokta ile ne olduğuna bakılır.

```js
// bag-say.mjs — alan modulunun ithal kapanisi, dogrudan bag sayisi ve iki bagdastirici takimiyla kosum
import { readFileSync } from "node:fs";
import { dirname, join, normalize } from "node:path";
import { kayitTablosu } from "./dis/kayit-tablosu.mjs";
import { bildirimKanali } from "./dis/bildirim-kanali.mjs";
import { BAGLANTI_NOKTALARI } from "./acik/alan/baglanti-noktalari.mjs";
import { varisKaydet as kapaliVaris } from "./kapali/uygulama/varis-kaydet.mjs";
import { varisKaydet as acikVaris } from "./acik/uygulama/varis-kaydet.mjs";
import { uretimCevresi } from "./acik/bagdastiricilar/uretim.mjs";
import { sinamaCevresi, tohum, GIDEN } from "./acik/bagdastiricilar/sinama.mjs";

const ITHAL = /^import[^"']*["']([^"']+)["']/gm;

function kapanis(kok) {
  const gorulen = new Set(), yigit = [kok], kenar = [];
  while (yigit.length > 0) {
    const dosya = yigit.pop();
    if (gorulen.has(dosya)) continue;
    gorulen.add(dosya);
    for (const [, yol] of readFileSync(dosya, "utf8").matchAll(ITHAL)) {
      if (yol.startsWith(".") === false) continue;
      const hedef = normalize(join(dirname(dosya), yol));
      kenar.push([dosya, hedef]);
      yigit.push(hedef);
    }
  }
  return { gorulen, kenar };
}

for (const [ad, kok] of [["kapali", "kapali/alan/teslimat.mjs"], ["acik", "acik/alan/teslimat.mjs"]]) {
  const { gorulen, kenar } = kapanis(kok);
  const disa = kenar.filter(([, hedef]) => hedef.startsWith("dis/"));
  console.log(`${ad} alan modulu: ithal kapanisi = ${gorulen.size}, dis dunyaya dogrudan bag = ${disa.length}`);
  for (const [k, h] of kenar) console.log(`  ${k} -> ${h}`);
}

const adSayisi = Object.values(BAGLANTI_NOKTALARI).flat().length;
console.log(`baglanti noktasi = ${Object.keys(BAGLANTI_NOKTALARI).length}, sozlesmedeki ad = ${adSayisi}`);

kayitTablosu.tohum("T-K"); kayitTablosu.tohum("T-U"); tohum("T-S");
const kosumlar = [
  ["kapali + dis moduller ", kapaliVaris("T-K", "34")],
  ["acik + uretim takimi  ", acikVaris("T-U", "34", uretimCevresi)],
  ["acik + sinama takimi  ", acikVaris("T-S", "34", sinamaCevresi)],
];
for (const [ad, s] of kosumlar) console.log(`${ad} ${JSON.stringify(s)}`);
const alan = kosumlar.map(([, s]) => `${s.durum}/${s.gecilen}`);
console.log(`alan alanlari esit mi = ${new Set(alan).size === 1}, ayri deger = ${new Set(alan).size}`);
console.log(`dis kanala giden duyuru = ${bildirimKanali.sayi()}, sinama kanalina giden = ${GIDEN.length}`);

try { acikVaris("T-S", "06", { kayitlar: sinamaCevresi.kayitlar }); }
catch (hata) { console.log(`eksik cevre: ${hata.message}`); }
```

```sh
node bag-say.mjs
```

```
kapali alan modulu: ithal kapanisi = 4, dis dunyaya dogrudan bag = 3
  kapali/alan/teslimat.mjs -> dis/kayit-tablosu.mjs
  kapali/alan/teslimat.mjs -> dis/takip-servisi.mjs
  kapali/alan/teslimat.mjs -> dis/bildirim-kanali.mjs
acik alan modulu: ithal kapanisi = 2, dis dunyaya dogrudan bag = 0
  acik/alan/teslimat.mjs -> acik/alan/baglanti-noktalari.mjs
baglanti noktasi = 3, sozlesmedeki ad = 5
kapali + dis moduller  {"kimlik":"T-K","numara":"V0001","kod":"IST-A1","durum":"aktarmada","gecilen":1}
acik + uretim takimi   {"kimlik":"T-U","numara":"V0002","kod":"IST-A1","durum":"aktarmada","gecilen":1}
acik + sinama takimi   {"kimlik":"T-S","numara":"S0001","kod":"SINAMA-34","durum":"aktarmada","gecilen":1}
alan alanlari esit mi = true, ayri deger = 1
dis kanala giden duyuru = 2, sinama kanalina giden = 1
eksik cevre: karsilanmayan baglanti noktasi: takip.noktaKodu, takip.varisNumarasi, duyurular.gonder
```

## Sayıların Okunması

Alan modülünün ithal kapanışı 4'ten 2'ye, dış dünyaya giden doğrudan bağ sayısı 3'ten 0'a
indi. İkinci sayı belirleyici olanıdır: kapalı düzende toplama kökünü yüklemek üç dış modülü
de yüklemek anlamına gelir, açık düzende alan modülü yalnız kendi sözleşme dosyasını tanır.

Üç bağ, üç bağlantı noktasına ve beş ada dönüştü. Nokta sayısı bağ sayısına eşit çıktı; bu
rastlantı değildir, dönüşüm bağların adlandırılmasından oluşur. Beş ad ise dışarının alandan
gördüğü yüzeydir: karşı taraf yalnız bu beş işlemi sağlamak zorundadır, kendi içinde kaç
dosyası olduğu alanı ilgilendirmez.

Üç koşumun alan sonuçları eşit çıktı: aynı durum, aynı geçilen sayısı, ayrı değer sayısı 1.
Farklı olan tek şey bağdaştırıcıdan gelen alanlardır — varış numarası ve nokta kodu takıma
göre değişti, çünkü onları alan üretmiyor. Duyuru sayaçları da bunu doğruluyor: dış kanala 2
duyuru gitti, sınama kanalına 1. Aynı alan dosyası hem üretim takımıyla hem bellek içi takımla
koştu ve dosyaya tek satır dokunulmadı.

Son satır sözleşme dosyasının koşum anındaki karşılığıdır. Eksik bir çevre verildiğinde
karşılanmayan üç ad adıyla bildirildi. Kapalı düzende böyle bir hata iletisi olamaz, çünkü
karşılanacak bir sözleşme yazılı değildir; eksik olan şey bir ithal hatası olarak görünür.

## Bedelin Sayılması

Düzen ücretsiz değildir. Açık düzen 1 dosya (sözleşme) ve bağdaştırıcı takımı başına 1 dosya
ekler; iki takımla toplam 3 dosya. Toplama kökünün her yaratımına bir parametre daha eklendi.
Nokta sayısı arttıkça bu parametre büyür: dokuz noktalı bir alanda çevre nesnesi dokuz alan
taşır ve her kullanım senaryosu onu baştan sona geçirir.

Kazanç iki koşula bağlıdır. Birincisi, bir noktanın gerçekten birden fazla bağdaştırıcısı
olmalıdır; tek bağdaştırıcılı bir nokta yalnız dolaylılık ekler. İkincisi, alan modülünün
kendi başına koşturulabilmesi bir işe yaramalıdır. Alanda karar yoksa — kararlar yine dışarıda
duruyorsa — bağlantı noktası boş bir sözleşmedir; ölçüm bunu doğrudan bağ sayısının 0 çıkması
ama karar noktası sayısının da 0 çıkması olarak gösterir.

## Özet

- Bağlantı noktası alanın dışa açıldığı bir yerin adı ve beklediği işlem kümesidir;
  bağdaştırıcı o kümenin gerçekleştirimidir ve aynı nokta için birden fazla olabilir.
- Altıgen mimari yeni bir ilke getirmez; sınır çizimi, politika–ayrıntı ayrımı ve bağımlılık
  yönünü alanı merkeze alacak biçimde düzenler.
- Alan modülünün ithal kapanışı 4'ten 2'ye, dış dünyaya giden doğrudan bağ sayısı 3'ten 0'a
  indi; üç bağ üç noktaya ve beş ada dönüştü.
- Aynı alan dosyası iki bağdaştırıcı takımıyla koştu; üç koşumun alan sonuçları eşit çıktı,
  yalnız bağdaştırıcıdan gelen numara ve kod değişti.
- Bedel 3 dosya ve her yaratımda bir parametredir; kazanç bir noktanın birden fazla
  bağdaştırıcısı olduğunda ve alanda gerçekten karar bulunduğunda doğar.

## Sonraki Adım

Buraya kadarki bütün ölçüler yazma yönündeydi: bir varış kaydının hangi kararlardan geçtiği,
hangi noktalardan dışarı çıktığı. Operasyon masasının asıl işi ise okumaktır — hangi
teslimatlar rotasının gerisinde, hangi aktarma merkezinde kaç paket bekliyor, hangi taşıyıcının
gecikme oranı yüksek. Bu soruların yanıtı toplama kökleri üzerinden aranırsa her soru için
onlarca nesne gezilir ve gezinti teslimat sayısıyla büyür. Sonraki ders aynı verinin okuma
için ayrı bir modelde tutulmasını ele alır: sorgu için gezilen nesne sayısını iki düzende
sayar, ayrı modelin kaç komut geriden geldiğini ölçer ve bunun karşılığında eklenen dosya ve
eşleme sayısını bedel olarak yazar.
