레거시 죽이기
새로운 프로젝트를 만나는 건 설렘과 기대로 넘쳐나는 순간이죠. 카페에서 테이크아웃한 음료를 한 모금씩 즐기며, 팀원들과 인사를 나누며 목표를 공유하고 비전에 공감합니다. 그러나 코드를 마주한 순간, 처음의 희망은 온데간데없고 갑갑함만이 자리를 차지하고 있었습니다.
코드는 복잡하고 이해하기 어렵습니다. 이걸 고치자니 손도 못 댈 것 같아서 더욱 답답해지기만 합니다. 새로운 마음과 느낌으로 시작한 프로젝트가 어느새 좌절만 남은 존재가 되었습니다. 이 코드로 지금까지 운영을 해왔다니, 정말 놀라운 일입니다.
“이것보다 더 나은 코드를 작성할 수 있을 것 같아…”
더 이상 이 더러운 코드와 공존할 수 없습니다. 그래서 개선해서 새로운 서비스를 만들자고 제안합니다. 새로운 아이디어와 열정을 담아 기존 구조를 깔끔하게 교체합니다. 많은 고비를 거쳐 새로운 서비스가 완성되었습니다. 이제는 예전의 폐기물 같던 서비스와 작별할 시간입니다.
더럽고 꼴 보기 싫은 기존 서비스를 시원하게 날려버리고, 우아하게 새 서비스를 배포합니다. 서비스는 어떤 버그도 없이 원활하게 동작하기 시작하죠. 드디어, 우리는 기존 서비스와 작별하게 되었습니다!
몇 달 후, 새로운 구성원이 합류하고 프로젝트를 살펴보며 조심스럽게 말합니다.
“새롭게 짜보는 것은 어떨까요?”
우리는 지금까지 무엇을 한 걸까요.
사실, 이런 상황은 매우 긍정적인 경우입니다. 우리는 최소한 새로운 서비스를 도입하여 기존 서비스를 대체했습니다. 그 효과에 대해서는 정확히 알 수 없지만요.
현실적으로는 많은 반대에 직면하면서 기존 서비스를 바꾸는 것을 포기하는 경우도 많고, 새로운 서비스를 개발하는 중에 끊임없는 요구사항에 쓸려 지연되어 결국 기존 서비스를 계속 사용하는 결정을 내릴 때도 있습니다. 심지어, 새로운 서비스가 출시된 후 여러 버그와 기능 부족으로 인해 기존 서비스를 완전히 대체하지 못하고 새 서비스가 종료될 수 있습니다.
이런 고난 속에서 우리가 한 일들이 어떤 가치를 창출해 냈는지 의문이 들기도 합니다. 성공적으로 기존 서비스를 바꾸려면 어떻게 해야 할까요?
정말 바꿔야 할까요?
기존 서비스가 조직에 제공하는 가치와 안정성을 고려해 보며 정말로 바꿔야 하는지 다시 한번 신중히 고민해 봅시다. 더 효율적이고 품질 좋게 만들 수 있을까요?
기존 서비스는 현재까지 문제없이 운영되어 온 것이기 때문에, 변경 시에 많은 위험을 감수해야 합니다. 또한, 기존에 서비스는 여러 동료가 심혈을 기울여 작성한 소중한 작품일 수 있습니다. 이것을 변경하는 건 동료들에 대한 도전으로 받아들여질 수 있으며, 많은 반대에 직면할 수 있습니다.
기존 서비스를 바꾸는 결정을 내리기 전에, 기존 서비스를 충분히 이해해야 합니다. 기존 서비스가 보기에 더럽고 복잡할 수 있습니다. 그리고 코드는 의도를 드러내지 못했을 것이고, 개선의 여지가 있을 것입니다. 하지만, 완전히 새로 구축할 정도로 잘못된 것일까요? 적어도 기존 서비스는 조금 복잡하고 때로는 이상하게 동작할 수 있지만, 여전히 빌드되어 정상적으로 가동되고 있습니다. 더불어 사용자 수는 적지만 여전히 서비스를 활용하고 있습니다. 그리고 여전히 조직에 가치를 제공하고 있습니다.
처음에는 이렇게 끔찍한 모습이 아니었을 겁니다. 수많은 요구사항, 버그, 그리고 시간을 만나면서 이렇게 변해간 것이겠죠. 코드가 직접적으로 의도를 드러내지 못하니, 여기까지 오게 된 역사와 도메인 지식을 살펴보며 왜 이렇게 변했고, 아직 어떤 가치를 제공하고 있는지를 알아야 합니다. 그래야 새로운 서비스에서는 최소한 현재 제공하던 가치 이상을 제공할 수 있을 것입니다.
새로운 서비스를 만들어 기존 서비스를 대체하기는 쉽지 않습니다. 다양한 비즈니스 요구사항과 경쟁을 하며 새 서비스를 만들기 위해 충분한 지원을 얻어내야 합니다. 그리고 최소한 고객과 동료들에게 기존 서비스가 제공하던 것만큼의 가치를 제공할 수 있어야 하고, 기존 서비스 사용자들이 불편함을 느끼지 않게 자연스럽게, 이전해야 합니다.
완전히 새로운 서비스를 만들어 대체할지, 아니면 점진적으로 기존 서비스를 향상하는 것이 더 나을지 고민해 보세요. 기존 서비스를 회피하기 위한 수단으로 재설계를 진행해서는 안 됩니다. 쓰레기통을 뒤지는 것 같더라도 기존 서비스를 조금씩 바꾸는 것이 더 좋을 수 있습니다. 물론 기존 서비스를 점진적으로 개선하기는 어렵고 힘든 일이지만, 더 위험부담이 적습니다.
그런데 기존 서비스가 너무 오래되고 더 이상 관리되지 않는 기술로 작성되어 있을 때는 어떨까요? 경우에 따라 리팩토링과 추후 유지보수 비용이 재설계에 필요한 비용보다 많을 수 있습니다. 이런 경우에는 재설계를 진지하게 고려해야 합니다.
하지만 기존 서비스를 대체하는 것은 많은 자원이 들어가야 하는 일입니다. 성공적으로 이를 이뤄내려면 동료들 간의 공감과 협력이 필요합니다. 다른 동료들을 설득하고 협력을 끌어내기 위해서는 먼저 신뢰를 쌓아야 합니다.
신뢰 자산
프로젝트에 새로 합류한 상황에서는 다른 동료들이 처음에는 당신을 충분히 신뢰하지 않아 의견에 공감하고 동의하지 않을 수 있습니다. 동의를 얻기 전에 먼저 신뢰 자산을 쌓아야 합니다.
신뢰 자산은 동의를 얻을때 사용되는 일종의 화폐입니다. 충분한 신뢰 자산을 구축해야만 다른 동료들을 설득하고 동의를 얻을 수 있습니다. 여러분의 의견이 긍정적인 영향을 미치면 신뢰 자산은 많아지고, 그렇지 않으면 적어집니다. 신뢰 자산이 많을수록 더 큰 영향을 미치는 의견에 동의를 받아낼 가능성이 높아집니다.
물론 가지고 있는 신뢰 자산을 넘어서 더 많은 변화를 일으킬 수 있습니다. 이는 마치 신뢰를 대출하여 부채를 갖는 것과 비슷합니다. 그러나 대출을 하기 위해서는 이미 최소한의 신뢰 자본이나 대채할 수 있는 사회적 명예나 권위와 같은 담보를 보유하고 있어야 합니다. 그리고 기꺼이 신뢰를 대출해줄 동료나 문화, 규칙이 있어야 합니다.
신뢰 자산을 넘어서 도전하는 순간, 의심의 눈초리를 받기 마련입니다. 하지만 성공한다면 부채를 상환하고 더 많은 자산을 쌓을 수 있습니다. 물론 실패한다면 대출한 신뢰를 모조리 잃어버리게 되겠지만요.
기존 서비스를 대체하는 것은 많은 신뢰 자산이 필요합니다. 어떤 경우는 다른 서비스를 시작하는 것 보다 많이 필요하기도 하죠. 서비스를 재설계하기 전에 다른 업무들을 성공적으로 완료해나가며 신뢰자산을 충분히 축적하며 다른 동료들과 공감대를 만들어야 합니다.
충분한 신뢰 자산이 모이고 다른 동료들과의 공감대가 형성이 되었다면 드디어 새로운 서비스를 만들 준비가 되었습니다.
점진적인 전환
새로운 서비스를 개발하는 중에도 지속해서 나타나는 요구사항에 대응해야 합니다. 재설계는 고객의 요청 사항을 무시하고 서비스의 성장을 막는 핑계가 될 수 없습니다. 재설계가 완료될 때까지 요구사항을 막아 주겠다는 약속이 있더라도, 그런 약속은 고객의 요청이나, 투자자들의 압박 그리고 다른 고위 관리자에 의해 쉽게 무산됩니다.
또한 신뢰 자본이 고갈되지 않게 꾸준히 관리해야 합니다. 신뢰 자본이 고갈되면 이 전환이 성공할 것이라는 확신을 더 이상 주지 못하여 프로젝트가 중단될 수 있습니다.
결국 최대한 빠르게 작동하는 소프트웨어를 개발해야 합니다.
기존 서비스의 기능을 이전하는 것만으로도 상당한 시간과 자원이 필요합니다. 노력을 최소화하면서 최대한의 영향을 창출해야 합니다. 그렇기에 이전에 제공된 기능보다 더 많은 가치를 만들어낼 수 있는 새로운 기능을 우선적으로 고려하여 작업해야 합니다. 그리고 기존 서비스는 최소한의 유지보수만 하며 새로운 기능은 새 서비스에 구현하고 배포하는 것이 좋습니다. 두 서비스를 변경하는 것은 복잡하고 시간이 많이 소요됩니다. 새 서비스는 기존 서비스가 제공하지 못했던 가치를 제공해야 합니다.
과거의 인터페이스를 개선하고 싶은 경우가 있을 것입니다. 그러나 새로운 인터페이스를 제공한다 하더라도 구 버전의 인터페이스를 함께 제공하는 것이 좋습니다. 새로운 서비스에서 제공하는 구 버전의 인터페이스는 신 버전의 인터페이스를 활용하여 구현될 수 있습니다. 이렇게 하면 인터페이스가 동일해져 두 서비스 간의 결과를 비교하고 서비스를 검증하며 안정화시키기가 용이해집니다.
무엇보다 신속한 서비스 구축이 중요합니다. 단 하나의 기능이라도 빠르게 배포하여 신뢰 자산을 회수하고 피드백을 수렴하여 방향을 조정해야 합니다. 새로운 서비스로 기능을 이전한 후엔 최소한의 공존 기간을 거치고 기존 서비스에서 기능을 제거 하여 비용을 줄여야 합니다.
안전한 제거
새로운 서비스의 안정성을 확인하기 위해 기존 서비스와 기능을 비교하며 충분히 테스트해야 합니다.
기능을 개발하는 과정에서는 기존 서비스의 사용자 요청을 수집하여 실제 데이터 분포와 유사한 테스트 데이터를 생성하고, 이를 활용하여 새로운 서비스의 동작을 확인합니다.
개발이 완료된 이후에는 데이터를 일괄적으로 수집하는 대신, 실시간으로 새로운 서비스에 요청을 전송하여 결과를 비교하고 차이를 감지하며, 실제 서비스의 처리 능력을 검증합니다. 새로운 서비스가 만들어 내는 결과는 실제 사용자에게 노출되지 않고, 단지 검증을 위해 사용됩니다. 또한 사용자 경험과 성능에 영향을 최소화하기 위해, 이 과정은 사용자에게 응답을 반환한 이후에 처리하거나 메시지 큐를 활용하여 비동기로 처리될 수 있습니다.
이후에는 충분한 양의 요청이 새로운 서비스에서 원활히 처리되도록 하여, 다양한 특징을 고려하여 새로운 서비스를 검증합니다. 서비스 간에 차이가 있을 것이므로, 이 단계에서 운영에 필요한 다양한 정보를 얻을 수 있습니다. 그리고 점진적으로 새로운 서비스로 오는 트래픽을 늘려가며, 기존 서비스의 기능을 완전히 대체합니다. 모든 요청이 새 서비스에서 원활하게 처리된다는 확신이 들면, 기존 서비스의 기능을 안전하게 제거할 수 있습니다.
이러한 과정에서 서비스에 오는 트래픽을 제어하고 사용자 요청을 수집하기 위해 API Gateway를 활용합니다. AWS API Gateway, AWS Lambda, NGINX Plus, Uniflow와 같은 서비스를 사용하거나, 직접 구축하여 활용할 수 있습니다.
참고 자료
- 신뢰 자본, 기억보단 기록을
- 프로덕트 팀이 신뢰를 ‘자산’처럼 관리해야 하는 이유, 요즘IT
- AWS API Gateway + Lambda 로 A/B 테스트하기, Haandol
- A/B 테스트 배포, NGINX Plus API Gateway로 시작하기, nginxstore
댓글남기기