Ders 03 / 12
Kalite Nitelikleri
İşlevsel beklentiler ile kalite niteliklerinin ayrılması, nitelik ailelerinin sınıflandırılması ve ölçülemez bir beklentinin uyaran-ortam-yanıt-ölçüt biçiminde ölçülebilir bir ölçüte çevrilmesi.
İçindekiler
Önceki ders ücret hesabının doğru sonucu vermesini konu aldı. Doğru sonuç, beklentilerin yalnız bir bölümüdür. Kitaplık doğru ücreti hesaplayıp da raporu dakikalarca ürettiğinde, bir üyenin borcunu başka bir üyeye gösterdiğinde ya da bozuk tek bir kayıt yüzünden hiç çalışmadığında kullanılamaz. Bu beklentiler belirtimde çoğu zaman yazılı değildir; yazılı olduklarında da “hızlı olsun”, “sağlam olsun” gibi sınanamaz cümlelerle geçer.
Bu ders o cümleleri adlandırır ve sınanabilir hâle getirir. Sınanabilir olmanın ölçütü tektir: bir beklenti, geçip geçmediğine bakılabilen bir ölçüte çevrilebiliyorsa sınanabilir.
İşlevsel Beklenti ve Kalite Niteliği
İşlevsel beklenti (functional requirement) sistemin ne yaptığını söyler: dört gün geciken kitaptan 2 birim ücret alınır, bilinmeyen üye türü reddedilir. Doğru ya da yanlış biçiminde yanıtlanır; ara değeri yoktur.
Kalite niteliği (quality attribute) sistemin o işi nasıl yaptığını söyler: ne kadar hızlı, ne kadar dayanıklı, ne kadar güvenli, ne kadar değiştirilebilir. Yanıtı derecelidir ve bir eşikle birlikte anlam kazanır. Bu yüzden nitelikler için doğruluk değil, bütçe konuşulur.
Ayrım tek başına bir sınıflandırma alıştırması değildir; iki beklenti türü farklı biçimde sınanır. İşlevsel beklenti tek bir girdi–çıktı çiftiyle sınanabilir. Nitelik ise ancak bir ölçüm düzeneği, bir yük ve bir eşikle sınanır.
Nitelik Aileleri
Nitelikler adlandırılmadığında konuşulamaz. Sık kullanılan aileler ve kitaplık bağlamındaki karşılıkları şunlardır:
| Nitelik ailesi | İngilizce | Kitaplıktaki sorusu |
|---|---|---|
| işlevsel uygunluk | functional suitability | Ücret hesabı kurala uyuyor mu? |
| başarım verimliliği | performance efficiency | Rapor ne kadar sürede çıkıyor? |
| güvenilirlik | reliability | Bozuk kayıt geldiğinde ne oluyor? |
| kullanılabilirlik | usability | Görevli borcu kaç adımda görüyor? |
| güvenlik | security | Bir üyenin borcu başkasına görünüyor mu? |
| sürdürülebilirlik | maintainability | Ücret kuralı kaç yerden değişiyor? |
| taşınabilirlik | portability | Başka bir çalışma zamanında kuruluyor mu? |
| uyumluluk | compatibility | Eski kayıt biçimi okunabiliyor mu? |
Liste kapalı değildir; her alanın kendi ekleri olur. Önemli olan, bir beklentinin hangi aileye girdiğinin sorulmasıdır — çünkü aile, ölçünün nasıl kurulacağını belirler.
Ölçülemez Beklentiyi Ölçüte Çevirmek
“Rapor hızlı olsun” cümlesi sınanamaz, çünkü ne kadar hızlı, hangi yükte, hangi ortamda sorularının yanıtı yoktur. Bu boşluğu dolduran biçim dört parçalıdır ve nitelik senaryosu (quality attribute scenario) olarak bilinir:
- Uyaran (stimulus): görevli borçlu üye raporunu ister.
- Ortam (environment): kitaplıkta 8.000 üye ve 80.000 ödünç kaydı vardır, sistem olağan yükte çalışmaktadır.
- Yanıt (response): rapor her üyenin toplam gecikme borcunu üretir.
- Yanıt ölçütü (response measure): beş koşunun ortancası 100 milisaniyeyi geçmez.
Dördüncü parça beklentiyi sınanabilir kılan parçadır. Frontend Kalitesi kursundaki Başarım Bütçesi dersinde kurulan bütçe düşüncesi burada alan bağımsız hâliyle kullanılır: ölçüt bir sayı, bir yük ve bir ölçüm yöntemiyle birlikte yazılır.
Ölçütü Ölçmek
Ölçüt yazıldıysa ölçülebilir. Rapor iki biçimde yazılır: her üye için bütün ödünç kayıtlarını tarayan sürüm ve kayıtları bir kez gezip üye numarasına göre toplayan sürüm.
// rapor.mjs — borclu uye raporunun iki uygulamasi export function veriUret(uyeSayisi, oduncSayisi) { const uyeler = Array.from({ length: uyeSayisi }, (_, i) => ({ no: i, tur: i % 3 === 0 ? 'ogrenci' : 'uye' })); const oduncler = Array.from({ length: oduncSayisi }, (_, i) => ({ uyeNo: (i * 7919) % uyeSayisi, gecikmeGun: i % 47, })); return { uyeler, oduncler }; } function ucret(gecikmeGun) { return Math.min(Math.max(gecikmeGun - 3, 0) * 2, 20); } export function raporTaramali(uyeler, oduncler) { return uyeler.map((u) => { let borc = 0; for (const o of oduncler) if (o.uyeNo === u.no) borc += ucret(o.gecikmeGun); return { no: u.no, borc }; }); } export function raporDizinli(uyeler, oduncler) { const borclar = new Map(); for (const o of oduncler) borclar.set(o.uyeNo, (borclar.get(o.uyeNo) ?? 0) + ucret(o.gecikmeGun)); return uyeler.map((u) => ({ no: u.no, borc: borclar.get(u.no) ?? 0 })); }
İki sürüm de aynı işlevsel gereksinimi karşılar; ürettikleri rapor birebir aynıdır. Ayrıldıkları yer nitelik ölçütüdür.
// olcum.mjs — yanit suresi olcutunun olculmesi import { veriUret, raporTaramali, raporDizinli } from './rapor.mjs'; const BUTCE_MS = 100; const { uyeler, oduncler } = veriUret(8000, 80000); function ortancaSure(islev, kosu = 5) { const sureler = []; for (let i = 0; i < kosu; i += 1) { const bas = performance.now(); islev(uyeler, oduncler); sureler.push(performance.now() - bas); } sureler.sort((a, b) => a - b); return sureler[Math.floor(kosu / 2)]; } for (const [ad, islev] of [['taramali', raporTaramali], ['dizinli', raporDizinli]]) { const ortanca = ortancaSure(islev); const yargi = ortanca < BUTCE_MS ? 'gecti' : 'kaldi'; console.log(`${ad.padEnd(9)}: ${BUTCE_MS} ms butcesi — ${yargi}`); }
taramali : 100 ms butcesi — kaldi dizinli : 100 ms butcesi — gecti
Çıktı ham süreyi değil yargıyı yazar; ham süre makineye bağlıdır ve bir dersten diğerine taşınamaz. Bu metni hazırlarken kullanılan makinede tarama sürümünün ortancası 548,6 ms, dizinli sürümünkü 2,7 ms ölçüldü — iki sayı da çalıştırıldığı donanıma ve çalışma zamanı sürümüne göre değişir. Değişmeyen şey, ölçütün iki sürümü ayırmasıdır: bütçe belirlendikten sonra “hızlı mı” sorusunun yanıtı tartışma konusu olmaktan çıkar.
Ölçümün tek koşuya değil beş koşunun ortancasına dayanması bilinçlidir. İlk koşu çalışma zamanının ısınma etkisini taşır; ortanca bu sıçramayı dışarıda bırakır.
İkinci Bir Nitelik: Güvenilirlik
Başarım tek nitelik değildir ve her nitelik kendi ölçüsünü ister. Güvenilirlik senaryosu şöyle yazılır: kayıtların bir bölümü bozuk geldiğinde rapor durmaz, bozuk kaydı atlar ve atlanan oranı bildirir; oran yüzde beşi aşarsa rapor geçersiz sayılır.
// dayaniklilik.mjs — guvenilirlik olcutunun olculmesi import { veriUret } from './rapor.mjs'; const ESIK = 0.05; const { oduncler } = veriUret(8000, 80000); for (let i = 0; i < oduncler.length; i += 33) oduncler[i].gecikmeGun = -1; let islenen = 0; let atlanan = 0; for (const o of oduncler) { if (!Number.isInteger(o.gecikmeGun) || o.gecikmeGun < 0) atlanan += 1; else islenen += 1; } const oran = atlanan / oduncler.length; console.log(`islenen kayit: ${islenen}`); console.log(`atlanan kayit: ${atlanan}`); console.log(`atlanan orani: ${(oran * 100).toFixed(2)} (esik ${ESIK * 100})`); console.log(`rapor durumu : ${oran <= ESIK ? 'gecerli' : 'gecersiz'}`);
islenen kayit: 77575 atlanan kayit: 2425 atlanan orani: 3.03 (esik 5) rapor durumu : gecerli
Bu ölçüm süre içermediği için her makinede aynı sonucu verir. Nitelik ölçütlerinin hepsi zamana bağlı değildir: oran, sayı, boyut ve adım sayısı da ölçüttür ve belirlenimci oldukları için sınanmaları daha ucuzdur.
Nitelikler Birbiriyle Yarışır
Dizinli sürüm süreyi kısalttı, ama bunu üye sayısı kadar girdi tutan bir eşleme kurarak yaptı. Bellek tüketimi arttı. Bozuk kayıtları atlayan sürüm raporu ayakta tuttu, ama sessizce eksik bir toplam üretti; doğruluk pahasına süreklilik satın alındı.
Bu genel bir durumdur: nitelikler birbirinden bağımsız artırılamaz. Başarım ile bellek, güvenlik ile kullanılabilirlik, esneklik ile yalınlık çoğu zaman ters yönde çeker. Bu yüzden nitelik kararları ödünleşimdir (trade-off) ve gerekçesiyle birlikte yazılmalıdır: hangi nitelik hangi nitelik uğruna ne kadar bırakıldı? Bütçe yazmanın asıl işlevi burada görünür. Bütçe, ödünleşimi bir kez tartışıp karara bağlar; sonraki her ölçüm o karara karşı yapılır.
Özet
- İşlevsel beklenti sistemin ne yaptığını, kalite niteliği bunu nasıl yaptığını söyler; birincisi doğru-yanlış, ikincisi dereceli yanıtlanır.
- Bir nitelik beklentisi uyaran, ortam, yanıt ve yanıt ölçütü olarak yazıldığında sınanabilir hâle gelir; ölçütü olmayan beklenti sınanamaz.
- Aynı işlevi karşılayan iki uygulama aynı bütçeye karşı farklı sonuç verebilir; örnekte tarama sürümü 100 ms bütçesinde kaldı, dizinli sürüm geçti.
- Ölçüm süre içeriyorsa çıktıya ham süre değil yargı yazılır; ham süre makineye bağlıdır.
- Oran, sayı ve boyut ölçütleri belirlenimcidir ve süre ölçütlerinden ucuza sınanır.
- Nitelikler birbiriyle yarışır; bütçe, ödünleşimi bir kez karara bağlayıp sonraki ölçümlere ortak ölçüt verir.
Sonraki Adım
İki derste de kusur, birinin onu araması sayesinde ortaya çıktı: gişe kayıtları karşılaştırıldığı için, bütçe ölçüldüğü için. Kimse o karşılaştırmayı yapmasaydı iki kusur da görünmeyecekti. Buradan bir soru doğar — kusuru arayan kişi neyi farklı yapar? Sonraki ders testin bir teknikler kümesi olmadan önce bir tutum olduğunu ele alır: programın çalıştığını göstermeye çalışan bakış ile kırıldığı yeri arayan bakış aynı koda bakıp farklı şeyler bulur.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.