안녕하세요, 맘편한세상의 백엔드 엔지니어 이재찬입니다.
맘편한세상의 백엔드 팀은 빠르고 안정적인 릴리즈를 가능케 하는 도구로 피쳐 토글(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();
}
피쳐 토글의 정의 자체는 이렇게 간단하게 설명할 수 있습니다. 하지만 피쳐 토글이라는 개념이 왜 필요한지, 언제 사용하면 좋을지는 조금 더 흥미로운 문제입니다.
피쳐 토글이 제공하는 기능의 본질은 “배포와 릴리즈를 분리할 수 있는 능력”입니다. “배포” 와 “릴리즈” 이 두 단어는 종종 혼용되지만, 여기서는 이 두 개념의 좀 더 정확한 정의와 특성을 한번 짚고 넘어가도록 하겠습니다.
일반적으로는, 코드는 배포되는 즉시 해당하는 기능들이 모든 사용자에게 제공됩니다. 즉, 배포와 릴리즈가 동일한 시점에 발생하는 것이죠. 피쳐 토글을 사용한다면, 코드를 배포했을 때 그 코드에 해당하는 기능이 즉시 릴리즈가 될 필요가 없습니다. 코드가 배포된 이후, 개발자가 기능이 릴리즈되기를 원할 때 피쳐 토글을 활성화하면, 그 때부터 기능이 사용자에게 릴리즈됩니다. 즉, 배포와 릴리즈의 분리가 달성되는 것입니다.
피쳐 토글을 사용해서 배포와 릴리즈의 결합을 끊어내는 것은, 크게 두 가지 상황에서 이점을 가져다줄 수 있습니다.
이 두 가지 상황에 대해서 조금 더 자세히 살펴봅시다.
피쳐 토글을 올바르게 사용한다면, 새로운 기능이 릴리즈될 때의 안정성을 크게 개선할 수 있습니다. 새롭게 작업한 기능이 운영환경에 안전하게 릴리즈될 수 있게 하기 위해서, 통상적으로는 아래의 두 가지 방식을 통해서 새로운 기능의 안정성을 검증합니다.
이 두가지 방식은 분명 널리 쓰이는 방식이지만, 기능의 안정성을 검증하기에는 약간의 아쉬운 구석들이 있습니다.
만약 배포와 릴리즈를 분리해서 새로운 기능의 릴리즈 여부를 피쳐 토글로 제어한다면, 기존 방식과 대비해서 기능 검증과 릴리즈가 더욱 유연하고 안전해집니다. 먼저 운영환경에서 일부 유저 대상으로만 기능을 릴리즈해서 피드백을 받을 수도 있고, 릴리즈 대상을 내부 유저 / 일반 유저들 중에서 임의로 결정할 수도 있습니다. 여러 기능을 동시에 검증하는 것도 가능합니다. 뿐만 아니라, 새로운 기능의 문제가 발견되었을 때, 별도의 코드 수정이나 배포 없이 빠르게 릴리즈 취소가 가능하기 때문에, 릴리즈로 인해 발생하는 문제의 영향도를 크게 줄일 수도 있습니다.
피쳐 토글을 사용한다면, 작업 중인 기능의 코드를 운영 환경에 배포해두고, 외부 유저 대상으로는 새로운 코드가 실행되지 않도록 제어할 수 있습니다. 이렇게 하면 기능 작업 기간이 길더라도, 개발 도중에 언제든지 메인 브랜치에 통합해두거나, 다른 운영 기능들과 함께 운영 서버에 배포하는 것이 자유롭습니다. 기능 준비가 완료되면, 그 때 피쳐 토글을 통해 기능을 릴리즈하면 됩니다.
작업 중인 기능에 대한 배포를 미리 잘게 쪼개서 수행하는 것은 여러 가지 이점을 가져다줍니다.
맘편한세상 백엔드 팀에서는 현재 Unleash라는 피쳐 토글 서비스를 사용하고 있습니다. 이 서비스는 작년 10월에 맘편한세상 백엔드 팀에서 피쳐 토글을 도입할 때부터 사용해왔고, 현재까지도 매우 만족하면서 사용하고 있습니다. Unleash 서비스에서 특히 만족하는 부분들은 아래와 같습니다.
isEnabled
함수가 호출될 때 저장된 피쳐 토글 설정을 통해 활성화 / 비활성화 여부를 서버 내에서 계산합니다. 즉, isEnabled
함수 호출마다 네트워크 요청이 발생하지 않아, 호출 오버헤드가 매우 낮습니다.Unleash의 피쳐 토글 리스트 페이지. 각 피쳐 토글이 가장 최근에 언제 호출되었는지도 확인할 수 있습니다.
Unleash의 개별 피쳐 토글 설정 페이지. 각 환경에서 토글이 활성화되었는지, 얼마나 자주 토글이 요청되는지 확인 가능합니다.
피쳐 토글 서비스 도입을 검토하거나, 자체 구현을 고민하고 있다면, 위와 같은 요소들을 충족할 수 있을지 생각하면서 결정하면 좋을 것입니다.
아래에서는 맘편한세상 백엔드 팀에서 피쳐 토글을 사용하고 있는 다양한 예시를 보여드리고자 합니다.
새롭게 작업한 기능으로 인해 예상하지 못한 에러가 발생해 Sentry 알림이 온 상황입니다. 기능 릴리즈를 피쳐 토글을 통해 진행했었기 때문에, 다시 피쳐 토글을 이용해 빠르게 기능을 비활성화하고, 문제를 그 후에 디버깅할 수 있었습니다.
특정 기능의 릴리즈를 위해서 백엔드와 프론트 릴리즈가 모두 필요한 상황입니다. 이 때 서버와 프론트에서 모두 미리 배포를 해두고, 정해진 릴리즈 시간에 서버와 프론트 모두 피쳐 토글을 활성화해서, 원하는 시간에 쉽게 릴리즈를 하고, QA 검증 또한 바로 순조롭게 진행할 수 있었습니다.
맘시터 앱 내 채팅 관련 POC(Proof Of Concept) 기능에 관한 PR입니다. 해당 기능을 이어서 개발하기 전에 스테이지에서 테스트해보기 위해, 기능을 아래와 같이 피쳐 토글을 통해 보호된 상태로 메인 브랜치에 머지했습니다. 저희는 트렁크 기반 개발 방식을 사용하고 있기 때문에, 코드는 바로 운영까지 배포되었지만, 해당 기능은 스테이지에서만 피쳐 토글을 사용해 안전하게 테스트할 수 있었습니다.
현재 맘시터 백엔드 팀에서는 레거시 Node 서버와 새로운 Kotlin 서버를 동시에 운영하고 있고, 점진적으로 Kotlin 서버로 Node 서버를 대체해 나가는 것을 목표로 하고 있습니다. 현재 두 서버 앞단에는 Spring Gateway를 두고 있습니다.
Gateway에서 커스텀한 Route Predicate를 만들어서, 특정 요청이 Node 서버로 갈지, Kotlin 서버로 갈지를 피쳐 토글을 통해 결정할 수 있게 작업했습니다. 이를 통해 기존 Node 엔드포인트를 대체하는 새로운 엔드포인트를 Kotlin 서버에 배포해 두고, 필요할 때만 새로운 엔드포인트가 호출되도록 해, 새로운 엔드포인트를 안정적으로 운영과 스테이지에서 테스트할 수 있었습니다.
Unleash를 사용하는 RoutePredicateFactory
해당 predicate를 이용해서, 검색 API를 점진적으로 Kotlin서버에 있는 엔드포인트로 대체하는 중
최근에 새롭게 개편된 홈 화면을 릴리즈했었는데, 새로운 홈 화면에는 특정 지역에서만 사용할 수 있는 기능이 포함되어 있어 해당 지역의 유저만 홈 화면을 볼 수 있도록 작업이 되어야 하는 상황이었습니다. 또한, 운영팀의 상황에 따라 해당 기능을 사용할 수 있는 지역이 자주 변화하는 상황이었습니다.
이 때, Unleash의 Custom Strategy 기능을 사용해서, Unleash에서 설정된 지역에 있는 유저에 대해서만 새로운 홈 화면을 릴리즈할 수 있었습니다.
Unleash 어드민에서, 새로운 홈 화면이 노출되는 지역 설정 가능
자체 어드민과 Unleash API를 연동해서, 운영팀이 어드민에서 손쉽게 새로운 홈 화면이 노출되는 지역을 설정할 수 있음
이에 관한 더 자세한 내용은 저희 팀의 백엔드 개발자 현구님이 작성해 주신 블로그에서도 확인하실 수 있습니다. Unleash custom strategy를 이용한 feature toggle 변수 필터 지정
위의 예시들과 같이, 저희 맘편한세상에서는 피쳐 토글 도입을 통해, 기존과 다른 방식으로 신규 기능을 더욱 빠르고 안전하게 검증하고 배포할 수 있었습니다.
만약 배포와 릴리즈가 강하게 결합된 환경으로 인해 어려움을 겪고 있다면, 피쳐 토글 도입을 강력하게 추천드리고 싶습니다. 이상으로 글을 마치겠습니다!
3장. 비즈니스 실천 방법
에서는 작은 릴리즈를 애자일 실천 방법 중 하나로 제시하고, 릴리즈와 배포 사이의 관계를 끊어야 릴리스 주기를 줄일 수 있다고 언급합니다.