---
title: Cephe
source: 'https://academia.sh/tr/kurslar/tasarim-kaliplari/cephe'
course: 'Tasarım Kalıpları'
language: tr
updated: '2026-08-17T18:10:39+00:00'
license: 'CC BY-SA 4.0'
---

# Cephe

Karmaşık alt sistemin sadeleştirilmesi: altı adımlı gönderi kabul akışını istemcilerin kendisinin sıraladığı düzen ile tek giriş noktası arkasına alan düzenin doğrudan bağ, ithal kapanışı ve bilinen adım sayısıyla karşılaştırılması, bir adım atlandığında ortaya çıkan farkın ölçülmesi ve akışa yeni adım eklendiğinde düzenlenen dosyaların sayılması.

Dekoratör zincirini kuran kod, hangi eklerin hangi sırayla uygulanacağını bilmek zorundaydı.
Tek bir çağrı için bu katlanılır bir bilgidir. Kitaplığın tamamı böyle çalıştığında ise
istemci sıralı adımların hepsini öğrenmek zorunda kalır.

Gönderi kabulü altı adımdır: adresi düzelt, bölgeyi çöz, taban ücreti hesapla, ekleri uygula,
taşıyıcıyı seç, teslim tarihini bul. Sıra keyfi değildir — bölge düzeltilmiş posta kodundan
çıkar, ücret bölgeye bağlıdır, taşıyıcı kapsamı yine bölgeye. İki istemci bu altı adımı ayrı
ayrı biliyorsa aynı sıra iki yerde durur ve bir adım atlandığında hata çalışma zamanında,
yanlış bir tutar biçiminde çıkar. **Cephe** (facade) alt sistemin önüne tek bir giriş noktası
koyar. Ölçüler: istemcinin doğrudan bağ sayısı, ithal kapanışı boyutu ve sıralı adım
bilgisinin kaç dosyada bulunduğu.

## Problem: Sıra Bilgisi İstemcide

Alt sistem altı küçük modüldür; her biri tek bir işi yapar ve ötekileri tanımaz.

```js
// alt/adres.mjs — alt sistem 1: adresi normallestirir
export const adresiDuzelt = (adres) => ({
  postaKodu: String(adres.postaKodu ?? "").replace(/\s+/g, ""),
  il: String(adres.il ?? "").trim(),
});
```

```js
// alt/bolge.mjs — alt sistem 2: posta kodundan ucret bolgesi
const POSTA_BOLGE = { 34: "yakin", "06": "orta", 35: "orta", 65: "uzak" };

export const bolgeBul = (postaKodu) => POSTA_BOLGE[postaKodu.slice(0, 2)] ?? "bilinmeyen";
```

```js
// alt/tarife.mjs — alt sistem 3: agirlik kademesi ve bolge katsayisi
const KADEME = [[1, 4990], [5, 8490], [15, 14990], [30, 24990]];
const KATSAYI = { yakin: 100, orta: 118, uzak: 145, bilinmeyen: 165 };

export const tabanUcret = (agirlik, bolge) => {
  const k = KADEME.find(([ust]) => agirlik <= ust) ?? [0, 24990];
  return Math.round((k[1] * KATSAYI[bolge]) / 100);
};
```

```js
// alt/ekler.mjs — alt sistem 4: sigorta ve vergi ekleri
export const ekleriUygula = (tutar, secenekler, deger) => {
  const sigortali = secenekler.sigorta === true ? Math.max(500, Math.round(deger * 0.005)) : 0;
  return Math.round((tutar + sigortali) * (secenekler.vergi === true ? 1.2 : 1));
};
```

```js
// alt/tasiyici.mjs — alt sistem 5: bolgeye gore en ucuz tasiyici
const CARPAN = { kara: 1, hava: 1.35, deniz: 0.9 };
const KAPSAM = { yakin: ["kara", "hava", "deniz"], orta: ["kara", "hava"], uzak: ["kara"], bilinmeyen: ["kara"] };

export const enUcuzTasiyici = (tutar, bolge) => KAPSAM[bolge]
  .map((t) => ({ tasiyici: t, tutar: Math.round(tutar * CARPAN[t]) }))
  .sort((a, b) => a.tutar - b.tutar)[0];
```

```js
// alt/teslim.mjs — alt sistem 6: bolgeye gore teslim tarihi
const GUN = { yakin: 1, orta: 2, uzak: 4, bilinmeyen: 5 };

export const teslimTarihi = (baslangic, bolge) => {
  const t = new Date(`${baslangic}T00:00:00Z`);
  t.setUTCDate(t.getUTCDate() + GUN[bolge]);
  return t.toISOString().slice(0, 10);
};
```

```js
// istekler.mjs — iki duzenin de isledigi istekler
export const ISTEKLER = [
  { kod: "G-1", agirlik: 0.8, deger: 120000, adres: { postaKodu: " 34100 ", il: " Istanbul " },
    secenekler: { sigorta: true, vergi: true }, tarih: "2026-03-02" },
  { kod: "G-2", agirlik: 12, deger: 40000, adres: { postaKodu: "06500", il: "Ankara" },
    secenekler: { vergi: true }, tarih: "2026-03-02" },
  { kod: "G-3", agirlik: 26, deger: 900000, adres: { postaKodu: "65100", il: "Van" },
    secenekler: {}, tarih: "2026-03-30" },
];
```

İlk düzende iki istemci altı modülü kendisi sıralar. İkinci istemci farklı bir sonuç
döndürüyor ama aynı altı adımı baştan tekrarlıyor.

```js
// dogrudan/kabul.mjs — istemci alti modulu kendisi sirayla cagirir
import { adresiDuzelt } from "../alt/adres.mjs";
import { bolgeBul } from "../alt/bolge.mjs";
import { tabanUcret } from "../alt/tarife.mjs";
import { ekleriUygula } from "../alt/ekler.mjs";
import { enUcuzTasiyici } from "../alt/tasiyici.mjs";
import { teslimTarihi } from "../alt/teslim.mjs";

export function kabulEt(istek) {
  const adres = adresiDuzelt(istek.adres);
  const bolge = bolgeBul(adres.postaKodu);
  const taban = tabanUcret(istek.agirlik, bolge);
  const tutar = ekleriUygula(taban, istek.secenekler, istek.deger);
  const secim = enUcuzTasiyici(tutar, bolge);
  return { kod: istek.kod, bolge, ...secim, tarih: teslimTarihi(istek.tarih, bolge) };
}
```

```js
// dogrudan/teklif.mjs — ikinci istemci ayni sirayi bastan tekrar eder
import { adresiDuzelt } from "../alt/adres.mjs";
import { bolgeBul } from "../alt/bolge.mjs";
import { tabanUcret } from "../alt/tarife.mjs";
import { ekleriUygula } from "../alt/ekler.mjs";
import { enUcuzTasiyici } from "../alt/tasiyici.mjs";
import { teslimTarihi } from "../alt/teslim.mjs";

export function teklifVer(istek) {
  const adres = adresiDuzelt(istek.adres);
  const bolge = bolgeBul(adres.postaKodu);
  const taban = tabanUcret(istek.agirlik, bolge);
  const tutar = ekleriUygula(taban, istek.secenekler, istek.deger);
  const secim = enUcuzTasiyici(tutar, bolge);
  return { tutar: secim.tutar, tarih: teslimTarihi(istek.tarih, bolge) };
}
```

## Çözüm: Alt Sistemin Önünde Tek Giriş

Cephe alt sistemi gizlemez, ona giden **tek bir yol** açar. İçinde iş kuralı yoktur; yalnız
sıra ve iki dış işlem vardır.

```js
// cephe/kabul-cephesi.mjs — cephe: alt sistemin sirasini bilen tek yer, dis yuzu iki islem
import { adresiDuzelt } from "../alt/adres.mjs";
import { bolgeBul } from "../alt/bolge.mjs";
import { tabanUcret } from "../alt/tarife.mjs";
import { ekleriUygula } from "../alt/ekler.mjs";
import { enUcuzTasiyici } from "../alt/tasiyici.mjs";
import { teslimTarihi } from "../alt/teslim.mjs";

const hesapla = (istek) => {
  const adres = adresiDuzelt(istek.adres);
  const bolge = bolgeBul(adres.postaKodu);
  const taban = tabanUcret(istek.agirlik, bolge);
  const tutar = ekleriUygula(taban, istek.secenekler, istek.deger);
  return { bolge, secim: enUcuzTasiyici(tutar, bolge), tarih: teslimTarihi(istek.tarih, bolge) };
};

export function kabulEt(istek) {
  const s = hesapla(istek);
  return { kod: istek.kod, bolge: s.bolge, ...s.secim, tarih: s.tarih };
}

export function teklifVer(istek) {
  const s = hesapla(istek);
  return { tutar: s.secim.tutar, tarih: s.tarih };
}
```

```js
// cephe/kabul.mjs — ayni istemci, tek bag
import { kabulEt as cepheKabul } from "./kabul-cephesi.mjs";

export const kabulEt = (istek) => cepheKabul(istek);
```

```js
// cephe/teklif.mjs — ikinci istemci, tek bag
import { teklifVer as cepheTeklif } from "./kabul-cephesi.mjs";

export const teklifVer = (istek) => cepheTeklif(istek);
```

```js
// kosum.mjs — iki duzen ayni kabul kaydini ve ayni teklifi uretiyor mu
import { ISTEKLER } from "./istekler.mjs";
import { kabulEt as dogrudanKabul } from "./dogrudan/kabul.mjs";
import { teklifVer as dogrudanTeklif } from "./dogrudan/teklif.mjs";
import { kabulEt as cepheKabul } from "./cephe/kabul.mjs";
import { teklifVer as cepheTeklif } from "./cephe/teklif.mjs";

let ayrilan = 0;
for (const istek of ISTEKLER) {
  const a = JSON.stringify([dogrudanKabul(istek), dogrudanTeklif(istek)]);
  const b = JSON.stringify([cepheKabul(istek), cepheTeklif(istek)]);
  if (a !== b) ayrilan += 1;
  console.log(`${istek.kod} ${JSON.stringify(dogrudanKabul(istek))}`);
}
console.log(`ayrilan sonuc = ${ayrilan} / ${ISTEKLER.length}`);
```

```
G-1 {"kod":"G-1","bolge":"yakin","tasiyici":"deniz","tutar":6037,"tarih":"2026-03-03"}
G-2 {"kod":"G-2","bolge":"orta","tasiyici":"kara","tutar":21226,"tarih":"2026-03-04"}
G-3 {"kod":"G-3","bolge":"uzak","tasiyici":"kara","tutar":36236,"tarih":"2026-04-03"}
ayrilan sonuc = 0 / 3
```

## Bağın ve Kapanışın Ölçülmesi

Ölçüm Tasarım İlkeleri kursundaki iki ayrı ölçüyü birlikte kullanıyor: doğrudan bağ sayısı
(bir dosyanın kendi ithal satırları) ve ithal kapanışı boyutu (o dosyanın dolaylı olarak
bağlandığı bütün dosyalar).

```js
// grafik.mjs — istemcilerin dogrudan bag sayisi, ithal kapanisi ve adim sirasini bilen dosyalar
import { readdirSync, readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";

const ADIM = ["adresiDuzelt", "bolgeBul", "tabanUcret", "ekleriUygula", "enUcuzTasiyici", "teslimTarihi"];

const ithaller = (yol) => [...readFileSync(yol, "utf8").matchAll(/from "(\.[^"]+)"/g)]
  .map((m) => resolve(dirname(yol), m[1]));

const kapanis = (yol, gorulen = new Set()) => {
  for (const c of ithaller(yol)) if (!gorulen.has(c)) { gorulen.add(c); kapanis(c, gorulen); }
  return gorulen;
};

for (const yol of ["dogrudan/kabul.mjs", "dogrudan/teklif.mjs", "cephe/kabul.mjs", "cephe/teklif.mjs"]) {
  const metin = readFileSync(yol, "utf8");
  const adim = ADIM.filter((a) => metin.includes(a)).length;
  console.log(`${yol.padEnd(20)} dogrudan bag=${ithaller(yol).length}  ithal kapanisi=${kapanis(yol).size}  ` +
    `bildigi adim=${adim}/6`);
}

const yuzey = (dosyalar) => dosyalar
  .reduce((t, y) => t + (readFileSync(y, "utf8").match(/^export /gm) ?? []).length, 0);

console.log(`alt sistem yuzeyi = ${yuzey(readdirSync("alt").map((d) => `alt/${d}`))} islev, ` +
  `cephe yuzeyi = ${yuzey(["cephe/kabul-cephesi.mjs"])} islem`);
```

```
dogrudan/kabul.mjs   dogrudan bag=6  ithal kapanisi=6  bildigi adim=6/6
dogrudan/teklif.mjs  dogrudan bag=6  ithal kapanisi=6  bildigi adim=6/6
cephe/kabul.mjs      dogrudan bag=1  ithal kapanisi=7  bildigi adim=0/6
cephe/teklif.mjs     dogrudan bag=1  ithal kapanisi=7  bildigi adim=0/6
alt sistem yuzeyi = 6 islev, cephe yuzeyi = 2 islem
```

Üç sayı üç ayrı şey söylüyor. Doğrudan bağ 6'dan 1'e indi. Bildiği adım 6/6'dan 0/6'ya indi:
sıra bilgisi iki istemciden çıkıp tek dosyada toplandı. Buna karşılık **ithal kapanışı
küçülmedi, 6'dan 7'ye çıktı** — cephe bir dosya olarak kapanışa eklendi. Cephe derleme
bağımlılığını azaltmaz; azalttığı şey istemcinin bilmek zorunda olduğu ad ve sıra sayısıdır.
Kapanışın gerçekten küçülmesi için alt sistemin bir kısmının hiç kullanılmaması gerekirdi.

Son satır cephenin yüzeyini veriyor: alt sistem 6 işlev sunuyor, cephe 2 işlem. Bu daralma
kazanç olduğu kadar bedeldir; aşağıda ölçülüyor.

## Bir Adım Atlanınca

Sıra bilgisinin istemcide durmasının maliyeti, atlanan bir adımın hata vermeden yanlış sonuç
üretmesidir.

```js
// atlanan.mjs — dogrudan duzende ilk adim atlanirsa ne olur
import { ISTEKLER } from "./istekler.mjs";
import { kabulEt } from "./dogrudan/kabul.mjs";
import { bolgeBul } from "./alt/bolge.mjs";
import { tabanUcret } from "./alt/tarife.mjs";
import { ekleriUygula } from "./alt/ekler.mjs";
import { enUcuzTasiyici } from "./alt/tasiyici.mjs";
import { teslimTarihi } from "./alt/teslim.mjs";

// Ayni sira, tek eksikle: adresiDuzelt cagrilmadi.
function atlayarakKabul(istek) {
  const bolge = bolgeBul(istek.adres.postaKodu);
  const taban = tabanUcret(istek.agirlik, bolge);
  const tutar = ekleriUygula(taban, istek.secenekler, istek.deger);
  const secim = enUcuzTasiyici(tutar, bolge);
  return { kod: istek.kod, bolge, ...secim, tarih: teslimTarihi(istek.tarih, bolge) };
}

const g = ISTEKLER[0];
const dogru = kabulEt(g), eksik = atlayarakKabul(g);
console.log(`tam sira   : ${JSON.stringify(dogru)}`);
console.log(`adim atlandi: ${JSON.stringify(eksik)}`);
const gun = (Date.parse(eksik.tarih) - Date.parse(dogru.tarih)) / 86400000;
console.log(`tutar farki = ${eksik.tutar - dogru.tutar} kurus, teslim farki = ${gun} gun`);
```

```
tam sira   : {"kod":"G-1","bolge":"yakin","tasiyici":"deniz","tutar":6037,"tarih":"2026-03-03"}
adim atlandi: {"kod":"G-1","bolge":"bilinmeyen","tasiyici":"kara","tutar":10601,"tarih":"2026-03-07"}
tutar farki = 4564 kurus, teslim farki = 4 gun
```

Posta kodundaki tek bir boşluk yüzünden bölge "bilinmeyen" oldu; ücret 4564 kuruş yüksek, teslim
tarihi 4 gün ileri çıktı ve hiçbir hata atılmadı. Cephe düzeninde bu hata istemcide yapılamaz,
çünkü istemcinin çağırdığı adım yoktur.

## Akışa Yeni Adım Girince

Yeni gereksinim yasak madde denetimidir ve akışın ortasına, bölge çözümünden hemen sonra girer.

```sh
mkdir -p yeni && cp -r alt dogrudan cephe istekler.mjs kosum.mjs grafik.mjs yeni/
ls yeni/alt
```

```
adres.mjs
bolge.mjs
ekler.mjs
tarife.mjs
tasiyici.mjs
teslim.mjs
```

```js
// yeni/alt/denetim.mjs — alt sistem 7: yasak madde denetimi
const YASAK = new Set(["yanici", "asindirici"]);

export const yasakMi = (istek) => (istek.icerik ?? []).some((i) => YASAK.has(i));
```

```sh
cd yeni
sed -i.y -e 's#^import { tabanUcret } from "../alt/tarife.mjs";#&\nimport { yasakMi } from "../alt/denetim.mjs";#' \
         -e 's#^  const bolge = bolgeBul(adres.postaKodu);#&\n  if (yasakMi(istek)) return { kod: istek.kod, red: "yasak madde" };#' dogrudan/kabul.mjs
sed -i.y -e 's#^import { tabanUcret } from "../alt/tarife.mjs";#&\nimport { yasakMi } from "../alt/denetim.mjs";#' \
         -e 's#^  const bolge = bolgeBul(adres.postaKodu);#&\n  if (yasakMi(istek)) return { red: "yasak madde" };#' dogrudan/teklif.mjs
sed -i.y -e 's#^import { tabanUcret } from "../alt/tarife.mjs";#&\nimport { yasakMi } from "../alt/denetim.mjs";#' \
         -e 's#^  const bolge = bolgeBul(adres.postaKodu);#&\n  if (yasakMi(istek)) return { red: "yasak madde" };#' \
         -e 's#^  return { kod: istek.kod, bolge: s.bolge, ...s.secim, tarih: s.tarih };#  if (s.red !== undefined) return { kod: istek.kod, red: s.red };\n&#' \
         -e 's#^  return { tutar: s.secim.tutar, tarih: s.tarih };#  if (s.red !== undefined) return { red: s.red };\n&#' cephe/kabul-cephesi.mjs
sed -i.y 's#  { kod: "G-3", agirlik: 26#  { kod: "G-4", agirlik: 2, deger: 5000, adres: { postaKodu: "34100", il: "Istanbul" },\n    secenekler: {}, tarih: "2026-03-02", icerik: ["yanici"] },\n  { kod: "G-3", agirlik: 26#' istekler.mjs
rm -f dogrudan/*.y cephe/*.y *.y
node kosum.mjs | tail -2
node grafik.mjs | head -2
for d in dogrudan cephe; do
  echo "$d duzenlenen: $(diff -rq "../$d" "$d" | grep '^Files ' | sed 's#.*/\([a-z-]*\.mjs\).*#\1#' | tr '\n' ' ')"
done
```

```
G-3 {"kod":"G-3","bolge":"uzak","tasiyici":"kara","tutar":36236,"tarih":"2026-04-03"}
ayrilan sonuc = 0 / 4
dogrudan/kabul.mjs   dogrudan bag=7  ithal kapanisi=7  bildigi adim=6/6
dogrudan/teklif.mjs  dogrudan bag=7  ithal kapanisi=7  bildigi adim=6/6
dogrudan duzenlenen: kabul.mjs teklif.mjs
cephe duzenlenen: kabul-cephesi.mjs
```

Doğrudan düzende iki istemcinin ikisi de düzenlendi ve doğrudan bağ sayısı 6'dan 7'ye çıktı.
Cephe düzeninde yalnız cephe düzenlendi; iki istemci dosyası da olduğu gibi kaldı ve bağ
sayıları 1'de durdu. Dört isteğin dördünde iki düzen aynı yanıtı verdi — yasak madde taşıyan
G-4 için ikisi de reddetti. İstemci sayısı arttıkça fark doğrusal büyür: on istemci olsa
doğrudan düzende on dosya düzenlenecek, cephe düzeninde yine bir.

## Bedel ve Ne Zaman Uygulanmayacağı

Cephenin bedeli üç maddedir. Birincisi bir dosya ve bir dolaylılık basamağıdır; ithal kapanışı
da bir büyüdü. İkincisi yüzeyin daralmasıdır: alt sistemin 6 işlevine karşı cephe 2 işlem
sunuyor. Cephenin geçirmediği bir yetenek — yalnız bölgeyi çözmek, taşıyıcıyı seçmeden ücret
hesaplamak — istemciye kapalıdır. Kalıp alt sistemi **kapatmaz**, alt sistem modülleri
kullanılabilir olarak kalır; ama istemci alt sisteme doğrudan gittiği anda cephenin sağladığı
sıra güvencesi de biter.

Üçüncüsü en sık rastlanan bozulmadır: cephe iş kuralı biriktirmeye başlarsa. Buradaki cephede
tek bir karar yok — yalnız çağrı sırası var. Cepheye indirim eşiği, red kuralı ya da tarife
seçimi yazıldığı anda dosya alt sistemin yedinci modülü olur ve hiçbir yerde ölçülmeyen bir
sorumluluk yığını büyür. Kalıbın sınırı şudur: cephe **sıra** bilir, **kural** bilmez.

İki durumda uygulanmaz. Alt sistem tek modül ve tek çağrıdan oluşuyorsa sıra bilgisi yoktur;
cephe yalnız yeniden adlandırma yapar. İstemcilerin her biri alt sistemin farklı bir alt
kümesini farklı bir sırayla kullanıyorsa tek bir cephe onların hiçbirine yetmez; o durumda
cepheye eklenen her seçenek bir bayrak parametresi olarak birikir ve Temiz Kod kursunda ölçülen
bayrak maliyeti geri döner.

## Özet

- Cephenin çözdüğü problem, sıralı çağrı bilgisinin her istemcide tekrarlanmasıdır; çözüm alt
  sistemin önüne sırayı bilen tek bir giriş noktası koymaktır.
- Doğrudan bağ sayısı istemci başına 6'dan 1'e, bilinen adım sayısı 6/6'dan 0/6'ya indi; üç
  isteğin sonuçları iki düzende de aynı kaldı.
- İthal kapanışı 6'dan 7'ye **çıktı**: cephe derleme bağımlılığını azaltmaz, istemcinin bilmesi
  gereken ad ve sıra sayısını azaltır.
- Doğrudan düzende bir adım atlandığında hata atılmadı; ücret 4564 kuruş, teslim tarihi 4 gün
  saptı. Akışa yedinci adım girince doğrudan düzende iki istemci de düzenlendi, cephe düzeninde
  yalnız cephe düzenlendi.
- Bedel bir dosya, bir dolaylılık basamağı ve yüzeyin 6 işlevden 2 işleme daralmasıdır; cephe
  sıra bilir, kural bilmez — kural biriktiği anda alt sistemin bir modülüne dönüşür.

## Sonraki Adım

Buraya kadarki dört kalıp nesneleri birleştirmenin farklı biçimlerini kurdu ve hepsinde ölçü
dosya, tip ya da bağ sayısıydı. Bir sonraki problem başka bir kaynağı ölçer: belleği. Ücret
hesabı sırasında her gönderi için bir tarife nesnesi kuruluyorsa, yüz binlerce gönderilik bir
toplu işlemde aynı kademe tablosu yüz binlerce kez kopyalanır. Oysa tablonun içeriği gönderiye
göre değişmez; gönderiye göre değişen şey yalnız ağırlık ve adrestir. Sonraki ders nesne
sayısını sayar, değişmeyen bilgiyi paylaşılan bir nesnede toplayan sinek siklet kalıbını yazar
ve kazancı hem nesne sayısıyla hem de ortama bağlı olduğu işaretlenmiş bir yığın ölçümüyle
gösterir.
