İçeriğe geç
academia.sh

Ders 03 / 13

İşlevsel ve İşlevsel Olmayan Gereksinimler

İki gereksinim türünün ayrı belirleyici olduğunun gösterilmesi: işlevsel listenin hangi tür bileşenin gerektiğini, eşiklerin aynı işin kaç parçaya bölüneceğini belirlemesi, tek tek oynatılan eşiklerin bileşen sayısında ürettiği değişim ve bir eşiğin tasarımı küçültebilmesi.

İçindekiler

Önceki ders soruları dört aileye ayırdı ve iki ailenin farklı şeyler sorduğunu işaretledi: aktör ve akış soruları sistemin ne yapacağını, eşik soruları bunu hangi sınır içinde yapacağını. İki yanıt kümesi birbirinden bağımsız değişebiliyorsa iki ayrı belirleyicidir.

Bu ders o bağımsızlığı gösterir. İşlevsel gereksinim listesi hangi türden bileşenin bulunması gerektiğini söyler; eşikler aynı işin kaç parçaya bölüneceğini söyler. İkisi ayrı ayrı oynatıldığında tasarımda farklı şeyler değişir ve bu fark sayılabilir.

İki Belirleyici

İşlevsel gereksinim (functional requirement) sistemin ne yaptığını söyler ve doğru ya da yanlış biçiminde yanıtlanır: takip numarasıyla durum döndürülür, aynı olayın ikinci kez gelmesi yutulur. Kalite ve Test Temelleri kursunun Kalite Nitelikleri dersi aynı kavramı “işlevsel beklenti” adıyla kurmuştu; burada katalog biçimi olan işlevsel gereksinim kullanılır, kastedilen aynı şeydir.

İşlevsel olmayan gereksinim (non-functional requirement) sistemin bu işi hangi sınır içinde yaptığını söyler ve dereceli yanıtlanır. Aynı derste kurulan kalite niteliği ve nitelik senaryosu kavramları burada yeniden tanımlanmaz; işlevsel olmayan gereksinim, bir kalite niteliğine eşik koyan nitelik senaryosunun yazılı hâlidir.

Ayrımın sınavı şudur: bir gereksinim tek bir girdi–çıktı çiftiyle sınanabiliyorsa işlevseldir. Sınanması için bir yük, bir ortam ve bir eşik gerekiyorsa işlevsel değildir.

Eşiğin Sınıfı Yoktur, Kaynağı Vardır

İlk ders sayıları üç sınıfa ayırdı: varsayım, hesap, ölçüm. Eşik bu üçünden hiçbiri değildir ve bu kasıtlıdır. Varsayım dünya hakkında bir tahmindir, hesap varsayımlardan çıkar, ölçüm bir düzenekten çıkar; üçü de bir olguyu bildirir. Eşik ise bir olguyu değil bir kabulü bildirir: hangi değerin yeterli sayıldığını.

Bu yüzden eşiğin yanına sınıf değil kaynak yazılır: eşik hangi beklentiden geliyor. “Takip yanıtı 200 milisaniyeyi geçmez” eşiğinin kaynağı alıcının takip sayfasından beklediği yanıttır; “olay kaybı sıfırdır” eşiğinin kaynağı taşıyıcı sözleşmesindeki teslim yükümlülüğüdür. Kaynağı yazılmayan eşik tartışılamaz, çünkü kimin adına konduğu bilinmez.

Bir işlevsel olmayan gereksinim tam olarak şu biçimde yazılır — dört parça nitelik senaryosundan, beşinci satır bu kursun eklediği kaynak alanıdır:

  • Uyaran: alıcı takip numarasıyla gönderisinin durumunu sorar.
  • Ortam: sistem tepe yükünde çalışmaktadır.
  • Yanıt: gönderinin son durumu, bölgesi ve güncellenme zamanı döner.
  • Yanıt ölçütü: yanıt süresinin ortancası 200 milisaniyeyi geçmez.
  • Eşiğin kaynağı: alıcının takip sayfasından beklediği yanıt.

İkinci parça şimdilik boştur. “Tepe yükünde” bir sayı değildir ve bu senaryo ölçülemez durumdadır; ortamın sayıya çevrilmesi sonraki dersin işidir.

Aynı İşlev, İki Eşik Kümesi

Bağımsızlığı göstermenin yolu bir tarafı sabit tutup öteki tarafı oynatmaktır. Altı işlevsel gereksinim sabit tutulur, iki ayrı eşik kümesi denenir.

Eşikten bileşene geçiş bir kural kümesiyle yapılır. Bu kurallar bir modeldir, evrensel bir türetme değil: her kural bir eşik koşulunu bir bileşen değişikliğine bağlar ve gerekçesi yanında durur. Kuralların dördüncüsü öteki üçünün tersine çalışır ve bileşen çıkarır.

// tasarim/gereksinim.mjs — islevsel liste, esik kumeleri ve ikisinden bilesen listesi ureten model
export const ISLEV = [
  { no: "I1", akis: "okuma", islem: "takipNo ile gonderinin durumunu dondur" },
  { no: "I2", akis: "okuma", islem: "gonderinin rota gecmisini dondur" },
  { no: "I3", akis: "yazma", islem: "tasiyicidan gelen durum olayini kaydet" },
  { no: "I4", akis: "yazma", islem: "ayni olayin ikinci kez gelmesini yut" },
  { no: "I5", akis: "toplu", islem: "saticinin gununu tara ve ucret uret" },
  { no: "I6", akis: "toplu", islem: "ucret raporunu dosya olarak teslim et" },
];

export const ESIK = {
  gevsek: { okumaMs: 900, olayKaybi: 0.01, topluSaat: 12, ucretMs: 40 },
  siki: { okumaMs: 200, olayKaybi: 0, topluSaat: 4, ucretMs: 1 },
};

export const KAYNAK = {
  okumaMs: "alicinin takip sayfasindan bekledigi yanit",
  olayKaybi: "tasiyici sozlesmesindeki teslim yukumlulugu",
  topluSaat: "saticinin raporu sabah istemesi",
  ucretMs: "taramanin gonderi basina harcayabildigi sure",
};

// Islevsel liste hangi turden bilesenin bulunmasi gerektigini belirler.
export function taban(islevler) {
  const b = new Set(["servis", "gonderi-deposu"]);
  if (islevler.some((i) => i.islem.includes("ucret"))) b.add("tarife-servisi");
  return b;
}

// Esikler ayni isin kac parcaya bolunecegini belirler.
export const KURAL = [
  { ad: "okuma esigi 300 ms altinda", kosul: (e) => e.okumaMs <= 300,
    ekle: ["takip-ucu", "olay-alici"], cikar: ["servis"] },
  { ad: "olay kaybi tolere edilmiyor", kosul: (e) => e.olayKaybi === 0,
    ekle: ["olay-kuyrugu"], cikar: [] },
  { ad: "toplu pencere 6 saatin altinda", kosul: (e) => e.topluSaat < 6,
    ekle: ["toplu-isci"], cikar: [] },
  { ad: "ucret cagrisi 1 ms altinda", kosul: (e) => e.ucretMs <= 1,
    ekle: [], cikar: ["tarife-servisi"] },
];

export function tasarim(islevler, esik) {
  const bilesen = taban(islevler);
  const isleyen = [];
  for (const k of KURAL) {
    if (k.kosul(esik) === false) continue;
    for (const b of k.cikar) bilesen.delete(b);
    for (const b of k.ekle) bilesen.add(b);
    isleyen.push(k.ad);
  }
  return { bilesen: [...bilesen].sort(), isleyen };
}
// tasarim/turet.mjs — ayni islevsel liste iki esik kumesiyle iki ayri tasarim veriyor
import { ESIK, ISLEV, KAYNAK, KURAL, tasarim } from "./gereksinim.mjs";

const sayim = (a) => ISLEV.filter((i) => i.akis === a).length;
console.log(`islevsel gereksinim = ${ISLEV.length} (okuma ${sayim("okuma")}, yazma ${sayim("yazma")}, toplu ${sayim("toplu")})`);
console.log(`${"esik".padEnd(11)}${"gevsek".padStart(7)}${"siki".padStart(6)}  esigin kaynagi`);
for (const a of Object.keys(KAYNAK)) {
  console.log(`${a.padEnd(11)}${String(ESIK.gevsek[a]).padStart(7)}${String(ESIK.siki[a]).padStart(6)}  ${KAYNAK[a]}`);
}

for (const [ad, esik] of Object.entries(ESIK)) {
  const t = tasarim(ISLEV, esik);
  console.log(`\n${ad}: isleyen kural ${t.isleyen.length}/${KURAL.length}, bilesen ${t.bilesen.length}`);
  console.log(`  ${t.bilesen.join(", ")}`);
}
islevsel gereksinim = 6 (okuma 2, yazma 2, toplu 2)
esik        gevsek  siki  esigin kaynagi
okumaMs        900   200  alicinin takip sayfasindan bekledigi yanit
olayKaybi     0.01     0  tasiyici sozlesmesindeki teslim yukumlulugu
topluSaat       12     4  saticinin raporu sabah istemesi
ucretMs         40     1  taramanin gonderi basina harcayabildigi sure

gevsek: isleyen kural 0/4, bilesen 3
  gonderi-deposu, servis, tarife-servisi

siki: isleyen kural 4/4, bilesen 5
  gonderi-deposu, olay-alici, olay-kuyrugu, takip-ucu, toplu-isci

Altı işlevsel gereksinim iki koşumda da aynı. Gevşek eşiklerle hiçbir kural işlemiyor ve tasarım üç bileşende kalıyor; sıkı eşiklerle dört kural işliyor ve tasarım beş bileşene çıkıyor. Bir tasarımın “üç bileşenli” ya da “beş bileşenli” olması bu yüzden işlevsel listeden okunamaz.

Beş bileşenin bileşimi de dikkat çekiyor: servis ve tarife-servisi listede yok, yerlerine takip-ucu, olay-alici, olay-kuyrugu ve toplu-isci var. Dördüncü kural bir bileşen çıkardığı için sıkılaşma bileşen sayısını tek yönde artırmıyor. Olay kuyruğunun bir bileşen olarak görünmesi, eşzamansız teslim mekaniğinin burada anlatıldığı anlamına gelmez; mesaj kuyruğu Eşzamansız İşleme kursunda kuruldu ve burada yalnız bir bileşen olarak sayılıyor.

Bağımsızlığın İki Yönü

Bağımsızlık iki yönlü olmalıdır: işlevsel listeye ekleme yapıldığında eşikler yerinde kalmalı, eşik oynatıldığında işlevsel liste yerinde kalmalı. İkinci betik ikisini de sınar.

// tasarim/bagimsizlik.mjs — islevsel listeyi ve esikleri tek tek oynatip bilesen sayisindaki degisimi olcer
import { ESIK, ISLEV, tasarim } from "./gereksinim.mjs";

const temel = tasarim(ISLEV, ESIK.gevsek);
console.log(`baslangic: islev ${ISLEV.length}, esik gevsek, bilesen ${temel.bilesen.length}`);

const I7 = { no: "I7", akis: "okuma", islem: "gonderinin tahmini teslim gununu dondur" };
const genis = tasarim([...ISLEV, I7], ESIK.gevsek);
console.log(`islev eklendi (${I7.no}): islev ${ISLEV.length + 1}, bilesen ${genis.bilesen.length}, ` +
  `degisim ${genis.bilesen.length - temel.bilesen.length}`);

console.log(`\n${"tek esik degisimi".padEnd(26)}${"bilesen".padStart(8)}${"degisim".padStart(8)}  cikan/giren`);
for (const a of Object.keys(ESIK.gevsek)) {
  const t = tasarim(ISLEV, { ...ESIK.gevsek, [a]: ESIK.siki[a] });
  const cikan = temel.bilesen.filter((b) => t.bilesen.includes(b) === false);
  const giren = t.bilesen.filter((b) => temel.bilesen.includes(b) === false);
  const not = [cikan.length ? `-${cikan.join(" -")}` : "", giren.length ? `+${giren.join(" +")}` : ""].filter(Boolean).join(" ");
  console.log(`${`${a} ${ESIK.gevsek[a]} -> ${ESIK.siki[a]}`.padEnd(26)}${String(t.bilesen.length).padStart(8)}` +
    `${String(t.bilesen.length - temel.bilesen.length).padStart(8)}  ${not}`);
}
baslangic: islev 6, esik gevsek, bilesen 3
islev eklendi (I7): islev 7, bilesen 3, degisim 0

tek esik degisimi          bilesen degisim  cikan/giren
okumaMs 900 -> 200               4       1  -servis +olay-alici +takip-ucu
olayKaybi 0.01 -> 0              4       1  +olay-kuyrugu
topluSaat 12 -> 4                4       1  +toplu-isci
ucretMs 40 -> 1                  2      -1  -tarife-servisi

İlk iki satır bir yönü veriyor: yedinci işlevsel gereksinim eklendiğinde bileşen sayısı 3’te kalıyor, değişim 0. Yeni işlev var olan okuma akışının içine düşüyor ve bileşen listesini oynatmıyor. İşlevsel liste büyüdükçe tasarımın büyüdüğü sezgisi bu satırla yanlışlanıyor.

Tablo öteki yönü veriyor. Dört eşiğin her biri tek başına oynatıldığında işlevsel liste altı maddede kalmasına karşın bileşen sayısı değişiyor: üç eşik onu 3’ten 4’e çıkarıyor, biri 3’ten 2’ye indiriyor. Son satır en öğretici olanıdır. Ücret çağrısının bütçesi 40 milisaniyeden 1 milisaniyeye çekildiğinde tarife servisi ayrı bir bileşen olarak kalamıyor, çünkü ayrı bileşen olmanın bedeli bir ağ adımıdır ve o adım bütçeye sığmıyor. Sıkı eşik her zaman daha çok parça istemez; bazen tersini ister.

Üçüncü satırdaki çıkan ve giren bileşenler ayrımı da bilgi taşıyor. Okuma eşiği sıkılaştığında servis çıkıp yerine iki bileşen giriyor, yani bu bir ekleme değil bir bölmedir. Öteki iki eşik yalnız ekleme yapıyor. Bir tasarım değişikliğinin bölme mi ekleme mi olduğu, sözleşme yüzeyine etkisini belirler: bölme var olan bir sınırı ikiye ayırır, ekleme yeni bir sınır getirir.

Özet

  • İşlevsel gereksinim sistemin ne yaptığını söyler ve tek bir girdi–çıktı çiftiyle sınanır; işlevsel olmayan gereksinim hangi sınır içinde yaptığını söyler ve yük, ortam ve eşik ister.
  • Eşiğin varsayım, hesap ya da ölçüm sınıfı yoktur; eşik bir kabuldür ve yanına sınıf değil kaynak yazılır — hangi beklentiden geldiği.
  • İşlevsel olmayan gereksinim nitelik senaryosunun dört parçasıyla ve eşiğin kaynağıyla yazılır; örnek senaryonun ortam parçası hâlâ sayısızdır.
  • Aynı altı işlevsel gereksinim gevşek eşiklerle 3, sıkı eşiklerle 5 bileşen verdi; bileşen sayısı işlevsel listeden okunamaz.
  • Yedinci işlevsel gereksinim bileşen sayısını değiştirmedi (değişim 0); dört eşiğin her biri tek başına değiştirdi (üçü +1, biri −1).
  • Sıkı eşik her zaman daha çok bileşen istemez: ücret çağrısı bütçesi 1 milisaniyeye çekildiğinde tarife servisi ayrı bileşen olmaktan çıktı.

Sonraki Adım

Nitelik senaryosunun dört parçasından üçü yazıldı, biri boş kaldı: ortam. “Tepe yükünde çalışmaktadır” cümlesi eşiği ölçülemez bırakıyor, çünkü tepe yükün kaç istek olduğu yazılmadı. Aynı boşluk eşiklerin kendisinde de var — 200 milisaniyenin karşılanabilir olup olmadığı, saniyede kaç isteğin geldiği bilinmeden söylenemez. Sonraki ders bu boşluğu doldurur: önceki derste altı varsayıma dönüşen altı yanıtsız soru bir varsayım tablosunda toplanır ve tablodan istek hızı, veri artışı ve bant genişliği ihtiyacı aritmetikle çıkarılır.

İ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