State Machine 방식으로 복잡한 Sequence를 구성하는 방법
복잡한 순서 제어를 위한 현명한 선택
우리는 일상에서 수많은 순서와 단계를 거쳐 일어나는 일들을 마주합니다. 스마트폰으로 음식을 주문할 때도 장바구니 담기, 결제, 조리, 배달이라는 일련의 단계를 거치며, 게임 속 캐릭터가 움직일 때도 대기, 달리기, 점프, 공격이라는 상태 변화가 끊임없이 일어납니다. 이렇게 순서가 있는 복잡한 작업을 프로그래밍할 때 무작정 코드를 길게 늘어놓으면 나중에는 어디서 문제가 생겼는지 찾기 힘든 골칫거리가 되곤 합니다.
이럴 때 구원투수처럼 등장하는 개념이 바로 상태 머신입니다. 머릿속으로 그리던 복잡한 순서도를 명확한 규칙으로 바꾸어주는 마법 같은 도구입니다. 프로그램이 지금 어떤 상태에 처해 있는지 명확히 정의하고, 특정 조건이 만족되면 다음 상태로 깔끔하게 넘어가는 방식을 뜻합니다. 이 방식을 잘 익혀두면 아무리 복잡한 흐름도 체계적으로 관리할 수 있습니다.
상태 머신이 무엇인지 이해하기
상태 머신은 시스템이 가질 수 있는 여러 가지 상태와, 그 상태 사이의 전환 조건을 정의하는 설계 모델입니다. 영어로는 Finite State Machine이라고 부르며 줄여서 FSM이라고도 합니다. 핵심 아이디어는 간단합니다. 시스템은 언제나 오직 하나의 상태에만 머물러야 한다는 것입니다. 그리고 외부에서 신호가 들어오거나 특정 조건이 충족되면 정해진 길을 따라 다른 상태로 이동합니다.
예를 들어 자동 자판기를 떠올려 봅시다. 자판기는 대기 상태, 동전 투입 상태, 음료 선택 상태, 제품 배출 상태라는 몇 가지 정해진 국면만을 가집니다. 대기 상태에서 동전이 들어오면 동전 투입 상태로 바뀝니다. 음료를 고르지도 않았는데 갑자기 제품 배출 상태로 건너뛰는 일은 벌어지지 않습니다. 이처럼 허용된 경로 외에는 움직이지 못하도록 단단하게 빗장을 걸어두는 것이 상태 머신의 본질입니다.
실생활에서 만나는 다양한 순서 제어 사례
우리가 자주 쓰는 소프트웨어와 기기 속에는 대부분 상태 머신 원리가 숨어 있습니다. 이를 살펴보면 이 기술이 왜 중요한지 더 쉽게 이해할 수 있습니다.
- 온라인 쇼핑몰의 주문 결제 시스템은 주문 생성, 결제 대기, 결제 완료, 상품 준비, 배송 중, 배송 완료 단계로 이루어진 거대한 상태 머신입니다.
- 가전제품의 대표주자인 세탁기는 전원 켜기, 물 채우기, 세탁, 헹굼, 탈수, 완료의 단계를 엄격한 순서대로 진행합니다.
- 엘리베이터는 정지, 상승 중, 하강 중, 문 열림 상태를 오가며 승객의 안전을 지킵니다.
- 비디오 게임 속 적 캐릭터는 플레이어를 찾는 순찰 상태, 플레이어를 발견한 추격 상태, 공격을 퍼붓는 전투 상태를 오갑니다.
조건문 지옥에서 벗어나는 확실한 방법
개발을 하다 보면 만약에 상황을 뜻하는 조건문이 끝없이 중첩되는 상황을 마주하곤 합니다. 상태 A일 때 만약 이렇고 저렇고 하다가 또 다른 조건이 붙으면 코드가 알아보기 힘들 정도로 복잡해집니다. 이를 흔히 조건문 지옥이라고 부릅니다. 이 상태가 오랫동안 지속되면 새로운 기능을 하나 추가하는 것조차 두려워집니다.
상태 머신 방식을 도입하면 이 지옥에서 벗어날 수 있습니다. 코드가 상태와 행동이라는 두 가지 축으로 깔끔하게 분리되기 때문입니다. 어떤 상태에서는 어떤 행동만 해야 하는지가 명확해지므로 전체적인 구조가 한눈에 들어옵니다. 새로운 단계를 추가해야 할 때도 기존 코드를 전부 뜯어고칠 필요 없이 새로운 상태와 연결 고리만 쏙 집어넣으면 끝납니다. 유지 보수 비용이 획기적으로 줄어드는 이유입니다.
상태 머신을 구성하는 핵심 구성 요소
상태 머신을 제대로 활용하려면 몇 가지 기초 부품을 잘 조립해야 합니다. 이 부품들이 모여 완벽한 순서 제어 시스템을 만들어냅니다.
- 상태는 시스템이 현재 처해 있는 고유한 상황을 말합니다. 시작, 진행, 일시정지, 종료 등이 이에 해당합니다.
- 이벤트는 상태를 바지게 만드는 외부의 자극이나 신호입니다. 버튼 클릭, 타이머 종료, 데이터 수신 등이 이벤트가 됩니다.
- 전환은 하나의 상태에서 다른 상태로 이동하는 과정 자체를 뜻합니다.
- 행동은 특정 상태에 진입하거나 빠져나올 때, 혹은 이벤트가 발생했을 때 실행되는 구체적인 작업입니다.
상태를 설계할 때 자주 저지르는 실수
상태 머신이 좋다고 해서 무작정 도입하면 오히려 역효과가 날 수 있습니다. 실제로 많은 초보자들이 겪는 시행착오를 미리 알아두면 큰 도움이 됩니다.
가장 흔한 실수는 상태를 너무 잘게 쪼개는 것입니다. 모든 사소한 변수 하나하나를 전부 상태로 만들어버리면 머신이 감당할 수 없을 정도로 복잡해집니다. 상태는 시스템의 거시적인 국면을 나타내야 합니다. 예를 들어 로그인 화면에서 사용자가 아이디를 한 글자씩 칠 때마다 상태를 바꿀 필요는 없습니다. 아이디 입력 중이라는 하나의 상태로 묶어두는 것이 현명합니다.
또 다른 실수는 상태 간의 연결을 엉키게 만드는 것입니다. 모든 상태에서 다른 모든 상태로 갈 수 있게 허용하면 무늬만 상태 머신일 뿐 결국 복잡한 스파게티 코드가 됩니다. 최대한 한 방향으로 흐르거나 명확하게 정의된 경로로만 이동하도록 규칙을 엄격하게 세워야 합니다.
효율적인 설계를 위한 전문가들의 조언
현장에서 수많은 시퀀스를 다뤄본 전문가들은 종이와 펜을 먼저 들라고 조언합니다. 코드를 바로 작성하기 전에 순서도나 상태 전환표를 그려보라는 것입니다. 어떤 상태들이 필요한지, 어떤 조건에서 움직이는지를 시각적으로 먼저 확인하면 머릿속에 있던 모호한 아이디어가 구체적인 설계도로 바뀝니다.
또한 예외 상황을 미리 고민해야 한다고 강조합니다. 정상적인 순서대로만 흘러가면 좋겠지만 네트워크가 끊기거나 사용자가 갑자기 창을 닫아버리는 등의 돌발 상황은 언제나 일어납니다. 비정상적인 입력이 들어왔을 때 시스템이 어떤 상태로 안전하게 돌아갈 수 있는지에 대한 대비책을 미리 심어두어야 탄탄한 프로그램을 완성할 수 있습니다.
비용과 시간을 아끼는 현명한 구현 요령
복잡한 순서를 제어하는 시스템을 처음부터 끝까지 직접 구현하려면 생각보다 많은 시간이 걸립니다. 바퀴를 다시 발명할 필요는 없습니다. 이미 검증된 오픈소스 라이브러리나 프레임워크를 활용하는 것이 비용 효율적입니다. 파이썬, 자바스크립트, 자바 등 대부분의 프로그래밍 언어에는 상태 머신을 손쉽게 구현할 수 있도록 도와주는 훌륭한 도구들이 이미 준비되어 있습니다.
이러한 도구들을 사용하면 복잡한 로직을 직접 짜느라 허비하는 시간을 아낄 수 있으며, 다른 사람들과 협업할 때도 코드를 훨씬 쉽게 공유할 수 있습니다. 이미 정의된 시각화 도구를 지원하는 라이브러리를 쓰면 현재 상태를 화면으로 직접 보면서 디버깅할 수 있으므로 개발 속도가 눈에 띄게 빨라집니다.
상태 머신 도입에 관해 자주 묻는 질문
상태 머신은 모든 프로그램에 무조건 적용해야 하는 절대적인 진리는 아닙니다. 단순하고 일직선으로 흐르는 아주 간단한 작업에는 오히려 과도한 엔지니어링이 될 수 있습니다. 순서가 복잡하게 얽히고, 조건에 따라 분기가 많이 생기며, 유지 보수가 오래 지속되어야 하는 프로젝트일수록 진가를 발휘합니다.
객체 지향 프로그래밍과 함께 사용할 때 효과가 배가되는지도 궁금해하는 분들이 많습니다. 그렇습니다. 각 상태를 별도의 클래스나 객체로 분리하여 관리하는 디자인 패턴을 적용하면, 코드가 더욱 모듈화되어 수정이 필요할 때 해당 상태 부품만 교체하면 되는 놀라운 경험을 할 수 있습니다. 순서 제어로 인해 머리가 아팠던 적이 있다면 오늘부터라도 간단한 기능 하나를 상태 머신 방식으로 다시 설계해보는 것을 권장합니다.
댓글 0
첫 댓글을 남겨보세요.