Cheondi
개발 · 알고리즘·CS

자동 로그인은 체크박스 하나가 아니었다

자동 로그인 흐름이 여러 조건에서 꼬이는 문제를 상태 전이로 정리해 본 기록입니다.

  • #state-machine
  • #login
  • #unity

자동 로그인은 “저장된 정보가 있으면 로그인한다” 정도로 이해하고 있었다. 실제 코드를 보니 앱 시작, 저장 데이터 읽기, 네트워크 연결, 세션 확인, 로그인 화면 표시가 각자 다른 시점에 움직였다. 연결이 느린 기기에서는 로그인 요청이 두 번 나가거나, 자동 로그인이 진행 중인데 로그인 화면이 잠깐 나타났다.

조건문을 하나씩 추가할수록 어떤 조합이 가능한지 알기 어려워졌다. isAutoLogin, isConnecting, hasSession, isLoginViewOpen 같은 bool이 서로 모순된 값이 되기도 했다.

bool 네 개보다 상태 하나가 읽기 쉬웠다

먼저 앱 시작 후 상태를 순서대로 적었다.

Booting
 -> LoadingCredentials
 -> WaitingForNetwork
 -> Authenticating
 -> SignedIn | NeedManualLogin | Failed

모든 상태를 거창한 프레임워크로 바꾸진 않았다. 최소한 현재 단계가 하나만 존재하도록 enum을 두고, 화면과 요청은 그 상태를 기준으로 움직이게 했다.

enum LoginState
{
    Booting, LoadingCredentials, WaitingForNetwork,
    Authenticating, SignedIn, NeedManualLogin, Failed
}

Authenticating 상태에서는 새 로그인 요청을 막으니 중복 호출도 자연스럽게 줄었다.

이벤트가 와도 바로 행동하지 않았다

네트워크 연결 이벤트가 오면 무조건 로그인하고, 저장 데이터 로드가 끝나면 또 로그인하던 구조가 문제였다. 이벤트는 조건 하나가 준비됐음을 알릴 뿐이었다. 실제 다음 행동은 현재 상태와 필요한 조건을 함께 확인한 뒤 한 곳에서 결정했다.

void TryAdvance()
{
    if (state == LoginState.WaitingForNetwork && networkReady)
        StartAuthentication();
}

이렇게 하니 어떤 이벤트가 먼저 와도 최종 전이는 한 번만 일어났다.

실패도 하나의 상태가 아니었다

저장 정보가 없어서 수동 로그인이 필요한 경우, 네트워크가 끊긴 경우, 저장된 세션이 만료된 경우는 사용자에게 보여줄 다음 행동이 달랐다. 전부 Failed로 보내면 재시도와 입력 화면 전환이 뒤섞였다.

세션 만료는 저장 정보를 지우고 수동 로그인으로, 일시적 연결 실패는 정보를 유지한 채 재연결로 보냈다. 실패 원인을 UI 메시지와 다음 전이까지 연결해 생각하게 됐다.

흐름을 그리면 빠진 경로가 보였다

자동 로그인 작업을 하며 상태 머신이라는 말을 실감했다. 복잡한 기능이라서 상태 머신을 쓰는 게 아니라, 이미 존재하는 상태를 코드에서 숨기지 않는 방법에 가까웠다.

이후 여러 bool이 서로를 막고 있는 코드를 만나면 먼저 가능한 상태와 전이를 적는다. 체크박스 하나처럼 보이던 자동 로그인이 이벤트 순서와 실패 복구를 다루는 작은 시스템이었다.