परिमित-राज्य-मशीन के टूटने से कैसे उबरें?


14

मेरा प्रश्न बहुत वैज्ञानिक लग सकता है, लेकिन मुझे लगता है कि यह एक सामान्य समस्या है और अनुभवी डेवलपर्स और प्रोग्रामर को उम्मीद है कि शीर्षक में मेरे द्वारा बताई गई समस्या से बचने के लिए कुछ सलाह होगी। Btw।, जो मैं वर्णन करता हूं कि bellow एक वास्तविक समस्या है जिसे मैं अपने iOS प्रोजेक्ट में लगातार हल करने की कोशिश कर रहा हूं, मैं इसे हर कीमत पर टालना चाहता हूं।

परिमित राज्य मशीन से मेरा यह मतलब है> मेरे पास कुछ बटनों के साथ एक UI है, कई सत्र उस UI के लिए प्रासंगिक हैं और यह UI क्या दर्शाता है, मेरे पास कुछ डेटा हैं जो मान यूआई में आंशिक रूप से प्रदर्शित होते हैं, मुझे कुछ बाहरी ट्रिगर मिलते हैं और संभालते हैं (सेंसर से कॉलबैक द्वारा दर्शाया गया है)। मैंने उन यूआई और एप्लिकेशन के लिए प्रासंगिक परिदृश्यों को बेहतर ढंग से चित्रित करने के लिए राज्य चित्र बनाए, जो उस यूआई और एप्लिकेशन में वांछनीय हैं। जैसा कि मैं धीरे-धीरे कोड को लागू करता हूं, ऐप को अधिक से अधिक व्यवहार करना शुरू करना चाहिए, जैसे कि यह चाहिए। हालांकि, मैं बहुत आश्वस्त नहीं हूं कि यह काफी मजबूत है। मेरी शंकाएँ मेरी अपनी सोच और क्रियान्वयन की प्रक्रिया को देखने से आती हैं। मुझे विश्वास था कि मेरे पास सब कुछ है, लेकिन यह यूआई में कुछ क्रूर परीक्षण करने के लिए पर्याप्त था और मुझे जल्दी से एहसास हुआ कि व्यवहार में अभी भी अंतराल हैं .. मैंने उन्हें पैच किया। तथापि, जैसा कि प्रत्येक घटक निर्भर करता है और किसी अन्य घटक से इनपुट के आधार पर व्यवहार करता है, उपयोगकर्ता या कुछ बाहरी स्रोत से एक निश्चित इनपुट घटनाओं की एक श्रृंखला को चलाता है, राज्य बदलता है..सीटीसी। मेरे पास कई घटक हैं और प्रत्येक ऐसे व्यवहार करता है जैसे इनपुट पर प्राप्त ट्रिगर -> ट्रिगर और इसके प्रेषक का विश्लेषण किया -> आउटपुट कुछ (एक संदेश, एक राज्य परिवर्तन) विश्लेषण के आधार पर

समस्या यह है, यह पूरी तरह से आत्मनिर्भर नहीं है, और मेरे घटकों (एक डेटाबेस आइटम, एक सत्र राज्य, कुछ बटन की स्थिति) ... COULD को घटना-श्रृंखला के दायरे से बाहर, प्रभावित, नष्ट, या अन्यथा संशोधित किया जा सकता है। वांछनीय परिदृश्य। (फोन क्रैश, बैटरी अचानक से फोन की खाली बारी है) यह सिस्टम में एक नॉनलाइड स्थिति को पेश करेगा, जिससे पुनर्प्राप्त करने के लिए सिस्टम संभावित रूप से COULD NOT BE ABLE होगा। मैं यह देखता हूं (इस बारे में लोगों को इस बात का एहसास नहीं है कि यह समस्या है) ऐप्पल स्टोर पर मौजूद मेरे कई प्रतिस्पर्धी ऐप में, ग्राहक इस तरह की बातें लिखते हैं> "मैंने तीन दस्तावेज़ जोड़े, और वहां और वहां जाने के बाद, मैं उन्हें नहीं खोल सकता, भले ही उन्हें देख लें। ” या "मैंने हर रोज़ वीडियो रिकॉर्ड किया है, लेकिन बहुत लॉग वीडियो रिकॉर्ड करने के बाद, मैं उन पर कैप्शन नहीं बदल सकता हूँ .. और कैप्शन के लिए बटन नहीं है '

ये केवल छोटे उदाहरण हैं, ग्राहक अक्सर इसका अधिक विस्तार से वर्णन करते हैं..उनमें वर्णित वर्णन और व्यवहार से, मेरा मानना ​​है कि विशेष एप्लिकेशन में FSM का टूटना है।

तो अंतिम सवाल यह है कि मैं इससे कैसे बच सकता हूं, और सिस्टम को खुद को ब्लॉक करने से कैसे बचा सकता हूं?

EDIT> मैं फोन पर एक व्यू कॉन्ट्रॉलर के दृष्टिकोण के संदर्भ में बात कर रहा हूं, मेरा मतलब है कि आवेदन का एक हिस्सा। मैं एमवीसी पैटर्न को समझता हूं, मेरे पास अलग-अलग कार्यक्षमता के लिए अलग-अलग मॉड्यूल हैं..सब कुछ मैं यूआई पर एक कैनवास के लिए प्रासंगिक हूं।


2
यूनिट परीक्षणों के लिए एक मामले की तरह लगता है!
माइकल के

जवाबों:


7

मुझे यकीन है कि आप पहले से ही यह जानते हैं लेकिन सिर्फ मामले में:

  1. सुनिश्चित करें कि राज्य आरेख के प्रत्येक नोड में हर तरह के इनपुट के लिए एक आउटगोइंग आर्क है (या इनपुट में वर्गों को विभाजित करें, प्रत्येक वर्ग के इनपुट के लिए एक आउटबाउंड आर्क के साथ)।

    हर उदाहरण जो मैंने देखा है कि राज्य मशीन किसी भी गलत इनपुट के लिए केवल एक आउटबाउंड आर्क का उपयोग करती है।

    यदि कोई निश्चित उत्तर नहीं है कि इनपुट हर बार क्या करेगा, तो यह या तो एक त्रुटि स्थिति है, या कोई अन्य इनपुट है जो अनुपलब्ध है (जो कि नए नोड पर जाने वाले इनपुट के लिए लगातार आर्क का परिणाम चाहिए)।

    यदि नोड में एक प्रकार के इनपुट के लिए चाप नहीं है, तो यह एक धारणा है कि इनपुट वास्तविक जीवन में कभी नहीं होगा (यह एक संभावित त्रुटि स्थिति है जिसे राज्य मशीन द्वारा नियंत्रित नहीं किया जाएगा)।

  2. सुनिश्चित करें कि प्राप्त की गई इनपुट के जवाब में केवल एक चाप ही राज्य मशीन ले सकता है या उसका अनुसरण कर सकता है (एक से अधिक चाप नहीं)।

    यदि विभिन्न प्रकार के त्रुटि परिदृश्य हैं, या इनपुट के प्रकार जिन्हें राज्य मशीन डिज़ाइन समय पर पहचाना नहीं जा सकता है, तो त्रुटि परिदृश्य और अज्ञात इनपुट को "सामान्य आर्क्स" से पूरी तरह से अलग पथ के साथ एक राज्य में आर्क होना चाहिए।

    IE यदि किसी "ज्ञात" स्थिति में कोई त्रुटि या अज्ञात प्राप्त होता है, तो त्रुटि-हैंडलिंग / अज्ञात इनपुट के परिणामस्वरूप आर्क्स का पालन किया जाना चाहिए, किसी भी स्थिति में वापस नहीं जाना चाहिए मशीन केवल यदि ज्ञात इनपुट प्राप्त होता है।

  3. एक बार जब आप एक टर्मिनल (अंतिम) स्थिति पर पहुंच जाते हैं, तो आपको केवल एक ही प्रारंभिक (प्रारंभिक) स्थिति में एक गैर-टर्मिनल पर वापस जाने में सक्षम नहीं होना चाहिए।

  4. एक राज्य मशीन के लिए एक से अधिक प्रारंभिक या प्रारंभिक स्थिति नहीं होनी चाहिए (उदाहरण मैंने देखा है उदाहरणों के आधार पर)।

  5. मैंने जो देखा है, उसके आधार पर एक राज्य मशीन केवल एक समस्या या परिदृश्य की स्थिति का प्रतिनिधित्व कर सकती है।
    एक राज्य के आरेख में एक समय में कई संभावित राज्य नहीं होने चाहिए।
    अगर मैं कई समवर्ती राज्यों के लिए क्षमता देखता हूं तो यह बताता है कि मुझे राज्य के आरेख को 2 या अधिक अलग-अलग राज्य मशीनों में विभाजित करने की आवश्यकता है जो कि प्रत्येक राज्य को स्वतंत्र रूप से संशोधित करने की क्षमता रखते हैं।


10

एक परिमित राज्य मशीन की बात यह है कि इसमें हर चीज के लिए स्पष्ट नियम हैं जो किसी राज्य में हो सकते हैं। इसलिए यह परिमित है

उदाहरण के लिए:

if a:
  print a
elif b:
  print b

है , परिमित क्योंकि हम इनपुट मिल सकता है c। इस:

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

परिमित है, क्योंकि सभी संभावित इनपुट के लिए जिम्मेदार है। यह एक राज्य के लिए संभावित आदानों के लिए खाता है , जो त्रुटि जाँच से अलग हो सकता है। निम्नलिखित राज्यों के साथ एक राज्य मशीन की कल्पना करें:

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

परिभाषित राज्यों के भीतर, चुने गए धन और सोडा के लिए सभी संभावित आदानों को संभाला जाता है। बिजली की विफलता राज्य मशीन के बाहर है, और "मौजूद नहीं है"। एक राज्य मशीन केवल उन राज्यों के लिए इनपुट संभाल सकती है, जो आपके पास हैं, इसलिए आपके पास दो विकल्प हैं।

  1. गारंटी है कि सब कुछ परमाणु है। मशीन में कुल बिजली हानि हो सकती है और अभी भी सब कुछ एक स्थिर, सही स्थिति में छोड़ सकता है।
  2. अज्ञात समस्या को शामिल करने के लिए अपने राज्यों का विस्तार करें, और त्रुटियां हैं जो आपको इस स्थिति में ले जाती हैं, जहां मुद्दों को नियंत्रित किया जाता है।

संदर्भ के लिए, राज्य मशीनों पर विकि लेख पूरी तरह से है। मैं स्थिर, भरोसेमंद सॉफ़्टवेयर के निर्माण पर अध्यायों के लिए भी कोड पूरा करने का सुझाव देता हूं ।


"हम इनपुट सी प्राप्त कर सकते हैं" - यही कारण है कि प्रकार की भाषाएं इतनी महत्वपूर्ण हैं। यदि आपका इनपुट प्रकार एक बूल है, तो आप प्राप्त कर सकते हैं trueऔर false, लेकिन कुछ नहीं। फिर भी आपके प्रकारों को समझना महत्वपूर्ण है - जैसे अशक्त प्रकार, फ्लोटिंग-पॉइंट NaN, आदि
MSalters

5

नियमित अभिव्यक्तियाँ परिमित राज्य मशीनों के रूप में कार्यान्वित की जाती हैं। लाइब्रेरी कोड द्वारा उत्पन्न ट्रांस्फ़ॉर्म टेबल में एक विफलता स्थिति होगी, जो इनपुट के पैटर्न से मेल नहीं खाने पर क्या होता है। कम से कम लगभग हर दूसरे राज्य से विफलता राज्य के लिए एक अंतर्निहित संक्रमण है।

प्रोग्रामिंग लैंग्वेज व्याकरण FSM नहीं हैं, लेकिन पार्सर जनरेटर (जैसे Yacc या bison) में आम तौर पर एक या एक से अधिक एरर स्टेट्स में डालने का एक तरीका होता है, ताकि अनपेक्षित इनपुट्स उत्पन्न कोड को एक एरर स्टेट में समाप्त कर सकें।

ऐसा लगता है कि आपके FSM को एक त्रुटि स्थिति या विफलता राज्य या नैतिक समतुल्य की आवश्यकता है, दोनों स्पष्ट (मामलों के लिए आप अनुमान लगाते हैं) और अंतर्निहित (उन मामलों के लिए जो आप अनुमान नहीं लगाते हैं) विफलता या त्रुटि राज्यों में से एक में संक्रमण।


मुझे माफ़ कर दो, अगर मेरा सवाल मूर्खतापूर्ण है, क्योंकि मेरे पास सीएस में कोई औपचारिक शिक्षा नहीं है, और मैं सिर्फ कुछ महीनों के लिए प्रोग्रामिंग सीख रहा हूं। क्या इसका मतलब यह है कि, जब मैंने एक हैंडलर विधि को एक बटन के लिए धकेलने वाली घटना के लिए कहा है, और उस पद्धति में मेरे पास मामूली जटिल है अगर-और-स्विच-कंडीशनिंग संरचना (कोड के 20-30 लाइनें), मुझे हमेशा विस्फोटक इनपुटों को संभालना चाहिए? या क्या आप इसका मतलब "वैश्विक" स्तर पर हैं? क्या मुझे इस FSM को देखने का एक अलग वर्ग होना चाहिए, और जब समस्या होती है, तो यह मूल्यों और राज्यों को रीसेट करेगा?
अर्ल ग्रे

येकाक या बाइसन उत्पन्न पार्सर्स को समझाना मेरे से परे है, लेकिन आमतौर पर, आप ज्ञात मामलों से निपटते हैं, और फिर "बाकी सब कुछ त्रुटि या असफलता की स्थिति में जाता है" के लिए एक छोटा कोड ब्लॉक होता है। त्रुटि / विफलता राज्य के लिए कोड सभी रीसेट करना होगा। शायद आपके पास एक अतिरिक्त मूल्य होना चाहिए जो कहता है कि आप विफलता की स्थिति में क्यों आए।
ब्रूस एडगर

आपके FSM में त्रुटियों के लिए कम से कम एक राज्य होना चाहिए, या विभिन्न प्रकार की त्रुटियों के लिए एकाधिक त्रुटि अवस्थाएँ होनी चाहिए।
whatsisname

3

इससे बचने का सबसे अच्छा तरीका है ऑटोमेटेड टेस्टिंग

कुछ इनपुट्स के आधार पर आपका कोड क्या करता है, इसके बारे में वास्तविक विश्वास रखने का एकमात्र तरीका उन्हें परीक्षण करना है। आप अपने आवेदन में चारों ओर क्लिक कर सकते हैं और चीजों को गलत तरीके से करने की कोशिश कर सकते हैं, लेकिन यह सुनिश्चित करने के लिए अच्छी तरह से पैमाने पर नहीं है कि आपके पास कोई प्रतिगमन नहीं है। इसके बजाय, आप एक परीक्षण बना सकते हैं जो आपके कोड के एक घटक में खराब इनपुट को पारित करता है और यह सुनिश्चित करता है कि यह इसे एक समझदार तरीके से संभालता है।

यह साबित नहीं कर पाएगा कि राज्य मशीन कभी भी टूट नहीं सकती है, लेकिन यह आपको बताएगी कि कई सामान्य मामलों को सही तरीके से संभाला जाता है और अन्य चीजों को तोड़ना नहीं है।


2

आप जो देख रहे हैं वह अपवाद हैंडलिंग है। असंगत स्थिति में रहने से बचने के लिए एक डिजाइन दर्शन के रूप में प्रलेखित किया गया है the way of the samurai: विजयी लौटें या न लौटें। दूसरे शब्दों में: एक घटक को अपने सभी इनपुटों की जांच करनी चाहिए और यह सुनिश्चित करना चाहिए कि यह उन्हें सामान्य रूप से संसाधित करने में सक्षम होगा। यह मामला नहीं है, इसे उपयोगी जानकारी वाले अपवाद को उठाना चाहिए।

एक बार एक अपवाद उठाया जाता है, यह ढेर को बुलबुले बनाता है। आपको एक एरर हैंडलिंग लेयर को परिभाषित करना चाहिए जिससे पता चलेगा कि क्या करना है। यदि कोई उपयोगकर्ता फ़ाइल दूषित है, तो अपने क्लाइंट को समझाएं कि डेटा खो गया है, और एक साफ खाली फ़ाइल को फिर से बनाएँ।

यहां महत्वपूर्ण हिस्सा एक कार्यशील स्थिति में वापस आना है, और त्रुटि प्रसार से बचना है। जब आप इसके साथ हो जाते हैं, तो आप उन्हें और अधिक मजबूत बनाने के लिए व्यक्तिगत घटकों पर काम कर सकते हैं।

मैं एक उद्देश्य-सी विशेषज्ञ नहीं हूं, लेकिन यह पृष्ठ एक अच्छा प्रारंभिक बिंदु होना चाहिए:

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


1

अपनी परिमित-राज्य-मशीन को भूल जाओ। यहां आपके पास एक गंभीर बहु-सूत्रण स्थिति है। किसी भी समय किसी भी बटन को दबाया जा सकता है और आपके बाहरी ट्रिगर किसी भी समय बंद हो सकते हैं। बटन संभवतः सभी एक धागे पर हैं, लेकिन एक ट्रिगर एक ही बटन या एक, कई, या अन्य सभी ट्रिगर के रूप में उसी पल में जा सकते हैं।

जिस समय आप कार्य करने का निर्णय लेते हैं, उस समय आपको अपने राज्य का निर्धारण करना चाहिए। सभी बटन प्राप्त करें और राज्यों को ट्रिगर करें। उन्हें स्थानीय चर में सहेजें । हर बार जब आप उन्हें देखते हैं तो मूल मान बदल सकते हैं। फिर स्थिति पर कार्य करें जैसा कि आपके पास है। यह एक स्नैपशॉट है कि सिस्टम ने एक बिंदु पर कैसे देखा। एक मिलीसेकंड बाद में यह बहुत अलग दिख सकता था, लेकिन बहु-थ्रेडिंग के साथ कोई वास्तविक वर्तमान "अब" नहीं है जिस पर आप लटका सकते हैं, केवल एक तस्वीर जिसे आपने स्थानीय चर में सहेजा है।

फिर आपको अपने सहेजे गए - ऐतिहासिक - राज्य का जवाब देना होगा। सब कुछ तय हो गया है और आपको सभी संभावित राज्यों के लिए एक कार्रवाई करनी चाहिए। आपके द्वारा स्नैपशॉट लेने और आपके परिणाम प्रदर्शित करने के समय के बीच किए गए परिवर्तनों को ध्यान में नहीं रखा जाएगा, लेकिन बहु-प्रसार दुनिया में यह जीवन है। और आपको अपने स्नैपशॉट को बहुत धुंधला होने से बचाने के लिए सिंक्रनाइज़ेशन का उपयोग करने की आवश्यकता हो सकती है। (आप अप-टू-डेट नहीं हो सकते हैं, लेकिन आप अपने पूरे राज्य को एक विशेष समय से तुरंत प्राप्त करने के करीब आ सकते हैं ।)

मल्टी-थ्रेडिंग पर पढ़ें। आपके पास सीखने के लिए बहुत कुछ है। और उन ट्रिगर्स के कारण, मुझे नहीं लगता कि आप समानांतर प्रसंस्करण को आसान बनाने के लिए अक्सर प्रदान की जाने वाली ट्रिक का उपयोग कर सकते हैं ("वर्कर थ्रेड्स" और ऐसे)। आप "समानांतर प्रसंस्करण" नहीं कर रहे हैं; आप 8 कोर के 75% का उपयोग करने की कोशिश नहीं कर रहे हैं। आप संपूर्ण CPU का 1% उपयोग कर रहे हैं, लेकिन आपके पास अत्यधिक स्वतंत्र, अत्यधिक इंटरेक्टिव थ्रेड्स हैं, और उन्हें सिंक्रनाइज़ करने और सिस्टम को लॉक करने से सिंक्रनाइज़ करने के लिए बहुत सारे विचार की आवश्यकता होगी।

दोनों सिंगल कोर और मल्टी-कोर मशीनों पर परीक्षण; मैंने पाया है कि वे बहु-थ्रेडिंग के साथ अलग तरह से व्यवहार करते हैं। सिंगल-कोर मशीनें कम बहु-थ्रेडिंग बग को बदल देती हैं, लेकिन वे बग अधिक अजीब हैं। (हालांकि मल्टी-कोर मशीनें आपके दिमाग को तब तक घेरेगी, जब तक आप उनकी आदत नहीं डालते।)

एक अंतिम अप्रिय विचार: यह परीक्षण करने के लिए आसान सामान नहीं है। आपको यादृच्छिक ट्रिगर्स और बटन प्रेस उत्पन्न करने की आवश्यकता होगी और सिस्टम को कुछ समय के लिए सपाट रन आउट करने की अनुमति देता है कि क्या दिखता है। मल्टी-थ्रेडेड कोड नियतात्मक नहीं है। एक अरब रन में एक बार कुछ विफल हो सकता है, सिर्फ इसलिए कि समय एक नैनोसेकंड के लिए बंद था। डिबग स्टेटमेंट्स में रखें (सावधानी के साथ-यदि स्टेटमेंट्स 999,999,999 अनावश्यक संदेश से बचने के लिए) और आपको केवल एक उपयोगी संदेश प्राप्त करने के लिए एक अरब रन बनाने की आवश्यकता है। सौभाग्य से, मशीनें इन दिनों वास्तविक तेज़ हैं।

आपके करियर के आरंभ में यह सब आप पर डंप करने के लिए क्षमा करें। उम्मीद है कि कोई व्यक्ति इस सब के साथ एक और जवाब के साथ आएगा (मुझे लगता है कि वहाँ सामान है जो ट्रिगर को वश में कर सकता है, लेकिन आपको अभी भी ट्रिगर / बटन संघर्ष मिल गया है)। यदि हां, तो यह उत्तर कम से कम आपको बताएगा कि आप क्या याद कर रहे हैं। सौभाग्य।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.