---
title: 'Özellik Bayrakları'
source: 'https://academia.sh/tr/kurslar/ci-cd/ozellik-bayraklari'
course: 'Sürekli Tümleştirme ve Teslimat'
language: tr
updated: '2026-08-17T18:09:03+00:00'
license: 'CC BY-SA 4.0'
---

# Özellik Bayrakları

Aynı değişiklik dizisi bayraklı ve bayraksız iki düzende yayınlanır; geri alma biriminin kod mu davranış mı olduğu tur ve etkilenen fatura sayısıyla ölçülür. Üç bayrağın açtığı sekiz kod yolu sayılır, sınanan yol oranı çıkarılır ve bir dönemin bayrak borcu ölü kod yoluyla birlikte yazılır.

Önceki dersin iki ortamlı düzeninde geri alma tek anahtara indi: trafik eski ortama çevrilir
ve dakikalar içinde önceki davranışa dönülür. O anahtarın geri aldığı şey **kodun tamamıydı**.
Yayın bir sürümü taşır; sürüm içindeki her değişiklik aynı anda gider ve aynı anda geri gelir.
Oysa geri alınması gereken çoğu zaman tek bir davranıştır.

Özellik bayrağı bu birimi ayırır: kod üretime dağıtılır, davranış ayrı bir anahtarla açılır.
Bu dersin ölçüsü bayrağın var olup olmadığı değil, bu ayrılığın **hangi sayıyı değiştirdiğidir**.
Aynı değişiklik dizisi iki düzende koşturulur, geri alma birimi ve turu sayılır, bayrağın açtığı
kod yolları sayılır ve bir dönemin sonunda geriye kalan bayrak borcu yazılır.

- **YS25.** Bayrak değeri hat dışında, çalışan sürecin okuduğu bir ayar kaydında durur;
  değiştirilmesi yeni bir yayın gerektirmez. Ayarın bütün düğümlere yayılması bir tur sürer.
- **YS26.** Bayraklar birbirinden bağımsızdır: herhangi bir kombinasyon geçerli bir kod yoludur.
- **YS27.** Üretimdeki sapma, doğrulayıcı servisin uyuşmazlık raporundan görülür; rapor iki
  dağıtım turunda bir üretilir. Fark etme süresi iki düzende de aynıdır.
- **YS28.** Bayraksız düzende geri alma birimi bir sürümdür: sürüm içindeki bütün değişiklikler
  birlikte geri gider.
- **YS29.** Bayrak okuma noktası, koşulun kodda yazıldığı yerdir; bir bayrak birden çok noktada
  okunabilir ve temizleme maliyeti bu sayıyla orantılıdır.
- **YS30.** Kurgu, bölgesel ölçüm ağının faturalama servisidir: sayaç okumasından fatura tutarı
  üretilir. Servis de, defter de, aşağıdaki sayılar da kurgudur.

## Geri Alma Birimi

Altı değişiklikten oluşan bir dönem yayınlanır. Üçüncüsü — gecikme faizi — kusurludur ve kusur
ancak sonraki değişiklikler de üretime çıktıktan sonra görülür. Bayraksız düzende değişiklikler
ikişerli üç yayına bölünür. Bayraklı düzende her değişiklik ayrı yayınlanır, kusurlu olan bayrak
arkasında dağıtılıp sonra açılır.

```js
// duzen.mjs — ayni degisiklik dizisi iki duzende yayinlanir; yayin duzeni MODELDIR

const DEGISIKLIK = ['tarife tablosu', 'kademeli tarife', 'gecikme faizi',
  'fatura ozet alani', 'is emri baglantisi', 'toplu is raporu'];
const KUSURLU = 2;        // gecikme faizi, kademe acikken sapiyor
const FATURA_TURU = 40;   // bir dagitim turunda hesaplanan fatura
const AYAR_TURU = 4;      // bir ayar yayilma turunda hesaplanan fatura
const FARK_ETME = 2;      // uyusmazlik raporunun kusuru gostermesi: iki dagitim turu

function bayraksiz() {
  const yayin = [[0, 1], [2, 3], [4, 5]];   // uc yayin, her yayin bir surum
  let surum = yayin.length, tur = 0;
  while (yayin.slice(0, surum).flat().includes(KUSURLU)) { surum -= 1; tur += 1; }
  const kalan = yayin.slice(0, surum).flat();
  const cikan = yayin.flat().filter((i) => !kalan.includes(i));
  return { ad: 'bayraksiz', birim: 'kod', tur, cikan,
    etkilenen: (FARK_ETME + tur) * FATURA_TURU };
}

function bayrakli() {
  // her degisiklik ayri yayinlandi; kusurlu olan bayrak arkasinda dagitilip acildi
  const bayrak = { 'gecikme faizi': 'acik' };
  let tur = 0;
  bayrak['gecikme faizi'] = 'kapali'; tur += 1;
  const cikan = Object.entries(bayrak).filter(([, d]) => d === 'kapali')
    .map(([ad]) => DEGISIKLIK.indexOf(ad));
  return { ad: 'bayrakli', birim: 'davranis', tur, cikan,
    etkilenen: FARK_ETME * FATURA_TURU + tur * AYAR_TURU };
}

console.log('duzen      geri alma birimi  tur  cikan  bunlardan saglam  etkilenen fatura');
for (const d of [bayraksiz(), bayrakli()]) {
  const saglam = d.cikan.filter((i) => i !== KUSURLU);
  console.log(`${d.ad.padEnd(10)} ${d.birim.padEnd(17)} ${String(d.tur).padEnd(4)} ` +
    `${String(d.cikan.length).padEnd(6)} ${String(saglam.length).padEnd(17)} ${d.etkilenen}`);
  console.log(`  uretimden cikan: ${d.cikan.map((i) => DEGISIKLIK[i]).join(', ')}`);
}
```

```
duzen      geri alma birimi  tur  cikan  bunlardan saglam  etkilenen fatura
bayraksiz  kod               2    4      3                 160
  uretimden cikan: gecikme faizi, fatura ozet alani, is emri baglantisi, toplu is raporu
bayrakli   davranis          1    1      0                 84
  uretimden cikan: gecikme faizi
```

Bayraksız düzende iki tur geri sarma gerekti, çünkü kusurlu değişiklik ortadaki sürümdeydi ve
ondan sonra bir sürüm daha yayınlanmıştı. Üretimden dört değişiklik çıktı; üçü sağlamdı. O üç
değişikliğin sahipleri kusurla ilgisiz kişilerdir ve işleri, kendi hataları olmayan bir nedenle
üretimden geri alınmıştır. Bayraklı düzende geri alınan tek şey bir davranıştır: sağlam
değişikliklerin hiçbiri üretimden çıkmadı.

Etkilenen fatura sayısındaki fark ise geri alma turunun uzunluğundan gelir. İki düzende de
fark etme aynı sürüyor — seksen fatura. Ayrılık ondan sonrasında: sürüm geri sarma iki dağıtım
turu, bayrak kapatma bir ayar yayılma turudur. Yüz altmışa karşı seksen dört. Bu farkın
tamamı geri alma yolunun kısalmasından gelir, kusurun daha erken görülmesinden değil.

## Bayrağın Açtığı Kod Yolları

Bayrak bir koşuldur ve her koşul kodu ikiye ayırır. Üç bayrak sekiz kod yolu açar. Aşağıdaki
hesap gerçekten koşar: fatura tutarı üç bayrağın her kombinasyonu için ayrı ayrı hesaplanır ve
o kombinasyon için ayrı yazılmış beklenen davranışla karşılaştırılır.

```js
// bayrak.mjs — uc bayragin actigi kod yollari sayilir; faturalama hesabi MODELDIR
// Bolgesel olcum agi kurgusu: sayac okumasindan fatura tutari uretilir.

const TABAN = 12.4;
const KADEME = [[10, 12.4], [25, 18.6], [Infinity, 27.9]];
const OKUMA = [
  { no: 'S-0431', m3: 8, gecikmeAy: 0 }, { no: 'S-0432', m3: 8, gecikmeAy: 2 },
  { no: 'S-0433', m3: 17, gecikmeAy: 0 }, { no: 'S-0434', m3: 17, gecikmeAy: 1 },
  { no: 'S-0435', m3: 34, gecikmeAy: 3 }, { no: 'S-0436', m3: 52, gecikmeAy: 0 },
];
const BAYRAK = ['kademe', 'gecikme', 'ozet'];
const kurus = (x) => Math.round(x * 100) / 100;

function kademeli(m3) {
  let kalan = m3, alt = 0, tutar = 0;
  for (const [ust, birim] of KADEME) {
    const dilim = Math.min(kalan, ust - alt);
    tutar += dilim * birim; kalan -= dilim; alt = ust;
    if (kalan <= 0) break;
  }
  return tutar;
}

// Uretimdeki kod: her bayrak bir dallanma noktasi.
function uretim(o, b) {
  let tutar = b.kademe ? kademeli(o.m3) : o.m3 * TABAN;
  const taban = o.m3 * TABAN;
  if (b.gecikme && o.gecikmeAy > 0) tutar += taban * 0.015 * o.gecikmeAy;
  const f = { tutar: kurus(tutar) };
  if (b.ozet) f.ozet = { m3: o.m3, gecikmeAy: o.gecikmeAy };
  return f;
}

// Her kombinasyonun beklenen davranisi ayri yazilir: faiz kendi tutari uzerinden isler.
function beklenen(o, b) {
  let tutar = b.kademe ? kademeli(o.m3) : o.m3 * TABAN;
  if (b.gecikme && o.gecikmeAy > 0) tutar += tutar * 0.015 * o.gecikmeAy;
  return kurus(tutar);
}

const yollar = [];
for (let m = 0; m < 2 ** BAYRAK.length; m += 1) {
  const b = Object.fromEntries(BAYRAK.map((ad, i) => [ad, Boolean(m & (1 << i))]));
  const sapan = OKUMA.filter((o) => uretim(o, b).tutar !== beklenen(o, b));
  yollar.push({ maske: BAYRAK.map((ad) => (b[ad] ? '1' : '0')).join(''), b, sapan });
}

// Sinama kumesi: uretimin bugunku hali ve her bayrak tek basina.
const SINANAN = new Set(['000', '100', '010', '001']);
console.log('yol   kademe gecikme ozet  sapan fatura  sinandi');
for (const y of yollar) {
  console.log(`${y.maske}  ${BAYRAK.map((a) => (y.b[a] ? 'acik  ' : 'kapali')).join(' ')}` +
    `  ${String(y.sapan.length).padEnd(13)} ${SINANAN.has(y.maske) ? 'evet' : 'hayir'}`);
}
const kusurlu = yollar.filter((y) => y.sapan.length > 0);
console.log('');
console.log(`toplam kod yolu            : ${yollar.length}`);
console.log(`sinanan yol                : ${SINANAN.size} (oran ${(SINANAN.size / yollar.length * 100).toFixed(0)} yuzde)`);
console.log(`sapan davranis ureten yol  : ${kusurlu.length} — ${kusurlu.map((y) => y.maske).join(', ')}`);
console.log(`bunlardan sinanani         : ${kusurlu.filter((y) => SINANAN.has(y.maske)).length}`);
console.log('');
console.log('kusurun gorundugu ilk yolda fatura basina fark');
for (const o of kusurlu[0].sapan) {
  const y = kusurlu[0];
  console.log(`  ${o.no} ${String(o.m3).padStart(3)} m3  ${o.gecikmeAy} ay gecikme` +
    `  uretim=${uretim(o, y.b).tutar}  beklenen=${beklenen(o, y.b)}`);
}
```

```
yol   kademe gecikme ozet  sapan fatura  sinandi
000  kapali kapali kapali  0             evet
100  acik   kapali kapali  0             evet
010  kapali acik   kapali  0             evet
110  acik   acik   kapali  2             hayir
001  kapali kapali acik    0             evet
101  acik   kapali acik    0             hayir
011  kapali acik   acik    0             hayir
111  acik   acik   acik    2             hayir

toplam kod yolu            : 8
sinanan yol                : 4 (oran 50 yuzde)
sapan davranis ureten yol  : 2 — 110, 111
bunlardan sinanani         : 0

kusurun gorundugu ilk yolda fatura basina fark
  S-0434  17 m3  1 ay gecikme  uretim=257.36  beklenen=258.01
  S-0435  34 m3  3 ay gecikme  uretim=673.07  beklenen=683.53
```

Kusur tek bir bayrakta değil, **iki bayrağın kesişiminde** duruyor: gecikme faizi kademeli
tutar yerine taban tutar üzerinden işliyor. Kademe kapalıyken iki değer eşit olduğu için hesap
doğru çıkıyor; kademe açıldığında sapıyor. Sınama kümesi her bayrağı tek başına denediği için
sekiz yolun dördünü hiç görmüyor ve kusurlu iki yolun ikisi de o dördün içinde.

Sapmanın büyüklüğü ayrıca kayda değer: fatura başına altmış beş kuruş ile on lira arasında.
Bu, bir hata mesajı üretmeyen, oran olarak yüzde birin altında kalan ve yalnız gecikmesi olan
abonelerde görünen bir sapmadır. Sekiz yolun kaçının sınandığı sorusu bu yüzden sorulur: bayrak
eklemek sınama yükümlülüğünü toplamaz, ikiyle çarpar.

## Kapının Üç Sayısı

Bayrak koşulu bir kapıdır ve öteki kapılar gibi üç sayıyla değerlendirilir. Birincisi tuttuğu.
Bayrak koşulunun tuttuğu kusur sayısı **sıfırdır**: koşul iki dalı da geçirir, hiçbir şeyi
sınamaz. Tuttuğu tek şey maruziyettir — yüz altmış yerine seksen dört fatura, yani yetmiş altı
faturalık fark. Bu farkın tamamı geri alma yolundan gelir ve bu kapının yalnız kendisinin
sağladığı şeydir: hat kapılarının hiçbiri geri alma birimini değiştiremez.

İkincisi kaçırdığı ve yanlış tuttuğu. Bayrak kapısı kaçırdığı kusuru kendisi üretmiştir:
sınanmayan dört yol, üç bayrak eklenmeden önce var olmayan yollardır. Yanlış tutmanın ölçüsü ise
kapalı bekleyen sağlam davranıştır — aşağıdaki defterde on iki haftalık dönemin sonunda hâlâ
kapalı duran, kusurla ilgisi olmayan, tamamlanmış ve dağıtılmış bir değişiklik vardır.

Üçüncüsü eklediği süre. Bu kapı öncü süreye dakika eklemez: kod yine tek yayında gider, hat
aşamaları değişmez. Eklediği şey **ertelenmiş turdur** — okuma noktalarının yazılması ve sonra
silinmesi. Erteleme bedava göründüğü için ödenmez ve borç olarak birikir. Kapının üçüncü sayısı
bu derste dakika değil, temizlenmemiş okuma noktası sayısıdır.

## Bayrak Borcu

Bayrağın maliyeti eklendiği anda değil, kaldırılmadığı sürece ödenir. On iki haftalık bir dönemin
defteri sayılır: hangi bayrak ne zaman eklendi, temizlendi mi, kaç noktada okunuyor.

```js
// borc.mjs — bir donemin bayrak defteri sayilir; defter MODELDIR
// [ad, eklendigi hafta, temizlendigi hafta (null: duruyor), okuma noktasi, bugunku deger]
const DONEM = 12;
const DEFTER = [
  ['kademeli-tarife', 1, 6, 3, 'acik'], ['gecikme-faizi', 2, null, 2, 'kapali'],
  ['fatura-ozeti', 2, 7, 1, 'acik'], ['is-emri-baglantisi', 3, null, 4, 'acik'],
  ['toplu-is-raporu', 4, null, 2, 'acik'], ['dogrulayici-ikinci-gecis', 5, 9, 2, 'acik'],
  ['okuma-yeniden-deneme', 7, null, 5, 'acik'], ['sozlesme-uyarisi', 8, null, 3, 'kapali'],
  ['ozet-yeni-alan', 10, null, 2, 'acik'],
];

const temiz = DEFTER.filter(([, , t]) => t !== null);
const kalan = DEFTER.filter(([, , t]) => t === null);
const nokta = kalan.reduce((t, [, , , n]) => t + n, 0);
const yasli = kalan.reduce((e, k) => (k[1] < e[1] ? k : e));
console.log(`donem                        : ${DONEM} hafta`);
console.log(`eklenen / temizlenen / kalan : ${DEFTER.length} / ${temiz.length} / ${kalan.length}`);
console.log(`temizlenenlerin ortalama omru: ` +
  `${(temiz.reduce((t, [, e, k]) => t + (k - e), 0) / temiz.length).toFixed(1)} hafta`);
console.log(`kalan bayraklarin actigi yol : ${2 ** kalan.length}`);
console.log(`bugun kosan yol              : 1 (kalanlarin degeri sabit)`);
console.log(`olu kod yolu                 : ${2 ** kalan.length - 1}`);
console.log(`her bayrak tek basina sinanirsa: ${kalan.length + 1} yol` +
  ` (yuzde ${((kalan.length + 1) / 2 ** kalan.length * 100).toFixed(0)})`);
console.log(`temizlenecek okuma noktasi   : ${nokta}`);
console.log(`acilmayi bekleyen kapali bayrak: ` +
  kalan.filter(([, , , , d]) => d === 'kapali').map(([a, e]) => `${a} (${DONEM - e} hafta)`).join(', '));
console.log(`en yasli temizlenmemis bayrak: ${yasli[0]} — ${DONEM - yasli[1]} hafta`);
```

```
donem                        : 12 hafta
eklenen / temizlenen / kalan : 9 / 3 / 6
temizlenenlerin ortalama omru: 4.7 hafta
kalan bayraklarin actigi yol : 64
bugun kosan yol              : 1 (kalanlarin degeri sabit)
olu kod yolu                 : 63
her bayrak tek basina sinanirsa: 7 yol (yuzde 11)
temizlenecek okuma noktasi   : 18
acilmayi bekleyen kapali bayrak: gecikme-faizi (10 hafta), sozlesme-uyarisi (4 hafta)
en yasli temizlenmemis bayrak: gecikme-faizi — 10 hafta
```

Altı bayrak kaldı ve altmış dört kod yolu açtı. Bugün bu yollardan yalnız biri koşuyor, çünkü
altı bayrağın da değeri sabit. Kalan altmış üçü ölü kod yoludur: hiçbiri çalışmıyor, hepsi
kodda duruyor ve her biri sınanabilir bir davranış olarak var sayılıyor. Sınama kümesi aynı
kalıpla — her bayrak tek başına — genişletilirse altmış dört yolun yedisini örter; oran yüzde
elliden yüzde on bire düşer. Bayrak sayısı doğrusal artarken kapsama üstel olarak seyrelir.

On sekiz okuma noktası, bu bayrakların temizlenmesi için silinecek koşul sayısıdır. Bu iş
ertelendikçe kod okunmaz hâle gelir, ama daha önemlisi, hangi dalın canlı olduğu kodun kendisinden
okunamaz olur. Temizlenen üç bayrağın ortalama ömrü dört buçuk haftaydı; kalanlardan biri on
haftadır duruyor. İki bayrak kapalı bekliyor: biri kusurlu, biri tamamlanmış ama hiç açılmamış.
İkincisi kapının yanlış tuttuğu değişikliktir — dört haftadır üretimde duran ve hiçbir aboneye
ulaşmayan bir davranış.

Kaldırılması gereken kapı burada görünür hâle gelir. `kademeli-tarife` altıncı haftada
temizlendi: bayrak açılmış, davranış kalıcı olmuş, koşul silinmiştir. Kapının kaldırılması
kapının kurulması kadar plana girer; girmediğinde defterdeki tek sayı büyür.

## Özet

- Bayrak geri alma birimini kodun tamamından tek davranışa indirdi: bayraksız düzende üretimden
  dört değişiklik çıktı ve üçü sağlamdı, bayraklı düzende çıkan tek şey kusurlu davranıştı.
- Geri alma turu ikiden bire, etkilenen fatura yüz altmıştan seksen dörde indi; farkın tamamı
  geri alma yolunun kısalmasından geldi, kusurun daha erken görülmesinden değil.
- Üç bayrak sekiz kod yolu açtı; her bayrağı tek başına sınayan küme dördünü kapsadı ve sapan
  davranış üreten iki yolun ikisi de kapsam dışında kaldı.
- Bayrak koşulu kusur tutmaz — tuttuğu şey maruziyettir; kaçırdığı yolları ise kendisi üretir.
- On iki haftada dokuz bayrak eklendi, üçü temizlendi; kalan altı bayrak altmış dört yol açtı,
  bunların altmış üçü ölü kod yolu olarak durdu ve on sekiz okuma noktası temizlenmeyi bekledi.

## Sonraki Adım

Bayrak kapatmak, geri alınabilecek şey bir davranışsa işe yarar. Kusur bir bayrağın arkasında
durmuyorsa — yapılandırma değişmişse, veri dönüştürülmüşse ya da değişiklik bayraklanmadan
yayınlanmışsa — geri dönüş yolu tek anahtar değil, sıralı bir adım listesidir. O listenin kaç
adım olduğu, her adımın kaç tur sürdüğü ve hangi adımdan sonra geri dönüşün kapandığı ayrı ayrı
ölçülür. Sonraki ders geri almayı bir düğme olarak değil, **plan olarak** ele alır ve planın
prova edilip edilmemesinin ilk koşumda kaç adıma mal olduğunu sayar.
