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.