DuplicatedStateDecisionPoints

분류:번역 분류:설계패턴


가마수트라 패턴 포럼에서 훔쳐온 글입니다. 적당히 짧은 이름이 필요할 것 같네요..


State Decision and Consequence Separation a.k.a. Duplicated State Decision Points

===상태 결정과 결과 분리(= 이중 상태 결정 시점)===

Submitted by Dave Weinstein

데이브 웨인스테인(Dave Weinstein)에 의해 제공됨.

Introduction

Not only is this our first pattern to be selected from our readership, it is also our first 밶nti-pattern.?Not long after the release of the infamous Design Patterns book, another popular book, AntiPatterns, followed which enumerated patterns of software failure. Not surprisingly, it is often more valuable to know a problem than to know a solution.

소개

이것은 독자로부터 선택된 첫 번째 패턴이자, 첫 번째 안티패턴이기도 하다. 그 유명한 Design Patterns 책이 나온 후 얼마 되지 않아서, 소프트웨어 실패 패턴들을 나열하는 AntiPatterns라는 책이 나왔다. 종종 해결책을 아는 것보다 문제를 아는 것이 더 가치가 있다.

Problem

문제

Games frequently consist of large numbers of interrelated state transitions. The complexity of such state machines is difficult to manage, and this is especially true for multiplayer games where the likelihood of clients receiving messages inappropriate for their state must be addressed.

흔히 게임들은 서로 밀접한 관계 있는 많은 수의 상태 전이들로 구성되어 있다. 그러한 상태머신들의 복잡한 관계는 관리하기 어려우며, 특히 클라이언트가 자신의 상태에 적합하지 않은 메시지들을 받을 가능성이 많은 멀티플레이어 게임에서 더욱 그렇다.

A common method of implementing such state transitions, usually because of lack of time or laziness, is to separate the decision-making process from the resulting consequences. For example, when a packet arrives, a flag is set in one module while several remote modules monitor that flag to modify their behavior.

시간에 쫓기거나 귀찮은 경우, 의사 결정 과정과 그에 따른 결과를 분리하는 식으로 그러한 상태 전이들을 구현하기도 한다. 예를 들면 하나의 패킷이 도착하면 하나의 모듈 안의 어떤 플래그가 설정되고, 한편 여러 개의 원격 모듈들은 그 플래그의 상태에 기반해서 자신의 행동을 수정하는 식으로 구현하는 것이다.

This anti-pattern captures the complexity that results as such related code fragments increase. The greater the separation, both in terms of location in the source code and in logical association between decisions and consequences, and the more such code is part of ad hoc development rather than coherent design, the worse the anti-pattern gets.

이 안티패턴은 서로 관련된 코드 조각들이 늘어남으로서 생기는 복잡성을 잡아낸다. 소스 코드 안에서의 위치의 측면에서든 결정과 결과 사이의 논리적 연관 측면에서든, 분리가 많아지면 많아질수록, 또한 코드가 응집성있는 설계 보다 임시 방편적인 개발에 기인한 것일수록, 안티패턴이 잡아내는 것들 역시 더 나빠진다.

Common problems include: difficult to follow code flow; state errors introduced as old functions are used as boilerplate for new code; the flow of state transitions is spread across the entire codebase leading to difficulty in changing or introducing new states; and code changes are increasingly vulnerable to human error because the distributed nature of the anti-pattern makes individual changes appear reasonable.

보편적인 문제들은 다음을 포함한다.:

Examples

예제

One common form of the anti-pattern is created by repeated state checks at the beginning of functions, aborting the function if the state is inappropriate. For example:

안티패턴의 흔한 형태중의 한가지는 함수의 시작부분에서 상태 체크를 반복하여, 만약 상태가 부적절하면 함수를 취소시키는 방법에 의해 만들어진다.

예를 들면,

onMenuSelect() { if ( ! inMenuMode ) return;

}

This construct is initially a straightforward way to monitor state and may work well for small codebases containing a limited number of states. However, it becomes increasingly vulnerable to failure as numerous ad hoc decision points accumulate. This is especially true when other programmers integrate code and blindly copy poorly understood code fragments, propagating state decision points into places with unexpected and difficult to test results.

이와같은 코드는 처음에 상태를 모니터링하는 데엔 직관적인 방법이며, 제한된 수의 상태들을 가진 조그마한 코드베이스에서는 잘 작동할지도 모른다. 하지만, 많은 수의 임시적인 결정지점이 누적될수록 점점 더 오동작하기가 쉬워 진다. 이것은 다른 프로그래머들이 코드들을 합치거나, 완전히 이해되지 않은 상태에서 부분적인 코드들을 마구(blindly) 복사할 때 등, 상태 결정 지점들을 예상치 못한 곳으로,결과를 검증해보기 힘든 곳으로 전파함으로써 특히 문제가 된다.

Solutions

해결책

Solutions involve minimizing disjoint decision and consequence processing. A common implementation combines the two operations (decision and consequence) into one module with related data structures or a class responsible for the entire state transition sequence. This should be bolstered with a well-documented process for how state transitions are to be added and how state-dependent code is to be integrated into this scheme. As an example, consider a multiplayer game which upon transitioning state also filters those packets which are irrelevant to the state. This might be done with an array of valid packets as in the following pseudocode:

결정과 결과처리를 분리하는 것을 최소한으로 하는 것도 해결책 중에 하나이다. 또한 두가지 연산(결정과 결과)을, 차례대로 일어나는 상태변환 전부를 책임질 수 있는 서로 연관된 자료구조(structure)나 객체(class)로서, 하나의 모듈로 조화시켜 일반적으로 구현해내는 것입니다. 그리고 어떻게 상태변화를 추가하고, 어떻게 상태에 의존하는(state-dependent)코드를 이 조직(scheme)에 합치는지에 대한 자세한 설명을 해두어야 합니다. 일례로서 상태에 적절하지 않은 패킷들을 가려내어 상태 변화를 해야 하는 다중사용자게임을 생각해 봅니다. 이것은 다음의 코드에서와 같이 쓸모있는 패킷들의 배열로서 구현이 가능할 것입니다.

changeState( newState ) {

    switch( newState )

        case mainMenuMode:
            validPacketsPtr =
                mainMenuModeValidPackets;
}

An alternative solution is to define a uniform interface that allows state-dependent objects to be tested in a centralized manner. For example:

또다른 해결책으로서 일정한 인터페이스를 정의 하는것은 하나로 통일된 방법으로 상태에 의존하는 객체들을 시험하는것을 가능하게 할것입니다. 다음의 예를 봅시다.

processMessage( Msg *msg ) {

  if ( msg->isValid() ) msg->process();

} // ChangeEquipmentMsg

// inherits and extends
Msg ChangeEquipmentMsg::isValid() {

   return state == inventoryMode;

}

In this example, the is-message-valid rules are encoded into the message class. On the surface this seems to suffer the problems of the anti-pattern by distributing state decisions and consequences, but the code can be considered easier to follow because of the single point where message processing is aborted depending on the state checks.

이 예제에는, is-message-valid 룰이 메세지 클래스 안에 포함되어 있다. 얼핏 보기에는 이 방법도 상태 결정과 결과를 마구 분산시키는 안티-패턴의 문제를 겪게 될 것처럼 보이지만, 이 코드는 상태 체크에 의하여 메세지 처리가 취소되는 곳이 한군데뿐이기 때문에 더 쉽게 코드를 이해할 수 있다.

Issues

문제점

It is crucial to document how to add and change states, and how to query them in your game to avoid ad hoc solutions like this anti-pattern describes. However, internal documentation is always the first thing to give when a schedule begins to slip, so this is a hard issue to overcome.

이러한 안티-패턴이 설명하는 것과 같은 임시 변통의 해결책을 피하기 위해 여러분의 게임에서 상태들을 어떻게 쿼리하는지, 또한 어떻게 상태를 추가하고 변화시키는지에 대하여 문서화하는 것은 아주 중요하다. 그러나, 내부적인 문서화는 스케줄이 빠듯하게 진행되기 시작한다면 가장 먼저 미루게 되는 일이므로, 이것은 매우 극복하기 어려운 문제이다.

Related Patterns and References

관련 패턴 및 참조

Solutions to this pattern are related to the State and Strategy patterns. See AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis by William Brown and others (Wiley & Sons, 1998).

이 패턴에 대한 해결책은 State and Strategy patterns 와 관련있음. 다음 서적을 참고하기 바람. AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis by William Brown and others (Wiley & Sons, 1998).

Credits

제공자

Thanks to Dave Weinstein from Red Storm Entertainment for submitting this anti-pattern!

이 안티-패턴을 제안한 레드스톰 엔터테인먼트사(Red Storm Entertainment)의 데이브 웨인스테인(Dave Weinstein)에게 감사한다.