---
title: 'Hollywood İlkesi'
source: 'https://academia.sh/tr/kurslar/tasarim-ilkeleri/hollywood-ilkesi'
course: 'Tasarım İlkeleri'
language: tr
updated: '2026-08-17T18:10:40+00:00'
license: 'CC BY-SA 4.0'
---

# Hollywood İlkesi

Çağıran ile çağrılan arasındaki yönün tersine çevrilmesi: adımların sırasını üç ayrı çağıranın yazdığı düzen ile adımların kendini bir iskelete kaydettiği düzenin karşılaştırılması, sırayı bilen dosya sayısının sayılması ve yeni bir adım eklendiğinde düzenlenen dosya ile dokunulan satır sayısının ölçülmesi.

Bir önceki dersin soyut yerleşiminde bileşim kökü hangi fiyat listesinin kullanılacağına karar
veriyordu, ama istemcileri hâlâ kendisi çağırıyordu. Adımların sırası ve sayısı çağıranın
gövdesinde duruyor. Bu akışa yeni bir adım eklemek, çağıranın gövdesini her seferinde
düzenlemeyi gerektirir.

**Hollywood ilkesi** yönü tersine çevirir: "bizi arama, biz seni ararız". Parçalar üst düzey
akışı çağırmaz; üst düzey akış parçalara çağrılma noktası verir. Eşzamansız JavaScript ve
Çalışma Zamanı kursunda tanıtılan **denetimin devri** (inversion of control) bu ilkenin genel
adıdır; burada ölçülen biçimi, adım sırasının hangi modülde yazılı olduğudur.

## Sırayı Çağıranın Yazdığı Düzen

Ücret hesabı üç adımdan oluşuyor: taban ücret, bölge katsayısı, sözleşmeli müşteri indirimi.
Üç ayrı çağıran bu sırayı kendi gövdesinde yazıyor.

```sh
mkdir -p cagiran iskelet
```

```js
// kayit.mjs — iki duzenin de kullandigi ornek gonderiler
export const KAYITLAR = [
  { kod: "GN-1", agirlik: 0.8, adres: "34100", sozlesmeli: false },
  { kod: "GN-2", agirlik: 3.0, adres: "06500", sozlesmeli: true },
  { kod: "GN-3", agirlik: 12.0, adres: "65200", sozlesmeli: true },
];
```

```js
// cagiran/adimlar.mjs — adimlar; sirayi bilmezler, cagirani da bilmezler
const KADEME = [[1, 3900], [5, 6400], [20, 11800]];
const BOLGE = { "34": 100, "06": 115, "65": 140 };

export const taban = (kurus, g) => KADEME.find(([ust]) => g.agirlik <= ust)?.[1] ?? 15000;
export const bolge = (kurus, g) => Math.round((kurus * (BOLGE[g.adres.slice(0, 2)] ?? 160)) / 100);
export const indirim = (kurus, g) => Math.round((kurus * (g.sozlesmeli ? 90 : 100)) / 100);
```

```js
// cagiran/fatura.mjs — sirayi cagiran yaziyor
import { taban, bolge, indirim } from "./adimlar.mjs";

export function fatura(gonderi) {
  let kurus = taban(0, gonderi);
  kurus = bolge(kurus, gonderi);
  kurus = indirim(kurus, gonderi);
  return `${gonderi.kod} ${kurus} kurus`;
}
```

```js
// cagiran/onizleme.mjs — ayni sirayi ikinci kez yaziyor
import { taban, bolge, indirim } from "./adimlar.mjs";

export function onizleme(gonderi) {
  let kurus = taban(0, gonderi);
  kurus = bolge(kurus, gonderi);
  kurus = indirim(kurus, gonderi);
  return `~${kurus}`;
}
```

```js
// cagiran/toplu.mjs — ayni sirayi ucuncu kez yaziyor
import { taban, bolge, indirim } from "./adimlar.mjs";

export function toplam(gonderiler) {
  let genel = 0;
  for (const g of gonderiler) {
    let kurus = taban(0, g);
    kurus = bolge(kurus, g);
    kurus = indirim(kurus, g);
    genel += kurus;
  }
  return `TOPLAM ${genel} kurus`;
}
```

```js
// cagiran/kur.mjs — bilesim koku
import { KAYITLAR } from "../kayit.mjs";
import { fatura } from "./fatura.mjs";
import { onizleme } from "./onizleme.mjs";
import { toplam } from "./toplu.mjs";

console.log(fatura(KAYITLAR[1]), onizleme(KAYITLAR[1]), toplam(KAYITLAR));
```

## Sırayı İskeletin Bildiği Düzen

İkinci düzende sıra bir iskelettedir. Adımlar iskeleti çağırmaz; iskelete kendilerini kaydeder
ve sıraları geldiğinde çağrılırlar.

```js
// iskelet/boru.mjs — iskelet: adimlari sirayla cagirir, adlarini onceden bilmez
const ADIMLAR = [];

export const adimEkle = (ad, islev) => ADIMLAR.push({ ad, islev });
export const adimAdlari = () => ADIMLAR.map((a) => a.ad);

export function calistir(gonderi) {
  let kurus = 0;
  for (const a of ADIMLAR) kurus = a.islev(kurus, gonderi);
  return kurus;
}
```

```js
// iskelet/adimlar.mjs — adimlar kendini iskelete kaydeder; iskeleti cagirmazlar
import { adimEkle } from "./boru.mjs";

const KADEME = [[1, 3900], [5, 6400], [20, 11800]];
const BOLGE = { "34": 100, "06": 115, "65": 140 };

adimEkle("taban", (kurus, g) => KADEME.find(([ust]) => g.agirlik <= ust)?.[1] ?? 15000);
adimEkle("bolge", (kurus, g) => Math.round((kurus * (BOLGE[g.adres.slice(0, 2)] ?? 160)) / 100));
adimEkle("indirim", (kurus, g) => Math.round((kurus * (g.sozlesmeli ? 90 : 100)) / 100));
```

```js
// iskelet/fatura.mjs — sirayi bilmez, iskeleti cagirir
import { calistir } from "./boru.mjs";

export const fatura = (gonderi) => `${gonderi.kod} ${calistir(gonderi)} kurus`;
```

```js
// iskelet/onizleme.mjs — sirayi bilmez
import { calistir } from "./boru.mjs";

export const onizleme = (gonderi) => `~${calistir(gonderi)}`;
```

```js
// iskelet/toplu.mjs — sirayi bilmez
import { calistir } from "./boru.mjs";

export const toplam = (gonderiler) =>
  `TOPLAM ${gonderiler.reduce((t, g) => t + calistir(g), 0)} kurus`;
```

```js
// iskelet/kur.mjs — bilesim koku: adimlari yukler, sonra istemcileri cagirir
import "./adimlar.mjs";
import { KAYITLAR } from "../kayit.mjs";
import { adimAdlari } from "./boru.mjs";
import { fatura } from "./fatura.mjs";
import { onizleme } from "./onizleme.mjs";
import { toplam } from "./toplu.mjs";

console.log(fatura(KAYITLAR[1]), onizleme(KAYITLAR[1]), toplam(KAYITLAR));
console.log("adimlar:", adimAdlari().join(" -> "));
```

```sh
node cagiran/kur.mjs
node iskelet/kur.mjs
```

```
GN-2 6624 kurus ~6624 TOPLAM 25392 kurus
GN-2 6624 kurus ~6624 TOPLAM 25392 kurus
adimlar: taban -> bolge -> indirim
```

Aynı sonuç. Fark, `adimAdlari()` satırında görünen şeydir: ikinci düzende adım listesi çalışma
zamanında sorulabilen bir veridir, birincisinde üç ayrı gövdeye dağılmış bir denetim akışıdır.

## Yeni Bir Adımın Maliyeti

Sigorta primi adımı ekleniyor: indirimden sonra tutar yüzde iki artıyor. Birinci düzende yeni
işlev yazılır ve üç çağıranın gövdesine eklenir; ikincisinde tek bir kayıt satırı yeter.
Yerinde düzenlemede yedek uzantısı verilmiştir; GNU ve BSD `sed` bu biçimde aynı davranır.

```sh
cp -r cagiran cagiran-yeni
cp -r iskelet iskelet-yeni

cat >> cagiran-yeni/adimlar.mjs <<'EOF'
export const sigorta = (kurus) => Math.round((kurus * 102) / 100);
EOF
sed -i.y 's/taban, bolge, indirim/taban, bolge, indirim, sigorta/' cagiran-yeni/*.mjs
sed -i.y 's/^  kurus = indirim(kurus, gonderi);/&\n  kurus = sigorta(kurus);/' cagiran-yeni/*.mjs
sed -i.y 's/^    kurus = indirim(kurus, g);/&\n    kurus = sigorta(kurus);/' cagiran-yeni/*.mjs
rm -f cagiran-yeni/*.y

cat >> iskelet-yeni/adimlar.mjs <<'EOF'
adimEkle("sigorta", (kurus) => Math.round((kurus * 102) / 100));
EOF

node cagiran-yeni/kur.mjs
node iskelet-yeni/kur.mjs
for k in cagiran iskelet; do
  echo "$k: duzenlenen dosya = $(diff -rq $k $k-yeni | grep -c '^Files')" \
    " dokunulan satir = $(diff -rU0 $k $k-yeni | grep -cE '^[+-][^+-]')" \
    " sirayi bilen dosya = $(grep -l 'kurus = ' $k/*.mjs | wc -l | tr -d ' ')"
done
```

```
GN-2 6756 kurus ~6756 TOPLAM 25899 kurus
GN-2 6756 kurus ~6756 TOPLAM 25899 kurus
adimlar: taban -> bolge -> indirim -> sigorta
cagiran: duzenlenen dosya = 4  dokunulan satir = 10  sirayi bilen dosya = 3
iskelet: duzenlenen dosya = 1  dokunulan satir = 1  sirayi bilen dosya = 1
```

İki düzen de aynı yeni sonucu üretiyor. Maliyet dört dosya ve on satıra karşı bir dosya ve bir
satır. Son sütun nedeni veriyor: birinci düzende sırayı bilen üç dosya vardı, ikincisinde bir.

Ölçü, açık–kapalı ilkesinin ölçtüğünden farklı bir şeyi söylüyor. Orada yeni bir **tür**
eklemenin maliyeti sayılmıştı; burada sayılan, var olan bir akışa yeni bir **adım**
eklemenin maliyeti. İkisi de aynı yöne çıkar: değişikliğin metne değil veriye düşmesi.

## Yönün Tersine Çevrilmesi

İki düzen arasındaki fark ithal grafiğinde de görünür. Birinci düzende `fatura.mjs` adımları
ithal eder ve onları çağırır; denetim yukarıdan aşağı akar. İkinci düzende `adimlar.mjs`
iskeleti ithal eder ve ona kaydolur; çağrı yönü aşağıdan yukarı kurulur, çalıştırma yönü
yukarıdan aşağı kalır. Çağıran ile çağrılan arasındaki ilişki tersine döndüğü için ilke bu
adı taşır.

Bu tersine çevirme, bağımlılığın tersine çevrilmesiyle aynı şey değildir. Orada soru
soyutlamanın hangi tarafta **tanımlandığıydı**; burada soru denetim akışının hangi tarafta
**yazıldığı**. İki ilke birlikte kullanılır: iskelet adımların sözleşmesini tanımlar
(bağımlılığın tersine çevrilmesi) ve adımları çağırma sırasını da o tutar (Hollywood ilkesi).

## İskeletin Bedeli

Tersine çevirmenin bedeli okunabilirlikte ödenir. Birinci düzende akışı görmek için tek bir
gövdeyi okumak yeterlidir; ikincisinde sıra, kayıt çağrılarının çalışma anındaki düzenine
bağlıdır ve bu düzen bileşim kökünün ithal sırasından gelir. `adimAdlari()` gibi bir sorgunun
bulunması bu yüzden zorunludur: sıra bir veri hâline geldiğinde, o verinin okunabilir olması
gerekir.

İkinci bedel hata ayıklamadadır. Bir adım yanlış sonuç ürettiğinde birinci düzende çağrı
zinciri yığıt izinde doğrudan görünür; ikincisinde iskeletin döngüsü araya girer. Ölçüt yine
sayıdır: sırayı bilen dosya sayısı birden büyükse ve akışa adım ekleme isteği tekrarlıyorsa
iskelet kazanır; akış sabitse ve tek çağıran varsa iskelet yalnız bir dolaylılık katmanıdır.

## Özet

- Hollywood ilkesi çağıran ile çağrılan arasındaki yönü tersine çevirir: parçalar akışı
  çağırmaz, akış parçalara çağrılma noktası verir.
- Ölçü, adım sırasının kaç dosyada yazılı olduğudur: çağıran düzeninde 3, iskelet düzeninde 1
  dosya sırayı biliyordu.
- Akışa yeni bir adım eklendiğinde çağıran düzeninde 4 dosya ve 10 satır, iskelet düzeninde
  1 dosya ve 1 satır düzenlendi.
- İskelet düzeninde adım listesi çalışma zamanında sorulabilen bir veridir; çağıran düzeninde
  üç ayrı gövdeye dağılmış bir denetim akışıdır.
- Bedel okunabilirlik ve hata ayıklamadadır; tek çağıranlı ve sabit bir akışta iskelet yalnız
  bir dolaylılık katmanı ekler.

## Sonraki Adım

Buraya kadarki bütün ölçüler **modül çiftleri** üzerindeydi: iki modül arasındaki bağın gücü,
bir modülün içindeki adların ilgililiği, bir çağrının kaç nesne üzerinden geçtiği, bir
değişikliğin dokunduğu dosya kümesi. Kod tabanı büyüdüğünde asıl soru biçim değiştirir: artık
hangi modülün hangisine bağlanacağı değil, sınırın **nereye çizileceği** sorulur. Bu sorunun
cevabı kararların ne kadar sık değiştiğinde saklıdır — hangi karar yıllarca duran kararlı bir
politikadır, hangisi fiyat listesi her yenilendiğinde oynayan bir ayrıntı. Sonraki konu bu
ayrımı kurar ve sınırın iki tarafını değişim sıklığıyla ölçer.
