피쳐 토글 - 빠르고 안정적인 릴리즈를 향한 도약

안녕하세요, 맘편한세상의 백엔드 엔지니어 이재찬입니다.

맘편한세상의 백엔드 팀은 빠르고 안정적인 릴리즈를 가능케 하는 도구로 피쳐 토글(feature toggle)을 사용하고 있습니다. 이 글에서는 피쳐 토글이 어떤 개념인지, 어떤 상황에서 사용하면 좋은지, 그리고 맘편한세상에서는 실제로 어떻게 사용하고 있는지를 공유해보고자 합니다.

피쳐 토글의 정의

피쳐 토글(또는 피쳐 플래그)을 한 마디로 축약하자면, 특정 코드의 실행 여부를 코드 외부에서 제어할 수 있게 하는 시스템입니다. 코드로 표현한다면, 아래와 같은 예시를 생각해볼 수 있습니다.

// isEnabled 함수는 서버 외부 설정에 따라, true / false중 하나를 반환
if (isEnabled("awesome-feature")) {
  provideAwesomeFeature();
} else {
  provideLegacyFeature();
}

isEnabled 함수가 어떤 값을 반환할지는 서버 외부 설정으로 변경할 수 있습니다. 예를 들어서, 개발자가 어드민 페이지에서 awesome-feature를 활성화하면, 서버에서는 provideAwesomeFeature가 실행되고, 비활성화하면 provideLegacyFeature 가 실행되는 방식입니다. 서버 배포 없이도, 둘 중에 어떤 함수가 실행될지 결정할 수 있는 것이죠.

여기서 조금 더 나아가서는, isEnabled 함수가 호출 환경에 관련된 값을 받아서, 피쳐 토글의 반환값이 호출 환경마다 (예를 들어서, 기능을 요청하는 유저마다) 다른 값을 반환하게 할 수도 있습니다.

if (isEnabled("awesome-feature", { context: { userId: user.id } })) {
  provideAwesomeFeature();
} else {
  provideLegacyFeature();
}

피쳐 토글의 정의 자체는 이렇게 간단하게 설명할 수 있습니다. 하지만 피쳐 토글이라는 개념이 왜 필요한지, 언제 사용하면 좋을지는 조금 더 흥미로운 문제입니다.

배포와 릴리즈의 분리

피쳐 토글이 제공하는 기능의 본질은 “배포와 릴리즈를 분리할 수 있는 능력”입니다. “배포” 와 “릴리즈” 이 두 단어는 종종 혼용되지만, 여기서는 이 두 개념의 좀 더 정확한 정의와 특성을 한번 짚고 넘어가도록 하겠습니다.

  • 배포(deployment): 코드가 서버에 배치되는 것 / 인프라 관점에서의 용어
  • 릴리즈(release): 기능이 사용자에게 제공되는 것 / 비즈니스 관점에서의 용어

일반적으로는, 코드는 배포되는 즉시 해당하는 기능들이 모든 사용자에게 제공됩니다. 즉, 배포와 릴리즈가 동일한 시점에 발생하는 것이죠. 피쳐 토글을 사용한다면, 코드를 배포했을 때 그 코드에 해당하는 기능이 즉시 릴리즈가 될 필요가 없습니다. 코드가 배포된 이후, 개발자가 기능이 릴리즈되기를 원할 때 피쳐 토글을 활성화하면, 그 때부터 기능이 사용자에게 릴리즈됩니다. 즉, 배포와 릴리즈의 분리가 달성되는 것입니다.

피쳐 토글을 사용해서 배포와 릴리즈의 결합을 끊어내는 것은, 크게 두 가지 상황에서 이점을 가져다줄 수 있습니다.

  • 새로운 기능을 릴리즈할 때
  • 작업중인 코드를 통합할 때

이 두 가지 상황에 대해서 조금 더 자세히 살펴봅시다.

새로운 기능을 피쳐 토글로 릴리즈

피쳐 토글을 올바르게 사용한다면, 새로운 기능이 릴리즈될 때의 안정성을 크게 개선할 수 있습니다. 새롭게 작업한 기능이 운영환경에 안전하게 릴리즈될 수 있게 하기 위해서, 통상적으로는 아래의 두 가지 방식을 통해서 새로운 기능의 안정성을 검증합니다.

  • 운영 환경과 최대한 비슷한 스테이지 환경에 배포해, 개발자와 QA 등 내부 사용자가 테스트 한 후, 이상이 없으면 운영 배포
  • 카나리 배포 전략을 통해서, 일시적으로 새로운 기능을 일부 유저에게만 배포한 후, 이상이 없다면 그 후 전체 배포

이 두가지 방식은 분명 널리 쓰이는 방식이지만, 기능의 안정성을 검증하기에는 약간의 아쉬운 구석들이 있습니다.

  • 스테이지 환경에 배포해서 테스트하는 것은 운영과 스테이지 환경의 차이를 감수해야 하고, 또한 내부 사용자의 테스트를 통해서만 피드백을 얻을 수 있습니다.
  • 카나리 배포는 운영 환경에서 실제 사용자 대상으로 피드백을 받을 수 있지만, 인프라 레벨에서 기존 서버와 신기능 서버를 나누기 때문에 세밀하게 대상 유저를 조정하기 어렵고, 여러 기능에 대해 동시에 검증을 진행하기도 어렵습니다.

만약 배포와 릴리즈를 분리해서 새로운 기능의 릴리즈 여부를 피쳐 토글로 제어한다면, 기존 방식과 대비해서 기능 검증과 릴리즈가 더욱 유연하고 안전해집니다. 먼저 운영환경에서 일부 유저 대상으로만 기능을 릴리즈해서 피드백을 받을 수도 있고, 릴리즈 대상을 내부 유저 / 일반 유저들 중에서 임의로 결정할 수도 있습니다. 여러 기능을 동시에 검증하는 것도 가능합니다. 뿐만 아니라, 새로운 기능의 문제가 발견되었을 때, 별도의 코드 수정이나 배포 없이 빠르게 릴리즈 취소가 가능하기 때문에, 릴리즈로 인해 발생하는 문제의 영향도를 크게 줄일 수도 있습니다.

작업 중인 코드를 피쳐 토글로 통합

피쳐 토글을 사용한다면, 작업 중인 기능의 코드를 운영 환경에 배포해두고, 외부 유저 대상으로는 새로운 코드가 실행되지 않도록 제어할 수 있습니다. 이렇게 하면 기능 작업 기간이 길더라도, 개발 도중에 언제든지 메인 브랜치에 통합해두거나, 다른 운영 기능들과 함께 운영 서버에 배포하는 것이 자유롭습니다. 기능 준비가 완료되면, 그 때 피쳐 토글을 통해 기능을 릴리즈하면 됩니다.

작업 중인 기능에 대한 배포를 미리 잘게 쪼개서 수행하는 것은 여러 가지 이점을 가져다줍니다.

  • 현재 작업중인 코드를 팀원이 활용하기 편리해집니다. 작업중인 기능에서 기존 공용 코드를 수정하거나, 새로운 공용 코드를 추가할 수도 있는데, 기능 전체를 미리 배포해둘 수 있으면 컨플릭트를 최소화하면서 공용 코드를 팀원과 쉽게 공유할 수 있습니다.
  • 작업 중에 내부 사용자 대상으로 테스트를 진행하기 더 용이합니다. 큰 작업의 일부분이 완료되었을 때, 완료된 부분에 대해서만 개발자나 QA 등 내부 사용자 대상으로 기능을 오픈해 피드백을 얻을 수 있습니다.
  • 트렁크 기반 개발 방식으로 개발하도록 돕습니다. 트렁크 기반 개발을 한 마디로 설명하자면, 개발자들이 단일 메인 브랜치에 자신의 코드를 자주 통합하는 것을 지향하는 브랜칭 전략입니다. 피쳐 토글의 도움을 받아 트렁크 기반 방식으로 개발한다면, 머지 컨플릭트 감소, 빠른 릴리즈 주기 등 여러 이점을 얻을 수 있습니다. (트렁크 기반 개발에 대한 더 자세한 정보는, 제가 작성한 다른 글인 Git Flow에서 트렁크 기반 개발으로 나아가기 에서 확인할 수 있습니다! )

맘편한세상에서 사용하는 피쳐 토글 서비스

맘편한세상 백엔드 팀에서는 현재 Unleash라는 피쳐 토글 서비스를 사용하고 있습니다. 이 서비스는 작년 10월에 맘편한세상 백엔드 팀에서 피쳐 토글을 도입할 때부터 사용해왔고, 현재까지도 매우 만족하면서 사용하고 있습니다. Unleash 서비스에서 특히 만족하는 부분들은 아래와 같습니다.

  • 낮은 호출 오버헤드: Unleash에서 제공하는 서버 SDK를 사용한다면, SDK가 피쳐 토글 설정을 메모리에 미리 저장하고 있다가, isEnabled함수가 호출될 때 저장된 피쳐 토글 설정을 통해 활성화 / 비활성화 여부를 서버 내에서 계산합니다. 즉, isEnabled함수 호출마다 네트워크 요청이 발생하지 않아, 호출 오버헤드가 매우 낮습니다.
  • 빠른 설정 전파 속도: Unleash SDK는 Unleash 서버를 주기적으로 폴링해서(기본값은 15초마다) 설정을 가져와 메모리에 저장하기 때문에, 피쳐 토글 활성화 여부를 변경하고 폴링 주기 만큼만 기다리면, 변경될 피쳐 토글 설정이 서버에 반영되는 것을 확인할 수 있었습니다. 폴링 주기 또한 커스텀한 설정이 가능합니다.
  • 합리적인 비용: 서비스 코드가 오픈소스로 공개되어 있고, 서비스를 자체 인프라에 배포하는 것도 매우 편리해서, 인프라 비용만 감당하고 저희 인프라에 배포해서 사용하고 있습니다.
  • 어드민 패널: 직관적이고 편리한 어드민 패널을 제공해서, 쉽게 피쳐 토글 설정을 변경할 수 있습니다.

image Unleash의 피쳐 토글 리스트 페이지. 각 피쳐 토글이 가장 최근에 언제 호출되었는지도 확인할 수 있습니다.

image Unleash의 개별 피쳐 토글 설정 페이지. 각 환경에서 토글이 활성화되었는지, 얼마나 자주 토글이 요청되는지 확인 가능합니다.

피쳐 토글 서비스 도입을 검토하거나, 자체 구현을 고민하고 있다면, 위와 같은 요소들을 충족할 수 있을지 생각하면서 결정하면 좋을 것입니다.

실제 사용 사례

아래에서는 맘편한세상 백엔드 팀에서 피쳐 토글을 사용하고 있는 다양한 예시를 보여드리고자 합니다.

배포에 이상이 있을 때, 피쳐 토글을 통해서 빠르게 릴리즈 취소

새롭게 작업한 기능으로 인해 예상하지 못한 에러가 발생해 Sentry 알림이 온 상황입니다. 기능 릴리즈를 피쳐 토글을 통해 진행했었기 때문에, 다시 피쳐 토글을 이용해 빠르게 기능을 비활성화하고, 문제를 그 후에 디버깅할 수 있었습니다.

image

배포를 미리 해놓고, 릴리즈는 피쳐 토글 활성화로 간편하게

특정 기능의 릴리즈를 위해서 백엔드와 프론트 릴리즈가 모두 필요한 상황입니다. 이 때 서버와 프론트에서 모두 미리 배포를 해두고, 정해진 릴리즈 시간에 서버와 프론트 모두 피쳐 토글을 활성화해서, 원하는 시간에 쉽게 릴리즈를 하고, QA 검증 또한 바로 순조롭게 진행할 수 있었습니다.

image

작업 중인 태스크에 대해 미리 배포 후 테스트

맘시터 앱 내 채팅 관련 POC(Proof Of Concept) 기능에 관한 PR입니다. 해당 기능을 이어서 개발하기 전에 스테이지에서 테스트해보기 위해, 기능을 아래와 같이 피쳐 토글을 통해 보호된 상태로 메인 브랜치에 머지했습니다. 저희는 트렁크 기반 개발 방식을 사용하고 있기 때문에, 코드는 바로 운영까지 배포되었지만, 해당 기능은 스테이지에서만 피쳐 토글을 사용해 안전하게 테스트할 수 있었습니다.

image

기존 엔드포인트를 새로운 엔드포인트로 점진적으로 대체

현재 맘시터 백엔드 팀에서는 레거시 Node 서버와 새로운 Kotlin 서버를 동시에 운영하고 있고, 점진적으로 Kotlin 서버로 Node 서버를 대체해 나가는 것을 목표로 하고 있습니다. 현재 두 서버 앞단에는 Spring Gateway를 두고 있습니다.

Gateway에서 커스텀한 Route Predicate를 만들어서, 특정 요청이 Node 서버로 갈지, Kotlin 서버로 갈지를 피쳐 토글을 통해 결정할 수 있게 작업했습니다. 이를 통해 기존 Node 엔드포인트를 대체하는 새로운 엔드포인트를 Kotlin 서버에 배포해 두고, 필요할 때만 새로운 엔드포인트가 호출되도록 해, 새로운 엔드포인트를 안정적으로 운영과 스테이지에서 테스트할 수 있었습니다.

image Unleash를 사용하는 RoutePredicateFactory

image 해당 predicate를 이용해서, 검색 API를 점진적으로 Kotlin서버에 있는 엔드포인트로 대체하는 중

일부 지역의 유저에게만 기능 릴리즈

최근에 새롭게 개편된 홈 화면을 릴리즈했었는데, 새로운 홈 화면에는 특정 지역에서만 사용할 수 있는 기능이 포함되어 있어 해당 지역의 유저만 홈 화면을 볼 수 있도록 작업이 되어야 하는 상황이었습니다. 또한, 운영팀의 상황에 따라 해당 기능을 사용할 수 있는 지역이 자주 변화하는 상황이었습니다.

이 때, Unleash의 Custom Strategy 기능을 사용해서, Unleash에서 설정된 지역에 있는 유저에 대해서만 새로운 홈 화면을 릴리즈할 수 있었습니다.

image Unleash 어드민에서, 새로운 홈 화면이 노출되는 지역 설정 가능

image 자체 어드민과 Unleash API를 연동해서, 운영팀이 어드민에서 손쉽게 새로운 홈 화면이 노출되는 지역을 설정할 수 있음

이에 관한 더 자세한 내용은 저희 팀의 백엔드 개발자 현구님이 작성해 주신 블로그에서도 확인하실 수 있습니다. Unleash custom strategy를 이용한 feature toggle 변수 필터 지정

마치며

위의 예시들과 같이, 저희 맘편한세상에서는 피쳐 토글 도입을 통해, 기존과 다른 방식으로 신규 기능을 더욱 빠르고 안전하게 검증하고 배포할 수 있었습니다.

만약 배포와 릴리즈가 강하게 결합된 환경으로 인해 어려움을 겪고 있다면, 피쳐 토글 도입을 강력하게 추천드리고 싶습니다. 이상으로 글을 마치겠습니다!

참고

devops
feature-toggle