İçeriğe geç
academia.sh

Ders 19 / 19

Dayanıklılık Kalıpları

Devre kesici ve yeniden deneme bir açıklamayla ekleniyor; çağrı yeri hiç değişmiyor. Kurgulanmış bir başarısızlıkta kaç gerçek deneme yapıldığı ve devrenin hangi eşikte açıldığı sayı olarak ölçülüyor. Sınırlayıcı ölçüm, açıklamanın yalnız vekilden geçen çağrıya uygulandığını, aynı sınıfın kendi içinden yaptığı çağrının korumasız kaldığını gösteriyor — web-and-data-layer/06'nın ölçtüğü sınırın aynısı, başka bir sonuçla. Bu ders kursu ve M08 müfredatını kapatıyor.

İçindekiler

Önceki ders bir çağrının hedefe ulaşıp ulaşamadığını ölçtü. Bu ders bu başarısızlığı tek bir olay değil, tekrar eden bir örüntü olarak ele alıyor: bir hedef arka arkaya başarısız olduğunda çağıran taraf ne yapmalı — hemen mi vazgeçmeli, birkaç kez mi denemeli, yoksa bir noktadan sonra denemeyi tümüyle mi kesmeli? Devre kesici ve yeniden deneme kalıplarının kavramı M19/K05 Dayanıklılık ve Güvenilirlik kursunda kuruldu ve burada tekrarlanmıyor; bu ders yalnız bu kalıpların bir açıklamayla nasıl eklendiğini ve kaynakta ne bıraktığını ölçüyor. Gerçek bir süre yazılmıyor — ölçülen şey deneme sayısı ve eşik, ikisi de tam sayı. Bu, kursun ve M08 müfredatının kapanış dersi.

Açıklamayla Eklenen Dayanıklılık: Deneme Sayısı ve Eşik

KirilganServis, her çağrıldığında başarısız olacak şekilde kurgulanmış bir hedef; üzerinde iki açıklama taşıyor — @YenidenDene(sayisi = 3) ve @DevreKesici(esik = 5). Bu iki işareti okuyup uygulayan taraf KirilganServis’in kendisi değil, onu saran DayaniklilikVekili.

// YenidenDene.java — bir hedefin kac kez tekrar denenecegini belirten aciklama tipi (yardimci kaynak, main yok)
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE)
@interface YenidenDene { int sayisi(); }
// DevreKesici.java — ard arda kac basarisizliktan sonra devrenin acilacagini belirten aciklama tipi (yardimci kaynak, main yok)
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE)
@interface DevreKesici { int esik(); }
// DisServis.java — cagrilan hedefin arayuzu (yardimci kaynak, main yok)
interface DisServis { String cagir(); }
// KirilganServis.java — her cagrildiginda basarisiz olacak sekilde kurgulanmis hedef (yardimci kaynak, main yok)
@YenidenDene(sayisi = 3) @DevreKesici(esik = 5)
class KirilganServis implements DisServis {
    int cagriSayaci = 0;

    public String cagir() {
        cagriSayaci++;
        throw new RuntimeException("hedef basarisiz");
    }

    String digerIslem() {
        // kendi icinden dogrudan cagiriyor, vekili hic gormuyor
        return cagir();
    }
}
// DayaniklilikVekili.java — aciklamalari okuyup yeniden deneme ve devre kesici davranisini uygulayan vekil (yardimci kaynak, main yok)
class DayaniklilikVekili implements DisServis {
    final DisServis hedef;
    final int denemeSayisi;
    final int esik;
    int ardArdaBasarisizlik = 0;
    boolean devreAcik = false;
    int gercekCagriSayaci = 0;

    DayaniklilikVekili(DisServis hedef) {
        this.hedef = hedef;
        Class<?> tip = hedef.getClass();
        YenidenDene yd = tip.getAnnotation(YenidenDene.class);
        DevreKesici dk = tip.getAnnotation(DevreKesici.class);
        this.denemeSayisi = yd != null ? yd.sayisi() : 1;
        this.esik = dk != null ? dk.esik() : Integer.MAX_VALUE;
    }

    public String cagir() {
        if (devreAcik) {
            throw new IllegalStateException("devre acik, hedefe hic ulasilmadi");
        }
        RuntimeException sonHata = null;
        for (int i = 1; i <= denemeSayisi; i++) {
            gercekCagriSayaci++;
            try {
                String sonuc = hedef.cagir();
                ardArdaBasarisizlik = 0;
                return sonuc;
            } catch (RuntimeException e) {
                sonHata = e;
                ardArdaBasarisizlik++;
                if (ardArdaBasarisizlik >= esik) { devreAcik = true; break; }
            }
        }
        throw sonHata;
    }
}
// Olcum.java — sonuc yazdirma yardimcisi (yardimci kaynak, main yok)
class Olcum {
    static void goster(String etiket, Object deger) {
        System.out.printf("%-52s: %s%n", etiket, deger);
    }
}

KirilganServis.cagir yönteminin gövdesinde ne bir deneme sayacı ne bir eşik karşılaştırması var; ikisi de DayaniklilikVekili tarafında. Aynı vekil.cagir() satırı üç kez art arda çağrılıyor.

// DenemeVeEsik.java — ayni cagri satiri, kurgulanmis surekli basarisizlikta gercek deneme sayisini ve devrenin actigi esigi ortaya cikariyor
public class DenemeVeEsik {
    public static void main(String[] args) {
        DayaniklilikVekili vekil = new DayaniklilikVekili(new KirilganServis());

        denemeYap(vekil, "1. cagri");
        denemeYap(vekil, "2. cagri");
        denemeYap(vekil, "3. cagri");

        Olcum.goster("toplam gercek deneme sayisi (hedefe ulasan)", vekil.gercekCagriSayaci);
        Olcum.goster("devre acik mi", vekil.devreAcik);
    }

    static void denemeYap(DayaniklilikVekili vekil, String etiket) {
        try {
            vekil.cagir();
            Olcum.goster(etiket, "basarili");
        } catch (Exception e) {
            Olcum.goster(etiket, e.getMessage());
        }
    }
}
1. cagri                                            : hedef basarisiz
2. cagri                                            : hedef basarisiz
3. cagri                                            : devre acik, hedefe hic ulasilmadi
toplam gercek deneme sayisi (hedefe ulasan)         : 5
devre acik mi                                       : true

GT32. Devre kesici ve yeniden deneme bir açıklamayla ekleniyor; vekil.cagir() çağrı satırı üç denemeYap çağrısı boyunca hiç değişmiyor, davranışı belirleyen tek şey KirilganServis üzerindeki iki işaret. GT33. Kurgulanmış sürekli başarısızlıkta gerçek deneme sayısı ve devrenin açıldığı eşik, hepsi sayı: ilk çağrı üç deneme yapıyor (sayisi = 3), henüz eşiğe (esik = 5) ulaşmadığı için devre kapalı kalıyor; ikinci çağrı iki deneme daha yapıyor ve ard arda başarısızlık beşe ulaştığı anda devre açılıyor — toplam gerçek deneme sayısı tam 5. GT34. Devre açıldıktan sonraki üçüncü çağrı hedefe hiç ulaşmadan reddediliyor; gercekCagriSayaci üçüncü çağrıdan sonra hâlâ 5, artmıyor.

Sınırlayıcı Ölçüm: Vekilden Geçmeyen Çağrı Korumasız Kalır

KirilganServis’in kendi içinde cagir’i çağıran ikinci bir yöntemi var: digerIslem. Bu çağrı DayaniklilikVekili’nden hiç geçmiyor — nesnenin kendisi kendi yöntemini doğrudan çağırıyor.

// KorumasizCagri.java — digerIslem() kendi icinden dogrudan cagir()'i cagiriyor, vekil hic devrede degil, hicbir yeniden deneme olmuyor
public class KorumasizCagri {
    public static void main(String[] args) {
        KirilganServis ic = new KirilganServis();
        try {
            ic.digerIslem();
        } catch (RuntimeException e) {
            Olcum.goster("digerIslem() cagrisinin sonucu", e.getMessage());
        }
        Olcum.goster("digerIslem icinden yapilan dogrudan cagri, kac deneme yapildi", ic.cagriSayaci);
    }
}
digerIslem() cagrisinin sonucu                      : hedef basarisiz
digerIslem icinden yapilan dogrudan cagri, kac deneme yapildi: 1

ic.cagriSayaci bir kez artıyor, üç değil. GT35. Açıklama yalnız vekilden geçen çağrıya uygulanır; aynı sınıfın kendi içinden yaptığı çağrı korumasız kalır, çünkü @YenidenDene ve @DevreKesici işaretlerini okuyan taraf DayaniklilikVekili, ve digerIslem onu hiç çağırmıyor. Bu, web-and-data-layer/06’nın ölçtüğü sınırın aynısı — bir bileşenin kendi kendini çağırması vekili atlıyordu — burada aynı sınır başka bir sonuçla karşımıza çıkıyor: orada sarmalanan bir işlem sınırı hiç açılmıyordu, burada sarmalanan bir dayanıklılık kalıbı hiç uygulanmıyor. Kod okuyan biri digerIslem’in de aynı korumaya sahip olduğunu varsayabilir, çünkü aynı sınıfın aynı cagir yöntemini çağırıyor; kaynakta bu varsayımı çürütecek hiçbir işaret yok.

Özet

  • Devre kesici ve yeniden deneme bir açıklamayla eklenir; çağrı yeri hiç değişmez.
  • Kurgulanmış sürekli başarısızlıkta gerçek deneme sayısı ve devrenin açıldığı eşik sayı olarak ölçülür, hiçbiri süre değildir.
  • Devre açıldıktan sonraki çağrılar hedefe hiç ulaşmadan reddedilir.
  • Açıklama yalnız vekilden geçen çağrıya uygulanır; aynı sınıfın kendi içinden yaptığı çağrı korumasız kalır.
  • Bu sınır, web-and-data-layer/06’nın ölçtüğü kendi-kendini-çağırma sınırının aynısı, başka bir sonuçla.

Kurs Kapanışı

Kurs tek bir soruyla açıldı: bir uygulama çerçevesi kullanan programın büyük bölümünü hiç kimse çağırmaz, çünkü nesneyi kuran ifade, bağımlılığı veren atama, kurulumu çağıran satır yerlerinde yalnız açıklamalar durur. On dokuz ders bu soruyu üç payda sordu — çekirdek kavramlar, web ve veri katmanı, güvenlik ve dağıtık kurulum — ve her seferinde aynı üçlüye döndü: bu davranışı kaynakta bir çağrı mı doğurdu, bir açıklama mı, yoksa hiçbiri mi.

Ders Ölçülen davranış Davranışın kaynağı Sınırlayıcı ölçüm
Denetimin Ters Çevrilmesi 12 davranışın 3’ü çağrı, 6’sı açıklama, 3’ü varsayılan çağrı · açıklama · varsayılan Kabın dışında kalan nesne açıklamaların hiçbirini almaz
Bağımlılık Enjeksiyonu Aynı Servis hem kapla hem elle kurulup ikisi de çalışıyor açıklama (sağlama) · çağrı (elle verme) Bağlanmamış arayüz hatası kap kurulurken değil ilk istekte düşer
Bileşen Kapsamları ve Yaşam Döngüsü Tekil kapsam varsayılan, her-istekte açık bir açıklama varsayılan (tekil) · açıklama (her-istekte) Tanınmayan kapsam adı hata vermez, bileşen sessizce tekil olmaktan çıkar
Yapılandırma Kaynakları 4 ayardan 1’i dış kaynaktan, 2’si dosyadan, 1’i gömülü varsayılandan kabın kod sırası (öncelik zinciri) Yazım farkı (ı/i) hiçbir hata vermeden gömülü varsayılana düşürür
Otomatik Yapılandırma Açıklamasız doğan davranış sayısı 3’ten 2’ye düşüyor varsayılan (koşullu bileşen seçimi) Bir bileşen eklemek başka birini sessizce devre dışı bırakır
Görünüş Odaklı Programlama Sarmalama açıklaması çağrı yerine dokunmadan sayaç ekliyor açıklama (vekil aracılığıyla) Arayüzsüz sınıfa konan işaret hata vermeden etkisiz kalır
Gömülü Sunucu ve İstek İşleme Modeli 6 halkanın 2’si varsayılan, 2’si açıklama, 2’si çağrı varsayılan · açıklama · çağrı Elle çağrılan sınıflarda açıklamadaki öncelik hiç okunmaz
Denetleyiciler ve Yönlendirme 4 uç noktanın 4’ü de açıklamadan doğuyor açıklama (@UcNokta) Eşleşmeyen yol sessizce varsayılan yanıt döner; çakışan yolda kazanan tarama sırasına bağlı
Doğrulama ve Hata İşleme 4 alanın 3’ü açıklamadan kural alıyor, 1’i hiç kural taşımıyor açıklama (kural) · varsayılan (zarf) Kap dışında işleyiciye verilen geçersiz veri hiç doğrulanmaz, “tamam” döner
Veri Erişim Soyutlaması Aynı derlenmiş çağıran iki gerçekleştirimle, yeniden derlenmeden koşuyor çağıran yalnız arayüzü anıyor DiziDepo kapasite sınırında istisna verir, BellekDepo aynı çağrıda vermez
Nesne ve Tablo Bağlaması 4 alanın 2’si yükleme anında, 2’si ilk erişimde yükleniyor açıklama (@Sutun / @TembelSutun) Kaptan ayrılan nesnede erişilmemiş tembel alan sessizce boş döner
İşlem Yönetimi Dıştan gelen her çağrıda sınır açılıyor, iç çağrı hiç sayılmıyor açıklama (@Islem, vekil üzerinden) Bileşenin kendi kendini çağırması vekili atlar, sınır hiç açılmaz
Kimlik Doğrulama ve Yetkilendirme Yetki kararı açıklamadan (panel) ya da varsayılandan (durum) geliyor açıklama · varsayılan · çağrı (elle) Aynı kaynak iki farklı varsayılanla iki farklı güvenlik duruşu üretir
Belirteç Tabanlı Kimlik Doğrulama İddia sayısı 1/3; doğrulama açıklama ve çağrıyla aynı sonucu veriyor açıklama (@GerekliIddia) · çağrı (elle) İptal edilen belirteç, iptal listesine hiç bakılmadığı için süresi dolana kadar geçerli kalır
Katman Testleri Dilim testi 2, tam bağlam testi 4 bileşen kuruyor kabın kurduğu bileşen sayısı Dilimin dışında kalan bileşenin kurulum kancası hiç çalışmasa da test yine geçer
Sağlık ve Ölçüm Uçları 2 uç varsayılandan, 1 uç açıklamadan; 3 alandan 1’i dışarı çıkıyor varsayılan (2 uç) · açıklama (1 uç) Yanlış işaretlenen alan da hiçbir hata vermeden dışarı verilir
Dağıtık Yapılandırma Tekil bileşen eski değeri, her istekte kurulan güncel değeri görüyor varsayılan (kapsam) · çağrı (yenile()) Aynı anda iki bileşen aynı değere iki farklı, ikisi de hatasız yanıt verir
Servis Keşfi ve Ağ Geçidi Hedef doğrudan referanstan, kayıttan, ya da kabın varsayılanından geliyor çağrı · kayıt · varsayılan Kayıttan silinmemiş ölü hedef aramada bulunur, kusur çağrı anında düşer
Dayanıklılık Kalıpları Gerçek deneme sayısı 5, devre eşik 5’te açılıyor açıklama (@YenidenDene, @DevreKesici) Vekilden geçmeyen kendi-kendini-çağırma korumasız kalır

Tablonun üçüncü sütunu tek bir örüntüyü doğruluyor: on dokuz dersin dördünde davranış tamamen açıklamadan (dört uç nokta, işlem sınırı, iddia doğrulaması, dayanıklılık kalıpları), üçünde tamamen ya da ağırlıkla varsayılandan doğuyor, geri kalanında üçü de bir arada görünüyor. Sınırlayıcı ölçüm sütunu ise başka bir örüntü taşıyor: on dokuz dersin neredeyse tamamında kusur sessiz — hata fırlatan yalnız ikisi (bağlanmamış arayüz, kapasite sınırı), geri kalanı ya beklenmedik bir değer döndürüyor ya da hiçbir şey değişmiyormuş gibi devam ediyor. Kaynağı yukarıdan aşağı okuyan biri, bu on dokuz dersin gösterdiği davranışın büyük bölümünü göremiyor, ve göremediğinin bozulduğunu da göremiyor.

M08 Java müfredatının altı kursu birbirinden ayrı altı soru sordu, ve hiçbiri ötekinin yerini almadı. M08/K01 Java Temelleri, derleyicinin kaynakta yazılmayan hangi adımı sınıf dosyasına eklediğini saydı. M08/K02 Nesneye Dayalı Java, çalışma zamanındaki bir kararı hangi tipin verdiğini ayırdı. M08/K03 Standart Kütüphane ve Akışlar, bir garantiyi kimin — çağıranın mı, kütüphanenin mi — verdiğini ölçtü. M08/K04 JVM, Eşzamanlılık ve Başarım, bir adımı hangi iş parçacığının koşturduğunu izledi. M08/K05 Derleme, Test ve Ekosistem, bir tipin hangi sınıf yolunda bulunmak zorunda olduğunu sayıp bunun derlemeyle koşum arasındaki farkı gösterdi. Bu kurs, M08/K06 Kurumsal Uygulama Çerçevesi, altıncı ve son soruyu sordu: bir davranışı kaynakta ne doğurdu — bir çağrı mı, bir açıklama mı, yoksa hiçbiri mi. Altı soru da aynı kaynak metne bakıyor, ama her biri farklı bir boşluğu arıyor; biri diğerinin genellemesi değil, ve hiçbiri kaynağı yukarıdan aşağı okumanın yeterli olduğunu söylemiyor.

M08 burada kapanıyor. Kaynak metin, bir Java programının ne yaptığının yalnız bir kısmını anlatıyor — eklenen adımı, kararı veren tipi, garantiyi veren tarafı, koşturan iş parçacığını, gerekli sınıf yolunu, davranışın kaynağını; altısı da kaynağı okuyanın gözünden en az kısmen saklı, ve altısı da yalnız koşturularak, sayılarak görünür hâle geliyor.

İ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