有限状態マシンの故障から回復する方法は?


13

私の質問は非常に科学的に思えるかもしれませんが、よくある問題だと思います。経験豊富な開発者やプログラマーは、タイトルで言及した問題を回避するためのアドバイスを希望します。ところで、私が以下で説明するのは、iOSプロジェクトで積極的に解決しようとしている真の問題です。

有限状態マシンとは、これを意味します>いくつかのボタン、そのUIに関連するいくつかのセッション状態、およびこのUIが表すものがあるUIがあり、UIに値が部分的に表示されるデータがあり、いくつかの外部トリガーを受信して​​処理します(センサーからのコールバックで表されます)。状態図を作成して、そのUIとアプリケーションで望ましい、必要なシナリオをより適切にマップしました。ゆっくりとコードを実装するにつれて、アプリはより適切に動作し始めます。ただし、十分な堅牢性があるとは確信がありません。私の疑問は、自分自身の思考と実装プロセスが進行するのを見ることです。私はすべてをカバーしていると確信していましたが、UIでいくつかのブルートテストを行うだけで十分であり、動作にまだギャップがあることにすぐに気付きました..それらにパッチを適用しました。しかしながら、各コンポーネントは、他のコンポーネントからの入力、ユーザーまたは特定の外部ソースからの特定の入力に基づいて動作し、一連のイベント、状態変更などをトリガーします。複数のコンポーネントがあり、それぞれが入力で受信したトリガーのように動作します->トリガーとその送信者が分析->分析に基づいて何か(メッセージ、状態変化)を出力します

問題は、これは完全に自己完結型ではなく、私のコンポーネント(データベース項目、セッション状態、ボタンの状態)...イベントチェーンの範囲外で変更、影響、削除、またはその他の方法で変更される可能性があることです望ましいシナリオ。(電話がクラッシュし、バッテリーが突然空になります)これにより、システムが無効になり、システムが回復できなくなる可能性があります。アップルストアにある競合他社のアプリの多くで、これが見られます(これは問題だと人々は認識していませんが)、顧客は次のように書きます>「3つのドキュメントを追加しました。たとえそれらを見たとしても。」または「毎日ビデオを録画しましたが、あまりにログの多いビデオを録画した後、それらのキャプションをオフにすることはできません。キャプションのボタンはありません」

これらは単なる短縮例であり、顧客はしばしばそれをより詳細に説明します。それらに記載されている説明と動作から、特定のアプリにFSMの内訳があると思います。

究極の問題は、これをどのように回避でき、システムがそれ自体をブロックするのを防ぐ方法ですか?

編集>私は電話で1つのviewcontrollerのビューのコンテキストで話している、私はアプリケーションの一部を意味します。MVCパターンを理解し、機能ごとに個別のモジュールを用意しています。説明するものはすべて、UIの1つのキャンバスに関連しています。


2
単体テストの場合のように聞こえます!
マイケルK

回答:


7

あなたはすでにこれを知っていますが、念のために:

  1. 状態図のすべてのノードに、すべての正当な種類の入力に対する発信アークがあることを確認してください(または入力クラスごとに1つの発信アークを使用して、入力をクラスに分割してください)。

    ステートマシンについて私が見たすべての例では、誤った入力に対して送信アークを1つだけ使用しています。

    入力が毎回何をするかについて明確な答えがない場合、それはエラー状態であるか、または欠落している別の入力があります(新しいノードに行く入力のアークを常に発生させるはずです)。

    ノードに1種類の入力に対するアークがない場合、それは入力が実際には決して発生しないという仮定です(これはステートマシンによって処理されない潜在的なエラー状態です)。

  2. ステートマシンは、受信した入力に応じて1つのアークのみを取得または追跡できることを確認します(1つ以上のアークは不可)。

    さまざまな種類のエラーシナリオ、またはステートマシンの設計時に識別できない種類の入力がある場合、エラーシナリオと不明な入力は、「通常のアーク」とは別の完全に別個のパスを持つ状態にアークします。

    IEが「既知」の状態でエラーまたは不明を受信した場合、エラー処理/不明な入力の結果として続くアークは、既知の入力のみを受信した場合のマシンの状態に戻らないようにします。

  3. ターミナル(終了)状態に到達すると、開始(初期)状態の1つだけに非ターミナルに戻ることはできません。

  4. 1つのステートマシンに対して、複数の開始状態または初期状態が存在することはありません(これまでの例に基づいています)。

  5. 私が見たものに基づいて、1つの状態マシンは1つの問題またはシナリオの状態のみを表すことができます。
    1つの状態図に一度に複数の状態が存在することはありません。
    複数の同時状態の可能性がある場合、これは、状態図を2つ以上の個別の状態マシンに分割し、各状態を個別に変更できる可能性があることを示しています。


9

有限状態マシンのポイントは、状態で発生する可能性のあるすべてについて明示的なルールがあることです。それが有限である理由です。

例えば:

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.

定義された状態内で、挿入されたお金とソーダが選択されたすべての可能な入力が処理されます。電源障害はステートマシンの外側にあり、「存在しません」。状態マシンは、その状態の入力のみを処理できるため、2つの選択肢があります。

  1. すべてのアクションがアトミックであることを保証します。マシンの総電力損失が発生しても、すべてが安定した正しい状態のままになります。
  2. 状態を拡張して未知の問題を含め、エラーがあると、この状態に追い込まれ、問題が処理されます。

参考のために、ステートマシンに関するwiki記事は徹底的です。また、安定した信頼できるソフトウェアの構築に関する章では、Code Completeをお勧めします。


「入力cを取得できます」-これが、タイプセーフ言語が非常に重要な理由です。あなたの入力タイプがブールの場合は、あなたが得ることができないtruefalse、しかし何も。それでも、型を理解することは重要です-たとえば、null許容型、浮動小数点NaNなど
-MSalters

5

正規表現は、有限状態マシンとして実装されます。ライブラリコードによって生成された遷移テーブルには、入力がパターンに一致しない場合に何が起こるかを処理するために、障害状態が組み込まれています。少なくとも、他のすべての状態から障害状態への暗黙的な遷移があります。

プログラミング言語の文法はFSMではありませんが、パーサージェネレーター(Yaccやbisonなど)には通常、1つ以上のエラー状態を設定する方法があるため、予期しない入力によって生成されたコードがエラー状態になる可能性があります。

FSMには、エラー状態または障害状態、または道徳的同等物が必要であるように聞こえますが、障害状態またはエラー状態のいずれかへの明示的(予想される場合)および暗黙的(予想されない場合)の遷移も必要です。


CSで正式な教育を受けていないため、質問がばかげているようであれば、許してください。数か月間プログラミングを学んでいます。つまり、ボタンのプッシュされたイベントに対してハンドラーメソッドを言うと、そのメソッドには適度に複雑なif-else-switch-conditioning構造(20〜30行のコード)があります。望ましくない入力は常に明示的に処理する必要がありますか?それとも「グローバル」レベルでの意味ですか?このFSMを監視する別のクラスが必要ですか?問題が発生すると、値と状態がリセットされますか?
アールグレイ

YaccまたはBisonで生成されたパーサーの説明は私の範囲を超えていますが、通常は既知のケースに対処し、「他のすべてがエラーまたはエラー状態になる」ための小さなコードブロックがあります。エラー/障害状態のコードはすべてリセットされます。失敗状態になった理由を示す追加の値が必要になる場合があります。
ブルースエディガー

FSMには、エラーに対して少なくとも1つの状態、またはさまざまな種類のエラーに対して複数のエラー状態が必要です。
-whatsisname

3

これを回避する最善の方法は自動テストです。

特定の入力に基づいてコードが何をするかについて真の自信を持つ唯一の方法は、それらをテストすることです。アプリケーション内をクリックして、間違って操作しようとすることもできますが、それがうまく機能しないため、リグレッションが発生しません。代わりに、不正な入力をコードのコンポーネントに渡し、それが正常な方法で処理されることを確認するテストを作成できます。

これは、ステートマシンが決して壊れないことを証明することはできませんが、一般的なケースの多くは正しく処理され、他のことを壊さないことを示します。


2

探しているのは例外処理です。一貫性のない状態にとどまることを回避するための設計哲学は、次のように文書化されthe way of the samuraiています。つまり、コンポーネントはすべての入力をチェックし、それらが正常に処理できることを確認する必要があります。そうではない場合、有用な情報を含む例外を発生させる必要があります。

例外が発生すると、スタックをバブルアップします。何をすべきかを知っているエラー処理層を定義する必要があります。ユーザーファイルが破損している場合は、データが失われたことをクライアントに説明し、クリーンな空のファイルを再作成します。

ここで重要なのは、動作状態に戻り、エラーの伝播を回避することです。これが完了したら、個々のコンポーネントを操作して、より堅牢にすることができます。

私はObjective-Cの専門家ではありませんが、このページは出発点として適切です。

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


1

有限状態マシンを忘れてください。ここにあるのは、深刻なマルチスレッドの状況です。任意のボタンをいつでも押すことができ、外部トリガーはいつでもオフにすることができます。ボタンはおそらくすべて1つのスレッド上にありますが、トリガーはボタンの1つまたは他のトリガーの1つ、多数、またはすべてと同じ瞬間に散らばる可能性があります。

あなたがしなければならないことは、行動することにした瞬間にあなたの状態を決定することです。すべてのボタンとトリガー状態を取得します。それらをローカル変数に保存します。元の値は、見るたびに変わる可能性があります。次に、状況に応じて行動します。これは、システムが1つのポイントでどのように見えたかのスナップショットです。ミリ秒後には非常に異なって見えるかもしれませんが、マルチスレッドを使用すると、ローカル変数に保存した画像のみを保持できる実際の現在の「現在」はありません。

次に、保存された(歴史的な)状態に応答する必要があります。すべてが修正されており、すべての可能な状態に対してアクションが必要です。スナップショットを撮ってから結果を表示するまでの間に行われた変更は考慮されませんが、それはマルチスレッドの世界での生活です。また、スナップショットがぼやけすぎないように、同期を使用する必要がある場合があります。(最新の状態になることはできませんが、ある特定の瞬間から状態全体を取得することに近づくことができます。)

マルチスレッドについて読んでください。学ぶべきことがたくさんあります。そして、これらのトリガーのために、並列処理を簡単にするためによく提供される多くのトリック(「ワーカースレッド」など)を使用できるとは思いません。「並列処理」を行っていません。8コアの75%を使用しようとはしていません。CPU全体の1%を使用していますが、非常に独立した相互作用の多いスレッドがあり、それらを同期し、同期がシステムをロックしないようにするために多くの考慮が必要になります。

シングルコアマシンとマルチコアマシンの両方でテストします。マルチスレッドでは、動作がかなり異なることがわかりました。シングルコアマシンでは、マルチスレッドのバグが少なくなりますが、これらのバグははるかに奇妙です。(マルチコアマシンは慣れるまであなたの心を揺さぶるでしょう。)

最後に不快な考えがありました:これは簡単にテストできるものではありません。ランダムトリガーとボタンを押して生成し、しばらくの間システムを完全に動作させて、結果を確認する必要があります。マルチスレッドコードは決定論的ではありません。ナノ秒のタイミングがずれていたからといって、10億回に1回失敗することがあります。デバッグステートメントを入れ(999,999,999の不要なメッセージを避けるために慎重なifステートメントを使用)、1つの有用なメッセージを取得するために10億回実行する必要があります。幸いなことに、マシンは最近非常に高速です。

キャリアの早い段階でこれをすべて捨ててすみません。誰かがこのすべてを回避する方法で別の答えを思いつくことを願っています(トリガーを飼いならすかもしれないものがそこにあると思いますが、トリガー/ボタンの競合がまだあります)。もしそうなら、この答えは少なくともあなたが何を失っているのかを知らせます。幸運を。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.