Ders 01 / 27
Kod Olarak Altyapı Nedir
Aynı hazırlık ortamı iki kez kurulur — bir düzyazı talepten elle, bir kayıttan — ve iki kurulum kalem kalem karşılaştırılır. Bir çeyreklik değişikliklerde kim, ne zaman ve ne değiştirdi sorusunun kaç kez yanıtlandığı, kaydın kapsamadığı kalem sayısı ve kayda bağlamanın satır ve ek adım olarak bedeli sayılır.
İçindekiler
Bir önceki kurs uygulamanın üretime çıkış yolunu depoya bağladı: dal birleşince hat koşuyor, kapılar geçiliyor, dağıtım kendiliğinden ilerliyor. Uygulamanın yolu baştan sona yazılı. Altında durduğu makineler, kuyruk, veri deposu ve ağ ise başka bir yolla kuruluyor — bir talep açılıyor, biri o talebi okuyup ortamı kuruyor, ve kurulumun sonucu yalnız ortamın kendisinde duruyor.
Kod olarak altyapı, altyapının okunabilir bir kayda bağlanmasıdır: ortamın ne olması gerektiği bir dosyada yazılıdır, ortam o dosyadan kurulur. Bu kursun ölçü birimi kayıttır ve her ders üç şeyi sayar — kaydın söylediği ile gerçeğin farkı, kaydın kapsamı, ve kaydın bedeli. Bu ders ilkini kurar: aynı ortam iki kez kurulur, bir düzyazı talepten elle ve bir kayıttan, sonra kalem kalem karşılaştırılır. Ardından bir çeyreklik değişiklikte “kim, ne zaman, ne değiştirdi” sorusunun kaç kez yanıtlandığı, kaydın kapsamadığı kalem sayısı ve kayda bağlamanın satır ve adım olarak bedeli ölçülür.
Ölçüm bölgesel ölçüm ağı üzerindedir: su sayacı okumalarını toplayan, doğrulayan, faturaya
çeviren ve saha iş emri açan kurgu yazılım. Üç ortamı vardır; burada yalnız hazırlık ortamı
kurulur. Altyapı gerçekten sağlanmaz — kaynaklar ve kurulumlar node ile modellenir; modelin
girdisi olan kayıt ve talep dosyaları gerçekten diske yazılır.
AT1. Hazırlık ortamı altı kaynakla temsil edilir — bir ağ, iki makine grubu, bir kuyruk, bir veri deposu, bir nesne deposu. Kalem bir kaynağın bir niteliğidir; kayıtta yirmi kalem yazılıdır. AT2. Kurulum talebi düzyazıdır ve on bir maddenin yedisi sayı vermez. El bir modeldir, yorumu önceden yazılıdır; rastgelelik yoktur. AT3. Sağlayıcı varsayılanı beş kalemdir: kayıtta yazmayan, ortamda her hâlükârda oluşan ayarlar. İki kurulumda da aynı doğar. AT4. Bir çeyrekte on dört değişiklik olur; her değişiklik üç soru sorar — kim, ne zaman, ne değiştirdi. Her değişikliğin yolu önceden yazılıdır. AT5. Kayıt üzerinden geçen değişiklik üç soruyu da yanıtlar; bir iş kaydına düşen değişiklik ikisini yanıtlar (ne değiştiğini yazmaz); izsiz değişiklik hiçbirini. AT6. Kayıt yolunun değişiklik başına üç ek adımı vardır: kaydı yaz, gözden geçirt, planı oku.
Aynı Ortam, İki Tarif
#!/usr/bin/env bash # Ayni ortamin iki tarifi: kayit (yapilandirma dili) ve duzyazi kurulum talebi. set -e cat > kayit.alt <<'SON' # Yapilandirma dilimizin bicimi: kaynak <tur> "<ad>" { <anahtar> = <deger> } # Deger sayi, "dize" ya da dogru/yanlis olur; # ile baslayan satir yorumdur. kaynak ag "olcum-agi" { blok = "10.40.0.0/16" ozel = dogru bolge = "kuzey" } kaynak makine "toplayici" { sayi = 3 boyut = "orta" disk_gb = 40 imaj = "taban-7" } kaynak makine "dogrulayici" { sayi = 2 boyut = "kucuk" disk_gb = 20 imaj = "taban-7" } kaynak kuyruk "okuma-kuyrugu" { saklama_saat = 72 bolum = 6 olu_mektup = dogru } kaynak veri_deposu "olcum-deposu" { boyut_gb = 200 yedek_gun = 14 surum = "5.2" } kaynak nesne_deposu "arsiv" { sinif = "seyrek" surumleme = dogru yasam_gun = 365 } SON cat > talep.txt <<'SON' hazirlik ortami kurulum talebi 1. olcum agini ozel olarak ac, adres blogu 10.40.0.0/16, kuzey bolgesi 2. toplayici makinelerden yeterli sayida ac, boyut orta, imaj taban-7 3. toplayici diski olcum hacmine gore ver 4. dogrulayici makinelerden iki tane, boyut kucuk, disk 20 GB, imaj taban-7 5. okuma kuyrugunu ac, saklama suresi uretime yakin olsun, olu mektup acik 6. kuyruk bolum sayisini isci sayisina gore ayarla 7. olcum deposunu 200 GB ac, surum 5.2 8. deponun yedek penceresini kurumsal olcute gore ayarla 9. arsiv icin nesne deposu ac, surumleme acik 10. arsiv saklama sinifini maliyete gore sec 11. arsiv yasam dongusu gunu icin makul bir deger yaz SON
Yapılandırma dili burada kendi küçük biçimimizle tanımlanır: bir kaynak satırı bir türü, bir adı
ve süslü parantez içinde anahtar-değer çiftlerini taşır. Altı satır yirmi kalemi sayar ve her kalem
tek bir değere bağlıdır — okuyan iki kişi aynı şeyi anlar. Talep aynı ortamı hedefler ama yedi
maddesi sayı yerine ölçüt verir: “yeterli sayıda”, “ölçüm hacmine göre”, “üretime yakın”, “kurumsal
ölçüte göre”, “maliyete göre”, “makul bir değer”. Bu yedi nokta talebin yazılmamış kısmıdır ve
onu kuran kişi doldurur.
// kur.mjs — kaydi ayristirir ve ayni ortami iki yoldan kurar: kayittan ve elle. Ikisi de modeldir. import { readFileSync } from "node:fs"; const BLOK = /^kaynak\s+(\w+)\s+"([\w-]+)"\s*\{(.*)\}$/; // dilin tek satirlik bicimi export const kaydiOku = (metin) => { const k = new Map(); for (const satir of metin.split("\n")) { const m = BLOK.exec(satir.trim()); // yorum ve bos satir atlanir if (m) for (const x of m[3].matchAll(/(\w+)\s*=\s*("[^"]*"|[\w./-]+)/g)) k.set(`${m[1]}.${m[2]}.${x[1]}`, x[2].replaceAll('"', "")); } return k; }; export const kayit = kaydiOku(readFileSync("kayit.alt", "utf8")); // Saglayici varsayilani: kayitta yazmayan, ortamda her halukarda olusan kalemler. const varsayilan = new Map([["ag.olcum-agi.cikis_yolu", "acik"], ["makine.toplayici.erisim_kurali", "yonetim-portu-acik"], ["kuyruk.okuma-kuyrugu.sifreleme", "saglayici-anahtari"], ["veri_deposu.olcum-deposu.bakim_penceresi", "pazar-03:00"], ["nesne_deposu.arsiv.erisim_kurali", "hesap-ici"]]); // Elin onceden yazili yorumu: talebin sayi vermedigi yedi nokta (2, 3, 5, 6, 8, 10, 11). const elinYorumu = new Map([["makine.toplayici.sayi", "2"], ["makine.toplayici.disk_gb", "40"], ["kuyruk.okuma-kuyrugu.saklama_saat", "24"], ["kuyruk.okuma-kuyrugu.bolum", "6"], ["veri_deposu.olcum-deposu.yedek_gun", "7"], ["nesne_deposu.arsiv.sinif", "sik"], ["nesne_deposu.arsiv.yasam_gun", "90"]]); const elinAtladigi = ["nesne_deposu.arsiv.surumleme"]; // talepte yazili, uygulamada atlandi const elinEkledigi = new Map([["ag.olcum-agi.erisim_kurali", "ofis-blogu"], ["makine.toplayici.ek_disk", "bagli"], ["makine.dogrulayici.ad_kaydi", "dogrulayici.ic"]]); export const kayittanKur = () => new Map([...kayit, ...varsayilan]); export const elleKur = () => { const o = new Map([...kayit, ...elinYorumu, ...varsayilan, ...elinEkledigi]); for (const a of elinAtladigi) o.delete(a); return o; }; export const yorumNoktasi = elinYorumu.size, kayitDisi = varsayilan.size;
Kalem Kalem Fark
// fark.mjs — iki kurulumu kalem kalem karsilastirir; hicbir sey duzeltmez. import { kayit, kayittanKur, elleKur, yorumNoktasi, kayitDisi } from "./kur.mjs"; const a = kayittanKur(), b = elleKur(); const tum = [...new Set([...a.keys(), ...b.keys()])].sort(); const fark = tum.filter((k) => a.get(k) !== b.get(k)).map((k) => ({ k, tur: !b.has(k) ? "eksik" : !a.has(k) ? "fazla" : "ayrik" })); const say = (t) => fark.filter((f) => f.tur === t).length; console.log(`kalem kayittan ${a.size} elle ${b.size} birlesim ${tum.length}`); console.log(`fark ${fark.length} kalem (ayrik ${say("ayrik")}, eksik ${say("eksik")},` + ` fazla ${say("fazla")})`); for (const f of fark) console.log(` ${f.tur.padEnd(6)} ${f.k.padEnd(38)} ${(a.get(f.k) ?? "-").padEnd(20)}` + ` ${b.get(f.k) ?? "-"}`); console.log(`kayittaki kalem ${kayit.size} talebin sayi vermedigi nokta ${yorumNoktasi}` + ` bu noktalarin ayrildigi ${fark.filter((f) => f.tur === "ayrik").length}`); console.log(`kaydin kapsamadigi kalem ${kayitDisi} iki kurulumda da ayni,` + ` hicbirinde yazili degil`);
kalem kayittan 25 elle 27 birlesim 28 fark 9 kalem (ayrik 5, eksik 1, fazla 3) fazla ag.olcum-agi.erisim_kurali - ofis-blogu ayrik kuyruk.okuma-kuyrugu.saklama_saat 72 24 fazla makine.dogrulayici.ad_kaydi - dogrulayici.ic fazla makine.toplayici.ek_disk - bagli ayrik makine.toplayici.sayi 3 2 ayrik nesne_deposu.arsiv.sinif seyrek sik eksik nesne_deposu.arsiv.surumleme dogru - ayrik nesne_deposu.arsiv.yasam_gun 365 90 ayrik veri_deposu.olcum-deposu.yedek_gun 14 7 kayittaki kalem 20 talebin sayi vermedigi nokta 7 bu noktalarin ayrildigi 5 kaydin kapsamadigi kalem 5 iki kurulumda da ayni, hicbirinde yazili degil
Aynı ortamın iki kurulumu dokuz kalemde ayrıldı ve fark üç ayrı türden geliyor. Ayrık beş kalem, talebin sayı vermediği yedi noktanın beşidir: kalan ikisi elin yorumu kayıtla aynı değere düştüğü için görünmez. Bu ikisi bir kazanç değil, bir tesadüftür — yorum noktası hâlâ yedidir, yalnız beşi bu koşumda ayrıldı. Eksik bir kalem talepte açıkça yazılıydı ve uygulanmadı; düzyazı bir listede atlanan madde hiçbir yerde iz bırakmaz. Fazla üç kalem ise talepte hiç geçmiyor: bir erişim kuralı, bir ek disk ve bir ad kaydı. Bunlar ortamı kuran kişinin rutininden geliyor ve hiçbir tarifte yazılı değil — kurulum bittiğinde varlar, ama neden var oldukları yalnız bir kişinin belleğinde.
Farkın yönü de anlamlıdır. Ayrık beş kalemin dördünde elin değeri kayıttakinden küçüktür — iki toplayıcı yerine üç, yetmiş iki saat yerine yirmi dört, on dört gün yerine yedi, üç yüz altmış beş gün yerine doksan. Ölçüt vermeyen bir talep okunduğunda seçilen değer, o anda görünen yükü karşılar; kaydın taşıdığı değer ise bir kez kararlaştırılmış olanı taşır. İki kurulum arasındaki fark bu yüzden bir hata listesi değil, iki ayrı karar anının listesidir.
Son satır bu dersin ölçü ekseninin ikinci yarısıdır. Kaydın kapsamadığı beş kalem her iki kurulumda da aynıdır, çünkü ikisini de sağlayıcı doğuruyor: çıkış yolu, yönetim portu kuralı, şifreleme anahtarı, bakım penceresi, hesap içi erişim kuralı. Kayıt bunlar hakkında bir şey söylemediği için bir karşılaştırma bunları hiçbir zaman fark olarak göstermez. Kaydı yazmak farkı sıfırlamaz; farkı kaydın kapsamı kadar görünür kılar.
Kim, Ne Zaman, Ne Değiştirdi
// izle.mjs — bir donemdeki degisiklikler iki ortamda ne kadar izlenebiliyor. Model. import { kayit } from "./kur.mjs"; // Bir ceyrekteki on dort degisiklik; onceden yazilidir, rastgelelik yoktur. const D = [["makine.toplayici.sayi", "kayit"], ["makine.toplayici.boyut", "kayit"], ["kuyruk.okuma-kuyrugu.bolum", "kayit"], ["veri_deposu.olcum-deposu.boyut_gb", "kayit"], ["makine.toplayici.erisim_kurali", "elle"], ["nesne_deposu.arsiv.yasam_gun", "kayit"], ["ag.olcum-agi.blok", "kayit"], ["makine.dogrulayici.sayi", "kayit"], ["kuyruk.okuma-kuyrugu.saklama_saat", "elle"], ["veri_deposu.olcum-deposu.yedek_gun", "kayit"], ["makine.dogrulayici.imaj", "kayit"], ["nesne_deposu.arsiv.sinif", "kayit"], ["ag.olcum-agi.cikis_yolu", "elle"], ["makine.toplayici.disk_gb", "kayit"]]; const isKaydiOlan = [0, 3, 7, 10]; // elle kurulan ortamda bilet acilan dortu // Kayit uzerinden gecen degisiklik uc soruyu da yanitlar; is kaydi ikisini (ne degistigini yazmaz). const yanit = { kayit: 3, bilet: 2, izsiz: 0 }; const A = D.map(([, y]) => (y === "kayit" ? "kayit" : "izsiz")); const B = D.map((_, i) => (isKaydiOlan.includes(i) ? "bilet" : "izsiz")); const topla = (x) => x.reduce((t, s) => t + yanit[s], 0); const oran = (n) => (100 * n / (D.length * 3)).toFixed(1); console.log(`degisiklik ${D.length} soru ${D.length * 3} (kim / ne zaman / ne degisti)`); for (const [ad, x] of [["kayittan kurulan ortam", A], ["elle kurulan ortam", B]]) console.log(` ${ad.padEnd(22)}: yanitlanan ${topla(x)}/${D.length * 3}` + ` (%${oran(topla(x))}) izsiz degisiklik ${x.filter((s) => s === "izsiz").length}`); const elleGecen = D.filter(([, y]) => y === "elle").map(([k]) => k); console.log(`kayittan kurulan ortamda kaydi atlayan ${elleGecen.length} degisiklik:`); for (const k of elleGecen) console.log(` ${k.padEnd(38)} ${kayit.has(k) ? "kayitta var -> sapma olarak gorunur" : "kayitta yok -> hicbir karsilastirmada cikmaz"}`);
degisiklik 14 soru 42 (kim / ne zaman / ne degisti) kayittan kurulan ortam: yanitlanan 33/42 (%78.6) izsiz degisiklik 3 elle kurulan ortam : yanitlanan 8/42 (%19.0) izsiz degisiklik 10 kayittan kurulan ortamda kaydi atlayan 3 degisiklik: makine.toplayici.erisim_kurali kayitta yok -> hicbir karsilastirmada cikmaz kuyruk.okuma-kuyrugu.saklama_saat kayitta var -> sapma olarak gorunur ag.olcum-agi.cikis_yolu kayitta yok -> hicbir karsilastirmada cikmaz
Kırk iki sorunun otuz üçü kayıt yolunda, sekizi elle yolda yanıtlanıyor. Aradaki fark bir disiplin farkı değil, bir saklama yeri farkıdır: kayıt yolunda değişiklik bir dosyada duruyor ve dosya sürümleniyor, dolayısıyla üç sorunun üçü de aynı yerden okunuyor. İş kaydı yolunda iki soru yanıtlanır — kim açtı, ne zaman kapandı — ama üçüncüsü, ne değişti, düzyazıya kalır ve düzyazıda ölçülebilir bir değer yoktur.
Asıl bilgi son üç satırdadır. Kayıttan kurulan ortamda bile üç değişiklik kaydı atladı ve bu üçü birbirinden farklı sonuç doğurdu. Kayıtta yazılı olan kalem elle değiştirildiğinde bir karşılaştırma onu sapma olarak gösterir; kayıtta yazılı olmayan kalem elle değiştirildiğinde hiçbir karşılaştırmada çıkmaz. İzlenebilirlik kaydın varlığından değil, kapsamından doğuyor: kaydın dokunmadığı kalemde kayıt yolu ile elle yol arasında hiçbir fark yok.
Kaydın Bedeli
#!/usr/bin/env bash # Kayda baglamanin bedeli: yazilan satir ve degisiklik basina ek adim. printf 'yazilan satir talep %s kayit %s ayristirici ve uygulayici %s (bir kez)\n' \ "$(wc -l < talep.txt | tr -d ' ')" "$(wc -l < kayit.alt | tr -d ' ')" \ "$(wc -l < kur.mjs | tr -d ' ')" printf 'kayitta %s kalem satiri, %s kalem -> satir basina %s kalem\n' \ "$(grep -c '^kaynak' kayit.alt)" "20" "$(node -e 'console.log((20/6).toFixed(2))')" printf 'degisiklik basina ek adim elle yol 0 kayit yolu 3 (yaz, gozden gecir, plani oku)\n' printf 'bir donemde (14 degisiklik) elle yol 0 ek adim kayit yolu %s ek adim\n' "$((14 * 3))"
yazilan satir talep 12 kayit 8 ayristirici ve uygulayici 38 (bir kez) kayitta 6 kalem satiri, 20 kalem -> satir basina 3.33 kalem degisiklik basina ek adim elle yol 0 kayit yolu 3 (yaz, gozden gecir, plani oku) bir donemde (14 degisiklik) elle yol 0 ek adim kayit yolu 42 ek adim
Kaydın kendisi talepten kısadır: sekiz satır, altısı kalem taşıyor, satır başına 3,33 kalem. Bedel orada değil. Otuz sekiz satırlık ayrıştırıcı ve uygulayıcı bir kez yazılır ve her ortam için yeniden kullanılır — bu bir kereliktir. Sürekli ödenen bedel son satırdadır: kayıt yolunda her değişiklik üç ek adım ister ve bir çeyrekte bu kırk iki ek adıma çıkar. Elle yolda bu adımlar sıfırdır; bir kişi ortama girer ve değeri değiştirir.
Kırk iki ek adım karşılığında alınan şey de sayılıdır: yirmi beş sorunun daha yanıtlanması ve yirmi kalemin karşılaştırılabilir olması. Ama alınmayan şey aynı ölçüde nettir. Beş kalem kaydın dışında kaldı ve kırk iki ek adım onlara dokunmuyor; üç değişiklik kaydı atladı ve ek adımlar onları da durduramadı. Kayıt bir zorunluluk üretmez, bir karşılaştırma zemini üretir — o zemini kimin kullandığı ayrı bir sorudur ve bu kursun geri kalanı büyük ölçüde onu ölçer.
Özet
- Aynı ortamın iki kurulumu 9 kalemde ayrıldı: 5 ayrık (talebin sayı vermediği 7 noktanın 5’i), 1 eksik (yazılıydı, atlandı), 3 fazla (hiçbir tarifte yazılı değil).
- Talebin yedi yorum noktasının ikisi elin yorumu kayıtla aynı değere düştüğü için görünmedi; yorum noktası sayısı değişmedi, yalnız bu koşumda ayrılmadılar.
- Kaydın kapsamadığı 5 kalem iki kurulumda da aynı doğdu; bir karşılaştırma bunları hiçbir zaman fark olarak göstermez.
- Bir çeyreklik 42 sorunun 33’ü kayıt yolunda, 8’i elle yolda yanıtlandı; farkı yapan şey disiplin değil, değişikliğin saklandığı yer.
- Kayıt 8 satır, ayrıştırıcı ve uygulayıcı 38 satır (bir kez); sürekli bedel değişiklik başına 3 ek adım, bir çeyrekte 42 ek adım.
Sonraki Adım
Kayıt bu derste bir kalem listesiydi: her satır bir kaynağın niteliklerini sayıyordu ve ortamın ne olması gerektiğini yazıyordu. Bu, kayıt yazmanın tek biçimi değil. Aynı ortam bir adım listesi olarak da yazılabilir — önce ağı aç, sonra makineleri aç, sonra kuyruğu bağla — ve o liste de bir dosyada durur, sürümlenir, gözden geçirilir. İki biçim de kayıttır, ikisi de aynı üç ek adımı ister.
Fark ilk koşumda görünmez. Sonraki ders aynı hedefi iki biçimde yazar ve ikisini kısmi başarısızlıkla koşturur: üçüncü adımda hata çıktığında adım listesi nerede kalıyor, istenen durum tanımı ne yapıyor; ikisi yeniden koşturulduğunda ne kadar iş üretiyor; ve hedef değiştiğinde her birinde kaç satır yazmak gerekiyor.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.