복잡한 인증 플로우를 단순하게: 상수 패턴을 선택한 이유

badahertz52·2025년 9월 5일
2

react

목록 보기
13/14

고민: 복잡한 인증 플로우

회사 입사 후, 첫 프로젝트로 신규 서비스의 어드민 개발에 참여했습니다. 어드민의 인증 플로우가 예상보다 훨씬 복잡했습니다.

  • 사용자 계정 상태에 따라 OTP 인증 필요 여부가 다르다
  • 비밀번호 변경이 필요한 계정들이 있다.
  • 신규 등록 프로세스를 거쳐야 하는 사용자들도 있다.
  • 앞으로 더 많은 인증 케이스가 추가될 수 있다.

인증 플로우 차트를 받아보니 머리가 복잡해졌습니다. 이걸 어떻게 코드로 구현해야 할지, 그리고 나중에 새로운 케이스가 추가되었을 때 어떻게 관리해야 할지 고민이 많았습니다.

디자인을 보니 다행히 공통 UI와 컴포넌트를 재사용할 수 있는 구조였지만, 복잡한 플로우를 어떻게 깔끔하게 관리할지가 가장 큰 과제였습니다.

해결 방법: 상수 패턴 도입

아이디어의 시작점

문득 이전에 진행했던 리뷰미 프로젝트가 떠올랐습니다. 그때 서버에서 내려주는 질문의 타입에 따라 관련 컴포넌트를 매핑했었습니다.

이 아이디어를 현재 상황에 적용해보면 서버가 내려주는 사용자 인증 정보에 따라 관련 인증 플로우를 상수화하면 되겠다는 생각이 들었습니다.

핵심 접근법

서버에서 사용자 정보를 받으면, 그 정보를 바탕으로 어떤 인증 단계를 거쳐야 하는지 상수로 정의하고 관리하는 방식으로 설계했습니다.

처음에는 어떤 방식이 가장 직관적일지 고민하는 시간이 꽤 있었습니다. 여러 접근법을 검토해보면서 최선의 구조를 찾아나갔습니다.

아이디어의 시작점을 떠올리기까지도 시간이 걸렸지만, 한 번 방향이 정해지니 구현은 비교적 순조롭게 진행되었습니다.

구현하면서 중요하게 고려한 것들

직관적인 플로우 관리:

다른 개발자가 보더라도 인증 플로우 관리가 직관적이고 쉽도록 하는 것이 가장 중요했습니다.

이를 위한 설계:

  • 인증 플로우 상수: 전체 플로우 단계와 규칙을 중앙에서 관리
  • 플로우 관리 컴포넌트: 현재 플로우 단계에 따라 해당 컴포넌트를 렌더링하는 역할만 담당
  • 각 단계별 컴포넌트/훅: 자신이 담당하는 그 단계만 책임지도록 설계

이렇게 각각의 역할을 명확히 분리하면 코드를 이해하기도 쉽고, 수정할 때도 해당 부분만 건드리면 되니까 훨씬 안전하다고 생각했습니다.

간단한 예시 코드

일반적인 웹 서비스 인증 플로우를 예로 들어보면, 이런 식으로 상수화할 수 있습니다

// 인증 플로우 단계 상수 정의
const AUTH_STEPS = {
  LOGIN: 'login',
  OTP_SETUP: 'otp-setup',
  OTP_VERIFICATION: 'otp-verification',
  PASSWORD_CHANGE: 'password-change',
  ACCOUNT_RECOVERY: 'account-recovery',
  COMPLETE: 'complete'
};

// 사용자 케이스별 인증 플로우 정의
const AUTH_FLOW = {
  NORMAL_USER: [AUTH_STEPS.LOGIN, AUTH_STEPS.OTP_VERIFICATION, AUTH_STEPS.COMPLETE],
  NEW_USER: [AUTH_STEPS.LOGIN, AUTH_STEPS.OTP_SETUP, AUTH_STEPS.OTP_VERIFICATION, AUTH_STEPS.COMPLETE],
  PASSWORD_EXPIRED: [AUTH_STEPS.LOGIN, AUTH_STEPS.PASSWORD_CHANGE, AUTH_STEPS.OTP_VERIFICATION, AUTH_STEPS.COMPLETE],
  LOCKED_ACCOUNT: [AUTH_STEPS.LOGIN, AUTH_STEPS.ACCOUNT_RECOVERY, AUTH_STEPS.COMPLETE]
};

React Context를 활용해 여러 컴포넌트에 걸쳐 진행되는 인증 단계를 관리하고, 각 단계에 맞는 컴포넌트를 렌더링하는 방식으로 책임을 분리할 수 있습니다.

const AuthStepRenderer = () => {
  const { flow, currentFlowStep } = useAuthFlow(); // context API
  const currentStep = flow[currentFlowStep];

  const STEP_COMPONENTS = {
    [AUTH_STEPS.LOGIN]: <LoginStep />,
    [AUTH_STEPS.OTP_SETUP]: <OTPSetupStep />,
    [AUTH_STEPS.OTP_VERIFICATION]: <OTPVerificationStep />,
    [AUTH_STEPS.PASSWORD_CHANGE]: <PasswordChangeStep />
  };

  return STEP_COMPONENTS[currentStep] || null;
};

성과

팀적 성과

프로젝트 진행 중에 인증 플로우가 초반 기획과 달라지는 상황이 발생했습니다. 처음부터 상수 패턴으로 구현해뒀기 때문에 해당 케이스에 대한 상수만 변경해서 빠르게 대응할 수 있었습니다.

새로운 인증 단계가 추가되거나 기존 단계의 순서가 바뀌어도 설정 부분만 수정하면 되니까 팀 전체의 개발 효율성이 크게 향상되었습니다.

개인적 성과

이번 작업을 하면서 한 가지 확실하게 깨달은 것이 있습니다. 저는 복잡한 플로우나 로직을 관리하기 쉽도록 정리하는 것에 보람을 느끼는 성향인 것 같습니다.

설계를 고민하는 초기 시간이 있었고, 아이디어를 떠올리기까지의 과정도 있었지만, 결과적으로 복잡했던 것들이 깔끔하게 정리되는 과정에서 큰 만족감을 느꼈습니다.

혹시 이게 대문자 J 성향의 '정리병'일 수도 있겠지만, 어쨌든 이런 작업을 통해 제가 어떤 일에서 보람을 느끼는지 더 명확해졌습니다.

마무리

복잡한 것을 단순하게 만드는 과정이 쉽지는 않지만, 그 결과로 얻는 깔끔함과 유지보수성은 충분히 그 노력을 보상해준다고 생각합니다. 앞으로도 이런 정리와 설계를 해보고 싶고, 이를 더 잘하기 위해 디자인 패턴을 공부해갈 예정입니다. 😎

profile
세상과 사람을 잇는 개발을 꿈꾸는 프론트엔드 개발자

2개의 댓글

comment-user-thumbnail
2025년 9월 6일

제 인생도 정리해주세요

1개의 답글