---
title: 'Geliştirici Portalı ve Servis Kataloğu'
source: 'https://academia.sh/tr/kurslar/platform-muhendisligi/gelistirici-portali-ve-servis-katalogu'
course: 'Platform Mühendisliği'
language: tr
updated: '2026-08-17T18:09:09+00:00'
license: 'CC BY-SA 4.0'
---

# Geliştirici Portalı ve Servis Kataloğu

On iki katalog kaydından sahiplik ve bağımlılık grafiği kurulur; sahipsiz servis, öksüz bağımlılık ve kayıtlı olmayan servis sayılır. Beş olayda doğru nöbet listesine ulaşma süresi katalogla ve katalogsuz ölçülür, sonra kaydın kendi bedeli çıkarılır: kaç alan elle yazılıyor ve kaç kayıt gerçekle uyuşmuyor.

Önceki ders beş servisi gerçek dosyalarla üretti; her birinin tanımında bir sahip satırı var. O satır
yazıldığı gün doğruydu. Gece yarısı fatura hesaplayıcı durduğunda arayan kişinin sorduğu üç soru ise
başkadır: bu servisin nöbetçisi kim, bu servis neye bağlı, ve bu servis durursa kim etkilenir. Üçüncü
sorunun cevabı hiçbir servisin kendi dosyasında yazılı değildir, çünkü ters kenarı kimse kendi deposunda
tutmaz.

**Servis kataloğu**, çalışan servislerin sahiplik ve bağımlılık kayıtlarını tek yerde tutan listedir;
**geliştirici portalı** o listeyi sorulabilir hâle getiren yüzeydir. Bu dersin ölçtüğü şey portalın
görünüşü değil, kataloğun cevapladığı sorular ve **cevabın ne kadar doğru olduğudur**.

Ölçüm **bölgesel ölçüm ağı** üzerindedir: su sayacı okumalarını toplayan, doğrulayan ve saha iş emri
açan **kurgu** yazılım. Katalog kayıtları ve yer gerçeği `node` ile yazılmış bir **modeldir**.

**PT13.** Katalog on iki kayıt tutar. Kayıt beş alanlıdır: ad, sahip ekip, nöbet listesi, bağımlılık
listesi, son elle güncellemeden bu yana geçen gün.
**PT14.** Yer gerçeği son doksan günün koşum kayıtlarından çıkarılır — gözlenen çağrı kenarları ve hattı
koşturan ekip — ve modelde ayrı bir yapı olarak durur.
**PT15.** Kişi adı geçmez; ulaşılan şey bir **nöbet listesidir**.
**PT16.** Beş olay ve her adımın dakikası **önceden yazılıdır**, rastgelelik yoktur.
**PT17.** Sahip alanı iskeletin ürettiği servis tanımından okunabilir; nöbet listesi ile bağımlılık
listesi elle yazılır.
**PT18.** **Sahipsiz servis**, sahip alanı boş olan ya da var olmayan bir ekibi gösteren kayıttır.
**Öksüz bağımlılık**, katalogda kaydı olmayan bir servise bağlanan kenardır.

## Kayıttan Grafiğe

Katalog düz bir listedir; sorulabilir olan şey listenin kendisi değil, ondan kurulan grafiktir. Her kayıt
bir düğüm, her bağımlılık bir kenar verir; sahiplik alanı düğümü bir ekibe bağlar. Grafiğin değeri iki
yerden gelir: kenarın **ters yönü** ve kayıtla gerçeğin **farkı**. İkisi de tek tek kayıtlara bakarak
görülemez.

```js
// katalog.mjs — servis katalogu kayitlari ve kosumdan cikarilan yer gercegi. Model, elle yazildi.
// kayit: [ad, sahip ekip, nobet listesi, bagimliliklar, son elle guncellemenin uzerinden gecen gun]
export const KAYIT = [
  ["okuma-toplayici", "sayac-okuma", "nobet-sayac", ["olcum-deposu", "kimlik-ucu"], 9],
  ["okuma-cozumleyici", "sayac-okuma", "nobet-sayac", ["okuma-toplayici"], 21],
  ["dogrulama-akisi", "dogrulama", "nobet-dogrulama", ["okuma-toplayici", "kural-deposu"], 14],
  ["kural-deposu", "dogrulama", "nobet-dogrulama", [], 27],
  ["fatura-hesaplayici", "faturalama", "nobet-fatura", ["dogrulama-akisi", "tarife-servisi"], 24],
  ["tarife-servisi", "faturalama", "nobet-fatura", [], 210],
  ["fatura-yazici", "faturalama", "nobet-fatura", ["fatura-hesaplayici"], 33],
  ["saha-emir", "saha", "nobet-saha", ["dogrulama-akisi", "harita-ucu"], 150],
  ["harita-ucu", "", "", [], 260],
  ["rapor-derleyici", "raporlama", "nobet-rapor",
    ["olcum-deposu", "arsiv-deposu", "fatura-yazici"], 120],
  ["gosterge-ucu", "raporlama", "nobet-rapor", ["rapor-derleyici"], 19],
  ["olcum-deposu", "dagitilmis-ekip", "nobet-eski", [], 180]];

export const GERCEK_BAG = {                         // son doksan gunde gozlenen cagri kenarlari
  "okuma-toplayici": ["olcum-deposu", "kimlik-ucu"], "okuma-cozumleyici": ["okuma-toplayici"],
  "dogrulama-akisi": ["okuma-toplayici", "kural-deposu"], "kural-deposu": [],
  "fatura-hesaplayici": ["dogrulama-akisi", "tarife-servisi", "kimlik-ucu"], "tarife-servisi": [],
  "fatura-yazici": ["fatura-hesaplayici"], "saha-emir": ["dogrulama-akisi"],
  "harita-ucu": ["kimlik-ucu"], "rapor-derleyici": ["olcum-deposu", "fatura-yazici"],
  "gosterge-ucu": ["rapor-derleyici"], "olcum-deposu": [], "kimlik-ucu": [] };

export const GERCEK_SAHIP = {                       // son doksan gunde hatti kosturan ekip
  "okuma-toplayici": "sayac-okuma", "okuma-cozumleyici": "sayac-okuma",
  "dogrulama-akisi": "dogrulama", "kural-deposu": "dogrulama", "fatura-hesaplayici": "faturalama",
  "tarife-servisi": "raporlama", "fatura-yazici": "faturalama", "saha-emir": "saha",
  "harita-ucu": "saha", "rapor-derleyici": "raporlama", "gosterge-ucu": "raporlama",
  "olcum-deposu": "sayac-okuma", "kimlik-ucu": "dogrulama" };

export const COK_EKIP = ["olcum-deposu", "harita-ucu"];   // birden cok ekibin dokundugu servis
export const EKIP = ["sayac-okuma", "dogrulama", "faturalama", "saha", "raporlama"];
```

```js
// graf.mjs — katalog kayitlarindan sahiplik ve bagimlilik grafigi kurulur, gercekle karsilastirilir.
import { KAYIT, GERCEK_BAG, GERCEK_SAHIP, EKIP } from "./katalog.mjs";

const kayitli = new Set(KAYIT.map((k) => k[0]));
const ters = {};                                    // kim bana bagli: ters kenari katalog kuruyor
for (const [ad, , , bag] of KAYIT) for (const b of bag) (ters[b] ??= []).push(ad);

const kayitsiz = Object.keys(GERCEK_BAG).filter((s) => !kayitli.has(s));
const sahipsiz = KAYIT.filter(([, s]) => !s || !EKIP.includes(s));
const oksuz = KAYIT.flatMap(([ad, , , bag]) => bag.filter((b) => !kayitli.has(b)).map((b) => [ad, b]));
console.log(`katalog ${KAYIT.length} kayit, ${KAYIT.reduce((a, k) => a + k[3].length, 0)} bagimlilik` +
  ` kenari, ${Object.keys(ters).length} servis icin ters kenar cikarilabiliyor`);
console.log(`gercekte kosan ama hic kayitli olmayan servis ${kayitsiz.length}: ${kayitsiz.join(", ")}`);
console.log(`sahipsiz servis ${sahipsiz.length}: ` +
  sahipsiz.map(([a, s]) => `${a} (${s || "alan bos"})`).join(", "));
console.log(`oksuz bagimlilik ${oksuz.length}: ` + oksuz.map(([a, b]) =>
  `${a} -> ${b} [${b in GERCEK_BAG ? "servis var, kayit yok" : "servis yok, kayit eski"}]`).join("; "));
const etkilenenKayitsiz = Object.entries(GERCEK_BAG)
  .filter(([, b]) => b.some((x) => kayitsiz.includes(x))).length;
console.log(`kayitsiz servise gercekte baglanan ${etkilenenKayitsiz} servis var;` +
  ` portalin bu ${etkilenenKayitsiz} servis icin verdigi bagimlilik cevabi eksik`);

let alan = 0, kayitUyusmaz = 0, bagFark = 0, sahipToplam = 0;   // kaydin eskimesi: kayit ile gercek
const yas = { genc: [0, 0], eski: [0, 0] };
for (const [ad, sahip, , bag, gun] of KAYIT) {
  const g = GERCEK_BAG[ad] ?? [];
  const eksik = g.filter((b) => !bag.includes(b)).length;
  const fazla = bag.filter((b) => !g.includes(b)).length;
  const sahipFark = GERCEK_SAHIP[ad] !== sahip ? 1 : 0;
  const fark = eksik + fazla + sahipFark;
  alan += fark; bagFark += eksik + fazla; sahipToplam += sahipFark;
  kayitUyusmaz += fark > 0 ? 1 : 0;
  const kova = gun <= 30 ? "genc" : "eski";
  yas[kova][0]++; yas[kova][1] += fark > 0 ? 1 : 0;
}
const elle = KAYIT.length * 2, uretilen = KAYIT.length * 2;     // nobetci ve bagimlilik elle yazilir
console.log(`\nkayit alani ${elle + uretilen}: ${uretilen} tanesi iskeletin urettigi servis` +
  ` tanimindan okunuyor, ${elle} tanesi (nobet listesi, bagimlilik) elle yaziliyor`);
console.log(`gercekle uyusmayan kayit ${kayitUyusmaz}/${KAYIT.length}, uyusmayan alan ${alan}`);
console.log(`kayit yasi <= 30 gun: ${yas.genc[1]}/${yas.genc[0]} uyusmuyor` +
  `   > 30 gun: ${yas.eski[1]}/${yas.eski[0]} uyusmuyor`);
console.log(`uyusmazligin kaynagi: bagimlilik ${bagFark}, sahiplik ${sahipToplam};` +
  ` ikisi de kosumdan cikarilabilir, nobet listesi cikarilamaz`);

const etkilenen = (s) => {                          // ters kenarda gezinti
  const yigin = [s], sonuc = new Set();
  while (yigin.length) for (const u of ters[yigin.pop()] ?? [])
    if (!sonuc.has(u)) { sonuc.add(u); yigin.push(u); }
  return [...sonuc];
};
console.log(`\n"fatura-hesaplayici durursa kim etkilenir" — katalogla ${etkilenen("fatura-hesaplayici")
  .length} servis (${etkilenen("fatura-hesaplayici").join(", ")}), 1 grafik gezintisi`);
console.log(`ayni soru katalogsuz: ${KAYIT.length} servisin bagimlilik listesi elle taranir,` +
  ` ters kenar hicbir dosyada yazili degil`);
```

```
katalog 12 kayit, 14 bagimlilik kenari, 11 servis icin ters kenar cikarilabiliyor
gercekte kosan ama hic kayitli olmayan servis 1: kimlik-ucu
sahipsiz servis 2: harita-ucu (alan bos), olcum-deposu (dagitilmis-ekip)
oksuz bagimlilik 2: okuma-toplayici -> kimlik-ucu [servis var, kayit yok]; rapor-derleyici -> arsiv-deposu [servis yok, kayit eski]
kayitsiz servise gercekte baglanan 3 servis var; portalin bu 3 servis icin verdigi bagimlilik cevabi eksik

kayit alani 48: 24 tanesi iskeletin urettigi servis tanimindan okunuyor, 24 tanesi (nobet listesi, bagimlilik) elle yaziliyor
gercekle uyusmayan kayit 6/12, uyusmayan alan 7
kayit yasi <= 30 gun: 1/6 uyusmuyor   > 30 gun: 5/6 uyusmuyor
uyusmazligin kaynagi: bagimlilik 4, sahiplik 3; ikisi de kosumdan cikarilabilir, nobet listesi cikarilamaz

"fatura-hesaplayici durursa kim etkilenir" — katalogla 3 servis (fatura-yazici, rapor-derleyici, gosterge-ucu), 1 grafik gezintisi
ayni soru katalogsuz: 12 servisin bagimlilik listesi elle taranir, ters kenar hicbir dosyada yazili degil
```

Grafiğin kurulması üç boşluğu bir arada gösterir. **Sahipsiz servis iki tanedir** ve ikisi farklı
biçimde sahipsizdir: harita ucunun sahip alanı boştur, ölçüm deposunun sahibi ise artık var olmayan bir
ekiptir. İkincisi daha tehlikelidir, çünkü kayıt dolu görünür ve hiçbir boşluk taraması onu yakalamaz.
**Öksüz bağımlılık da iki tanedir** ve nedenleri birbirinin tersidir: kimlik ucu gerçekten koşan ama
katalogda hiç kaydı olmayan bir servistir, arşiv deposu ise kayıtta duran ama gerçekte olmayan bir
servistir. Biri kaydın eksikliğidir, öteki kaydın eskimesi.

Ters kenar kataloğun tek başına verdiği cevaptır. Fatura hesaplayıcı durduğunda etkilenen üç servis
tek bir grafik gezintisiyle çıkar; aynı soruyu katalogsuz cevaplamak on iki servisin bağımlılık
listesini tek tek taramayı gerektirir, çünkü hiçbir servis kendisine kimin bağlı olduğunu bilmez.

## Bir Olayda Doğru Nöbet Listesi

```js
// olay.mjs — bes olayda dogru nobet listesine ulasma suresi: katalogla ve katalogsuz.
import { KAYIT, GERCEK_SAHIP, COK_EKIP } from "./katalog.mjs";

const ADIM = { depo: 6, ilkMesaj: 8, ekipKanali: 15, nobetBul: 12, katalogOku: 2, cagri: 3,
  yanlisListe: 10, gozdenGecirme: 4 };              // dakika, onceden yazili; rastgelelik yok
const OLAY = ["fatura-hesaplayici", "harita-ucu", "tarife-servisi", "saha-emir", "olcum-deposu"];

const katalogsuz = (s) => ADIM.depo + ADIM.ilkMesaj + ADIM.nobetBul +
  (COK_EKIP.includes(s) ? ADIM.ekipKanali : 0);     // depo gecmisi, mesaj, gerekirse ekip kanali
const katalogla = (s) => {
  const k = KAYIT.find(([a]) => a === s);
  if (!k || !k[2]) return [ADIM.katalogOku + katalogsuz(s), k ? "nobet alani bos" : "kayit yok"];
  if (GERCEK_SAHIP[s] !== k[1])
    return [ADIM.katalogOku + ADIM.yanlisListe + katalogsuz(s), "kayit yanlis listeye yonlendirdi"];
  return [ADIM.katalogOku + ADIM.cagri, "kayit guncel"];
};

console.log("olay                 katalogsuz  katalogla  fark  durum");
let a = 0, b = 0, kazanan = 0;
for (const s of OLAY) {
  const x = katalogsuz(s), [y, not] = katalogla(s);
  a += x; b += y; kazanan += y < x ? 1 : 0;
  console.log(`${s.padEnd(20)}${String(x).padStart(8)} dk${String(y).padStart(8)} dk` +
    `${String(y - x).padStart(6)}  ${not}`);
}
const guncel = OLAY.length * (ADIM.katalogOku + ADIM.cagri);
console.log(`toplam ${a} dk -> ${b} dk   ortalama ${(a / OLAY.length).toFixed(1)} dk -> ` +
  `${(b / OLAY.length).toFixed(1)} dk   sureyi kisaltan olay ${kazanan}/${OLAY.length}`);
console.log(`butun kayitlar guncel olsaydi: ${guncel} dk, ortalama ` +
  `${(guncel / OLAY.length).toFixed(1)} dk; su anki kazanc ${a - b} dk, olabilecek ${a - guncel} dk`);

const bakim = KAYIT.length * ADIM.gozdenGecirme;    // aylik gozden gecirme: kayit basina dort dakika
const olayBasi = (a - guncel) / OLAY.length;
console.log(`\naylik gozden gecirme ${bakim} dk (${KAYIT.length} kayit x ${ADIM.gozdenGecirme} dk);` +
  ` guncel kaydin olay basina kazanci ${olayBasi} dk`);
console.log(`esik: ayda ${Math.ceil(bakim / olayBasi)} olaydan sonra gozden gecirme kendini oduyor;` +
  ` ${Math.ceil(bakim / olayBasi) - 1} olayda odemiyor`);
```

```
olay                 katalogsuz  katalogla  fark  durum
fatura-hesaplayici        26 dk       5 dk   -21  kayit guncel
harita-ucu                41 dk      43 dk     2  nobet alani bos
tarife-servisi            26 dk      38 dk    12  kayit yanlis listeye yonlendirdi
saha-emir                 26 dk       5 dk   -21  kayit guncel
olcum-deposu              41 dk      53 dk    12  kayit yanlis listeye yonlendirdi
toplam 160 dk -> 144 dk   ortalama 32.0 dk -> 28.8 dk   sureyi kisaltan olay 2/5
butun kayitlar guncel olsaydi: 25 dk, ortalama 5.0 dk; su anki kazanc 16 dk, olabilecek 135 dk

aylik gozden gecirme 48 dk (12 kayit x 4 dk); guncel kaydin olay basina kazanci 27 dk
esik: ayda 2 olaydan sonra gozden gecirme kendini oduyor; 1 olayda odemiyor
```

Katalogun kazandırdığı yer nettir: kaydı güncel olan iki serviste ulaşma süresi yirmi altı dakikadan
beş dakikaya iner. Kazandırmadığı yer daha öğreticidir. Beş olayın üçünde katalog süreyi **uzatmıştır**.
Nöbet alanı boş olan kayıt iki dakika okuma masrafı ekler ve hiçbir şey söylemez; yanlış sahip yazan iki
kayıt ise on iki dakika ekler, çünkü arayan kişi önce yanlış nöbet listesine yazar, yanıt bekler ve
ancak sonra katalogsuz yola döner. **Yanlış kayıt, kayıtsızlıktan pahalıdır** — kayıtsızlık kimseyi
yanıltmaz.

Toplamda ortalama 32 dakikadan 28,8 dakikaya iner; ölçülen kazanç on altı dakikadır. Bütün kayıtlar
gerçekle uyuşsaydı aynı beş olay yirmi beş dakikada biterdi ve kazanç yüz otuz beş dakika olurdu.
Kataloğun sunduğu değerin **yüzde on ikisi** alınmaktadır ve eksik olan şey portal değil, kaydın
doğruluğudur.

## Kaydın Kendi Bedeli

Kayıt bedeli iki sayıda toplanır. Kırk sekiz kayıt alanının yarısı iskeletin ürettiği servis tanımından
okunur ve bedelsizdir; öteki yarısı — nöbet listesi ve bağımlılık listesi — elle yazılır. Elle yazılan
alan eskir: on iki kaydın altısı gerçekle uyuşmaz ve yedi alan yanlıştır. Eskime yaşla birlikte
gider; otuz günden genç altı kaydın biri, otuz günden eski altı kaydın beşi gerçekle uyuşmamaktadır.

Bakımın hesabı da buradan çıkar. Aylık gözden geçirme kayıt başına dört dakikadan kırk sekiz dakikadır;
güncel kaydın olay başına kazancı yirmi yedi dakikadır. **Eşik ayda iki olaydır**: ayda tek olay yaşayan
bir ağda gözden geçirme kendini ödemez, iki olaydan sonra öder. Ölçüm ağı gibi az sayıda servisin olduğu
bir yerde bu eşik yakındır ve katalog bakımının kâğıt üstünde iyi görünüp pratikte yapılmamasının nedeni
tam olarak budur.

Kataloğun gizlediği katman şudur: her ekip artık öteki ekiplerin depolarını, kanal geçmişini ve dağıtım
kayıtlarını okumak zorunda değildir, tek bir kaydı okur. Sızma da tam bu noktadadır — kayıt tek kaynak
gibi davranır ama tek kaynak değildir, ve sızdığında bunu belli etmez. Dışına çıkanlar sayılıdır:
kayıtsız tek servise gerçekte üç servis bağlanmakta, yani portalın o üç servis için verdiği bağımlılık
cevabı eksik kalmaktadır. Bu üç servisin ekipleri kataloğa bakıp yanlış bir bütünlük görürler; katalogsuz
çalışan bir ekip en azından eksik baktığını bilir.

Üçüncü bir yol daha vardır ve sayıyı temelden değiştirir. Yedi uyuşmazlığın dördü bağımlılık, üçü
sahiplik kaynaklıdır; bağımlılık kenarları koşum kayıtlarından, sahiplik ise hat koşumlarından
çıkarılabilir. İkisi de çıkarılırsa uyuşmazlık sıfırlanır ve elle yazılan alan yirmi dörtten on ikiye
iner. Geriye kalan tek alan **nöbet listesidir** ve o hiçbir koşumdan çıkarılamaz, çünkü nöbet bir
gözlem değil, bir karardır.

## Özet

- On iki kayıttan kurulan grafik üç boşluk gösterdi: 2 sahipsiz servis, 2 öksüz bağımlılık ve gerçekte
  koşup katalogda hiç kaydı olmayan 1 servis.
- İki sahipsizlik ve iki öksüzlük farklı türdendi: biri boş alan, öteki var olmayan ekip; biri kaydın
  eksikliği, öteki kaydın eskimesi.
- Ters kenar kataloğun tek başına verdiği cevaptı: fatura hesaplayıcı durunca etkilenen 3 servis tek
  gezintiyle çıktı, aynı soru katalogsuz 12 bağımlılık listesinin taranmasını gerektirirdi.
- Beş olayda ulaşma süresi ortalama 32 dakikadan 28,8 dakikaya indi, ama 5 olayın 3'ünde katalog süreyi
  uzattı; yanlış kayıt 12 dakika, boş alan 2 dakika ekledi.
- Kayıtlar güncel olsaydı aynı beş olay 25 dakikada biterdi: ölçülen kazanç 16 dakika, olabilecek kazanç
  135 dakika.
- 48 kayıt alanının 24'ü elle yazılıyor ve 6/12 kayıt gerçekle uyuşmuyor; 7 uyuşmazlığın 7'si koşumdan
  çıkarılarak kapanabilir, kapanamayan tek alan nöbet listesidir.

## Sonraki Adım

Katalog kimin sorumlu olduğunu söyler, ama kimsenin uymak zorunda olduğu bir kural koymaz. Ölçüm ağının
kişisel veri taşıyan üç servisi için saklama süresi, kütük maskeleme ve imzalı paket zorunludur; bu
kurallar bugün bir belgede yazılıdır ve her ekibin okuyup uygulaması beklenir. Bir sonraki ders aynı
kural kümesini iki biçimde karşılaştırır: belge olarak yayımlamak ve hatta gömmek. Ölçülen şey uyum
oranı, ihlal sayısı ve ekiplerin harcadığı zamandır — ve asıl sayı kuralı hiç görmeden uyan ekip
sayısıdır.
