Ders 11 / 11
Çalışma Zamanı Doğrulama
Dört ihlali üç katman ayrı ayrı görür: çalışma zamanı 0, denetleyici 2, alan kuralı 2 yakalar ve dördü ancak iki katman birlikte kullanıldığında görünür; şema tabanlı doğrulama dördünü de yakalar ama yalnız uğradığı çağrıda.
İçindekiler
Önceki ders alan kuralını tipe taşıdı ve kuralın bir yapıcının gövdesine, yani çalışma zamanına düştüğünü gösterdi. Her alan için ayrı bir sınıf yazmak ölçeklenmez: kural sayısı arttıkça yapıcılar birbirini tekrar eder ve kuralların nerede durduğu dağılır.
Kuralları tek bir yerde toplamanın adı **şema (schema)**dır: hangi alanın hangi tipte olduğu ve hangi koşulu sağlaması gerektiği, veriden ayrı bir tanımda durur. Çalışma zamanı doğrulama (runtime validation) bu tanımı çağrı anında değere uygular. Bu ders o katmanı kurar ve kursun son sayısını sorar: dört ihlali görmek için kaç katman gerekir?
Şema Ders İçinde Modellenmiştir
Bir uyarı, önceki derstekinin aynısı: buradaki şema ve doğrulayıcı ders içinde yazılmıştır. Hazır bir doğrulama katmanı kullanılmaz ve hiçbir aracın adı geçmez. Ölçülen şey bir programın davranışı değil, yaklaşımın kapsamıdır.
Şema doğrulamanın kendisi bu kursta ilk kez geçmiyor. Veri Modelleme ve İlişkisel Kuram kursu şemayı veri tarafında bütünlük kısıtlarıyla kurdu; Web API Tasarımı kursu da alan düzeyi hata bildirimini istek ve yanıt gövdelerinde kurdu. O yordamlar burada tekrarlanmaz. Buradaki soru dar ve ölçülebilir: hangi katman hangi ihlali yakalar?
Ölçümün varsayımları:
- TP28 — Kâhin kurgunun kendisidir: beş çağrının ikisi tip ihlali, ikisi alan ihlali taşır, biri temizdir. Dizi kursun ortak kurgusundan gelir ve değiştirilmez.
- TP29 — Denetleyici ve alan kuralı önceki derslerdeki modellerin aynısıdır; denetleyici yalnız tipi, alan kuralı yalnız değerin anlamını görür.
- TP30 — Şema üç şeyi tek yerde tutar: alan adı, beklenen tip ve alan koşulu. Sınama önce tipe, tip geçerse koşula bakar; bu sıra bir tasarım kararıdır ve iletilerde görünür.
- TP31 — Doğrulama, işlevi saran bir katman olarak uygulanır: sınama geçmezse çağrı hiç başlamaz. Yakalama ölçüsü bu sarmalın istisna fırlatmasıdır.
- TP32 — Çalışma zamanı sütunu sarmalsız çağrının istisna fırlatıp fırlatmadığıdır; gövde bir dizgi biçimlemesidir ve her tipi kabul eder.
- TP33 — “Birlikte” sayısı iki katmanın yakaladığı çağrıların birleşimidir, toplamı değil.
- TP34 — Kapsam ölçümünde beş çağrının üçünün çalıştırıldığı bir koşum varsayılır; hangi üçü olduğu kurguya yazılıdır ve ölçüm bunu bir olasılık olarak değil, tek bir koşum olarak sayar.
- TP35 — Ortama bağlı hiçbir veri yazılmaz; bütün sayılar kurgudan ve koşumdan gelir.
Ölçüm
"""Calisma zamani dogrulama: dort ihlali kac katman gorur.""" def yas_yaz(ad: str, yas: int) -> str: return f"{ad}:{yas}" CAGRILAR = ( ("ad", 30), # uygun ("ad", "otuz"), # tip ihlali: yas dizgi (7, 30), # tip ihlali: ad sayi ("ad", -5), # tip uygun, alan ihlali: yas negatif ("", 30), # tip uygun, alan ihlali: ad bos ) def denetleyici(islev, cagrilar): """Aciklamalari okuyan modellenmis denetleyici: yalniz tipi gorur.""" aciklama = [(a, t) for a, t in islev.__annotations__.items() if a != "return"] bulunan = [] for i, arg in enumerate(cagrilar): for (ad, tip), deger in zip(aciklama, arg): if not isinstance(deger, tip): bulunan.append((i, ad)) return bulunan def alan_kurali(ad, yas): """Tipin goremedigi anlam kosullari.""" hatalar = [] if isinstance(ad, str) and not ad: hatalar.append("ad bos") if isinstance(yas, int) and yas < 0: hatalar.append("yas negatif") return hatalar # Sema ders icinde modellenmistir: alan adi, tip ve alan kurali tek yerde. SEMA = (("ad", str, lambda d: bool(d), "boş"), ("yas", int, lambda d: d >= 0, "negatif")) def dogrula(sema, degerler): """Sema tabanli dogrulama: cagri aninda hem tipi hem alani sinar.""" hatalar = [] for (alan, tip, kural, ileti), deger in zip(sema, degerler): if not isinstance(deger, tip): hatalar.append(f"{alan}: tip") elif not kural(deger): hatalar.append(f"{alan}: {ileti}") return hatalar def korumali(sema, islev): """Islevi semayla saran katman: dogrulama gecmezse cagri hic baslamaz.""" def sarmal(*arg): hatalar = dogrula(sema, arg) if hatalar: raise ValueError("; ".join(hatalar)) return islev(*arg) return sarmal bulunan = {b[0] for b in denetleyici(yas_yaz, CAGRILAR)} tip_ihlali = [i for i, a in enumerate(CAGRILAR) if not isinstance(a[0], str) or not isinstance(a[1], int)] alan_ihlali = [i for i, a in enumerate(CAGRILAR) if alan_kurali(*a)] korunan = korumali(SEMA, yas_yaz) ham_hata = 0 sema_yakalanan = set() for i, arg in enumerate(CAGRILAR): try: yas_yaz(*arg) except Exception: ham_hata += 1 try: korunan(*arg) except ValueError: sema_yakalanan.add(i) print(f"{'çağrı':>6s} {'tip ihlali':>11s} {'alan ihlali':>12s} " f"{'çalışma zamanı':>15s} {'denetleyici':>12s} {'alan kuralı':>12s} " f"{'şema':>6s}") for i, arg in enumerate(CAGRILAR): print(f"{i:6d} {str(i in tip_ihlali):>11s} {str(i in alan_ihlali):>12s} " f"{'hata yok':>15s} {str(i in bulunan):>12s} " f"{str(i in alan_ihlali):>12s} {str(i in sema_yakalanan):>6s}") print() print(f"çağrı {len(CAGRILAR)}, ihlalli " f"{len(set(tip_ihlali) | set(alan_ihlali))} | yakalayan: çalışma zamanı " f"{ham_hata}, denetleyici {len(bulunan)}, alan kuralı {len(alan_ihlali)}, " f"şema {len(sema_yakalanan)}") print(f"denetleyici ile alan kuralı birlikte: " f"{len(bulunan | set(alan_ihlali))}") print(f"şema iletileri: {[dogrula(SEMA, a) for a in CAGRILAR]}") CALISAN = [0, 2, 4] print() print(f"yazılan çağrı yeri {len(CAGRILAR)}, çalıştırılan {len(CALISAN)} | " f"denetleyicinin gördüğü {len(CAGRILAR)}, yakaladığı {len(bulunan)} | " f"şemanın uğradığı {len(CALISAN)}, yakaladığı " f"{len(sema_yakalanan & set(CALISAN))}")
çağrı tip ihlali alan ihlali çalışma zamanı denetleyici alan kuralı şema
0 False False hata yok False False False
1 True False hata yok True False True
2 True False hata yok True False True
3 False True hata yok False True True
4 False True hata yok False True True
çağrı 5, ihlalli 4 | yakalayan: çalışma zamanı 0, denetleyici 2, alan kuralı 2, şema 4
denetleyici ile alan kuralı birlikte: 4
şema iletileri: [[], ['yas: tip'], ['ad: tip'], ['yas: negatif'], ['ad: boş']]
yazılan çağrı yeri 5, çalıştırılan 3 | denetleyicinin gördüğü 5, yakaladığı 2 | şemanın uğradığı 3, yakaladığı 2
Üç Katman, Üç Ayrı Yakalama
Tablo dört ihlali üç sütunda dağıtıyor ve hiçbir sütun ötekinin kopyası değil.
Çalışma zamanı 0 yakalıyor. Beş satırda da “hata yok”. Açıklama çağrıyı durdurmaz; kursun ilk dersinde ölçülen sayı burada da aynı çıkıyor.
Denetleyici 2 yakalıyor ve yakaladıkları tip ihlalleridir. Alan ihlallerinde sütun yanlış diyor, çünkü -5 bir tam sayı, boş dizgi bir dizgidir.
Alan kuralı 2 yakalıyor ve yakaladıkları tam olarak denetleyicinin göremedikleridir. İki sütun kesişmiyor: birinin bulduğunu öbürü bulamıyor.
Bunun doğrudan sonucu alt satırda: denetleyici ile alan kuralı birlikte 4 yakalıyor — ihlallerin tamamı. Toplam değil birleşim; iki katmanın kapsamı çakışmadığı için birleşim toplama eşit çıkıyor. Dört ihlalin tamamı ancak iki katman birlikte kullanıldığında görünür.
Şema sütunu ise beş çağrının 4’ünde yakalıyor. Sebebi şemanın iki bilgiyi tek yerde
taşıması: tip ve koşul. İleti listesi bunu ayrıntısıyla veriyor — iki çağrıda tip, birinde
negatif, birinde boş. Yani şema yeni bir görme yeteneği getirmiyor; denetleyicinin
bildiğiyle alan kuralının bildiğini aynı tanımda birleştiriyor ve ikisini çağrı anında
uyguluyor.
İleti listesi şemanın bir tasarım kararını da açığa çıkarıyor. Yaşı dizgi olan çağrıda ileti
yas: tip, negatif olan çağrıda yas: negatif. Aynı alan için iki ileti birden çıkmıyor,
çünkü sınama önce tipe bakıyor ve tip geçmeden koşula geçmiyor. Bu sıra zorunlu: d >= 0
karşılaştırması bir dizgiyle yapılamaz. Alan koşulu tipin doğru olduğunu varsayar;
kural yazarken bu varsayımın nereden geldiğini bilmek, kuralın kendisini yazmak kadar
önemlidir.
Sarmal katmanın bir farkı daha var. Doğrulama geçmediğinde çağrı hiç başlamıyor; gövde koşmuyor, yarım bir iş kalmıyor. Önceki derslerde ölçülen “çalışma zamanı ancak işlemi yaparken düşer” durumu burada ortadan kalkıyor: düşme çağrının önünde.
Bunun bir bedeli var ve ölçümde görünüyor: sarmal, ihlalli olsun olmasın her çağrıda şemayı baştan sona uyguluyor. Temiz çağrı da sınanıyor. Denetleyici ise çalışma zamanında hiçbir şey yapmıyor; işini bir kez, koşumdan önce görüyor. İki katmanın bedeli de kapsamı gibi ayrı cinsten: biri koşum başına bir kez, öbürü çağrı başına her seferinde.
Kapsam: Yazılan Kod ve Uğranan Çağrı
Son satır şemanın bedelini gösteriyor ve bu bedel kursun ölçü ekseninin son sözü.
Yazılan çağrı yeri 5, tek bir koşumda çalıştırılan 3. Denetleyici beşinin beşini de görüyor ve 2 ihlal bildiriyor — kodu hiç çalıştırmadan. Şema yalnız uğradığı 3 çağrıyı sınıyor ve o üçte 2 ihlal yakalıyor; uğramadığı iki çağrıdaki ihlaller o koşumda görünmüyor.
Örüntü şudur: denetleyicinin kapsamı yazılan koddur, doğrulamanın kapsamı uğranan çağrıdır. Şemayı daha titiz yazmak bu farkı kapatmaz, çünkü fark titizlikte değil, katmanın ne zaman çalıştığındadır. Aynı biçimde, denetleyiciyi daha titiz yazmak alan ihlallerini bulmasını sağlamaz — o da bilgi sınırıdır.
İki katman birbirinin yerine geçmiyor ve birbirini de doğrulamıyor: biri her yerde az şey, öbürü bazı yerlerde çok şey biliyor.
Kapsam farkı doğrulamanın nereye konacağını da belirliyor. Şemayı her işlevin önüne koymak sınama sayısını çağrı sayısıyla büyütür ve aynı değer aynı koşumda defalarca sınanır. Buna karşılık verinin programa girdiği noktaya konan tek bir doğrulama, o noktadan sonraki bütün çağrılar için bir güvence üretir — sınama bir kez yapılır, sonuç içeride taşınır. Ölçümdeki şema bu yüzden alan adını da taşıyor: bir ihlal bildirildiğinde hangi alanın sorunlu olduğu, sınamanın yapıldığı yerden uzakta da okunabilir olmalı.
Bu, önceki dersteki Yas sınıfının yaptığı işin ölçeklenmiş biçimidir. Orada kural tek bir
yapıcının gövdesine yazılmıştı ve her alan için ayrı bir sınıf gerekiyordu; burada kurallar
tek bir tanımda toplandı ve doğrulayıcı o tanımı okuyor. Değişen şey kuralın ne zaman
çalıştığı değil — ikisi de çalışma zamanıdır — kuralın nerede yazılı olduğudur.
Özet
- Şema, alan adını, beklenen tipi ve alan koşulunu tek bir tanımda toplar; çalışma zamanı doğrulama bu tanımı çağrı anında uygular ve doğrulama geçmezse çağrı hiç başlamaz.
- Üç katman üç ayrı şey yakalar: çalışma zamanı 0, denetleyici 2, alan kuralı 2. İki katmanın kapsamı kesişmez, bu yüzden birleşimleri 4’tür — dört ihlalin tamamı ancak birlikte görünür.
- Şema tabanlı doğrulama tek başına 4 yakalar, çünkü denetleyicinin ve alan kuralının bildiklerini aynı tanımda birleştirir; yeni bir görme yeteneği eklemez.
- Kapsamlar ayrıdır: denetleyici yazılan 5 çağrı yerinin beşini de görür, şema tek koşumda uğranan 3 çağrıyı sınar ve o üçte 2 ihlal yakalar.
- Katmanların sınırları ayrı cinstendir; denetleyicininki bilgi sınırı, doğrulamanınki kapsam sınırıdır ve hiçbiri ötekini titizlikle kapatamaz.
Kurs Kapanışı
Kurs tek bir soruyla açıldı ve on bir derste aynı soruyu iki yarıda ölçtü: çağrıyı kim yanıtladı, sözü kim denetledi? Birinci yarıda yanıt bir sınıftı; ikinci yarıda bir katman. İkisinde de ölçülen şey tasarımın ne yaptığı değil, sorumluluğun nerede durduğuydu.
| ders | ölçülen | yanıtlayan ya da yakalayan |
|---|---|---|
| Sınıf ve Örnek | özniteliğin sınıfta mı örnekte mi durduğu: 1’e karşı 3 nesne | adı ilk bulan ad alanı — önce örnek sözlüğü, sonra sınıf |
| Kalıtım ve Yöntem Çözümleme Sırası | dört yeteneğin gövdesinin nerede yazılı olduğu: 0/4’e karşı 4/4 | çözümleme sırasında ilk gelen sınıf; bileşimde Sarmal |
| Kapsülleme Sözleşmeleri | dört erişim biçiminden kaçının değeri verdiği: 3, engellenen 0 | yöntem gövdesi — ad değil |
| Özel Yöntemler | hiçbir özel yöntem yazmayan sınıfın katıldığı sözdizim: 5, yanıtladığı: 0 | sessiz varsayılan; yazan sınıfta yöntemin kendisi |
| Özellikler ve Betimleyiciler | aynı yedi erişimin çalıştırdığı gövde: doğrudan alanda 0, araya giren tanımda 7 | araya giren gövde; betimleyici sınıfta bir kez var edilir |
| Veri Sınıfları | kısa tanımın yazdığı özel yöntem: 4; seçeneklerle 8, 6 ve 10 | kısa tanımın sınıf sözlüğüne yazdığı yöntemler |
| Soyut Temel Sınıflar ve Protokoller | üç adaydan soy bağı sınamasını geçen 1, yöntem sınamasını geçen 3 | iki sınama da; ama geçmek çağrının karşılanacağını söylemez |
| Tip İpuçları | beş çağrının 4’ü ihlalli, çalışma zamanında hata veren 0 | hiçbir katman |
| Genellikler ve Tip Değişkenleri | dört yazımın bildirdiği ihlal: 0, 4, 3, 2 | açıklamayı okuyan taraf — bağ kurulmuşsa |
| Statik Tip Denetimi | denetleyicinin bulduğu 2, göremediği 2 | denetleyici; kapsamı yazılan kod |
| Çalışma Zamanı Doğrulama | çalışma zamanı 0, denetleyici 2, alan kuralı 2 | şema tabanlı doğrulama — uğradığı çağrıda 4 |
Tablonun iki yarısı aynı örüntüyü veriyor. Kalıtımda gövdenin nerede yazılı olduğunu okumak yanıtın nereden geleceğini söylemedi; açıklamanın koda yazılmış olması da sözün denetleneceğini söylemedi. Her iki durumda da sorunun yanıtı yazının kendisinde değil, onu çözen düzenekte duruyor: birinde çözümleme sırası, öbüründe denetim katmanı.
Bütün bu ölçümlerin ortak bir varsayımı vardı ve hiç yazılmadı: tek bir akış. Yanıtı veren sınıf sorulduğunda tek bir çözümleme zinciri yürüdü; ihlali yakalayan katman sorulduğunda çağrılar sırayla, biri bitince öbürü başlayarak koştu. Bu yüzden “kim yanıtladı” sorusunun her seferinde tek bir yanıtı oldu.
Birden çok akış olduğunda bu soru yeniden açılır. Aynı nesneye iki yerden aynı anda uğrandığında özniteliği hangi yazmanın bıraktığı, doğrulamayı geçen bir değerin gövde koşarken hâlâ geçerli olup olmadığı ve iki akıştan hangisinin önce davrandığı, artık kaynağa bakarak okunamaz. Sonraki kurs Eşzamanlılık ve Başarım tam buradan başlıyor: tek akışta kimin yanıtladığı bellidir; birden çok akışta bu soru yeniden sorulur ve yanıtı bu kez bir sıralamaya bağlıdır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.