(Çıkış) uygulama çöküyor, lütfen!
Yayınlanan: 2020-02-12Programcılar kodlarında çökmeleri önlemeye çalışırlar. Birisi uygulamalarını kullanırsa, beklenmedik bir şekilde kırılmamalı veya sonlandırılmamalıdır. Bu, kalitenin en basit ölçümlerinden biridir - bir uygulama sık sık çökerse, muhtemelen iyi yapılmamıştır.
Bir program, bir değeri sıfıra bölmek veya bir makinedeki kısıtlı kaynaklara erişmek gibi tanımsız veya kötü bir şey yapmak üzereyken uygulama çökmeleri meydana gelir . Ayrıca uygulamayı yazan programcı tarafından açıkça yapılabilir. “Bu asla olmayacak, bu yüzden atlayacağım” - bu oldukça yaygın ve tamamen mantıksız bir düşünce değil. Sadece gerçekleşemeyecek bazı durumlar vardır, asla, ta ki gerçekleşene kadar.
Bozulan sözler
Bir şeyin olamayacağını bildiğimiz en yaygın durumlardan biri API'lerdir. Arka uç ve ön uç arasında anlaştık - bu istek için alabileceğiniz tek sunucu yanıtı budur. Bu kitaplığın koruyucuları bu işlev davranışını belgelemiştir. Fonksiyon başka bir şey yapamaz. Her iki düşünce şekli de doğrudur, ancak her ikisi de sorunlara neden olabilir.
Bir kitaplık kullanırken, olası tüm durumları ele almanıza yardımcı olacak dil araçlarına güvenebilirsiniz. Kullandığınız dil herhangi bir tür denetimi veya statik analizden yoksunsa, bunu kendiniz halletmeniz gerekir. Yine de, üretim ortamına göndermeden önce bunu kontrol edebilirsiniz, bu yüzden çok önemli değil. Bu zor olabilir, ancak bağımlılıklarınızı güncellemeden ve birim testleri yazmadan önce değişiklik günlüklerini okursunuz, değil mi? Ya kullanırsınız ya da bir kitaplık yaparsanız, kodunuz ve diğer programcılar için daha iyi bir yazma sağlayabilirsiniz.
Arka uç-ön uç iletişimi biraz daha zordur. Genellikle gevşek bir şekilde bağlanır, bu nedenle bir taraftaki değişiklik, diğer tarafı nasıl etkileyeceğinin farkında olmadan kolayca yapılabilir. Arka uçtaki değişiklik, genellikle ön uçtaki varsayımlarınızı bozabilir ve her ikisi de genellikle ayrı olarak dağıtılır. Kötü bitmeli. Biz sadece insanız ve bazen karşı tarafı anlamadığımız veya bu küçük değişikliği onlara söylemeyi unuttuğumuz oluyor. Yine, uygun ağ teslimi ile bu çok da önemli değil - kod çözme yanıtı başarısız olacak ve bununla nasıl başa çıkacağımızı biliyoruz. En iyi kod çözme kodu bile kötü tasarımdan etkilenebilir...
Kısmi fonksiyonlar. Kötü tasarım.
“Burada iki boole değişkenimiz olacak: 'isActive' ve 'canTransfer', elbette aktif olmadığında transfer yapamazsınız, ancak bu sadece bir ayrıntı.” İşte başlıyor, sert vurabilecek kötü tasarımımız. Şimdi birisi bu iki argümanla bir fonksiyon yapacak ve buna dayalı olarak bazı verileri işleyecek. En basit çözüm… sadece geçersiz bir durumda çökmek, asla olmamalı, bu yüzden umursamamalıyız. Hatta bazen önemsiyoruz ve daha sonra düzeltmek veya ne olması gerektiğini sormak için bazı yorumlar bırakıyoruz, ancak sonunda bu görevi tamamlamadan gönderilebilir.
// sözde kod function doTransfer(Bool isActive, Bool canTransfer) { If ( isActive ve canTransfer ) { // mevcut transfer için bir şeyler yap } else if ( isActive değil ve canTransfer değil ) { // transfer için bir şeyler yap mümkün değil } else if ( isActive ve canTransfer değil ) { // transfer için bir şeyler yap mümkün değil } else { // aka ( isActive değil ve canTransfer ) // dört olası durum var // bu olmamalı, transfer aktif değilken mevcut olmamalı kaza() } }
Bu örnek size saçma gelebilir ama bazen kendinizi fark etmesi ve çözmesi bundan biraz daha zor olan bu tür bir tuzağa yakalayabilirsiniz. Kısmi işlev adı verilen bir şeyle sonuçlanacaksınız. Bu, yalnızca bazı olası girdileri yok sayan veya diğerleriyle çakışan için tanımlanan bir işlevdir. Kısmi işlevlerden her zaman kaçınmalısınız (lütfen dinamik olarak yazılan dillerde çoğu işlevin kısmi olarak ele alınabileceğini unutmayın). Diliniz, tür denetimi ve statik analiz ile uygun davranışı sağlayamıyorsa, bir süre sonra beklenmedik bir şekilde çökebilir. Kod sürekli gelişiyor ve dünkü varsayımlar bugün geçerli olmayabilir.
Hızlı başarısız ol. Sık sık başarısız olun.
Kendini nasıl koruyabilirsin? En iyi savunma saldırıdır! Güzel bir söz vardır: “Hızlı başarısız olun. Sık sık başarısız ol.” Ancak uygulama çökmelerinden, kısmi işlevlerden ve kötü tasarımdan kaçınmamız gerektiği konusunda hemfikir değil miydik? Erlang OTP, programcılara beklenmedik durumlardan sonra kendini iyileştirmesi ve çalışırken güncelleme yapması gibi efsanevi bir avantaj sağlar. Bunu karşılayabilirler, ancak herkesin böyle bir lüksü yoktur. Öyleyse neden hızlı ve sık sık başarısız olalım?
Her şeyden önce, bu beklenmedik durum ve davranışları bulmak . Uygulama durumunuzun doğru olup olmadığını kontrol etmezseniz, çökmeden daha kötü sonuçlara yol açabilir!
İkincisi, diğer programcıların aynı kod bazında işbirliği yapmasına yardımcı olmak . Şu anda bir projede yalnızsanız, sizden sonra başka biri olabilir. Bazı varsayımları ve gereksinimleri unutabilirsiniz. Sağlanan belgeleri her şey işe yarayana kadar okumamak veya dahili yöntemleri ve türleri hiç belgelememek oldukça yaygındır. Bu durumda, birisi kullanılabilir işlevlerden birini beklenmeyen ancak geçerli bir değerle çağırır. Örneğin, herhangi bir tamsayı değeri alan ve o kadar saniye bekleyen bir 'bekle' fonksiyonumuz olduğunu varsayalım. Ya birisi ona '-17' geçerse? Bunu yaptıktan hemen sonra çökmezse, bazı ciddi hatalara ve geçersiz durumlara neden olabilir. Sonsuza kadar bekler mi yoksa hiç beklemez mi?

Kasıtlı çarpmanın en önemli kısmı, bunu zarif bir şekilde yapmaktır . Uygulamanızı kilitlerseniz, tanıya izin vermek için bazı bilgiler sağlamanız gerekir. Bir hata ayıklayıcı kullanırken oldukça kolaydır, ancak uygulama çökmelerini onsuz bildirmenin bir yolunuz olmalıdır. Bu bilgileri uygulama başlatmaları arasında sürdürmek veya dışarıdan bakmak için günlük sistemlerini kullanabilirsiniz.
Kasıtlı çökmenin ikinci en önemli kısmı, üretim ortamında bundan kaçınmaktır…
Başarısız olma. Durmadan.
Sonunda kodunuzu göndereceksiniz. Onu mükemmelleştiremezsiniz, çoğu zaman doğruluk garantisi vermeyi düşünmek bile çok pahalıdır. Ancak, hatalı davranmayacağından veya çökmeyeceğinden emin olmalısınız. Zaten hızlı ve sık sık çökmeye karar verdiğimize göre bunu nasıl başarabilirsiniz?
Kasıtlı çökmenin önemli bir kısmı, bunu yalnızca üretim dışı ortamlarda yapmaktır . Uygulamanızın üretim yapılarında çıkarılmış iddiaları kullanmalısınız. Bu, geliştirme sırasında yardımcı olacak ve son kullanıcıları etkilemeden sorunların tespit edilmesini sağlayacaktır. Ancak, geçersiz uygulama durumlarından kaçınmak için bazen çökmek daha iyidir. Zaten kısmi fonksiyonlar yapmışsak bunu nasıl başarabiliriz?
Tanımsız ve geçersiz durumları temsil etmeyi imkansız hale getirin ve aksi takdirde geçerli olanlara geri dönün. Bu kulağa kolay gelebilir ancak çok fazla düşünce ve çalışma gerektirir. Ne kadar olursa olsun, her zaman hata aramaktan, geçici düzeltmeler yapmaktan ve… rahatsız edici kullanıcılardan daha azdır. Kısmi işlevlerin bazılarının olma olasılığını otomatik olarak azaltacaktır.
// sözde kod function doTransfer(Durum durumu) { geçiş (durum) { case State.canTransfer { // mevcut transfer için bir şeyler yap } case State.cannotTransfer { // transfer için bir şey yap mümkün değil } case State.notActive { // transfer için bir şey yap mümkün değil } // Aktif olmadan transferin mevcut olduğunu göstermek mümkün değil // sadece üç olası durum var } }
Geçersiz durumları nasıl imkansız hale getirebilirsiniz? Önceki örneklerden ikisini seçelim. İki boole değişkenimiz 'isActive' ve 'canTransfer' durumunda, bu ikisini tek bir numaralandırmayla değiştirebiliriz. Tüm olası ve geçerli durumları kapsamlı bir şekilde temsil edecektir. O zaman bile birileri tanımsız değişkenler gönderebilir, ancak bununla başa çıkmak çok daha kolaydır. Her şeyi daha da zorlaştıran geçersiz bir durum yerine programımıza aktarılmayacak geçersiz bir değer olacaktır.
Bekleme işlevimiz, güçlü yazılan dillerde de güzel bir şekilde geliştirilebilir. Girişte yalnızca işaretsiz tamsayıları kullanmasını sağlayabiliriz. Geçersiz argümanlar derleyici tarafından ayıklanacağından, bu tek başına tüm sorunlarımızı çözecektir. Ama ya dilinizin türleri yoksa? Bazı olası çözümlerimiz var. İlk olarak – sadece crash, bu fonksiyon negatif sayılar için tanımsızdır ve geçersiz veya tanımsız şeyler yapmayacağız. Testler sırasında geçersiz kullanımını bulmamız gerekecek. Birim testleri (ki zaten yapmalıyız) burada gerçekten önemli olacak. İkincisi – bu riskli olabilir, ancak bağlama bağlı olarak faydalı olabilir. Mümkün olduğunda geçersiz durumları düzeltmek için üretim dışı yapılarda iddiayı sürdüren geçerli değerlere geri dönebiliriz. Bunun gibi işlevler için iyi bir çözüm olmayabilir, ancak tamsayı yerine mutlak değer yaparsak uygulama çökmelerini önlemiş oluruz. Somut dile bağlı olarak, bunun yerine bazı hata/istisnalar atmak/yükseltmek iyi bir fikir olabilir. Mümkünse geri dönmeye değer olabilir, kullanıcı bir hata gördüğünde bile çökmekten çok daha iyi bir deneyimdir.
Burada bir örnek daha verelim. Ön uç uygulamanızdaki kullanıcı verilerinin durumu bazı durumlarda geçersiz olmak üzereyse, oturumu kapatmaya zorlamak ve çökmek yerine sunucudan tekrar geçerli veriler almak daha iyi olabilir. Kullanıcı yine de bunu yapmaya zorlanabilir veya sonsuz bir kilitlenme döngüsüne yakalanabilir. Bir kez daha – üretim dışı ortamlarda bu tür durumlarda iddiada bulunmalı ve çökmeliyiz, ancak kullanıcılarınızın harici test kullanıcıları olmasına izin vermemeliyiz.
Özet
Kilitlenen ve kararsız uygulamaları kimse sevmez. Bunları yapmayı da kullanmayı da sevmiyoruz. Geliştirme ve testler sırasında faydalı teşhis sağlayan iddialarla hızlı bir şekilde başarısız olmak, birçok sorunu erken yakalayacaktır. Üretimdeki geçerli durumlara geri dönüş, uygulamanızı çok daha kararlı hale getirecektir. Geçersiz durumları temsil edilemez kılmak, bütün bir sorun sınıfını ortadan kaldıracaktır. Geliştirmeden önce, geçersiz durumları nasıl çıkaracağınız ve geri döneceğiniz hakkında düşünmek için kendinize biraz daha zaman tanıyın ve bazı iddiaları eklemek için yazarken biraz daha zaman verin. Uygulamalarınızı bugün daha iyi hale getirmeye başlayabilirsiniz!
Devamını oku:
- Sözleşmeye göre tasarım
- cebirsel veri türü