LY Corporation Tech Blog

LY Corporation과 LY Corporation Group(LINE Plus, LINE Taiwan and LINE Vietnam)의 기술과 개발 문화를 알립니다.

과격하게 레거시를 쇄신하는 세 가지 방법과 그 사례

안녕하세요. 일본 최대 규모의 음식 배달 서비스 Demaecan(出前館, 이하 데마에칸) 프로덕트를 담당하는 김영재라고 합니다. 어느덧 프로덕트를 쇄신한 지 2년 반이 되어가고 있습니다. 이번 글은 레거시를 해소하면서 서비스를 혁신해 나가는 데마에칸의 여정 중 기록을 남기는 의미로 작성했습니다.

레거시의 정의는 다양합니다. 단순히 오래된 코드를 의미하는 경우도 있고, 새로운 서비스 구현에 제약이 되는 기존 구조를 말하기도 합니다. 하지만 사전에 실려 있는 '유산'이라는 긍정적인 의미처럼, 레거시는 지금까지 서비스가 생존할 수 있게 해준 기반이기도 합니다.

레거시에 관한 재미있는 표현도 많습니다.

  • 어제 내가 작성한 코드는 레거시이다.
  • 사용자가 한 명이라도 있는 시스템은 레거시이다. 그 한 명이 바로 당신이다.
  • 레거시를 고칠 바엔 다시 만드는 게 더 빠르다.

위와 같은 표현이 셀 수 없이 많을 정도로 엔지니어는 레거시 때문에 웃고 울곤 합니다.

데마에칸도 여느 회사처럼 레거시가 있습니다. 아니, 많습니다. 데마에칸은 업력이 20년이 넘은 회사입니다. 다시 말해 20여 년의 레거시가 쌓여 있습니다. 레거시는 코드나 시스템만 의미하지는 않습니다. 스펙이나 업무 프로세스에도 레거시가 있습니다. 예를 들어 점포의 속성 중에 '2-in-1'이라는 것이 있는데요. 이것을 정의하고 구현한 모습은 세 가지가 있었습니다. 회사 안에서도 '2-in-1 점포'라고 말할 때 부서마다 다르게 이해하고 있는 것이죠. 이 또한 레거시라고 말할 수 있습니다.

현재 데마에칸은 앱부터 백엔드까지, 백엔드부터 운영 프로세스까지 하나씩 재작성하면서 레거시를 쇄신하는 장기 프로젝트를 진행하고 있습니다. 쇄신하는 방법은 여러 가지가 있는데요. 이번 글에서는 일반적인 방법 외에 조금 색다른 세 가지 방법을 말씀드리고자 합니다.

레거시를 해소하는 대표적인 방법

레거시를 해소하는 대표적인 방법으로는 Strangler Fig 패턴이 있습니다. 아래 그림과 같이 새로운 시스템을 마련한 후 조건에 따라 옛 시스템에서 새로운 시스템으로 이행하다가 새로운 시스템이 잘 작동한다는 확신이 들면 옛 시스템으로 가는 경로를 없애고 폐쇄하는 방법입니다. 직접 본 적은 없지만 Strangler Fig라는 나무가 이와 같은 방식으로 생장한다고 합니다.

데마에칸에서도 이 방법으로 백엔드의 여러 컴포넌트를 활발히 개선하고 있습니다. 가장 안전하면서도 결과와 일정을 예측하기 쉬운 방법이기에 운영 중인 서비스라면 어디든 적용할 수 있습니다. 데마에칸에서는 결제, 주문, 회원 정보 등 이커머스로서 가장 핵심적인 도메인에 이 방법을 사용하고 있습니다.

이 방법의 단점으로는 차근히 개선해 나가는 방식이므로 꽤 오랜 시간이 걸린다는 점과, 안정성을 중시하는 만큼 레거시의 가장 핵심적인 부분은 교체하지 못하는 경우가 많다는 점을 꼽을 수 있습니다. 그래서 보다 극단적인 방법들도 쓰이는데요. 어떤 방법이 있는지 하나씩 사례와 함께 소개하겠습니다.

보다 과격하게 레거시를 해소하는 세 가지 방법

어떤 방법을 사용하든 레거시를 해소하는 것은 어느 지점에서 레거시를 단절하고 새 시스템으로 교체하는 일입니다. 그 단절을 어느 정도로 깊게 만드는지에 따라 작업 난이도와 규모가 달라집니다. 다시 말해 '과격하다'는 것은 그만큼 깊고 명확하게 레거시와 단절하려고 노력했다는 의미이기도 한데요. 데마에칸에서 서비스를 개선하기 위해 직접 사용해 본 과격한 레거시 해소 방법 세 가지를 하나씩 사례와 함께 살펴보겠습니다. 

  1. 인프라 단절하기
  2. 코드 재작성하기(Recode)
  3. 사양 경량화하기

1. 인프라(infrastructure) 단절하기

한 단위의 시스템은 인프라와 그 인프라에서 작동하는 데이터베이스 및 애플리케이션, 이들을 잇는 메시징 등 여러 컴포넌트로 구성됩니다. 이 중에서 레거시의 상당수는 데이터 구조에 기인합니다. 그렇기에 데이터 구조는 그대로 둔 채 코드와 패턴의 일부만 수정하는 작업은 레거시를 해소하는 노력 대비 성과가 그다지 크지 않은 경우가 많습니다. 즉 리팩토링으로 더 좋은 패턴을 적용하는 것도 유의미한 변화이지만, 데이터 구조와 이를 활용하는 데이터 구성 방법을 바꾸는 것만큼 극적인 변화를 만들기는 어렵습니다. 

3계층(3-tier) 구조든 헥사고날(hexagonal) 구조든 도메인과 데이터 레이어, 애플리케이션 등은 소프트웨어 이론에서 각각을 명확히 구분하는 개념이지만, 현실에서는 모호한 지점이 있기 마련입니다(아마도 그래서 수십 년간 도메인 설계에 대한 책이 그렇게나 많이 나온 것인지도 모릅니다). 즉, 다이어그램에서는 별도의 컴포넌트처럼 그려져 있지만 실제로 코드는 뒤섞여 있는 경우가 많은데요. 이때 각각을 이론처럼 명확히 구분하려면 어떻게 하면 좋을까요?

가장 좋은 방법은 물리적으로 구분하는 것입니다. 인프라를 단절하면 외부 인터페이스로만 통신해야 합니다. 예를 들어 WebAPI로 JSON 또는 Protocol Buffers를 활용할 수 있겠죠. 이렇게 하면 자신이 만든 시스템을 하나의 거대한 SaaS(Software as a Service)로 취급하는 효과를 얻을 수 있습니다. 다시 말해, 서로가 외부 시스템으로 취급할 수밖에 없도록 강제하게 되는 것입니다. 이를 통해 기존의 데이터 구조를 생각하지 않은 채, 두 환경 사이의 통신을 위한 인터페이스와 그 안에 담을 데이터를 가장 이상적인 모습으로 만들도록 유도합니다(두 환경 사이의 인터페이스를 고려할 때는 저의 이전 글 오픈소스답게 설계하기에서 확장성 - 참여를 위한 외부 인터페이스를 참고하시기 바랍니다).

이 방법이 성공하려면 팀 조직 및 운영 관점에서도 처음부터 겸직이나 다른 팀과의 업무 중복 없이 하나의 팀이 서비스 사양부터 인프라 셋업 및 개발까지 독립적으로 작업할 수 있도록 분리할 필요가 있습니다. 

인프라 단절 방법의 사례

데마에칸에서는 2022년 Delivery 도메인 전체를 인프라부터 다른 도메인과 단절해 만드는 작업을 진행했습니다. Delivery3.0이라는 프로젝트로, 아래 그림은 Delivery 3.0 전환 과정에서 두 시스템 사이의 인증 흐름을 간단히 나타낸 것입니다. 시스템을 교체해도 모두 로그아웃을 당하는 일 없이 인증을 유지하면서 작업을 진행하고 싶었기 때문에, 앱에서는 레거시 시스템으로 로그인한 후 새로운 시스템의 토큰을 다시 발급받는 흐름을 만들었습니다.  

릴리스할 때는 지역 단위로 반년간 4단계에 걸쳐서 적용 지역을 확대했습니다. 도쿄에서 선정된 점포를 대상으로 릴리스를 시작해서 그다음으로 서일본 전역, 그 이후 도쿄 전역, 마지막으로 일본 전체로 전개하기까지 각 2개월 단위로 릴리스를 진행했습니다. 다행히 데마에칸은 점포 하나 단위로만 주문할 수 있다는 서비스의 특징이 있었기 때문에 점포 단위로 새로운 시스템의 적용 대상을 제어할 수 있었습니다.

데마에칸은 실시간으로 사람이 움직이고 물건과 돈도 실시간으로 오가는 굉장히 역동적인 서비스입니다. 따라서 지역 단위로 적용할 때마다 서비스 품질이 다를 수 있다 보니 CS(customer service) 상황에도 주의를 기울일 필요가 있었습니다. 시스템을 만드는 입장에서는 단 한 번만 성공해도 이후의 모든 흐름 역시 100% 성공한다고 확신할 수 있지만, 사용자 입장에서는 그렇지 않기 때문입니다. 서비스 사용에 익숙지 않은 가맹점주의 조작 실수나 해당 지역에 배달 가능한 배달원이 없는 등의 여러 가지 이유로 항상 모든 흐름이 100% 성공할 수 없고, 이는 소비자나 가맹점, 배달원의 세 엔드 유저 중 누군가가 CS로 문의하는 상황이 발생합니다.

음식 배달은 전 세계적으로 '30분 이내 배달'이 중요한 서비스 지표 중 하나인데요. 데마에칸은 Delivery 3.0 프로젝트의 론칭부터 이를 달성해 온 것은 물론 2% 미만의 배달 지연, 90%가 넘는 배달 만족도로 세계적인 수준의 배달 품질을 달성하고 있습니다.

정리하자면 환경을 단절해 쇄신하는 방법은 아래와 같은 장점이 있습니다.

  1. 새로운 기능을 선보임과 동시에 과거의 시스템을 자신 있게 삭제할 수 있다.
  2. 데이터 구조를 새로운 요구사항에 맞게 다시 구성하고 더 좋은 패턴과 구조를 도입할 수 있다.
  3. 기존 시스템의 운영 비용이 너무 높다면 전환 즉시 비용을 크게 줄일 수 있다.

하지만 모든 기술 선택에는 트레이드오프가 있기에 유의할 점도 있습니다. 인프라 환경을 단절하는 방법은 성공 확률이 낮은데요. 그 이유는 아래와 같습니다.

  1. 높은 수준의 팀워크가 필요하다.
  2. 집중력을 유지할 수 있게 팀을 유지 및 보존하기 어렵기 때문에 그만큼 많은 투자가 필요하다.
  3. 처음부터 새로 만드는 만큼 시행착오가 발생할 수 있어서 예정보다 일정이 하염없이 지연될 수 있다.
  4. 사람도 레거시가 될 수 있다. 새롭게 만들 기회가 있어도 기존의 익숙한 지식에 기대 이전과 비슷하게 만드는 경우가 많다.

2. 코드 재작성하기(Recode)

Recode는 제가 이름 붙인 방법인데요. 레거시의 스펙은 그대로 유지하는 상태에서 코드를 처음부터 재작성하는 방법을 의미합니다. 앞서 소개한 인프라 단절 방법은 예전 시스템이 새로운 기능을 도저히 소화할 수 없을 때 유용한데요. 이번 섹션의 Recode는 그와 다르게 구 버전과 완전히 동일한 사양으로 만든다는 특징이 있습니다.

Recode를 하는 이유와 Recode의 장단점

언뜻 이해가 가지 않습니다. 도대체 왜 동일한 사양으로 다시 만들까요? 보통 세 가지 상황이 있습니다.

  • 사양서(스펙 문서)가 유실되어 코드와 프로그램만 있는 경우
  • 담당 팀이 바뀌면서 기존 팀이 작업한 이력을 파악하기 어렵거나 접근 권한이 없는 경우
  • 사용한 기술보다 진보된 기술이 나와서 새로운 기술 세트로 전환이 필요한 경우

이 방법의 장점은 아래와 같습니다.

  • 기존 코드를 분석하는 것보다 새로 만드는 게 사양을 이해하는 데 더 집중할 수 있는 작업이고, 결과물에 대한 확신도 더 높아집니다.
  • 유실된 사양서와 기능 명세를 한 번에 복구할 수 있습니다.
  • 기술 선택의 자유도가 높습니다.

단점을 말하자면 아래와 같습니다.

  • 코드 재작성 기간 동안 사양을 동결해야 하므로 비즈니스 요건을 받지 못합니다.
  • 실력이 부족한 팀이 만들면 새로 만든 결과가 더 나쁠 수 있습니다.
  • 버그가 사양이 되어버린 레거시라면 이를 없앨 때 혼란이 생길 수 있습니다.

제가 Recode 프로젝트를 여러 번 진행하면서 큰 효과를 본 방법은 언어와 기술 세트를 바꾸는 것입니다. 앞서 인프라 단절 방법에서는 데이터 접근을 제약으로 했는데요. Recode에서는 언어를 제약 사항으로 걸 수 있습니다. 예를 들어, Python으로 작성된 기존 서버를 Recode에서는 Kotlin으로 작성하는 것입니다. 

보통 어떤 언어를 사용할 때 그 언어의 생태계 안에서 성숙한 라이브러리들이 권장하는 패턴을 사용하곤 합니다. 그러므로 언어를 바꾸면 패턴이 바뀌고 나아가 아키텍처나 상태 관리도 달라지는데요. 저는 이 과정이 프로그래머에게 매우 좋은 훈련이 된다고 생각합니다. 외국어를 공부하는 이유 중 하나가 다른 문화를 보다 폭넓게 이해하기 위해서 인 것처럼, 다룰 수 있는 언어가 늘어나면 기술을 이해하는 폭이 넓어집니다.

Recode 적용 사례

데마에칸에서는 2년간 네 개의 앱을 모두 Recode했습니다. 이전에는 앱마다 언어부터 프레임워크까지 모두 달랐습니다. 네이티브는 물론이고 React Native와 Xamarin 등도 있었는데요. Recode를 통해 결과적으로 Flutter로 단일화할 수 있었습니다. 

모바일 앱은 사용자가 업데이트를 받으면 패키지 단위로 완전히 대체되기 때문에 앞서 언급한 Strangler Fig 패턴을 적용하기 어렵습니다. 그렇다고 앱 하나에 여러 기술과 프레임워크를 섞는 것도 비효율적입니다. 업데이트하면서 보존되는 것은 단말 내에 저장된 로그인 토큰이나 간단한 텍스트 정보뿐인 경우가 대부분입니다. 그래서 앱의 경우 단 한 번의 업데이트만으로 레거시를 없앨 수도 있습니다.

아래 그림은 Recode 프로젝트를 진행할 때 기획부터 개발까지의 스케줄을 대략적으로 나타낸 그림입니다. 새로운 기획을 잠시 중단한다고 선언한 후 약 3개월간 현재의 사양대로 코드를 새롭게 작성합니다. QA도 한 달 또는 그 이상 소요되기도 합니다.

Recode 프로젝트는 내부는 완전히 새로 작성하지만 외부 동작은 동일하게 유지합니다. 그래서 업데이트했을 때 사용자가 바뀐 것을 모르면 성공이라고 말할 수 있는 독특한 프로젝트입니다. 이를 위해 이전 앱과 새로운 앱을 나란히 놓고 동일한 경험을 제공할 수 있도록 QA를 진행합니다. 업데이트 후에는 '뭐가 바뀌었는지 모르겠지만 반응이 빨라졌다' 정도의 의견만 받곤 합니다.

시행착오도 있었습니다. 저희는 Driver 앱을 첫 사례로 프로젝트를 진행했는데요. 처음에는 React Native로 개발돼 있던 것을 당시에 인기를 끌던 KMM(Kotlin Multiplatform Mobile)으로 Recode했습니다. 그런데 iOS 디버깅 경험이 생산성과 안정성을 너무 낮추는 문제가 발생해 다시 Flutter로 전환했습니다. 그러니까 Recode 작업만 두 번 한 것입니다. 

Recode에 대한 경험을 조금 더 자세히 듣고 싶으시다면 아래 시리즈를 참고하시기 바랍니다.

  1. 일본 1위 배달, 바닥부터 다시 짠다
  2. 멀쩡한 앱을 Flutter 앱으로 다시 짠 이유 - 일본 1위 배달 앱, 두 번째 Recode
  3. Flutter 전환의 마침표

결과적으로 현재 Flutter 기술에 대해서는 데마에칸이 제일 선도적인 회사 중 하나라고 생각합니다. 기술 통합도 하고, 레거시도 해소하고, 기술력도 높아진 것이니 개인적으로 매우 완성도 높은 레거시 해소 프로젝트였다고 생각하고 있습니다.

Recode는 클라이언트 앱에만 의미 있는 작업이 아닙니다. 백엔드에도 의미가 있습니다. DB만 그대로 유지한 상태에서 Java 코드를 TypeScript/Node.js 또는 C#/.NET으로 바꾸거나 혹은 JVM 생태계에서 나가는 게 부담스럽다면 Kotlin 또는 Scala로 바꾸기만 해도 더 효율적인 패턴을 시도해 볼 수 있습니다.

3. 사양 경량화하기

레거시가 되는 것은 프로그램의 문제보다는 프로그램을 통해 실현하고 싶은 비즈니스 요구 사항이 원인인 경우가 더 많습니다. 그렇다고 기존의 비즈니스 요구 사항과 이를 실현한 사양을 원망할 수는 없습니다. 소프트웨어의 존재 이유는 비즈니스 요건의 실현이기 때문입니다. 자주 변화하는 요건도, 무리한 요구도 결국은 회사의 생존과 성장을 위한 노력이니까요. 

서비스 사양 중에는 업무에 미치는 영향은 크지 않아도 시스템에 미치는 영향은 큰 사양이 있습니다. 이런 경우에는 영업이나 운영 팀과 상의해서 사양과 기능을 없애는 방법이 필요한데 영업과 운영에서는 대부분 현재의 사양을 유지하고 싶어 합니다. 한 번 기능이 완성돼 시스템에서 작동하기 시작하면 단 한 명이라도 영향을 받는 사용자가 있기 때문입니다. 그래서 경영진과 이야기해 결정하는 과정도 필요합니다.

따라서 여러 가지 레거시 해소 방법 중 기존의 사양을 없애는 방법이 가장 어려운 방법이라고 말할 수 있습니다. 상담해야 할 팀도 여럿이고, 영향받는 사용자 분석도 필요하며, 운영부터 CS 매뉴얼에까지 영향을 미치므로 작업 기간이 예정된 일정보다 훨씬 길어질 수도 있습니다. 기존 사양에서 창출되고 있는 이익도 있기 때문에 그 경제적 손실을 감내할 이유를 프로덕트의 가치로 설명할 필요도 있습니다.

사양 경량화의 적용 사례

현재 데마에칸은 백엔드 리프레시 작업에 본격적으로 들어가기에 앞서 사양을 경량화하는 작업을 진행하고 있습니다. 일례로, 데마에칸은 사용자가 웹에서 주문하면 가맹점에서 그 주문을 팩스로 받았던 것이 최초의 사업 모델이었기에 최근까지도 팩스로 주문서를 송신하는 기능이 있었습니다. 이제는 대부분 태블릿으로 대체됐지만 일부 가맹점에서는 특정 조건에서 팩스로 주문서를 송신하는 기능을 계속 사용하고 있었으며, 최근까지도 한 달에 1천 건 정도 송신하고 있었습니다. 

팩스를 송신하려면 팩스 연계 서버가 필요하고 팩스 회선도 필요합니다. 데마에칸에서는 아래 그림처럼 로컬 데이터 센터 중 하나의 이중화된 물리 서버에서 팩스 서버를 가동하고 있었는데요. 작년에 팩스 서버를 SaaS 서비스로 전환하는 것을 조사해 봤지만 그다지 효율적이지 않거나 요구 조건에 맞지 않아서 전환하지 못했습니다. 그 대신 팩스 사양을 완전히 없애는 것을 논의했고, 올해 7월 팩스 사양을 제거했습니다.

팩스 사양 제거 결과 로컬 데이터 센터가 없어져 인프라 비용이 절감됐고, 물리 서버를 모니터링할 필요도 없어졌으며, 로직도 단순해지고, CS 부담도 줄었습니다. 물론 가맹점주의 일부는 여전히 팩스 사양을 희망하시기도 했지만 그보다는 전체 서비스가 더 건강하게 운영될 수 있도록 프로덕트를 만드는 것이 서비스의 지속가능성을 더 높일 수 있는 방향이라고 믿고 실행했습니다.

저는 지속 가능한 시스템을 만들기 위해 20여 년간 쌓인 부채를 대폭 줄이고 싶었습니다. 이에 경영진을 설득한 끝에 시스템 개발 시 경제적 가치가 애매한 레거시 기능이 큰 부담으로 작용하는 경우 해당 기능을 과감히 제거하는 것에 대한 경영진의 합의를 얻어냈습니다. 회계상 몇 % 이하의 경제적 손실은 장래에 더 건강한 시스템으로 가꾸기 위해 회사에서 감당하겠다는 기준도 만들었습니다. 앞서 말씀드렸듯 이 방향이 서비스의 지속가능성을 더 높이는 방향이라고 믿기 때문입니다.

마치며

이번 글에서는 데마에칸에서 사용했거나 사용 중인 레거시 해소 방법을 소개했습니다. 이 모든 노력은 결국 지역의 퀵 커머스(Q-Commerce)를 보다 이상적으로 실현하기 위함입니다.

데마에칸 서비스의 매력은 사람이 움직인다는 것입니다. 인간이 하는 행위 중 가장 복잡한 행위가 요리하는 것과 운전하는 것이라고 하는데요. 이 둘을 직업으로 삼은 사람들이 데마에칸을 사용하고 있습니다. 뜨거운 불과 습기가 가득한 곳에 놓인 태블릿 단말로 들어오는 주문은 지역의 가맹점주에게 웃음을 안겨줍니다. 자전거와 오토바이로 도로 위를 달리는 사람들은 가맹점에서 잘 부탁한다는 말과 함께 음식을 받아 책임감을 갖고 고객에게 음식을 배달합니다. 이 모든 과정이 아주 다이내믹하며, 열기가 가득합니다. 이처럼 지역에 활기를 불어넣고 있는 분들을 위해 더욱 좋은 서비스를 만들어야겠다고 다짐하며, 그 결과를 앞으로 더 좋은 글로 소개하겠습니다.