Ders 01 / 14
Bağlantı Kısaltma Servisi
Okuma ağırlıklı ilk vaka: kısıtların işlevsel ve işlevsel olmayan gereksinim olarak sayıya çevrilmesi, dokuz varsayımdan kabaca büyüklük hesabının çıkarılması, kısa anahtar uzunluğunun doluluk oranı ile çakışma ve tahmin maliyeti üzerinden seçilmesi, sayaç tabanlı üretimin ölçülmüş bir farkla elenmesi ve tasarımın parça arızasındaki davranışıyla feda ettiği tazeliğin yazılması.
İçindekiler
Altı kurs bir tasarım dilini parça parça kurdu. Bu kursun işi yeni bir mekanik öğretmek değildir; kurulmuş kalıpları tek bir problemde birlikte kullanmak ve seçimleri gerekçesiyle savunmaktır. Her vaka aynı altı adımı yürür: kısıtlar sayıya çevrilir, varsayımlar kendi tablosunda toplanır, tablodan kabaca büyüklük hesabı çıkar, tasarım kalıplardan adıyla derlenir, en az bir alternatif bir sayıyla elenir ve tasarımın arıza altındaki davranışıyla feda ettiği şey yazılır.
İlk vaka bağlantı kısaltma servisidir: uzun bir bağlantı verildiğinde kısa bir anahtar üretilir, o anahtar istendiğinde asıl hedefe yönlendirilir. Tasarım tek bir karara bakar — kısa anahtarın nasıl üretileceğine — ve bu ders o kararı ölçer.
Kısıtlar
İşlevsel gereksinimler. I1: uzun bağlantı için kısa anahtar üretilir ve döndürülür. I2: kısa anahtar istendiğinde hedefe yönlendirilir. I3: bağlantının sona erme zamanı vardır, süresi dolan yönlendirilmez. I4: sahibi bağlantıyı siler. I5: bir kısa anahtar iki ayrı hedefe verilmez.
Kapsam daraltması. Tıklama sayımı, kişiye özel anahtar talebi, hedef bağlantının zararlılık taraması ve hesap yönetimi bu tasarımın dışındadır; her biri kendi yazma yolunu getirir ve aşağıdaki kararları oynatmaz.
İşlevsel olmayan gereksinimler. Eşiğin sınıfı değil kaynağı yazılır; biçim Sistem Tasarımına Giriş kursunun İşlevsel ve İşlevsel Olmayan Gereksinimler dersinindir.
| Kod | Eşik | Eşiğin kaynağı |
|---|---|---|
| G1 | yönlendirme yanıtının ortancası 50 ms’yi geçmez | yönlendirme, tıklama ile hedef sayfa arasına giren fazladan bir turdur |
| G2 | kısaltma çağrısı 300 ms’yi geçmez | sonuç ekranda beklenir |
| G3 | yönlendirme yolunun hizmet erişilebilirliği yüzde 99,95 | kısaltılmış bağlantı yazının içine gömülür ve geri alınamaz |
| G4 | rastgele bir anahtar tahmininin isabet olasılığı 1/1000’in altındadır | bağlantı gizli değildir ama listelenebilir de olmamalıdır |
Varsayımlar
Tablo bu dersin kendisinindir; sonraki vakalar kendi tablolarını kurar ve buradan sayı devralmaz.
| Kod | Varsayım | Değer | Gerekçe |
|---|---|---|---|
| BK1 | günde oluşturulan kısaltma | 500.000 | kısaltma bir paylaşım eylemine bağlıdır, seyrektir |
| BK2 | kısaltma başına günlük yönlendirme | 100 | bağlantı paylaşıldığı gün çok kez açılır |
| BK3 | tepe çarpanı | 3 | tepe saatteki hızın gün ortalamasına oranı |
| BK4 | bağlantı kaydı | 500 bayt | hedef bağlantı, sahip, oluşturma ve sona erme zamanı |
| BK5 | saklama süresi | 1825 gün | yenilenmeyen bağlantı beş yıl sonra düşer |
| BK6 | isteklerin 0,80’ini alan anahtar payı | 0,01 | erişim az sayıda yeni bağlantıda yoğunlaşır |
| BK7 | alfabe boyutu | 62 | rakam ve iki kasa harf; ayraç yok, elle yazılabilir |
| BK8 | önbellek kaydı | 300 bayt | anahtar ve hedef bağlantı |
| BK9 | yönlendirme yanıtı | 300 bayt | gövdesiz yanıt ve başlıkları |
Kabaca Büyüklük Hesabı
// kisaltma/hesap.mjs — BK1–BK9'dan cikan kabaca buyukluk hesabi ve anahtar uzunlugu taramasi const BK = { gunlukKisaltma: 500_000, // BK1 yonlendirmeOrani: 100, // BK2 tepeCarpani: 3, // BK3 kayitBayt: 500, // BK4 saklamaGun: 1825, // BK5 sicakPay: 0.01, // BK6: isteklerin 0,80'ini alan anahtar payi sicakIstekPayi: 0.80, // BK6 alfabe: 62, // BK7 onbellekKayitBayt: 300, // BK8 yanitBayt: 300, // BK9 }; const GUN = 86_400, AY_DK = 43_800, HEDEF = 0.9995; // HEDEF: G3 esigi, varsayim degil function hesapla(v) { const okumaTepe = ((v.gunlukKisaltma * v.yonlendirmeOrani) / GUN) * v.tepeCarpani; const toplam = v.gunlukKisaltma * v.saklamaGun; return { toplam, okumaTepe, yazmaTepe: (v.gunlukKisaltma / GUN) * v.tepeCarpani, depoOkuma: okumaTepe * (1 - v.sicakIstekPayi), cikisMbit: (okumaTepe * v.yanitBayt * 8) / 1e6, depoGB: (toplam * v.kayitBayt) / 1e9, onbellekGB: (toplam * v.sicakPay * v.onbellekKayitBayt) / 1e9, }; } const b = (x, n = 2) => x.toFixed(n); const r = hesapla(BK); console.log(`saklama penceresinde toplam baglanti = ${r.toplam.toLocaleString("tr-TR")}`); console.log(`tepe yonlendirme/s = ${b(r.okumaTepe)} tepe kisaltma/s = ${b(r.yazmaTepe)} oran = ${b(r.okumaTepe / r.yazmaTepe)}`); console.log(`onbellek arkasi yonlendirme/s = ${b(r.depoOkuma)} cikis = ${b(r.cikisMbit)} Mbit/s`); console.log(`depo = ${b(r.depoGB)} GB onbellek = ${b(r.onbellekGB)} GB G3 kesinti butcesi = ${b((1 - HEDEF) * AY_DK, 1)} dk/ay`); console.log(`\n${"uzunluk".padEnd(9)}${"anahtar uzayi".padStart(19)}${"doluluk".padStart(11)}` + `${"fazla deneme/kayit".padStart(20)}${"tepede fazla dokunus/s".padStart(24)}${"isabet basina tahmin".padStart(22)}`); const fazlaDeneme = {}; for (const L of [5, 6, 7, 8]) { const uzay = BK.alfabe ** L, d = r.toplam / uzay; // Yeniden deneme beklentisi: k anahtar dagitilmisken bir denemenin bosa cikma olasiligi k/uzay. let fazla = 0; for (let k = 0; k < r.toplam; k += r.toplam / 1e5) fazla += (1 / (1 - k / uzay) - 1) / 1e5; fazlaDeneme[L] = fazla; console.log(`${String(L).padEnd(9)}${uzay.toLocaleString("tr-TR").padStart(19)}${b(d, 6).padStart(11)}` + `${b(fazla, 6).padStart(20)}${b(fazla * r.yazmaTepe, 4).padStart(24)}${b(1 / d, 1).padStart(22)}`); } const PARCA = 8, dusen = r.okumaTepe / PARCA * (1 - BK.sicakIstekPayi); console.log(`\ntek parca arizasi (${PARCA} parca): dusen yonlendirme ${b(dusen)}/s = isteklerin ` + `${b(dusen / r.okumaTepe, 4)}'i, reddedilen kisaltma ${b(r.yazmaTepe / PARCA)}/s`); console.log(`G3 butcesinin tek parca arizasina karsiligi = ${b((1 - HEDEF) * AY_DK / (dusen / r.okumaTepe), 1)} dk/ay`); const iki = hesapla({ ...BK, gunlukKisaltma: BK.gunlukKisaltma * 2 }); console.log(`\nBK1 duyarliligi: gunluk kisaltma 500.000 -> 1.000.000 ise depo ${b(r.depoGB)} -> ${b(iki.depoGB)} GB, ` + `7 karakterde doluluk ${b(r.toplam / BK.alfabe ** 7, 6)} -> ${b(iki.toplam / BK.alfabe ** 7, 6)}, ` + `isabet basina tahmin ${b(BK.alfabe ** 7 / r.toplam, 1)} -> ${b(BK.alfabe ** 7 / iki.toplam, 1)}`);
saklama penceresinde toplam baglanti = 912.500.000 tepe yonlendirme/s = 1736.11 tepe kisaltma/s = 17.36 oran = 100.00 onbellek arkasi yonlendirme/s = 347.22 cikis = 4.17 Mbit/s depo = 456.25 GB onbellek = 2.74 GB G3 kesinti butcesi = 21.9 dk/ay uzunluk anahtar uzayi doluluk fazla deneme/kayit tepede fazla dokunus/s isabet basina tahmin 5 916.132.832 0.996035 4.550910 79.0089 1.0 6 56.800.235.584 0.016065 0.008120 0.1410 62.2 7 3.521.614.606.208 0.000259 0.000130 0.0022 3859.3 8 218.340.105.584.896 0.000004 0.000002 0.0000 239276.8 tek parca arizasi (8 parca): dusen yonlendirme 43.40/s = isteklerin 0.0250'i, reddedilen kisaltma 2.17/s G3 butcesinin tek parca arizasina karsiligi = 876.0 dk/ay BK1 duyarliligi: gunluk kisaltma 500.000 -> 1.000.000 ise depo 456.25 -> 912.50 GB, 7 karakterde doluluk 0.000259 -> 0.000518, isabet basina tahmin 3859.3 -> 1929.7
Bu sayılar hesap sınıfındadır ve dördü tasarımı belirliyor. Uçtaki oran tam 100: saniyede 1736,11 yönlendirmeye karşılık 17,36 kısaltma. Saklama penceresi 912.500.000 bağlantı ve 456,25 GB tutuyor, tek düğümün taşımayacağı kadar. Önbelleğin arkasına 347,22 istek/s düşüyor ve sıcak kümenin tamamı 2,74 GB, yani belleğe sığıyor. En belirleyicisi anahtar uzunluğu tablosudur: beş karakter bu hacim için doludur (doluluk 0,996035), altı karakter G4’ü karşılamaz (isabet başına 62,2 tahmin, eşik 1000), yedi karakter ikisini birden karşılar (3859,3 tahmin, kayıt başına 0,000130 fazla deneme). BK1 iki katına çıksa bile yedide isabet başına 1929,7 tahmin kalıyor ve eşik tutuyor.
Anahtar Üretiminin Çakışma Oranı
Tablodaki fazla deneme/kayit sütunu bir beklentidir. Rastgele üretimin böyle davrandığı, çakışma
oranının yalnız doluluk oranına bağlı olduğu ve sayaçla farkın nerede oluştuğu ölçülür.
// kisaltma/anahtar.mjs — anahtar uretiminin cakisma orani: rastgele uretimin doluluga bagimliligi // ve sayac tabanli uretimle karsilastirilmasi. Anahtar uzayi bir yuva dizisiyle temsil edilir, // uretec kendi yazilmistir, tohum sabittir; sayilar makineye bagli degildir. MODELDIR. const TOHUM = 20260730; const uretec = (t) => { let s = t % 2147483647; return () => (s = (s * 48271) % 2147483647) / 2147483647; }; function rastgeleDoldur(m, n, rast) { // cakisirsa yeni anahtar cekilir const dolu = new Uint8Array(m); let deneme = 0; for (let i = 0; i < n; i += 1) { let y; do { y = Math.floor(rast() * m); deneme += 1; } while (dolu[y]); dolu[y] = 1; } return { dolu, fazla: deneme - n }; } function beklenenFazla(m, n) { // k yuva doluyken bir denemenin bosa cikma olasiligi k/m let t = 0; for (let k = 0; k < n; k += 1) t += 1 / (1 - k / m) - 1; return t; } const M = 2_000_000, DOLULUK = [0.016065, 0.1, 0.5, 0.9, 0.996035]; const b = (x, n = 6) => x.toFixed(n); const say = (x) => x.toLocaleString("tr-TR"); console.log(`model: ${say(M)} yuvali anahtar uzayi, tohum ${TOHUM}, uretec kendi yazildi`); console.log(`\n${"doluluk".padEnd(10)}${"eklenen".padStart(10)}${"fazla deneme".padStart(14)}` + `${"olculen/kayit".padStart(15)}${"beklenen/kayit".padStart(16)}${"olculen/beklenen".padStart(18)}`); for (const d of DOLULUK) { const n = Math.round(d * M); const { fazla } = rastgeleDoldur(M, n, uretec(TOHUM)); const bek = beklenenFazla(M, n); console.log(`${b(d).padEnd(10)}${say(n).padStart(10)}${say(fazla).padStart(14)}` + `${b(fazla / n).padStart(15)}${b(bek / n).padStart(16)}${b(fazla / bek, 4).padStart(18)}`); } // Olcek denetimi: cakisma orani uzayin buyuklugune degil doluluga bagli. console.log(""); for (const m of [250_000, 2_000_000, 8_000_000]) { const n = m / 2; const { fazla } = rastgeleDoldur(m, n, uretec(TOHUM)); console.log(`olcek denetimi: uzay ${say(m).padStart(9)}, doluluk 0,500000 -> fazla deneme/kayit ${b(fazla / n)}`); } // Iki uretim bicimi ayni dolulukta: sayac cakismaz, ama anahtarlari bitisiktir. const TAHMIN = 20_000, BLOK = 1000, d6 = 0.016065, n6 = Math.round(d6 * M); const rastgele = rastgeleDoldur(M, n6, uretec(TOHUM)); const sayacDolu = new Uint8Array(M); for (let i = 0; i < n6; i += 1) sayacDolu[i] = 1; // sayac 0'dan artarak dagitir const tahminci = uretec(TOHUM + 1); let rastIsabet = 0, sayacIsabet = 0; for (let g = 0; g < TAHMIN; g += 1) { if (rastgele.dolu[Math.floor(tahminci() * M)]) rastIsabet += 1; // rastgele anahtarda rastgele tahmin if (sayacDolu[g]) sayacIsabet += 1; // sayac anahtarda sirali tahmin } const satir = (ad, fazla, esgudum, isabet) => console.log(`${ad.padEnd(18)}${say(fazla).padStart(14)}` + `${esgudum.padStart(17)}${say(isabet).padStart(12)}${(TAHMIN / isabet).toFixed(1).padStart(22)}`); console.log(`\ndoluluk ${b(d6)}, ${say(n6)} anahtar dagitilmis, ${say(TAHMIN)} tahmin`); console.log(`${"uretim bicimi".padEnd(18)}${"fazla deneme".padStart(14)}${"esgudum cagrisi".padStart(17)}` + `${"isabet".padStart(12)}${"isabet basina tahmin".padStart(22)}`); satir("rastgele", rastgele.fazla, "0", rastIsabet); satir(`sayac (blok ${BLOK})`, 0, (n6 / BLOK).toFixed(1), sayacIsabet);
model: 2.000.000 yuvali anahtar uzayi, tohum 20260730, uretec kendi yazildi doluluk eklenen fazla deneme olculen/kayit beklenen/kayit olculen/beklenen 0.016065 32.130 256 0.007968 0.008119 0.9813 0.100000 200.000 10.771 0.053855 0.053605 1.0047 0.500000 1.000.000 385.317 0.385317 0.386294 0.9975 0.900000 1.800.000 2.802.181 1.556767 1.558425 0.9989 0.996035 1.992.070 9.053.122 4.544580 4.552201 0.9983 olcek denetimi: uzay 250.000, doluluk 0,500000 -> fazla deneme/kayit 0.386128 olcek denetimi: uzay 2.000.000, doluluk 0,500000 -> fazla deneme/kayit 0.385317 olcek denetimi: uzay 8.000.000, doluluk 0,500000 -> fazla deneme/kayit 0.384476 doluluk 0.016065, 32.130 anahtar dagitilmis, 20.000 tahmin uretim bicimi fazla deneme esgudum cagrisi isabet isabet basina tahmin rastgele 256 0 344 58.1 sayac (blok 1000) 0 32.1 20.000 1.0
Ölçüm üç şey veriyor. Ölçülen ile beklenen oranı her dolulukta 0,98 ile 1,01 arasında; kapalı biçim rastgele üretimi temsil ediyor ve tablodaki 0,000130 güvenilir. Ölçek denetimi çakışma oranının uzayın büyüklüğüne değil doluluğa bağlı olduğunu gösteriyor: uzay otuz iki katına çıktığında oran 0,386128’den 0,384476’ya, aynı üçüncü haneye oturuyor — iki milyon yuvalık modelin 3,5 trilyonluk uzay hakkında konuşabilmesinin gerekçesi budur. Üçüncüsü, oran doluluğa doğrusal bağlı değil: 0,10’da kayıt başına 0,05 fazla deneme varken 0,996035’te 4,54.
Son tablo iki üretim biçimini yan yana koyuyor. Sayaç hiç çakışmıyor; bedeli iki kalemdir. Birincisi eşgüdüm: sayaç tek yerden dağıtılır, bin anahtarlık bloklarla 32.130 anahtar için 32,1 çağrı eder — tepe hızda saniyede 0,017 çağrı, ihmal edilebilir. İkincisi tahmin edilebilirlik ve ihmal edilemez: sıralı tahmin eden bir istemci 20.000 denemenin 20.000’inde isabet ediyor, rastgelede 344’ünde.
Tasarım
Hiçbir bileşen yeniden anlatılmaz; her biri kurulduğu derse bağlanır ve bu vakadaki parametresi yazılır.
- Kenar önbelleği (Trafik Katmanı, İçerik Dağıtım Ağları). Parametre, yönlendirme yanıtının kenardaki ömrüdür: 300 saniye. Bu, Veri Katmanı Ölçekleme kursunun Tutarlılık ve Bayat Veri dersindeki bayatlık penceresidir ve I3 ile I4’ün kenarda gecikmeli geçerli olması demektir.
- Yönlendirme servisi durumsuzdur (Uygulama Katmanı, Durumsuz Servisler); istek başına taşınan durum sıfır olduğu için oturum yapışkanlığı (Trafik Katmanı, Oturum Yapışkanlığı) kapalıdır.
- Anahtar–değer deposu (Veri Katmanı Ölçekleme, Depo Türleri), sekiz parçaya parçalanmış (Veri Dağıtımı, Parçalama). Parça anahtarı kısa anahtarın kendisidir: hem yönlendirme hem silme anahtarı zaten bilir, iki örüntü de tek düğüme dokunur ve dağıt–topla oluşmaz.
- Yanında okuma önbelleği (Veri Katmanı Ölçekleme, Yanında Okuma). Parametre BK6’dan gelir: 2,74 GB’lık sıcak küme isteklerin 0,80’ini karşılar, arkasına 347,22 istek/s kalır.
- API ağ geçidi ve hız sınırlama (Trafik Katmanı, API Ağ Geçidi), yalnız kısaltma yolunda. Parametre hesap başına dakikada 20 kısaltmadır: tepe yazma saniyede 17,36’dır ve tek bir istemcinin bu akışı doldurabilmesi istenmez.
- Sonunda tutarlılık (Sistem Tasarımına Giriş, Tutarlılık Modelleri). Yeni anahtarın kopyalara yayılması zaman alır; parametre, kısaltmadan hemen sonraki ilk yönlendirmenin ana kopyaya gitmesidir, ki oluşturan kendi bağlantısını açabilsin.
Bilerek kullanılmayan iki kalıp. Komut ve sorgu sorumluluğu ayrımı (Veri Katmanı Ölçekleme, Komut ve Sorgu Ayrımı) kullanılmıyor: okuma modeli yazma modelinin aynısıdır, türetilecek izdüşüm yoktur. İleti kuyruğu (Uygulama Katmanı, Mesaj Kuyrukları) kısaltma yolunda kullanılmıyor: çağıran anahtarı yanıtın içinde bekler.
Elenen Alternatif: Sayaç Tabanlı Üretim
Alternatif tasarım anahtarı rastgele çekmez; artan bir sayacı 62 tabanına çevirerek üretir. Çakışma tanım gereği sıfırdır, I5 aritmetikle garanti edilir ve deponun varlık denetimi hiç yapılmaz.
Eleme sayısı G4’tedir. Sayaç anahtarları bitişik olduğu için sıralı tahmin eden bir istemci her denemesinde isabet eder (ölçümde 20.000/20.000, isabet başına 1,0 tahmin); yedi karakterlik rastgele üretimde isabet başına 3859,3 tahmin gerekir. Fark 3859 kattır ve eşik 1000’dir; sayaç bunu hiçbir anahtar uzunluğunda karşılayamaz, çünkü sorun uzay büyüklüğü değil bitişikliktir. Kazandığı şey ise ölçüldü ve küçük: yedi karakterde rastgele üretimin tepede eklediği fazla depo dokunuşu saniyede 0,0022’dir, 17,36 yazmanın on binde birinden azı.
Alternatif hangi kısıt değişirse kazanır: anahtar uzunluğu beş karaktere sabitlenseydi doluluk 0,996035 olur, rastgele üretim kayıt başına 4,55 fazla deneme ve tepede saniyede 79,01 fazla dokunuş üretir — yazma yükünün dört buçuk katı. O durumda tek çalışan üretim biçimi sayaçtır ve G4 zaten hiçbir biçimle karşılanamaz.
Arıza Davranışı ve Feda Edilen
Bir depo parçası düşerse (Dayanıklılık ve Güvenilirlik, Arıza Kipleri) o parçanın anahtarları yalnız önbellekten karşılanır: yönlendirmelerin 0,0250’si, saniyede 43,40 istek düşer ve 2,17 kısaltma reddedilir. G3’ün aylık 21,9 dakikalık kesinti bütçesi bu kısmi arızayla ölçüldüğünde 876,0 dakikalık tek parça kesintisine karşılık geliyor.
Depo tümüyle düşerse yönlendirme zarif bozulmayla (Dayanıklılık ve Güvenilirlik, Zarif Bozulma) önbellekten sürer, isteklerin 0,80’i yanıtlanır; kısaltma yolu kapatılır, çünkü yazılamayan bir anahtarı döndürmek I5’i bozar.
Feda edilen tazeliktir. Silinen ya da süresi dolan bir bağlantı kenardaki 300 saniyelik pencere boyunca çalışmaya devam eder. Tasarım bu pencereyi bilerek satın aldı: karşılığında yönlendirmelerin büyük bölümü kökene hiç ulaşmıyor.
Özet
- Kısıtlar beş işlevsel gereksinime ve dört eşiğe indi; kapsam dışı dört iş yazıldı ve eşiklerin yanına sınıf değil kaynak kondu.
- Dokuz varsayımdan çıkan hesap uçtaki oranı 100 verdi (1736,11 yönlendirme/s, 17,36 kısaltma/s), saklama penceresini 456,25 GB’ye ve sıcak kümeyi 2,74 GB’ye oturttu.
- Anahtar uzunluğu iki eşik tarafından birden belirlendi: beş karakter dolu (0,996035), altı karakter G4’ü karşılamıyor (62,2 tahmin), yedi karakter ikisini de karşılıyor (0,000130 fazla deneme, 3859,3 tahmin).
- Çakışma oranı uzayın büyüklüğüne değil doluluğa bağlı: 0,50 dolulukta üç ayrı uzayda 0,386128 / 0,385317 / 0,384476 çıktı, ölçülen/beklenen her satırda 0,98–1,01 arasında.
- Sayaç tabanlı üretim çakışmayı sıfırlıyor ama sıralı tahminde isabet başına 1,0 tahmin bırakıyor; kazandığı şey tepede saniyede 0,0022 depo dokunuşudur, bu yüzden elendi.
- Tek parça arızası isteklerin 0,0250’sini düşürüyor, G3’ün 21,9 dakikalık bütçesi 876,0 dakikalık parça kesintisine denk geliyor; feda edilen, kenardaki 300 saniyelik bayatlık penceresidir.
Sonraki Adım
Bu vakada okuma yazmayı yüz katı geçiyordu ve okumanın yanıtı tek bir kayıttı: anahtar verilir, hedef döner. Önbellek kararı bu yüzden basit kaldı ve yönlendirme yolunda hiçbir birleştirme yapılmadı. Sonraki vakada okuma oranı benzer kalır ama yanıt değişir: tek kayıt değil, çok sayıda kaynaktan derlenmiş sıralı bir liste istenir. Soru o zaman “kaydı nerede önbelleğe alayım” olmaktan çıkar ve şuna döner: liste ne zaman derlenir — yazma anında herkesin kutusuna dağıtılarak mı, okuma anında toplanarak mı? İki seçeneğin iş miktarı aynı akış için çok farklıdır ve fark kullanıcı başına değil, takipçi dağılımının ucuna göre belirlenir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.