İçeriğe geç
academia.sh

Ders 07 / 12

Ortamlar

Geliştirme, sınama, hazırlık ve üretim arasındaki farkın nerede saklandığı sayılır: on boyutun kaçı üretimden ayrılıyor, kaçı ortam künyesinde yazıyor, hangi fark hangi hata sınıfını gizliyor ve bir halkayı atlamak kaç hata sınıfını üretime taşıyor.

İçindekiler

Önceki konu geri bildirim döngülerini kurdu ve bir olgunun hangi role kaç adımda ulaştığını saydı. O ölçümlerin hepsi tek bir sessiz varsayım taşıyordu: geliştiricinin makinesinde koşan yazılım ile gece yarısı üretimde koşan yazılım aynı yazılımdır. Varsayım doğru olsaydı, üretimde ilk kez görülen bir hatanın geliştirme makinesinde de görülmesi gerekirdi.

Fark bir yerde saklıdır ve adı konmadıkça ölçülmez. Bu ders farkın saklandığı ilk yeri ele alır: yazılımın koştuğu ortam. Ortam burada sınamanın yapıldığı yer değil, üretime giden zincirin bir halkasıdır; sorulan soru da her halkanın neyi görebildiğidir.

Konu boyunca tek bir kurgu sürer: bir belediyenin bölgesel ölçüm ağı. Yazılım su sayaçlarından okuma toplar, okumaları doğrular, faturaya çevirir ve saha ekiplerine iş emri açar. Bir gecelik toplu iş bütün günün okumalarını işler. Kurgudur; aşağıdaki sayılar da bu kurgunun modelinden gelir, ölçülmüş bir kurulumdan değil.

DK1. Ağı yazan ekip ile işleten ekip ayrıdır. Ağda üç ortam işletilir: geliştirme, sınama ve üretim. Dördüncü halka olan hazırlık ortamı kurulu değildir; bu dersin ölçtüğü şey tam olarak o halkanın ne kazandırdığıdır.

Zincirin Dört Halkası

Ortam, bir değişikliğin üretime giderken uğradığı duraktır. Dört durak birbirinden amaçla ayrılır, adla değil.

Geliştirme ortamı yazanın makinesidir. Tek süreç koşar, dış bağımlılıkların hepsi taklittir, veri elle üretilmiş birkaç yüz kayıttır. Amacı değişikliğin biçimini görmektir: kod derleniyor mu, işlev beklenen değeri döndürüyor mu.

Sınama ortamı değişikliği yazandan bağımsız çalıştırır. Otomatik sınamalar burada koşar, veri gerçek biçimlidir ama küçüktür, bağımlılıkların bir kısmı gerçektir. Amacı değişikliğin kendi başına doğru olup olmadığını yazanın makinesinden bağımsız doğrulamaktır.

Hazırlık ortamı üretime en yakın halkadır. Dış bağımlılıklar gerçektir, kaynak sınırları üretimin sınırlarıdır, sürümler üretimin sürümleridir. Amacı doğrulamak değil, üretime özgü hata sınıflarını üretime varmadan görmektir.

Üretim ortamı gerçek sayaç okumalarının işlendiği, gerçek faturaların üretildiği ve gerçek saha ekiplerine iş emri açılan yerdir. Buradaki bir hatanın bedeli yanlış faturadır.

Bu dört durağın hangisinin neyi görebildiği, o durağın üretime ne kadar benzediğine bağlıdır. Benzerliğin ölçüsünün adı ortam denkliği (environment parity), ölçülemez hâline gelmesinin adı ise yapılandırma sapmasıdır (configuration drift): halkalar zamanla birbirinden ayrılır ve ayrıldıkları yer kayda geçmez.

Denklik Neyle Ölçülür

Denkliğin sayılabilmesi için boyutların adlandırılması gerekir. Kurgudaki ağın ortam belgesi yedi boyut bildirir: iki paket sürümü, bir kaynak sınırı, bir eşzamanlılık ayarı, bir veri hacmi ve iki dış bağımlılığın gerçek mi taklit mi olduğu.

DK2. Yedi boyut ortam künyesinde yazılıdır ve iki ekip de bu belgeyi okuyabilir. DK3. Üç boyut daha vardır — saat dilimi, dosya sisteminin harf duyarlılığı, ağ gecikmesi — ve bunlar hiçbir belgede yazmaz; yalnız süreç koşarken ölçülebilir.

// olcum-agi/ortamlar.mjs — dort ortamin kunyesi ve kosum yoklamasi (model, kurgu veri)

// Ortam belgesinde yazan yedi boyut. Degerler bolgesel olcum agi kurgusuna aittir.
export const KUNYE = {
  gelistirme: { cozumleyiciSurumu: "3.2.1", kuralPaketiSurumu: "9.1.0", bellekMB: 512,
    esZamanliIsci: 1, sayacSayisi: 120, faturaKapisi: "taklit", isEmriKuyrugu: "taklit" },
  sinama: { cozumleyiciSurumu: "3.2.1", kuralPaketiSurumu: "9.1.0", bellekMB: 1024,
    esZamanliIsci: 2, sayacSayisi: 5000, faturaKapisi: "taklit", isEmriKuyrugu: "gercek" },
  hazirlik: { cozumleyiciSurumu: "3.4.0", kuralPaketiSurumu: "9.1.0", bellekMB: 4096,
    esZamanliIsci: 8, sayacSayisi: 180000, faturaKapisi: "gercek", isEmriKuyrugu: "gercek" },
  uretim: { cozumleyiciSurumu: "3.4.0", kuralPaketiSurumu: "9.1.0", bellekMB: 4096,
    esZamanliIsci: 8, sayacSayisi: 1240000, faturaKapisi: "gercek", isEmriKuyrugu: "gercek" },
};

// Kunyede yazmayan, yalniz surecin icinden olculebilen uc boyut.
export const YOKLAMA = {
  gelistirme: { saatDilimi: "+03:00", harfDuyarliDosyaSistemi: false, agGecikmeMs: 0 },
  sinama: { saatDilimi: "+03:00", harfDuyarliDosyaSistemi: true, agGecikmeMs: 2 },
  hazirlik: { saatDilimi: "+00:00", harfDuyarliDosyaSistemi: true, agGecikmeMs: 11 },
  uretim: { saatDilimi: "+00:00", harfDuyarliDosyaSistemi: true, agGecikmeMs: 34 },
};

// Her boyutun, uretimden farkli oldugunda gizledigi hata sinifi.
export const GIZLENEN = {
  cozumleyiciSurumu: "cozumleme sapmasi", kuralPaketiSurumu: "tutar hatasi",
  bellekMB: "bellek tukenmesi", esZamanliIsci: "yaris durumu",
  sayacSayisi: "olcek cokusu", faturaKapisi: "sozlesme sapmasi",
  isEmriKuyrugu: "sozlesme sapmasi", saatDilimi: "gun siniri kaymasi",
  harfDuyarliDosyaSistemi: "yol cozumleme hatasi", agGecikmeMs: "zaman asimi",
};

export const BILDIRILEN = Object.keys(KUNYE.uretim);
export const YOKLANAN = Object.keys(YOKLAMA.uretim);
export const BOYUTLAR = [...BILDIRILEN, ...YOKLANAN];
export const tam = (ortam) => ({ ...KUNYE[ortam], ...YOKLAMA[ortam] });
export const farklar = (ortam) =>
  BOYUTLAR.filter((b) => tam(ortam)[b] !== tam("uretim")[b]);

Ölçüm her ortamı üretimle karşılaştırır ve farkı boyut boyut yazar.

// olcum-agi/denklik.mjs — ortam denkligini boyut boyut sayar
import { BOYUTLAR, YOKLANAN, GIZLENEN, tam, farklar } from "./ortamlar.mjs";

const HALKA = ["gelistirme", "sinama", "hazirlik"];
const yildiz = (b) => (YOKLANAN.includes(b) ? b + " *" : b);

console.log("uretime gore denklik (* = kunyede yazmaz, yalniz kosumda gorunur)");
console.log("boyut".padEnd(26) + HALKA.map((o) => o.padEnd(11)).join("") + "gizledigi hata sinifi");
for (const b of BOYUTLAR) {
  const hucre = HALKA.map((o) => (tam(o)[b] === tam("uretim")[b] ? "ayni" : "FARK").padEnd(11));
  console.log(yildiz(b).padEnd(26) + hucre.join("") + GIZLENEN[b]);
}

const sayim = HALKA.map((o) => farklar(o));
const toplam = sayim.flat().length;
const kosumda = sayim.flat().filter((b) => YOKLANAN.includes(b)).length;
console.log("\nfark sayisi: " + HALKA.map((o, i) => `${o} ${sayim[i].length}/${BOYUTLAR.length}`).join(", "));
console.log(`toplam ${toplam} fark; kunyede yazan ${toplam - kosumda}, yalniz kosumda goruneni ${kosumda}`);
console.log("hazirligin uretimden ayrildigi boyut: " + farklar("hazirlik").join(", "));
console.log("hicbir ortamda uretime denk olmayan boyut: " +
  BOYUTLAR.filter((b) => HALKA.every((o) => tam(o)[b] !== tam("uretim")[b])).join(", "));
uretime gore denklik (* = kunyede yazmaz, yalniz kosumda gorunur)
boyut                     gelistirme sinama     hazirlik   gizledigi hata sinifi
cozumleyiciSurumu         FARK       FARK       ayni       cozumleme sapmasi
kuralPaketiSurumu         ayni       ayni       ayni       tutar hatasi
bellekMB                  FARK       FARK       ayni       bellek tukenmesi
esZamanliIsci             FARK       FARK       ayni       yaris durumu
sayacSayisi               FARK       FARK       FARK       olcek cokusu
faturaKapisi              FARK       FARK       ayni       sozlesme sapmasi
isEmriKuyrugu             FARK       ayni       ayni       sozlesme sapmasi
saatDilimi *              FARK       FARK       ayni       gun siniri kaymasi
harfDuyarliDosyaSistemi * FARK       ayni       ayni       yol cozumleme hatasi
agGecikmeMs *             FARK       FARK       FARK       zaman asimi

fark sayisi: gelistirme 9/10, sinama 7/10, hazirlik 2/10
toplam 18 fark; kunyede yazan 12, yalniz kosumda goruneni 6
hazirligin uretimden ayrildigi boyut: sayacSayisi, agGecikmeMs
hicbir ortamda uretime denk olmayan boyut: sayacSayisi, agGecikmeMs

Üç ortam ile üretim arasında 18 fark vardır. Bunların 12’si künyede yazar: bir okuyan için görünür durumdadır, tartışılabilir ve kapatılabilir. Kalan 6’sı hiçbir belgede yazmaz; ancak süreç o ortamda koşarken görülebilir. Bu ayrım dersin ölçü eksenidir: bildirilmiş fark bir karar konusudur, yalnız koşumda görünen fark ise bir sürprizdir.

Bu 18 farkın hiçbiri bir kararla konmuş değildir. Ortamlar farklı tarihlerde kurulmuş, farklı zamanlarda yükseltilmiş ve bakımları ayrı ayrı yapılmıştır: üretimin paket sürümü yükseltilince geliştirme makinesi geride kalmış, sınamaya gerçek iş emri kuyruğu bağlanınca fatura kapısı taklit bırakılmıştır. Yapılandırma sapmasının anlamı budur — fark, kimsenin karar vermediği yerde birikir. Sapmanın ölçülebilir olması için de tek koşul vardır: boyutların adlandırılmış ve künyenin okunabilir olması.

Gradyan da okunabilir: geliştirme üretimden on boyutun dokuzunda ayrılır, sınama yedisinde, hazırlık ikisinde. Halkalar üretime yaklaştıkça fark sayısı düşer — zincirin sıralı olmasının nedeni budur. Ayrıca iki boyut — veri hacmi ve ağ gecikmesi — hiçbir ortamda üretime denk değildir. Bir buçuk milyon sayaç ile yüz yirmi sayaç arasındaki farkı taşımayan hiçbir halka yoktur.

Farkın Gizlediği Hata Sınıfı

Fark sayısı tek başına karar taşımaz; farkın neyi gizlediği taşır. Aşağıdaki model her boyuta bir kusur bağlar ve kusurun zincirin hangi halkasında ilk kez görüneceğini hesaplar.

DK4. Model kuralı tektir: bir kusur, bağlı olduğu boyutta ortam üretimle aynı değeri taşıyorsa görünür, taşımıyorsa görünmez. DK5. Her boyut tek bir hata sınıfı taşır; on boyut on kusur demektir. DK6. Zincir sırayla geçilir ve kusur ilk görüldüğü halkada durur.

// olcum-agi/zincir.mjs — bir kusurun zincirin hangi halkasinda gorundugunu sayar
import { GIZLENEN, tam } from "./ortamlar.mjs";

// Model kurali: kusur, bagli oldugu boyutta ortam uretimle ayni degeri tasiyorsa gorunur.
const KUSURLAR = [
  ["bos okuma alani cozumlenemiyor", "cozumleyiciSurumu"],
  ["yeni tarife dilimi yanlis yuvarlaniyor", "kuralPaketiSurumu"],
  ["toplu is butun okumalari bellege aliyor", "bellekMB"],
  ["ayni sayac icin iki fatura satiri", "esZamanliIsci"],
  ["dogrulama sorgusu sayac sayisinin karesinde", "sayacSayisi"],
  ["fatura kapisinin ret kodu islenmiyor", "faturaKapisi"],
  ["is emri kuyruguna ayni emir iki kez", "isEmriKuyrugu"],
  ["gecelik is gun sinirini yerel saatle kesiyor", "saatDilimi"],
  ["tarife dosyasi buyuk harfle araniyor", "harfDuyarliDosyaSistemi"],
  ["toplayici yaniti zaman asimini asiyor", "agGecikmeMs"],
];

const DORT = ["gelistirme", "sinama", "hazirlik", "uretim"];
const UC = ["gelistirme", "sinama", "uretim"];
const ilkGoren = (zincir, boyut) =>
  zincir.find((o) => tam(o)[boyut] === tam("uretim")[boyut]);

console.log("kusur".padEnd(45) + "dort halka".padEnd(12) + "uc halka");
for (const [ad, boyut] of KUSURLAR) {
  console.log(ad.padEnd(45) + ilkGoren(DORT, boyut).padEnd(12) + ilkGoren(UC, boyut));
}

const say = (zincir) => {
  const d = Object.fromEntries(zincir.map((o) => [o, 0]));
  for (const [, boyut] of KUSURLAR) d[ilkGoren(zincir, boyut)] += 1;
  return zincir.map((o) => `${o} ${d[o]}`).join(", ");
};
console.log("\ndort halkali zincir: " + say(DORT));
console.log("uc halkali zincir  : " + say(UC));

const kacan = (zincir) => KUSURLAR.filter(([, b]) => ilkGoren(zincir, b) === "uretim");
const dortKacan = kacan(DORT).map(([, b]) => GIZLENEN[b]);
const ucKacan = kacan(UC).map(([, b]) => GIZLENEN[b]);
const ek = ucKacan.filter((s) => !dortKacan.includes(s));
console.log(`hazirlik dururken de uretime kacan ${dortKacan.length} sinif: ` + dortKacan.join(", "));
console.log(`hazirlik atlandiginda kacan ${ucKacan.length} sinif; eklenen ${ek.length}:`);
for (let i = 0; i < ek.length; i += 3) console.log("  " + ek.slice(i, i + 3).join(", "));

console.log("\nzincir uzunlugu tarandi (halkalar sirayla eklenir):");
let onceki = 0;
for (let n = 0; n <= 3; n++) {
  const z = [...DORT.slice(0, n), "uretim"];
  const yakalanan = KUSURLAR.filter(([, b]) => ilkGoren(z, b) !== "uretim").length;
  console.log(`${n} halka + uretim`.padEnd(20) + `uretimden once yakalanan ${yakalanan}` +
    `  (son halkanin katkisi ${yakalanan - onceki})`);
  onceki = yakalanan;
}
kusur                                        dort halka  uc halka
bos okuma alani cozumlenemiyor               hazirlik    uretim
yeni tarife dilimi yanlis yuvarlaniyor       gelistirme  gelistirme
toplu is butun okumalari bellege aliyor      hazirlik    uretim
ayni sayac icin iki fatura satiri            hazirlik    uretim
dogrulama sorgusu sayac sayisinin karesinde  uretim      uretim
fatura kapisinin ret kodu islenmiyor         hazirlik    uretim
is emri kuyruguna ayni emir iki kez          sinama      sinama
gecelik is gun sinirini yerel saatle kesiyor hazirlik    uretim
tarife dosyasi buyuk harfle araniyor         sinama      sinama
toplayici yaniti zaman asimini asiyor        uretim      uretim

dort halkali zincir: gelistirme 1, sinama 2, hazirlik 5, uretim 2
uc halkali zincir  : gelistirme 1, sinama 2, uretim 7
hazirlik dururken de uretime kacan 2 sinif: olcek cokusu, zaman asimi
hazirlik atlandiginda kacan 7 sinif; eklenen 5:
  cozumleme sapmasi, bellek tukenmesi, yaris durumu
  sozlesme sapmasi, gun siniri kaymasi

zincir uzunlugu tarandi (halkalar sirayla eklenir):
0 halka + uretim    uretimden once yakalanan 0  (son halkanin katkisi 0)
1 halka + uretim    uretimden once yakalanan 1  (son halkanin katkisi 1)
2 halka + uretim    uretimden once yakalanan 3  (son halkanin katkisi 2)
3 halka + uretim    uretimden once yakalanan 8  (son halkanin katkisi 5)

Tablo bir kuralı görünür kılar: bir ortam, yalnız üretimle aynı olduğu boyutlardaki kusurları görebilir. Geliştirme ortamı on kusurdan yalnız birini yakalar, çünkü üretimle yalnız tek bir boyutta — kural paketi sürümünde — aynıdır. Sınama iki kusur yakalar; ikisi de sınamanın üretimle aynı olduğu boyutlara bağlıdır: gerçek iş emri kuyruğu ve harf duyarlı dosya sistemi.

Ters yönde okumak daha çok şey söyler: bir ortamın yakalayamadığı hata sınıflarının listesi, o ortamın üretimden ayrıldığı boyutların listesidir. Hazırlık ortamı iki boyutta ayrılıyordu; hazırlık dururken üretime kaçan iki hata sınıfı da tam olarak o iki boyuta bağlı olanlardır. Bu, modelin bir çıkarımı değil, tanımının sonucudur — ama tanımı sayıya çevirdiği için ortam tartışmasını fikirden çıkarır: “hazırlık ortamına gerek var mı” sorusunun yerine “hangi boyutlarda denklik satın alıyoruz” sorusu geçer.

Çıktının son bölümü zincir uzunluğunu tarar: halkalar sırayla eklendiğinde üretimden önce yakalanan sınıf sayısı 0, 1, 3 ve 8 olur. Halka başına katkı eşit değildir — birinci halka bir sınıf, ikincisi iki, üçüncüsü beş sınıf ekler. Sıralama bunun nedenini de verir: her halka bir öncekinin göremediği boyutları kapatır ve üretime en yakın halka en çok boyutu kapatan halkadır. Zincirin başına yeni bir ortam eklemek katkının küçük olduğu yere yatırım yapmaktır; kapatılan boyut sayısı, halkanın adından değil künyesinden okunur.

Halkayı Atlamanın Bedeli

Kurgudaki ağ hazırlık ortamını işletmiyordu. Modelin iki koşumu bu kararın bedelini sayar.

Dört halkalı zincirde üretime iki hata sınıfı kaçar: ölçek çöküşü ve zaman aşımı. Üç halkalı zincirde yediye çıkar. Hazırlık halkası beş hata sınıfını üretimin önünde yakalar: çözümleme sapması, bellek tükenmesi, yarış durumu, sözleşme sapması ve gün sınırı kayması. Bu beşi, ağın hazırlığı kurmadığı sürece ilk kez gerçek fatura üretilirken görünen sınıflardır.

Atlamanın kazandırdığı da sayılabilir: zincir dört duraktan üçe iner, yani bir yayım daha az bekleme ve bir devir daha az el değiştirme demektir. Bu kazanç öncü süreye yazılır; bedel ise geri dönüş oranına ve kurtarma süresine yazılır, çünkü kaçan beş sınıfın her biri üretimde görüldüğünde geri alınacak bir değişiklik ve onarılacak bir kesinti üretir. Tek ölçüte bakan bir cümle burada karar taşımaz: hızlanma bir yerden alınıp başka bir yere konur.

Kaçan iki sınıf ise hazırlık kurulsa bile yerinde kalır, çünkü hiçbir halka bir buçuk milyon sayaçlık veri hacmini ve otuz dört milisaniyelik ağ gecikmesini taşımaz. Bu iki boyutu kapatmanın yolu vardır — üretim ölçeğinde biçimlendirilmiş veri kümesi ve yapay gecikme eklenmesi — ve her ikisinin de bir bedeli vardır: ortamın kurulum maliyeti ve koşum süresi. Ölçüm bu tartışmayı da somutlaştırır: kapatılacak boyut iki tanedir, ikisinin adı bellidir ve kapatıldığında hangi hata sınıfının önünün alınacağı yazılıdır.

Son olarak künye ile koşum arasındaki altı farkın anlamı buradadır. Künyede yazan on iki fark bir toplantıda gündeme gelebilir; yazmayan altısı gelemez. Saat diliminin geliştirme ile üretim arasında ayrılması, gecelik toplu işin gün sınırını yanlış yerden kesmesi olarak ortaya çıkar ve nedeninin ortam farkı olduğu, hata bulunana kadar kimsenin aklına gelmez. Ortam künyesinin kapsamını genişletmek — koşumda ölçülen üç boyutu da bildirmek — bu altı farkın altısını da tartışılabilir hâle getirir.

Özet

  • Ortam, üretime giden zincirin bir halkasıdır; dört halka amaçla ayrılır ve her halka yalnız üretimle aynı olduğu boyutlardaki kusurları görebilir.
  • Ortam denkliği boyut boyut sayılır. Kurgu modelinde on boyut vardır; üç ortam ile üretim arasında 18 fark ölçülmüştür: geliştirme 9, sınama 7, hazırlık 2.
  • Bu 18 farkın 12’si ortam künyesinde bildirilmiştir, 6’sı yalnız süreç koşarken görünür; bildirilmemiş fark tartışılamadığı için karar konusu olamaz.
  • Her farkın gizlediği bir hata sınıfı vardır ve bir ortamın yakalayamadığı sınıfların listesi, o ortamın üretimden ayrıldığı boyutların listesine eşittir.
  • Hazırlık halkası beş hata sınıfını üretimin önünde yakalar; atlanması bu beşini üretime taşır. Veri hacmi ve ağ gecikmesi hiçbir halkada denk olmadığı için iki sınıf her koşulda üretime kalır.

Sonraki Adım

Bu dersin zinciri bir şeyi varsaydı: halkalar arasında yolculuk eden nesne hep aynı nesnedir. Oysa ortam künyeleri bunu doğrulamıyor — her halkanın kendi paket sürümleri, kendi dosya yolları ve kendi ortam değişkenleri var. Değişiklik her durakta kaynaktan yeniden derleniyorsa zincirde dolaşan tek bir nesne değil, dört ayrı nesne vardır ve hangisinin hangisiyle aynı olduğu ölçülmemiştir. Sonraki ders bu nesneyi adlandırır ve ölçer: aynı kaynaktan iki kez üretilen çıktı gerçekten aynı mı, değilse farkı hangi kaynaklar sokuyor ve ortam başına yeniden derleme kaç ayrı ikili doğuruyor?

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat