유한 상태 머신 고장을 복구하는 방법?


14

내 질문은 매우 과학적으로 보일 수 있지만 일반적인 문제라고 생각하며 숙련 된 개발자와 프로그래머는 제목에서 언급 한 문제를 피하기 위해 조언을 줄 것입니다. Btw., 아래에 설명하는 것은 iOS 프로젝트에서 적극적으로 해결하려고하는 실제 문제이며 모든 비용을 피하고 싶습니다.

유한 상태 머신으로 나는 이것을 의미합니다.> 몇 개의 버튼이있는 UI, 해당 UI와 관련된 여러 세션 상태 및이 UI가 나타내는 것, UI에 부분적으로 표시되는 값이 있으며 외부 트리거를 수신하고 처리합니다. (센서의 콜백으로 표시). UI와 응용 프로그램에서 바람직하고 허용 가능한 관련 시나리오를 더 잘 매핑하기 위해 상태 다이어그램을 만들었습니다. 코드를 천천히 구현함에 따라 앱은 점점 더 동작을 시작합니다. 그러나 나는 그것이 충분히 견고하다고 확신하지 않습니다. 내 의심은 내 생각과 이행 과정을 지켜 보는 데서 나옵니다. 나는 모든 것을 다루었다고 확신했지만 UI에서 약간의 테스트를 수행하기에 충분했으며 동작에 여전히 틈이 있음을 빨리 깨달았습니다. 하나, 각 구성 요소는 다른 구성 요소의 입력, 사용자 또는 일부 외부 소스의 특정 입력에서 이벤트 체인, 상태 변경 등의 입력에 따라 달라지고 작동합니다. 여러 구성 요소가 있으며 각각 입력에서 수신 된 트리거-> 트리거 및 보낸 사람 분석-> 분석을 기반으로 무언가 (메시지, 상태 변경) 출력

문제는 이것이 완전히 자체 포함되어 있지 않으며 내 구성 요소 (데이터베이스 항목, 세션 상태, 일부 버튼 상태) ... 이벤트 체인 범위 밖에서 변경, 영향, 삭제 또는 수정 될 수 있다는 것입니다. 바람직한 시나리오. (휴대 전화가 갑자기 꺼지고 배터리가 갑자기 방전 됨) 시스템에 잘못된 상황이 생겨 시스템을 복구 할 수없는 상태가 될 수 있습니다. 애플 스토어에있는 많은 경쟁사 앱에서이 문제 (사람들이이 문제를 깨닫지 못하는 것 같음)를보고 고객이 다음과 같은 글을 쓴다> "세 개의 문서를 추가했는데 거기로 가면 열 수 없습니다. "보이더라도." 또는 "매일 비디오를 녹화했지만 너무 로그 비디오를 녹화 한 후에는 자막을 켤 수 없습니다. 자막 버튼이 작동하지 않습니다."

이것들은 단지 단축 된 예이며, 고객은 종종 더 자세하게 설명합니다.. 설명 및 설명에서 특정 앱에는 FSM 고장이 있다고 가정합니다.

따라서 궁극적 인 질문은 어떻게 이것을 피할 수 있으며 시스템 자체를 차단하지 않는 방법입니다.

편집> 전화에서 하나의 viewcontroller보기의 맥락에서 이야기하고 있습니다. 응용 프로그램의 한 부분을 의미합니다. MVC 패턴을 이해하고 고유 한 기능을위한 별도의 모듈이 있습니다. 설명하는 모든 것은 UI의 하나의 캔버스와 관련이 있습니다.


2
단위 테스트의 경우처럼 들립니다!
Michael K

답변:


7

나는 당신이 이미 이것을 알고 있다고 확신하지만, 만일을 위해 :

  1. 상태 다이어그램의 모든 노드에 모든 유효한 종류의 입력에 대한 발신 호가 있는지 확인하십시오 (또는 각 입력 클래스에 대해 하나의 발신 호를 사용하여 입력을 클래스로 나눕니다).

    상태 머신에 대해 본 모든 예제는 잘못된 입력에 대해 하나의 아웃 바운드 아크만 사용합니다.

    입력이 매번 수행 할 작업에 대한 명확한 대답이 없으면 오류 조건이거나 누락 된 다른 입력이 있습니다 (일관되게 새 노드로 이동하는 입력의 아크가 발생 함).

    노드에 한 가지 유형의 입력에 대한 호가없는 경우 입력이 실제로는 발생하지 않는다고 가정합니다 (상태 머신이 처리 할 수없는 잠재적 오류 조건입니다).

  2. 수신 된 입력 (하나 이상의 아크)에 응답하여 상태 머신이 하나의 아크만 취하거나 따를 수 있는지 확인하십시오.

    상태 머신 설계시 식별 할 수없는 다른 종류의 오류 시나리오 나 입력이있는 경우, 오류 시나리오와 알 수없는 입력은 "일반 아크"와는 완전히 분리 된 경로를 가진 상태로 아크되어야합니다.

    IE "알려진"상태에서 오류 또는 알 수 없음을 수신 한 경우 오류 처리 / 알 수없는 입력의 결과로 아크가 따라 오게됩니다. 알려진 입력 만받은 경우 기계가 어떤 상태로 돌아 가지 않아야합니다.

  3. 일단 터미널 (종료) 상태에 도달하면 터미널이 아닌 시작 상태 (초기) 상태로만 돌아올 수 없습니다.

  4. 하나의 상태 머신의 경우 하나 이상의 시작 또는 초기 상태가 없어야합니다 (본 예제에 따라).

  5. 내가 본 하나의 상태 머신에 따르면 하나의 문제 또는 시나리오의 상태 만 나타낼 수 있습니다.
    하나의 상태 다이어그램에서 한 번에 여러 가능한 상태가 없어야합니다.
    여러 개의 동시 상태에 대한 가능성을 발견하면 상태 다이어그램을 각 상태를 독립적으로 수정할 수있는 두 개 이상의 개별 상태 시스템으로 분할해야한다는 것을 알 수 있습니다.


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. 알 수없는 문제를 포함하도록 상태를 확장하고 문제가 처리되는이 상태로 오류가 발생하도록합니다.

참고 로 상태 머신에 관한 위키 기사 는 철저하다. 또한 안정적이고 신뢰할 수있는 소프트웨어 구축에 대한 장을 위해 Code Complete를 제안 합니다.


"우리는 입력 c를 얻을 수 있습니다"-이것이 타입 세이프 언어가 중요한 이유입니다. 귀하의 의견 타입이 BOOL 인 경우 얻을 수 truefalse하지만 아무것도. 그럼에도 불구하고 타입을 이해하는 것이 중요합니다. 예를 들어 nullable 타입, 부동 소수점 NaN
MSalters

5

정규식은 유한 상태 머신으로 구현됩니다. 라이브러리 코드에 의해 생성 된 전이 테이블에는 입력이 패턴과 일치하지 않을 때 발생하는 상황을 처리하기 위해 실패 상태가 내장되어 있습니다. 거의 모든 다른 상태에서 실패 상태로의 암시 적 전이가 있습니다.

프로그래밍 언어 문법은 FSM이 아니지만 파서 생성기 (예 : Yacc 또는 bison)는 일반적으로 하나 이상의 오류 상태를 설정하여 예기치 않은 입력으로 인해 생성 된 코드가 오류 상태가 될 수 있습니다.

FSM이 오류 상태 또는 실패 상태 또는 도덕적 등가와 함께 명시 적 (예상 한 경우) 및 암시 적 (예상하지 않은 경우) 전환과 함께 실패 또는 오류 상태 중 하나로 전환해야합니다.


CS에 정식 교육이 없기 때문에 내 질문이 어리석은 경우 용서하십시오. 몇 달 동안 프로그래밍을 배우는 중입니다. 즉, 처리기 메서드를 말하고 버튼의 푸시 이벤트에 대해 말했을 때 그 방법에는 적당히 복잡한 if-else-switch-conditioning 구조 (20-30 줄)가 있습니다. 항상 바람직하지 않은 입력을 명시 적으로 처리해야합니까? 아니면 "글로벌"수준에서 그것을 의미합니까? 이 FSM을 감시하는 별도의 클래스가 있어야하며 문제가 발생하면 값과 상태가 재설정됩니까?
얼 그레이

Yacc 또는 Bison에서 생성 한 파서를 설명하는 것은 저 너머이지만 일반적으로 알려진 사례를 처리 한 다음 "다른 모든 것은 오류 또는 실패 상태가됩니다"라는 작은 코드 블록이 있습니다. 오류 / 실패 상태에 대한 코드는 모두 재설정을 수행합니다. 실패 상태에 도달 한 이유를 알려주는 추가 값이 필요할 수 있습니다.
Bruce Ediger

FSM에는 오류에 대해 하나 이상의 상태가 있거나 다른 종류의 오류에 대해 여러 오류 상태가 있어야합니다.
whatsisname

3

이를 피하는 가장 좋은 방법은 자동 테스트 입니다.

특정 입력을 기반으로 코드가하는 일에 대해 확신을 가질 수있는 유일한 방법은 코드를 테스트하는 것입니다. 응용 프로그램에서 주변을 클릭하고 잘못 수행하려고 시도하지만 회귀가 없도록 확장이 잘되지 않습니다. 대신, 잘못된 입력을 코드 구성 요소에 전달하고 제대로 처리하도록 테스트를 만들 수 있습니다.

이것은 상태 머신이 절대로 깨지지 않는다는 것을 증명할 수는 없지만 많은 일반적인 경우가 올바르게 처리되고 다른 것을 깨뜨리지 않는다는 것을 알려줍니다.


2

당신이 찾고있는 것은 예외 처리입니다. 일관성이없는 상태를 유지하지 않는 설계 철학은 다음과 같이 문서화됩니다 the way of the samurai. 다시 말해, 컴포넌트는 모든 입력을 확인하고 정상적으로 처리 할 수 ​​있는지 확인해야합니다. 그렇지 않은 경우 유용한 정보가 포함 된 예외를 발생시켜야합니다.

예외가 발생하면 스택을 버블 링합니다. 수행 할 작업을 알 수있는 오류 처리 계층을 정의해야합니다. 사용자 파일이 손상된 경우 클라이언트에게 데이터가 손실되었다고 설명하고 깨끗한 빈 파일을 다시 작성하십시오.

여기서 중요한 부분은 작동 상태로 돌아가 오류 전파를 피하는 것입니다. 이 작업을 마치면 개별 구성 요소를 사용하여 구성 요소를보다 강력하게 만들 수 있습니다.

나는 objective-c 전문가는 아니지만이 페이지는 좋은 출발점이되어야합니다.

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


1

유한 상태 머신은 잊어 버리십시오. 당신이 여기있는 것은 심각한 멀티 스레딩 상황입니다. 언제든지 버튼을 누를 수 있으며 언제든지 외부 트리거가 꺼질 수 있습니다. 버튼은 모두 하나의 스레드에있을 수 있지만 트리거는 버튼 중 하나 또는 하나, 다수 또는 모든 다른 트리거와 같은 순간에 문자 그대로 해제 될 수 있습니다.

당신이해야 할 일은 행동하기로 결정한 순간의 상태를 결정하는 것입니다. 모든 버튼과 트리거 상태를 가져옵니다. 지역 변수에 저장하십시오 . 원래 값은 볼 때마다 변경 될 수 있습니다. 그런 다음 상황에 따라 행동하십시오. 시스템이 한 지점에서 어떻게 보이는지에 대한 스냅 샷입니다. 밀리 초 후에는 매우 다르게 보일 수 있지만 멀티 스레딩을 사용하면 현재 "현재"가 없어 로컬 변수에 저장 한 그림 만 있습니다.

그런 다음 저장된 (역사적) 상태에 응답해야합니다. 모든 것이 고정되어 있으며 가능한 모든 주에 대해 조치를 취해야합니다. 스냅 샷을 생성 한 시간과 결과를 표시하는 시간 사이의 변경 사항은 고려하지 않지만 멀티 스레딩 환경의 수명입니다. 스냅 샷이 너무 흐려지지 않도록 동기화를 사용해야 할 수도 있습니다. (최신 상태 일 수는 없지만 특정 시점에서 전체 상태를 확보하는 데 가까이 갈 수 있습니다 .)

멀티 스레딩을 읽어보십시오. 당신은 배울 것이 많습니다. 그리고 이러한 트리거 때문에 병렬 처리를 쉽게하기 위해 종종 제공되는 많은 트릭 ( "Worker Threads"등)을 사용할 수 있다고 생각하지 않습니다. "병렬 처리"를 수행하지 않습니다. 8 코어 중 75 %를 사용하려고하지 않습니다. 전체 CPU의 1 %를 사용하고 있지만 독립적이고 상호 작용이 많은 스레드가 있으므로이를 동기화하고 동기화가 시스템을 잠그지 않도록주의를 기울여야합니다.

단일 코어 및 멀티 코어 머신 모두에서 테스트하십시오. 멀티 스레딩과는 다르게 작동합니다. 싱글 코어 머신은 멀티 스레딩 버그를 줄이지 만 그 버그는 훨씬 더 이상합니다. (멀티 코어 머신은 익숙해 질 때까지 마음이 흔들릴 것입니다.)

마지막으로 불쾌한 생각 : 테스트하기 쉬운 것은 아닙니다. 임의 트리거 및 버튼 누름을 생성하고 시스템이 일정 시간 동안 실행되어 무엇이 켜지는지 확인해야합니다. 멀티 스레드 코드는 결정적 이지 않습니다 . 타이밍이 나노초 동안 중단 되었기 때문에 10 억 번 실행하면 무언가 실패 할 수 있습니다. 디버그 문을 넣으십시오 (필요하지 않은 메시지 999,999,999를 피하기 위해 신중한 if 문으로). 단 하나의 유용한 메시지를 얻으려면 10 억 실행해야합니다. 다행히 요즘 기계는 정말 빠릅니다.

경력 초기에이 모든 것을 버려서 죄송합니다. 바라건대 누군가 가이 모든 것을 둘러싼 방법으로 다른 대답을 제시 할 것입니다 (트리거를 길들이는 물건이 있지만 트리거 / 버튼 충돌이 여전히 있다고 생각합니다). 그렇다면이 답변은 적어도 당신이 잃어버린 것을 알려줄 것입니다. 행운을 빕니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.