Ders 01 / 13
Sistem Tasarımı Nedir
Bir sistem tasarımının üç karar türüne ayrılması: bileşen sınırları, sınırdan geçen sözleşmeler ve niteliklere konan eşikler; eşiğin nereden geldiği sorusunun yanıtı olarak sayının üç sınıfının ayrılması ve sınıfsız sayının karar taşımadığının gösterilmesi.
İçindekiler
Mimari Biçemler kursu aynı gönderi kitaplığının düzenlenişlerini karşılaştırdı ve her karşılaştırmayı üç parçaya indirdi: nitelik senaryosu, eşik ve ölçülen değer. Eşikler o kursta verilmişti; “sınırdan geçen bayt en çok 100” gibi bir sayı alıştırmanın girdisiydi. Kursun son cümlesi bunu işaretledi: biçem seçimi burada da aynı üç parçayla savunulur, değişen yalnız eşiklerin nereden geldiğidir.
Bu kurs o soruyla açılır. Bir sistemde eşik keyfi değildir, bir yerden gelir ve nereden geldiği yazılabilir. Bu ders eşiğin bağlı olduğu karar türlerini ayırır ve kursun bütün derslerinde geçerli olacak kuralı kurar: bir tasarım metnindeki her sayının sınıfı söylenir.
Üç Karar Türü
Sistem tasarımı (system design), birden çok bileşene bölünmüş bir yazılımın bu bölünmeyi ve bölünmenin getirdiği kısıtları belirleme işidir. Bir programın parçaları birlikte çalışır ve birlikte durur; bir sistemin bileşenleri (component) ayrı ölçeklenebilir ve ayrı arızalanabilir. Bu iki cümle arasındaki fark, sistem tasarımının bütün sorularını üretir.
Bir tasarım üç tür karardan oluşur ve üçü ayrı ayrı gerekçelendirilir.
Bileşen kararı hangi işin hangi birimde durduğunu söyler. Ölçüsü basittir: bir bileşenin tek başına ölçeklenebilmesi ve durduğunda geri kalanın ne kadarının ayakta kalması.
Sözleşme kararı (contract) bileşen sınırından neyin geçtiğini söyler: hangi alanlar, hangi yönde, hangi biçimde. Sınırdan geçen her alan iki bileşen arasında bir bağdır ve sonradan değiştirilmesi ikisini birlikte değiştirmeyi gerektirir.
Nitelik kararı bir kalite niteliğine eşik koyar: takip sorgusunun yanıt süresi, kabul edilen olay kaybı oranı, gün sonu işinin bitmesi gereken saat. Kalite niteliği ve nitelik senaryosu Kalite ve Test Temelleri kursunun Kalite Nitelikleri dersinde kuruldu; burada yeniden tanımlanmazlar, eşiğin taşıyıcısı olarak kullanılırlar.
İlk iki karar türü tek makinede de verilir ve Mimari Biçemler kursu onları orada ölçtü. Üçüncüsü sistemi sistem yapan karardır, çünkü eşik yazılımın içinden değil dışından gelir: yükten, beklentiden ve arıza tolerans kararından.
Sistem Olarak Gönderi Takibi
Kurs boyunca tek bir sistem üzerinde çalışılır: gönderi takip ve ücretlendirme servisi. Kullanıcı bir takip numarasıyla gönderisinin durumunu sorar, taşıyıcı gönderi hareket ettikçe durum olayı gönderir, satıcı gün sonunda ücretlendirme ister. Üç akış birbirinden ayrılır çünkü üçü ayrı eşik ister: okuma akışı çok ve küçük, yazma akışı sürekli ve küçük, toplu akış seyrek ve büyüktür.
Tasarımın ilk hâli bir veri yapısı olarak yazılabilir. Bileşenler, sözleşmeler ve akışlar listelendiğinde tasarım hakkında sayılabilir şeyler ortaya çıkar.
// tasarim/sistem.mjs — gonderi takip ve ucretlendirme servisi: bilesenler, sozlesmeler ve uc akis export const BILESEN = { "takip-ucu": "takip sorgusunu yanitlar", "olay-alici": "tasiyicidan gelen durum olayini kabul eder", "gonderi-deposu": "gonderi ve teslimat durumunu tutar", "tarife-kurali": "bir gonderinin ucretini hesaplar", "toplu-isci": "saticinin gun sonu ucretlendirmesini uretir", }; export const SOZLESME = { "takip-istegi": { yon: "istemci -> takip-ucu", alan: ["takipNo"] }, "takip-yaniti": { yon: "takip-ucu -> istemci", alan: ["takipNo", "durum", "bolge", "guncellenme"] }, "durum-olayi": { yon: "tasiyici -> olay-alici", alan: ["takipNo", "durum", "rota", "zaman"] }, "durum-okuma": { yon: "takip-ucu -> gonderi-deposu", alan: ["takipNo"] }, "durum-yazma": { yon: "olay-alici -> gonderi-deposu", alan: ["takipNo", "durum", "rota", "zaman"] }, "gun-taramasi": { yon: "toplu-isci -> gonderi-deposu", alan: ["sozlesmeNo", "gun"] }, "ucret-istegi": { yon: "toplu-isci -> tarife-kurali", alan: ["agirlik", "bolge", "oran"] }, }; export const AKIS = { okuma: { ad: "takip sorgusu", bilesen: ["takip-ucu", "gonderi-deposu"], sozlesme: ["takip-istegi", "durum-okuma", "takip-yaniti"] }, yazma: { ad: "durum olayi", bilesen: ["olay-alici", "gonderi-deposu"], sozlesme: ["durum-olayi", "durum-yazma"] }, toplu: { ad: "gun sonu ucretlendirme", bilesen: ["toplu-isci", "gonderi-deposu", "tarife-kurali"], sozlesme: ["gun-taramasi", "ucret-istegi"] }, };
Bu listeden çıkan ilk ölçü tasarım yüzeyidir: kaç bileşen, kaç sözleşme, sözleşmelerin taşıdığı kaç alan.
// tasarim/yuzey.mjs — her akisin dokundugu bilesen, gectigi sozlesme ve tasidigi alan sayisi import { BILESEN, SOZLESME, AKIS } from "./sistem.mjs"; console.log(`bilesen = ${Object.keys(BILESEN).length}, sozlesme = ${Object.keys(SOZLESME).length}`); console.log(`${"akis".padEnd(23)}${"bilesen".padStart(8)}${"sozlesme".padStart(9)}${"alan".padStart(6)}`); for (const a of Object.values(AKIS)) { const alan = a.sozlesme.reduce((t, s) => t + SOZLESME[s].alan.length, 0); console.log(`${a.ad.padEnd(23)}${String(a.bilesen.length).padStart(8)}${String(a.sozlesme.length).padStart(9)}${String(alan).padStart(6)}`); } for (const b of Object.keys(BILESEN)) { const akislar = Object.values(AKIS).filter((a) => a.bilesen.includes(b)).map((a) => a.ad); console.log(`${b.padEnd(16)} dokunan akis = ${akislar.length}${akislar.length > 1 ? ` (${akislar.join(", ")})` : ""}`); }
bilesen = 5, sozlesme = 7 akis bilesen sozlesme alan takip sorgusu 2 3 6 durum olayi 2 2 8 gun sonu ucretlendirme 3 2 5 takip-ucu dokunan akis = 1 olay-alici dokunan akis = 1 gonderi-deposu dokunan akis = 3 (takip sorgusu, durum olayi, gun sonu ucretlendirme) tarife-kurali dokunan akis = 1 toplu-isci dokunan akis = 1
Son satırlar tasarımın en önemli olgusunu veriyor: beş bileşenin dördü tek akışa hizmet
ediyor, gonderi-deposu ise üçüne birden. Bu bileşen üç ayrı eşiğin kesiştiği yerdir ve
kursun ilerleyen konularında her yeni kısıt önce burada görünür. Bir tasarımın en kırılgan
noktası, en çok akışın dokunduğu bileşendir.
Eşiğin Nereden Geldiği
Nitelik kararı bir sayı taşır ve o sayının bir kaynağı vardır. Kaynak üç sınıftan birine girer; hangisi olduğu metinde yazılmadıkça karar denetlenemez.
Varsayım, tasarımın girdisi olarak seçilen sayıdır: günlük etkin kullanıcı, kullanıcı başına takip sorgusu, kayıt boyutu. Doğruluğu tasarımın içinden gösterilemez, bu yüzden gerekçesi ve iki katına çıktığında ne olacağı yazılır.
Hesap, varsayımlardan aritmetikle çıkan sayıdır: saniyedeki istek, günlük veri artışı, gereken bant genişliği. Bir hesap ancak dayandığı varsayımlar kadar geçerlidir.
Ölçüm, bir düzenekten çıkan sayıdır: bu makinede koşturulan bir işlevin süresi, bir tamponun zirvesi. Ölçüm ortama bağlıdır ve bu bağlılık metinde işaretlenir.
Aşağıdaki betik dört kararı bu üç sınıfa göre denetler. Dördüncü karar bilinçli olarak sınıfsız bırakılmıştır.
// tasarim/karar.mjs — bir kararin yanindaki sayinin sinifi: varsayim, hesap ya da olcum const SINIF = ["varsayim", "hesap", "olcum"]; const BUTCE_US = 50; // tarife cagrisi icin secilen butce (mikrosaniye) // Iki varsayim; tam varsayim tablosu Kabaca Buyukluk Hesabi dersinde kurulur. const V = { gunlukKullanici: 2_000_000, kullaniciBasinaSorgu: 6, gunlukGonderi: 400_000, gonderiBasinaOlay: 7 }; const sorgu = V.gunlukKullanici * V.kullaniciBasinaSorgu; const olay = V.gunlukGonderi * V.gonderiBasinaOlay; const KADEME = [[1, 3000], [5, 4800], [20, 9600]]; const BOLGE = { "34": 100, "06": 115, "35": 125 }; function tarife(g) { const kademe = KADEME.find(([k]) => g.agirlik <= k) ?? [0, 9600]; const taban = Math.max(2500, Math.round((kademe[1] * BOLGE[g.bolge]) / 100)); return taban - Math.round(taban * Math.min(g.oran, 0.4)); } function ortancaMikrosaniye(kosu = 9) { const sureler = []; for (let i = 0; i < kosu; i += 1) { const bas = process.hrtime.bigint(); tarife({ agirlik: 4, bolge: "35", oran: 0.15 }); sureler.push(Number(process.hrtime.bigint() - bas) / 1000); } sureler.sort((a, b) => a - b); return sureler[Math.floor(kosu / 2)]; } const KARAR = [ { ad: "okuma yolu yazmadan ayri olceklenir", olcu: "okuma/yazma istek orani", sayi: (sorgu / olay).toFixed(2), sinif: "hesap" }, { ad: "takip yaniti onbellekten karsilanir", olcu: "onbellek isabet orani", sayi: "0.90", sinif: "varsayim" }, { ad: "tarife kurali surec icinde cagrilir", olcu: `${BUTCE_US} us butcesi`, sayi: ortancaMikrosaniye() < BUTCE_US ? "gecti" : "kaldi", sinif: "olcum" }, { ad: "toplu is gece penceresinde kosar", olcu: "pencere saati", sayi: "4", sinif: null }, ]; console.log(`${"karar".padEnd(37)}${"olcu".padEnd(25)}${"sayi".padStart(7)} sinif`); for (const k of KARAR) { console.log(`${k.ad.padEnd(37)}${k.olcu.padEnd(25)}${String(k.sayi).padStart(7)} ${k.sinif ?? "-"}`); } const sinifsiz = KARAR.filter((k) => SINIF.includes(k.sinif) === false); console.log(`\nsinifsiz sayi tasiyan karar = ${sinifsiz.length}: ${sinifsiz.map((k) => k.ad).join("; ")}`); console.log(`gunluk takip sorgusu = ${sorgu}, gunluk durum olayi = ${olay}`); console.log(`varsayim ikiye katlanirsa: kullanici basina sorgu 12 -> oran ${((sorgu * 2) / olay).toFixed(2)}`);
karar olcu sayi sinif okuma yolu yazmadan ayri olceklenir okuma/yazma istek orani 4.29 hesap takip yaniti onbellekten karsilanir onbellek isabet orani 0.90 varsayim tarife kurali surec icinde cagrilir 50 us butcesi gecti olcum toplu is gece penceresinde kosar pencere saati 4 - sinifsiz sayi tasiyan karar = 1: toplu is gece penceresinde kosar gunluk takip sorgusu = 12000000, gunluk durum olayi = 2800000 varsayim ikiye katlanirsa: kullanici basina sorgu 12 -> oran 8.57
Dört satır dört ayrı okuma gerektiriyor. Okuma/yazma oranı 4.29 bir hesaptır: iki varsayımın bölümüdür ve son satır duyarlılığını gösteriyor — kullanıcı başına sorgu 6 yerine 12 olsaydı oran 8.57 olurdu. Önbellek isabet oranı 0.90 bir varsayımdır; gerekçesi aynı takip numarasının teslime kadar birkaç kez sorulmasıdır, doğruluğu ancak sistem çalıştığında sınanır. Tarife çağrısının bütçeyi geçmesi bir ölçümdür ve çıktıya ham süre değil yargı yazılmıştır, çünkü ham süre bu makineye ve çalışma zamanı sürümüne bağlıdır.
Dördüncü satırın sınıfı yoktur. “Toplu iş dört saatlik gece penceresinde koşar” cümlesi tasarım metninde makul görünür ama denetlenemez: dört saat bir varsayım mı, satıcının beklentisinden çıkan bir hesap mı, yoksa bir koşumda ölçülmüş bir süre mi belirsizdir. Sınıfsız sayı karar taşımaz — ölçülmemiş eksenin tartışmada ağırlığı olmadığı gibi.
Bileşen Kararı Nitelik Kararına Bağlıdır
Üç karar türü sırayla verilmez, birbirini belirler. Bileşen listesinin ilk hâli işlevsel beklentiden çıkar: takip sorgusunu yanıtlayan bir uç, olayı kabul eden bir alıcı, durumu tutan bir depo. Bu liste bir düzen değil, yalnız işin bölünüşüdür.
Bileşen sayısının bu listenin ötesine geçmesi nitelik kararlarından olur. Okuma akışının eşiği yazma akışının eşiğinden bağımsız tutulmak isteniyorsa iki akış ayrı ölçeklenebilir bileşenlere konur ve bileşen sayısı artar. Toplu işin gün sonu penceresi okuma akışının yanıt süresini bozmamalıysa toplu iş kendi birimine taşınır. Her ayırma sözleşme sayısını ve sınırdan geçen alan sayısını büyütür; Mimari Biçemler kursunda ölçülen bedel budur.
Sıralamanın yönü bu yüzden tersinden okunur: eşikler bilinmeden bileşen sayısı savunulamaz. Bir tasarımı “beş bileşen” diye anlatmak, hangi eşiğin hangi ayırmayı zorunlu kıldığını söylemedikçe bir karar değildir. Sonraki iki ders eşiğin kaynağını sırayla açar: önce gereksinimlerin nasıl toplandığı, sonra işlevsel olanla işlevsel olmayanın ayrı belirleyici olması.
Özet
- Sistem tasarımı üç tür karardan oluşur: bileşen sınırları, sınırdan geçen sözleşmeler ve niteliklere konan eşikler; ilk ikisi tek makinede de verilir, üçüncüsü yükten ve beklentiden gelir.
- Tasarım yüzeyi sayılabilir: örnek sistemde 5 bileşen, 7 sözleşme; takip sorgusu 3 sözleşme ve 6 alan, durum olayı 2 sözleşme ve 8 alan, gün sonu ücretlendirmesi 2 sözleşme ve 5 alan taşıyor.
- En çok akışın dokunduğu bileşen en kırılgan noktadır:
gonderi-deposuüç akışın da içinde, öteki dört bileşen birer akışta. - Bir kararın yanındaki sayı üç sınıftan birine girer: varsayım seçilir ve duyarlılığı yazılır, hesap varsayımlardan çıkar, ölçüm bir düzenekten çıkar ve ortama bağlılığı işaretlenir.
- Sınıfsız sayı karar taşımaz; örnekte dört karardan biri sınıfsız kaldığı için denetlenemez sayıldı.
- Bileşen sayısı işlevsel bölünüşten değil nitelik eşiklerinden büyür; eşik bilinmeden bileşen sayısı savunulamaz.
Sonraki Adım
Bu ders eşiğin bir kaynağı olduğunu söyledi ama kaynağı aramadı. Örnekteki beş bileşen ve yedi sözleşme hazır verildi; oysa gerçek bir tasarım işi tek satırlık bir istekle başlar: “satıcıların gönderilerini takip edebileceği ve gün sonunda ücretlendirilebileceği bir servis.” O satır bileşen adı içermez, sayı içermez, sınır içermez. Sonraki ders o satırdan bir tasarıma nasıl geçildiğini ele alır: hangi soruların sorulduğunu, yanıtsız kalan her sorunun neden bir varsayıma dönüştüğünü ve kapsamın daraltılmasının tasarım yüzeyinde ne kadar yer açtığını.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.