이민(immigration): '사용자 마이그레이션'을 다시 생각하기

엽토군·2021년 11월 12일
0
post-thumbnail

"기존 사용자들 어떻게 할 거에요?"

지금 다니는 회사에서 이런 서비스를 제공하고 있었다.

  1. 루트 계정을 생성할 수 있다.
  2. 루트 계정에 귀속되는 '사용자 계정'을 만들 수 있다.
  3. 각 사용자 계정이 '스페이스'(가칭)를 만들 수 있다.

분명 누군가가 (아무리 멍청한 이유일지언정) 이유가 있어서 빡세게 고민해서 적용한 정책의 반영일 터였다.
그래서 다들 이해는 잘 안 되더라도 꾹 참고 이를 이해한 다음 각종 업무에 적용해 왔다.
그런데 언제부터인가 이게 너무 복잡해서 못 참겠다는 안팎의 피드백이 들어왔다.

  • 같은 루트 R 밑의 사용자 A가 스페이스에 뭔가를 갖다 쓰면, 그걸 사용자 B의 스페이스에는 갖다쓸 수가 없다. (데이터 구조가 그러했음)
  • 루트 로그인과 사용자 로그인이 같은 경로를 타고 있어서, 깜박 잘못해 사용자로 로그인해야 했을 것을 루트로 로그인하고서는 왜 스페이스가 없나 의아해지는 경우가 있다.
  • 어차피 1루트 1사용자가 태반인데 뭐가 이렇게 추가적으로 복잡한지 모르겠다.

결국 새로 오신 Product Owner님의 과감한 용단 덕에 정책을 뒤집기로 결의했다.

  • 이제 스페이스는 무조건 1개다.
  • 그 1개 스페이스를 모든 루트/사용자가 공용으로 쓴다.
  • 스페이스를 '만드는' 행위 자체를 폐지한다. 이를 위해 루트 가입 시점에 적당히 빈 스페이스를 하나 만들어준다.

명쾌하군! 기획, 개발, QA, PM 모두가 행복하게 동의한 다음 이번 릴리즈에 이를 반영했다. 알파 테스트를 위해 stage 서버에 코드를 올린 다음, '뭐 잘되겠지' 하고 stage 서버에 들어가 미리 만들어 둔 기존 계정으로 로그인하여 스페이스 목록 화면을 봤다.

어? 아무것도 없다. 원래 있던 'create space' 버튼도 없고 빈 목록 컴포넌트도 안 뜨고 하여간 아무것도 없는 빈 화면이 나온다. 음... 그렇지 생각해 보면 이렇게 될 수밖에 없긴 한데... 쎄한 느낌을 받고 있으려니까 아니나 다르랴 QA에서 재깍 문의가 들어온다.

스페이스 진입시 빈화면 뜹니다

답변을 적었다.

스페이스를 안 만들었던 계정이 이번 릴리즈 업데이트를 당했을때 → 스페이스를 하나 만들어줘야 하는가? 가 결정되지 않아서 나온 결과입니다. 이력을 확인해보았고 "기존 스페이스가 있던" 사람들에 대해서는 논의됐었으나 "기존 스페이스가 없던" 사람들에 대해서는 논의된 적이 없어 보입니다. 정책 결정되는 대로 반영하겠습니다.

그 다음날 '데일리 스크럼'은 이 안건으로 옥신각신 아주 재밌었고 결국은 "잠수함 패치"를 해주기로 했다. 없앴던 버튼을 다시 살리는 편이 원칙적으로는 타당하지만, 현실적으로는 기존/신규 사용자 모두 '스페이스가 없으면 하나 만들어준다' 하는 정책을 적용해줘도 될 거라고 합의된 것이다. 다행인지 불행인지, 아직은 거기 해당되는 사용자가 그렇게 많지는 않을 거라면서.

내가 이번 일을 통해 얻은 교훈은 이것이다.

이런 작업/처리 방침에 이름을 붙이고 공론화를 해봐야 하는 것 아닐까?
단순히 '잠수함 패치'라고 부르지 말고, 기존 사용자를 처리하는 작업에 대한 정식 접근법으로서 연구해 보면 어떨까?

어느 시점부터는 data migration만으로 충분하지 않게 된다

비슷한 일을, 리얼 월드 유지보수를 하는 곳이라면 어디서나 한 번쯤은 겪는다고 생각한다. 당연한 일이다. 처음 만든 세상을 끝까지 그대로 유지하는 서비스란 세상에 없다. 랄까 그러면 그 서비스만 손해다. 서비스 생명 주기 차원에서 정책을 개선하고 주변 세상의 최신 상황을 반영하고 신기능을 추가하는 일련의 '변경'은 필연적이며, 결과적으로 모든 서비스는 테세우스의 배가 되어간다. 여기서는, 이런 변경 작업 자체에 별다른 이름이 없어 왔다는 점만 짚고 넘어가자.

문제는 그렇게 했을 때, 어느 순간엔가는 기존의 사용자, 기존의 데이터를 새로운 세상에 맞게 고쳐야만 한다는 것이다. 그리고 그 수준과 범위는 예측하기가 매우 어렵다. 예컨대 더 이상 회원정보에서 이메일이 필수가 아니게 된다고 생각해 보자. 간단한 변경 같지만 파급력은 어마어마하다.

  • 어쨌든 '이메일'은 사칭되어서는 안 된다. 그러면 사용자는, 아예 이메일 입력을 안 하든지, 귀찮은 소유권 인증을 받아 가며 입력을 하든지 둘 중 하나를 하게 된단 말인가?
  • 지금 인증받은 이메일을 나중에 지우겠다고 하면 그때는 허용해 줘야 하는가? 왜 그런 짓을 하려고 하는지 생각해 보면, 정황이 좀 너무 수상하지 않은가?
  • 사용자 연락처가 이메일밖에 없었던 상황이라면, 정말 이메일마저 필수 해제를 해도 되는가?

이때는 단지 users.email 필드의 NOT NULL을 해제하고 <input name="email"> 입력칸 속성에서 required를 빼는 것만으로는 실제 문제를 거의 해결하지 못한다. 도리어, 이렇게까지만 작업하면 '이걸로 변경이 완료됐다, 우리의 할 일은 끝났다'고 믿어 버리기 쉬워진다는 문제가 하나 더 생기기까지 한다. 누가 일을 그렇게 하겠나? 싶지만 사실 앞서 소개한 사례에 있어 우리 회사 개발팀 모두가 바로 그렇게 했다.

  • DBA는 컬럼명을 root_id로 변경하고 일감을 닫았다.
  • 백엔드는 마이그레이션된 개발DB 기준으로 스페이스 관련 기능이 user_id 컬럼 대신 root_id 컬럼을 사용하도록 고치고 테스트를 쭉 돌린 뒤 브랜치를 푸시했다.
  • 프론트는 생성 버튼을 없애고 PR을 올렸다.

뭐가 잘못될(지 누가 알) 수 있었을까?

잠시 후에 언급할 개념이지만, 이게 '이민'(immigration)임을 알아차리지 못한 한 이런 맹점은 존재할 수밖에 없었다, 라는 것이 내 생각이다. 최근 몇 년간은 그냥 경험적으로 어렴풋이만 갖고 있었는데, 오늘날에는 드디어 이런 글로 구체화가 됐다.

최신화된 시민권을 수시로 확인하고 인가하기

이번 릴리즈 픽스를 올리면서, 까먹을까봐 커밋 메시지에 이런 메모를 적어놨다.

사용자 "이주"(immigration) 개념 도입
신분 인증 과정에서 환경의 최신 정책에 맞게 사용자의 권리/의무를 수시 최신화하는 작업

이 단락은 그냥 이 메모 자체를 해설하는 방향으로 전개해 볼까 한다. '"이주" 말고 "이민"이라 적었으면 좋았을걸' 하는 점만 빼면, 거의 모든 요점이 거의 그대로 있기 때문이다.

이민이란 무엇인가? 이에 대해서는 넷플릭스 다큐멘터리 시리즈 '이민자의 나라'가 가장 좋은 시야를 제공해주는 것 같다. 'ICE'라 부르는 미국 이민세관집행국은 'POLICE ICE'라 적힌 (그래서 공연히 헷갈리는) 조끼를 입고 다니며 '더 이상 미국에 있으면 안 되는' 사람들을 적발하여 집이나 법정이나 국경으로 회송한다. "나는 (트럼프를 찍었지만) 트럼프가 시켜서 어쩔 수 없이 한다", "이 사람들은 (설령 미군 전역자라 하더라도) 추방될 이유가 있어서 추방된다" 같은 답변을 하면서.

다큐 얘기는 각설하고 핵심은 뭐냐면, 이 사람들은 "지금 정부에서 이러이러한 사람들을 그냥 냅둬도 되는가?"를 판별하는 게 주 업무이며, 슬프게도 누군가는 그 일을 해야 한다는 것이다. 여기서 미국과 우리 서비스의 공통점을 찾아보자.

  • 수시 변경 가능한 정책이 존재하는가?
  • 그 정책에 따라서 현재/미래 거주자의 권익과 의무가 변할 수 있는가?
  • 현재의 정책에 의거하여 누군가의 현재의 권익과 의무를 파악하고 적절한 추가 조치를 집행할 필요가 있는가?

상당히 많은 공통점이 있다. 이 맥락에서 유일한 차이점은, 미국은 이민집행국이 있고, 우리 서비스는 없다는 것이다. 그러다 보니 미국은 트럼프 정권의 아수라장 속에서도 그 이민집행국 사람들에게 최신 정책을 하달함으로써 어떻게든 미국 국토 내의 모든 사람들이 그 정책의 영향을 받도록 집행할 수 있는 반면, 우리 서비스는 그럴 수가 없어서 정책이 하나 바뀔 때마다 이미 가입한, 혹은 가입하게 될 사람들을 장차 어떻게 대해야 할지 몰라 번번이 우왕좌왕한다는 점이다.

그럴 필요가 있나? 언제까지고 헤매고 있을 수는 없다. 우리가 해야 할 일은 우리 서비스에도 이민국을 설치하고 이민(immigration)을 집행하는 것이다. 그래서 과감한 수정을 커밋했다. '스페이스'를 사용하기 전의 모든 사용자가 최소 한 번은 거치게 되는 관문인 '로그인'에, 이런 느낌의 코드를 추가했다. (정확히는, 원래는 루트 계정 가입 구간에 두었던 코드를 거의 그대로 잘라서 붙여넣은 것이다.)

// 신원 확인...
$user = User::authenticate($request);
if (!$user) {
    throw new UnauthorizedHttpException;
}

// ---- 여기서부터 새로 추가됨 ----

// 스페이스가 없다면 하나 만들 것
$rootID = $user->root_id;
$space = Space::firstOrCreate(['root_id' => $rootID]);
// 이민 절차 완료, 로그인 절차 계속

// ---- 여기까지 추가됨 ----

// 로그인 완료, 첫 화면으로 이동하여 종료
return $response->withAuthInfo($user->auth_info)->redirect('/');

코드는 여러모로 조잡하지만 핵심 아이디어는 명확하다. 누군가의 신분이 명확히 확인되었을 때, 단지 거기서 그치지 말고, 그 신분의 소유자가 최신 정책을 준수하는 상태인지까지를 확인하자는 것이다. 우리 입장에서 내부 방침이 바뀌었으니, 그 방침에 따라 새로/기존에 부여된 의무의 준수 여부를 확인하고, 혹시 새로 주어져야 할 권리가 있다면 주고, 의무와 권리 사이의 충돌이 발생한다면 해결하고, 추가로 안내가 필요하다면 사용자들을 적절히 안내해 주는 단계를 추가함으로써 말이다. 미국 ICE 하는 것 따라해서.

그리고 결과적으로는, 예상하시다시피, 이 부분 QA 이슈는 아무 문제 없이 완료 처리된 상태다. 이걸로 끝이라고 손 털고 그냥 지나갈 수도 있는 일이었지만, 제대로 글로 써서 남길 필요를 느껴서 이렇게 긴 회고글을 적는 중이다. 그 필요란 바로, 이 이민(immigration)이라는 자작(?) 개념에 대한 본격적인 후속 논의에 대한 필요이다.

이런 마이그레이션이 새로운 이야기일 리가 없는데...

사실 이 글을 쓰기 전, 그리고 "이민 개념 도입" 운운하는 커밋 메시지를 쓰기 전에도 이번 문제 때문에 검색하고 조사한 문제가 있었다. 우리가 해야 하는 작업은 분명 migration의 일종일 텐데, 어째서인지 기존의 '마이그레이션 이론'은 이 개념을 다루지 않는 것처럼 보였다는 것이다. 물론 찾아보면 일부 애플리케이션은 "사용자 마이그레이션 마법사" 같은 걸 지원하긴 하는데, 그들도 그걸 정확한 용어나 이론에 근거해서 제공하는 것은 아니었고, 그나마도 대부분은 DB, 서버, 도메인 변경에 따른 후속 조치처럼 개념이 협소한 사례들이었다.

요컨대 '서비스 이관', '소프트웨어 마이그레이션', '데이터 이전' 등등은 설명이 있었지만, '신분과 권리와 의무의 조합으로서의 사용자 정보의 우아한 갱신 적용'에 관한 아이디어는 좀체로 찾아보기가 어려웠다. 이상하지 않은가? 그럴 리가 없는데. 무식이 배짱이니 감히 이것이 사실이라고 전제해 보자. "사용자"를 마이그레이션한다는 개념 자체가 지금까지 고려된 적이 없었다고 한번 과감히 가정해 보자고. 만약 그렇다면 그 이유는 무엇일까? 추정컨대, 그간 'migration'이란 용어는 '데이터'를 '인프라'로 옮기는 일만을 가리키는 아주 좁은 의미의 단어였기 때문이다.

IT 마이그레이션은 데이터나 소프트웨어를 한 시스템에서 다른 시스템으로 이동하는 것입니다. (중략) IT 마이그레이션의 일반적인 몇 가지 예시는 다음과 같습니다.

  • 애플리케이션 또는 운영 체제(OS) 업그레이드
  • 데이터를 한 종류의 데이터베이스에서 다른 종류의 데이터베이스로 이동
  • 하나의 데이터 스토리지 시스템을 다른 데이터 스토리지 시스템으로 교체
  • 온프레미스 인프라에서 클라우드 인프라로 이동
  • 모놀리식 애플리케이션을 컨테이너화된 서비스로 교체

출처: Red Hat

종류는 많아 보이지만 공통적으로는 다들 매우 물리적이고 일괄적인 작업이다. 어딘가에 전원이 켜져 있는 두 벌의 시스템이 있어서, 한쪽 시스템의 자료들을 다른 쪽 시스템으로 통째로 옮긴다는 얘기로 요약된다. 아마도 의도적으로, 전통적인 마이그레이션들은 데이터를 일괄적으로 취급하지, 각 데이터를 어떻게 확인하고 취급해야 한다는 지침은 정하지 않는다. 이유는 간단하다. 거기서부터는 인프라의 손을 떠나는 '애플리케이션' 레벨의 업무이기 때문이다.

따를 지침이 없다면 정해서 따라야 한다. 그리고 사실 대부분의 리얼 월드 서비스는 이 일을 하고 있다. 그런데 내 경험상으로는, 다들 이 일을 하기는 하는데, 하나같이 이 일을 어려워하며, 말하기를 껄끄러워하고, 그래서 할 수만 있다면 피하려고 한다. 거의 금기에 가깝다. 예나 지금이나 그런 광경들을 볼 때마다 항상 잘 이해는 안 된다는 느낌이었다. 아니 왜? 몇천만 건의 데이터는 이 DB에서 저 DB로 잘만 옮기면서, 수십 명에 불과한 일부 과거 데이터 회원이 뭔가를 null로 갖고 있을 때 기본값을 넣어주자는 처리에 대해서는 왜 며칠이고 몇 주일이고 회의를 거듭하며 회의하는 거지?

공포는 미지로부터 온다. 규명된 것은 두려움의 대상이 아니다. 그렇다면 그냥 일단 임의로 초안을 잡아 규명을 해 보자. 데이터의 조합을 근거로 하여 개념적으로 구성되는 사용자, 아이템, 구독권(subscription) 등의 '엔티티(entity)'를, 그 엔티티가 존재할 수 있는 위치로서의 특정 '애플리케이션 환경/버전'으로 옮겨, 그 환경/버전에 맞는 최신화된 서비스 정책, 약관 등의 적용을 받도록 정정하고 최신화하는 작업, 이것을 엔티티 이민(entity immigration)이라고 부르면 어떨까? 이미 그런 게 있었다면? 그렇다면 차라리 더 잘됐다. 더 고민할 것 없이 그냥 그걸 배우고 익혀서 앞으로의 우리 회사 업무 처리에 써먹으면 되니까.

만약, 이런 게 없던 개념이라면? 뭐 거기서부터는 우리 모두에게 남겨진 과제다. 어차피 하는 일이라면 이름을 붙이고 작전을 짜서 과감하게 수행하고 싶지 않은가 말이다. 심지어 그게 '스페이스 안 만든 기존 사용자들에게 기본 스페이스 만들어주기' 같은 정말 흔히 일어나는 일이라면, 더더욱 말이다.

profile
4년차 PHP 개발자입니다.

0개의 댓글