Sonlu-durum-makine dökümünden nasıl kurtulur?


14

Sorum çok bilimsel görünebilir, ancak bence bu yaygın bir sorundur ve deneyimli geliştiriciler ve programcılar, bahsettiğim sorunu önlemek için bazı tavsiyelerde bulunacaklardır. Btw., Aşağıda tarif ettiğim şey, iOS projemde proaktif olarak çözmeye çalıştığım gerçek bir problem, ne pahasına olursa olsun önlemek istiyorum.

Sonlu durum makinesi ile bunu kastediyorum> birkaç düğmeli bir kullanıcı arayüzüm var, bu kullanıcı arayüzü ile ilgili birkaç oturum durumu ve bu kullanıcı arayüzü neyi temsil ediyor, değerler kullanıcı arayüzünde kısmen görüntülenen bazı verilerim var, bazı harici tetikleyicileri alıyorum ve işliyorum (sensörlerden gelen geri çağrılarla temsil edilir). Bu kullanıcı arayüzünde ve uygulamada arzu edilen ve mevcut olan ilgili senaryoları daha iyi haritalamak için durum diyagramları yaptım. Kodu yavaşça uyguladığımda, uygulama olması gerektiği gibi gittikçe daha fazla davranmaya başlar. Ancak, yeterince sağlam olduğundan pek emin değilim. Şüphelerim, kendi düşünme ve uygulama süreçlerimi izlemekten geliyor. Her şeyi kapsadığımdan emindim, ancak kullanıcı arayüzünde birkaç kaba test yapmak yeterliydi ve çabucak davranışta hala boşluklar olduğunu fark ettim .. Onları yamaladım. Ancak, çünkü her bileşen başka bir bileşenden gelen girdiye bağlı olarak hareket eder ve kullanıcıdan veya bazı harici kaynaklardan gelen belirli bir girdi bir olaylar zincirini tetikler, durum değişiklikleri .. vb. Ben birkaç bileşen var ve her biri gibi Tetik girdi -> tetik ve onun analiz analiz -> analiz dayalı bir şey (bir mesaj, bir durum değişikliği) alınan davranır

Sorun şu ki, bu tamamen kendi kendine yetmez ve bileşenlerim (veritabanı öğesi, oturum durumu, bazı düğmelerin durumu) ... Olay zincirinin kapsamı dışında değiştirilebilir, etkilenebilir, silinebilir veya başka şekilde değiştirilebilir istenen senaryo. (telefon çökerse, pil aniden boştur telefon dönüşü) Bu sisteme, sistemin kurtarılması için potansiyel OLMADIĞI GEREKEN OLMAYAN geçersiz bir durum getirecektir. Bunu görüyorum (düşünülen insanlar bu sorunun farkında değil) Apple mağazasındaki rakiplerimin uygulamalarının çoğunda, müşteriler böyle şeyler yazıyor> "Üç belge ekledim ve oraya gidip onları açamıyorum, onları görse bile. " veya "Her gün video kaydettim, ancak çok günlük bir video kaydettikten sonra, altyazıları açamıyorum .. ve altyazı düğmesi görünmüyor '

Bunlar sadece kısaltılmış örneklerdir, müşteriler genellikle daha ayrıntılı olarak açıklar ... bunlarda açıklanan açıklamalardan ve davranışlardan, belirli bir uygulamanın bir FSM arızası olduğunu varsayalım.

Yani asıl soru bundan nasıl kaçınabilirim ve sistemi kendi kendini engellemekten nasıl koruyacağım?

EDIT> Ben bir viewcontroller telefonda görüş bağlamında konuşuyorum, ben uygulamanın bir parçası demek. MVC modelini anlıyorum, farklı işlevsellik için ayrı modüllerim var ... Açıkladığım her şey kullanıcı arayüzündeki bir tuvalle ilgili.


2
Ünite testleri için bir dava gibi geliyor!
Michael K

Yanıtlar:


7

Bunu zaten bildiğinizden eminim ama her ihtimale karşı:

  1. Durum şemasındaki her düğümün HER yasal girdi türü için giden bir yay olduğundan emin olun (veya girişleri sınıflara ayırın, her girdi sınıfı için bir giden yayla).

    Bir durum makinesinde gördüğüm her örnek, HERHANGİ BİR hatalı giriş için yalnızca bir giden ark kullanır.

    Bir girişin her seferinde ne yapacağına dair kesin bir cevap yoksa, bu bir hata şartıdır veya eksik olan başka bir giriş vardır (sürekli olarak yeni bir düğüme giden girişler için bir yayla sonuçlanmalıdır).

    Bir düğümün bir tip giriş için ark yoksa, bu girişin gerçek hayatta asla gerçekleşmeyeceği bir varsayımdır (bu durum durum makinesi tarafından ele alınmayacak potansiyel bir hata durumudur).

  2. Durum makinesinin, alınan girişe yanıt olarak yalnızca bir ark alabildiğinden veya takip edebildiğinden emin olun (birden fazla ark olamaz).

    Durum makinesi tasarım zamanında farklı türde hata senaryoları veya tanımlanamayan girdi türleri varsa, hata senaryoları ve bilinmeyen girdiler "normal yaylardan" ayrı bir yol içeren bir duruma yayılmalıdır.

    IE herhangi bir "bilinen" durumda hata veya bilinmeyen bir durumda alınırsa, hata işleme / bilinmeyen girişin sonucu olarak izlenen yaylar, yalnızca bilinen girişleri alırsa makinenin bulunduğu duruma geri dönmemelidir.

  3. Bir terminal (bitiş) durumuna ulaştıktan sonra, terminal olmayan bir konuma yalnızca bir başlangıç ​​(başlangıç) durumuna geri dönememelisiniz.

  4. Bir durum makinesi için birden fazla başlangıç ​​veya başlangıç ​​durumu olmamalıdır (gördüğüm örneklere dayanarak).

  5. Ne gördüm dayalı bir devlet makine sadece bir sorun veya senaryo durumunu temsil edebilir.
    Tek bir durum diyagramında aynı anda asla birden fazla olası durum olmamalıdır.
    Birden fazla eşzamanlı durum için potansiyel görürsem, bu durumun durum diyagramını, her durumun bağımsız olarak değiştirilme potansiyeline sahip 2 veya daha fazla ayrı durum makinesine ayırmam gerektiğini söyler.


10

Sonlu durum makinesinin amacı, bir durumda olabilecek her şey için açık kurallara sahip olmasıdır. Bu yüzden sonludur .

Örneğin:

if a:
  print a
elif b:
  print b

değil biz girdi alabilir çünkü, sonlu c. Bu:

if a:
  print a
elif b:
  print b
else:
  print error

sonludur, çünkü olası tüm girdiler hesaba katılır. Bu , hata kontrolünden ayrı olabilecek bir duruma olası girişleri açıklar . Aşağıdaki durumlara sahip bir durum makinesi düşünün:

No money state. 
Not enough money state.
Pick soda state.

Tanımlanan durumlar dahilinde, olası tüm girdiler eklenen para ve soda için ele alınır. Elektrik kesintisi durum makinesinin dışında ve "mevcut değil". Bir durum makinesi, yalnızca sahip olduğu durumlar için girişleri işleyebilir, böylece iki seçeneğiniz vardır.

  1. Her şeyin atomik olduğunu garanti edin. Makine toplam güç kaybına sahip olabilir ve yine de her şeyi istikrarlı, doğru bir durumda bırakabilir.
  2. Durumlarınızı bilinmeyen bir sorunu içerecek şekilde genişletin ve hataların sizi sorunların ele alındığı bu duruma yönlendirmesini sağlayın.

Referans olarak, devlet makinelerine ilişkin wiki makalesi ayrıntılıdır. Ayrıca kararlı, güvenilir yazılım oluşturma bölümleri için Code Complete'i öneriyorum .


"Giriş c'yi alabiliriz" - bu yüzden yazım kuralları çok önemlidir. Giriş türünüz bir bool ise, alabilirsiniz trueve falsebaşka hiçbir şey yoktur. O zaman bile türlerinizi anlamak önemlidir - örneğin null olabilecek türler, kayan nokta NaN, vb.
MSalters

5

Düzenli ifadeler sonlu durum makineleri olarak uygulanır. Kütüphane kodu tarafından oluşturulan geçiş tablosunda, girdi modelle eşleşmezse ne olacağını işlemek için yerleşik bir arıza durumu olacaktır. Hemen hemen her eyaletten başarısızlık durumuna en azından örtülü bir geçiş var.

Programlama dili dilbilgileri FSM değildir, ancak ayrıştırıcı jeneratörleri (Yacc veya bison gibi) genellikle bir veya daha fazla hata durumuna sokma yoluna sahiptir, böylece beklenmedik girdiler üretilen kodun bir hata durumuna gelmesine neden olabilir.

FSM'nizin bir hata durumuna veya bir başarısızlık durumuna veya ahlaki eşdeğere ihtiyacı olduğu gibi, hem hata (tahmin ettiğiniz durumlar için) hem de başarısızlık veya hata durumlarından birine örtük (öngörmediğiniz durumlar için) geçişler gerekir.


CS'de resmi bir eğitimim olmadığı için sorum aptalca geliyorsa beni affet ve sadece birkaç ay boyunca programlamayı öğreniyorum. Bu, bir işleyici yöntemini söylediğimde, bir düğme için itilen bir olay için ve bu yöntemde orta derecede karmaşık bir if-switch-koşullandırma yapısına (20-30 kod satırı) sahip olduğum anlamına mı geliyor? İstenmeyen girdileri her zaman açık bir şekilde ele almalıyım? VEYA bunu "küresel" düzeyde mi kastediyorsunuz? Bu FSM'yi izleyen ayrı bir sınıfım olmalı ve sorun oluştuğunda değerleri ve durumları sıfırlar mı?
Earl Grey

Yacc veya Bison tarafından üretilen ayrıştırıcıları açıklamak benim ötesimde, ancak genellikle bilinen vakalarla ilgileniyorsunuz ve daha sonra "her şey hataya veya başarısızlık durumuna gidiyor" için küçük bir kod bloğuna sahipsiniz. Hata / hata durumunun kodu tüm sıfırlamaları yapar. Arıza durumuna neden geldiğini söyleyen ekstra bir değere sahip olmalısın.
Bruce Ediger

FSM'nizde hatalar için en az bir durum veya farklı türde hatalar için birden çok hata durumu bulunmalıdır.
whatsisname

3

Bundan kaçınmanın en iyi yolu Otomatik Test'tir .

Kodunuzun belirli girdilere dayalı olarak ne yaptığına dair gerçek bir güven sahibi olmanın tek yolu bunları test etmektir. Uygulamanızda tıklayabilir ve işleri yanlış yapmaya çalışabilirsiniz, ancak herhangi bir gerileme olmadığından emin olmak için iyi ölçeklenmez. Bunun yerine, kötü girdiyi kodunuzun bir bileşenine geçiren ve bunu akılcı bir şekilde ele almasını sağlayan bir test oluşturabilirsiniz.

Bu durum, devlet makinesinin asla kırılamayacağını kanıtlayamayacaktır, ancak yaygın durumların çoğunun doğru bir şekilde ele alındığını ve başka şeyleri kırmadığını söyleyecektir.


2

aradığınız şey istisna işleme. Tutarsız bir durumda kalmaktan kaçınmak için bir tasarım felsefesi şu şekilde belgelenmiştir the way of the samurai: muzaffer dönüş veya geri dönme. Başka bir deyişle: bir bileşen tüm girdilerini kontrol etmeli ve bunları normal şekilde işleyebildiğinden emin olmalıdır. Durum böyle değil, yararlı bilgiler içeren bir istisna ortaya koymalıdır.

Bir istisna ortaya çıktığında, yığını oluşturur. Ne yapacağınızı bilecek bir hata işleme katmanı tanımlamalısınız. Bir kullanıcı dosyası bozuksa, istemcinize verilerin kaybolduğunu açıklayın ve temiz, boş bir dosya oluşturun.

Buradaki önemli kısım, çalışma durumuna geri dönüp hata yayılmasından kaçınmaktır. Bununla işiniz bittiğinde, bileşenleri daha sağlam hale getirmek için ayrı ayrı bileşenler üzerinde çalışabilirsiniz.

Ben bir obj-c uzmanı değilim, ama bu sayfa iyi bir başlangıç ​​noktası olmalı:

http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocExceptionHandling.html


1

Sonlu durum makinenizi unutun. Burada ne var bir ciddi çoklu iş parçacığı durum. Herhangi bir düğmeye herhangi bir zamanda basılabilir ve harici tetikleyicileriniz herhangi bir zamanda kapanabilir. Düğmeler muhtemelen bir iş parçacığındadır, ancak bir tetikleyici düğmelerden biri veya bir, birçok veya diğer tüm tetikleyicilerle aynı anda tamamen sönebilir.

Yapmanız gereken, harekete geçmeye karar verdiğiniz andaki durumunuzu belirlemek. Tüm düğmeleri alın ve durumları tetikleyin. Bunları yerel değişkenlere kaydedin . Orijinal değerler, her baktığınızda değişebilir. Sonra duruma sahip olduğunuz gibi davranın. Sistemin bir noktaya nasıl baktığının bir fotoğrafıdır. Milisaniye sonra çok farklı görünebilir, ancak çoklu iş parçacığıyla, asabileceğiniz gerçek bir akım "şimdi" yoktur, sadece yerel değişkenlere kaydettiğiniz bir resim vardır.

O zaman kayıtlı - tarihsel - durumunuza cevap vermelisiniz. Her şey sabittir ve olası tüm durumlar için bir eyleminiz olmalıdır. Anlık görüntüyü çektiğiniz zamanla sonuçlarınızı görüntülediğiniz zaman arasında yapılan değişiklikleri hesaba katmaz, ancak bu çok iş parçacıklı dünyada hayattır. Ayrıca, anlık görüntünüzün çok bulanık olmasını önlemek için senkronizasyon kullanmanız gerekebilir. (Güncel olamazsınız, ancak tüm durumunuzu belirli bir andan zamanında almaya yaklaşabilirsiniz .)

Çoklu iş parçacığı üzerinde okumaya devam edin. Öğrenecek çok şeyin var. Ve bu tetikleyiciler nedeniyle, paralel işlemeyi kolaylaştırmak için sık sık verilen hileleri kullanabileceğinizi sanmıyorum ("İşçi Konuları" ve benzeri). "Paralel işleme" yapmıyorsunuz; 8 çekirdeğin% 75'ini kullanmaya çalışmıyorsunuz. Tüm CPU'nun% 1'ini kullanıyorsunuz, ancak oldukça bağımsız, son derece etkileşimli iş parçacıklarınız var ve bunları senkronize etmek ve senkronizasyonu sistemi kilitlemekten korumak için çok fazla düşünmeniz gerekecek.

Hem tek çekirdekli hem de çok çekirdekli makinelerde test edin; Çoklu iş parçacığıyla oldukça farklı davrandıklarını gördüm. Tek çekirdekli makineler daha az çok iş parçacıklı hataya neden olur, ancak bu hatalar çok daha gariptir. (Çok çekirdekli makineler, alışana kadar aklınızı başınızdan alacak olsa da.)

Hoş olmayan son bir düşünce: bu test edilmesi kolay bir şey değil. Rastgele tetikleyiciler ve düğme basmaları oluşturmanız ve neyin ortaya çıktığını görmek için sistemin bir süre düz kalmasına izin vermeniz gerekir. Çok iş parçacıklı kod deterministik değildir . Bir milyar seferde bir şey başarısız olabilir, çünkü zamanlama nanosaniye için kapalı olduğu için. Hata ayıklama ifadeleri koyun (999,999,999 gereksiz mesajlardan kaçınmak için dikkatli if ifadeleriyle) ve sadece bir yararlı mesaj almak için bir milyar çalıştırma yapmanız gerekir. Neyse ki, makineler bugünlerde çok hızlı.

Tüm bunları kariyerinize bu kadar erken döktüğünüz için üzgünüm. Umarım birileri tüm bunların etrafında bir yolla başka bir cevap bulur (Bence orada tetikleyicileri evcilleştirebilecek şeyler var, ama hala tetik / düğme çakışması var). Öyleyse, bu cevap en azından neyi kaçırdığınızı size bildirecektir. İyi şanslar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.