---
title: 'On İki Etmen Uygulama İlkeleri'
source: 'https://academia.sh/tr/kurslar/sunucu-temelleri/on-iki-etmen-uygulama-ilkeleri'
course: 'Sunucu Tarafı Temelleri'
language: tr
updated: '2026-08-17T18:06:52+00:00'
license: 'CC BY-SA 4.0'
---

# On İki Etmen Uygulama İlkeleri

Bu bölümde alınan kararlar taşınabilirlik sözleşmesi olarak adlandırılmış on iki ilkeyle eşleştirilir; tek yapının iki ortamda değişmeden çalıştığı dosya özetiyle, hızlı açılış ve zarif kapanma ise uçuştaki isteğin tamamlanmasıyla ölçülür.

Bu bölümde alınan kararlar birbirinden bağımsız gibi görünür: dizinleri katmanlara bölmek,
yapılandırmayı ortamdan okumak, gizli değerleri maskelemek, kütüğü standart çıktıya yazmak,
hataları tek bir katmandan geçirmek. Aralarında bir bağ vardır ve bağ tek bir hedefte
toplanır: uygulamanın **çalıştığı makineden bağımsız** olması.

Bu hedefi adlandırılmış kurallar hâline getiren bir yöntem vardır: **on iki etmen uygulama
ilkeleri** (twelve-factor app). İlkeler bir çatı ya da araç değil, bir sözleşmedir; uygulamayı
yazan ile onu çalıştıran arasındaki arayüzü tanımlar. Bu ders ilkeleri sayar, bu bölümde
hangilerinin karşılandığını ölçümlerle eşleştirir ve karşılanmayanları işaret eder.

## Sözleşmenin Konusu

İlkelerin ortak varsayımı şudur: uygulamayı çalıştıran taraf, uygulamanın içini bilmeden onu
kurabilmeli, ayarlayabilmeli, çoğaltabilmeli, izleyebilmeli ve durdurabilmelidir. Bu
sağlandığında uygulama bir makineye değil, bir sözleşmeye bağlanır.

Kütüphane ödünç servisi açısından bunun karşılığı somuttur. Servisi bir dizüstü bilgisayarda
çalıştıran geliştirici ile bir sunucuda çalıştıran işletmeci aynı dosyayı kullanır; aralarındaki
tek fark verdikleri ortam değişkenleridir. Kod, hangi makinede olduğunu bilmez.

On iki ilke ve bu bölümdeki karşılıkları aşağıdaki gibidir.

| İlke | İçerik | Bu bölümdeki karşılığı |
|---|---|---|
| Kod tabanı | Tek kod tabanı, çok dağıtım | Sürüm Kontrolüne Giriş kursu |
| Bağımlılıklar | Açıkça bildirilir ve yalıtılır | Modüller, Araçlar ve Ekosistem kursu |
| Yapılandırma | Ortamda saklanır | Yapılandırma Yönetimi dersi |
| Destekleyici servisler | Bağlı kaynak sayılır | Yerel Geliştirme Ortamı dersi |
| Derle, yayımla, çalıştır | Aşamalar kesin ayrılır | Oluşturma Stratejileri ve Altyapı kursu |
| Süreçler | Durumsuz ve paylaşımsız | Uygulama Çalışma Zamanı dersi |
| Bağlantı noktası bağlama | Hizmet kendi bağlar | Web Sunucusu Kavramı dersi |
| Eşzamanlılık | Süreç modeliyle ölçeklenir | Uygulama Çalışma Zamanı dersi |
| Tek kullanımlık olma | Hızlı açılış, zarif kapanma | Bu ders |
| Geliştirme/üretim eşliği | Ortamlar birbirine yakın tutulur | Bu ders |
| Kütükler | Olay akışı sayılır | Günlükleme Kurulumu dersi |
| Yönetim süreçleri | Tek seferlik iş olarak çalıştırılır | Backend Geliştirme müfredatının ileri kursları |

Tabloda dört ilke bu kursun dışına düşer; ikisi bu dersin ölçümleridir.

## Ölçüm: Tek Yapı, İki Ortam

**Geliştirme/üretim eşliği** ilkesi, aynı yapının farklı ortamlarda değişmeden çalışmasını
ister. Bunun sınanabilir biçimi şudur: dosyanın özeti değişmeden, davranışı ortam
değişkenleriyle değişmelidir.

```js
// kaynak/http/sunucu.mjs — ayni dosya her ortamda; baglanti noktasini kendi baglar,
// kutugu standart cikisa yazar, SIGTERM aldiginda ucustaki istegi bitirip iner.
import { createServer } from "node:http";
import { setTimeout as bekle } from "node:timers/promises";

const BAGLANTI_NOKTASI = Number(process.env.KUTUPHANE_BAGLANTI_NOKTASI ?? 8440);
const ORTAM = process.env.KUTUPHANE_ORTAM_ETIKETI ?? "yerel";
const ODUNC_GUN = Number(process.env.KUTUPHANE_ODUNC_GUN ?? 14);

const kutuk = (kayit) => console.log(JSON.stringify({ an: new Date().toISOString(), ...kayit }));

let acikIstek = 0;

const sunucu = createServer(async (istek, yanit) => {
  yanit.sendDate = false;
  acikIstek++;
  const yol = new URL(istek.url, "http://yerel").pathname;
  if (yol === "/odunc") await bekle(1500);            // suren bir odunc islemi
  const metin = JSON.stringify({ ortam: ORTAM, oduncGun: ODUNC_GUN, yol });
  yanit.writeHead(200, { "content-type": "application/json; charset=utf-8",
    "content-length": Buffer.byteLength(metin) });
  yanit.end(metin);
  acikIstek--;
});

sunucu.listen(BAGLANTI_NOKTASI, "127.0.0.1", () => kutuk({
  olay: "acildi", baglantiNoktasi: BAGLANTI_NOKTASI, ortam: ORTAM, oduncGun: ODUNC_GUN,
  acilisMs: Number(performance.now().toFixed(1)),      // surec baslangicindan bu yana
}));

process.on("SIGTERM", () => {
  kutuk({ olay: "sigterm_alindi", acikIstek });
  sunucu.close(() => {                                // yeni baglanti yok, acik olanlar biter
    kutuk({ olay: "kapandi", acikIstek });
    process.exit(0);
  });
  sunucu.closeIdleConnections();                      // bos bekleyen baglantilar hemen kapanir
  setTimeout(() => { kutuk({ olay: "zorla_kapandi" }); process.exit(1); }, 5000).unref();
});
```

```bash
#!/usr/bin/env bash
# Ayni dosyayi iki ortamla calistirir; dosyanin ozeti degismeden davranisin degistigini gosterir.
echo "dosya ozeti: $(shasum -a 256 kaynak/http/sunucu.mjs | cut -c1-16)…"

dene() {  # $1 = ortam etiketi, $2 = odunc gunu, $3 = baglanti noktasi
  KUTUPHANE_ORTAM_ETIKETI="$1" KUTUPHANE_ODUNC_GUN="$2" KUTUPHANE_BAGLANTI_NOKTASI="$3" \
    node kaynak/http/sunucu.mjs > "kutuk-$1.jsonl" 2>&1 & s=$!
  sleep 0.7
  printf '%-8s -> ' "$1"
  curl -sS "http://127.0.0.1:$3/kitaplar"; echo
  kill -TERM "$s"; wait "$s" 2>/dev/null
  grep -o '"acilisMs":[0-9.]*' "kutuk-$1.jsonl"
  rm -f "kutuk-$1.jsonl"
}

dene yerel 14 8441
dene yayin 21 8442
```

```
dosya ozeti: cc28586133fd7c6a…
yerel    -> {"ortam":"yerel","oduncGun":14,"yol":"/kitaplar"}
"acilisMs":28.5
yayin    -> {"ortam":"yayin","oduncGun":21,"yol":"/kitaplar"}
"acilisMs":28.2
```

Dosya özeti ve açılış süreleri her makinede ve her düzenlemeden sonra değişir; özet, dosyanın
iki çalıştırma arasında değişmediğini göstermek için buradadır.

Aynı dosya iki ortamda iki farklı yanıt üretmiştir: ödünç süresi bir ortamda on dört, diğerinde
yirmi bir gündür. Kodda hiçbir dallanma yoktur; ortamın adını taşıyan bir koşul, bir
`if (ORTAM === "yayin")` satırı bulunmaz. Böyle bir satır eklendiği anda ilke kırılır, çünkü
uygulama artık nerede çalıştığını bilir ve yerelde sınanan yol ile yayında çalışan yol
ayrışır.

Aynı çıktı bir başka ilkeyi de doğrular. **Bağlantı noktası bağlama** ilkesi, hizmetin dış bir
bileşene ihtiyaç duymadan kendi bağlantı noktasını açmasını ister. `curl` çağrısı doğrudan
sürece gitmiştir; arada hiçbir bileşen yoktur. Önceki bölümde kurulan ters vekil bir seçenektir,
bir zorunluluk değil — ve tam olarak bu yüzden yerel geliştirme ile yayın aynı kodu çalıştırır.

## Ölçüm: Tek Kullanımlık Olma

**Tek kullanımlık olma** (disposability) ilkesi süreçlerin hızlı açılmasını ve düzgün
inmesini ister. İkisi de aynı gerekçeye dayanır: süreçler sık başlatılır ve sık durdurulur.
Yayın, ölçek değişikliği, makine değişimi ve çökme sonrası yeniden başlatma bunu zorunlu kılar.

Açılış süresi yukarıdaki çıktıda görülür: süreç başlangıcından dinlemeye geçişe kadar otuz
milisaniyenin altı. Asıl sınanması gereken ise inişin nasıl olduğudur. Aşağıdaki ölçüm,
uçuşta bir istek varken sürece `SIGTERM` gönderir.

```bash
#!/usr/bin/env bash
# Ucusta bir istek varken SIGTERM gonderir; istegin bitip yeni baglantinin reddedildigini olcer.
node kaynak/http/sunucu.mjs > kutuk.jsonl 2>&1 & surec=$!
sleep 0.7

curl -sS -o /dev/null -w 'ucustaki istek : %{http_code}  %{time_total} s\n' \
  http://127.0.0.1:8440/odunc > ucus.txt & istek=$!
sleep 0.4
echo "SIGTERM gonderildi"
kill -TERM "$surec"
sleep 0.4

printf 'kapanma sirasinda yeni istek : '
if curl -s -o /dev/null --max-time 2 http://127.0.0.1:8440/kitaplar; then
  echo "yanit alindi"
else
  echo "baglanti kurulamadi (curl cikis kodu=$?)"
fi

wait "$istek"; cat ucus.txt
wait "$surec"; echo "surec cikis kodu=$?"
echo "--- kutuk ---"
cat kutuk.jsonl
rm -f kutuk.jsonl ucus.txt
```

```
SIGTERM gonderildi
kapanma sirasinda yeni istek : baglanti kurulamadi (curl cikis kodu=7)
ucustaki istek : 200  1.505712 s
surec cikis kodu=0
--- kutuk ---
{"an":"2026-07-28T20:20:44.905Z","olay":"acildi","baglantiNoktasi":8440,"ortam":"yerel","oduncGun":14,"acilisMs":25.9}
{"an":"2026-07-28T20:20:45.986Z","olay":"sigterm_alindi","acikIstek":1}
{"an":"2026-07-28T20:20:47.101Z","olay":"kapandi","acikIstek":0}
```

Zaman damgaları ve süreler her çalıştırmada değişir.

Üç gözlem sabittir. **Uçuştaki istek tamamlanmıştır**: sinyal isteğin ortasında gelmiş,
buna rağmen yanıt `200` olarak dönmüş ve bir buçuk saniyelik iş kesilmemiştir. Kütükteki
`sigterm_alindi` satırı o anda bir açık istek bulunduğunu, `kapandi` satırı ise kapanma
tamamlandığında sıfır açık istek kaldığını yazar.

**Yeni bağlantı reddedilmiştir.** Sinyalden sonra yapılan istek bağlantı bile kuramamıştır;
`sunucu.close` çağrısı dinleyen soketi kapatmış, ama açık bağlantıları kesmemiştir. Kapanan
bir süreç için doğru davranış budur: yeni iş alma, aldığın işi bitir.

**Çıkış kodu sıfırdır.** Bir denetçi bu kodu gördüğünde sürecin isteyerek indiğini bilir;
sıfırdan farklı bir kod ise beklenmedik bir sonlanmayı bildirir ve farklı bir tepki gerektirir.

Zorla kapanma zamanlayıcısı bu düzenin kaçınılmaz tamamlayıcısıdır. Bitmeyen bir istek
süreci sonsuza kadar bekletebilir; beş saniyelik sınır dolduğunda süreç sıfırdan farklı bir
kodla iner. `unref` çağrısı bu zamanlayıcının, kapanma erken tamamlandığında sürecin ömrünü
uzatmasını engeller.

## Karşılanmayanlar

İlkeler listesinin dürüst okunması, karşılanmamış olanları da saymayı gerektirir.

**Destekleyici servisler** ilkesi henüz uygulanmadı. Bu bölümdeki depolar süreç belleğindeydi;
bir veritabanının ya da dış servisin yalnız bir adresle tanımlanan, değiştirilebilir bir bağlı
kaynak olarak ele alınması, bu kursun Yerel Geliştirme Ortamı dersinde kurulur.

**Yönetim süreçleri** ilkesi de açıktır. Veri göçü, toplu düzeltme, rapor üretimi gibi tek
seferlik işlerin uygulamanın kendisiyle aynı kod ve aynı ortamla çalıştırılması gerekir; ayrı
bir betikle yapıldığında iki farklı gerçeklik oluşur.

**Derle, yayımla, çalıştır** ayrımı bu bölümde ölçülmedi; yapı çıktısının ortam
değişkenlerinden ayrı tutulması ve her yayının geri alınabilir bir kimlik taşıması Oluşturma
Stratejileri ve Altyapı kursunda ele alınmıştı ve sunucu tarafındaki karşılığı ileri
kurslardadır.

Bir ilkeyi karşılamamak kusur değildir; karşılamadığını bilmemek kusurdur. Listenin işlevi
budur — kararların hangisinin alınmış, hangisinin ertelenmiş olduğunu ada bağlar.

## Özet

- On iki etmen ilkeleri bir araç değil, uygulamayı yazan ile çalıştıran arasındaki
  sözleşmedir; ortak hedefleri uygulamayı çalıştığı makineden bağımsız kılmaktır.
- Geliştirme/üretim eşliği, dosya özeti değişmeden davranışın ortam değişkenleriyle
  değişmesiyle ölçüldü; kodda ortam adına bakan hiçbir dallanma yoktur.
- Bağlantı noktası bağlama ilkesi gereği hizmet kendi soketini açar; ters vekil bir seçenektir,
  önkoşul değildir.
- Tek kullanımlık olma ölçümünde `SIGTERM` sonrası uçuştaki istek `200` ile tamamlanmış, yeni
  bağlantı reddedilmiş ve süreç sıfır çıkış koduyla inmiştir; zorla kapanma zamanlayıcısı
  bitmeyen isteğe karşı sınırı korur.
- Destekleyici servisler, yönetim süreçleri ve derle-yayımla-çalıştır ayrımı bu bölümde
  karşılanmadı; listenin işlevi ertelenmiş kararları adlandırmaktır.

## Sonraki Adım

İskelet artık ayakta: yapılandırma ortamdan okunuyor, gizli değerler ayrılmış, kütük standart
çıktıya yazılıyor, hatalar ortak bir biçimde yanıta dönüşüyor ve süreç düzgün inip kalkıyor.
Buna karşılık uygulama dışarıya hâlâ hiçbir gerçek içerik vermiyor; verdiği tek şey kendi
durumu. Sonraki bölüm bu boşluğu doldurmaya en yalın olandan başlar: diskte duran bir dosyayı
ağ üzerinden vermek. Sonraki ders o dosyanın hangi koşulla okunmasına izin verildiğini,
alıcının içeriği nasıl yorumlayacağını, aynı dosya ikinci kez istendiğinde ne olacağını ve bu
yükün sunucuda kalıp kalmayacağını kurar.
