Backend
전시 API 서비스 전환기: Part-1
Jude여기어때
2022년 12월 13일
원문에서 보기 ↗안녕하세요. 여기어때 서비스개발팀에서 백엔드 개발을 담당하고 있는 주드입니다. 저는 여기어때 전시를 위한 상품데이터와 메인데이터를 동기화 하는 서비스 개발을 담당하고 있습니다.
최근 팀장님께서 서비스개발팀에서 진행한 전시 API 서비스 개선 프로젝트에 대해 블로그에 남겨보는 건 어떻겠냐는 제안을 하셨습니다. 우리 팀의 일하는 방식과 프로젝트를 진행하는 방식, 그리고 개발 과정을 소개할 수 있는 좋은 기회인 것 같아 흔쾌히 제안을 받아들였고 지금부터 그 이야기를 들려드리려 합니다.
1. 전시 API 서비스?
전시 API 서비스는 서비스개발팀에서 관리하고 있는 다양한 API 중 국내 숙박 도메인에 노출된 상품 정보를 조회하는 서비스라고 할 수 있습니다. 이 서비스는 트래픽 분산의 목적과 사용 방법에 따라 다음과 같이 2개의 API 서비스로 구성됩니다.

Builder-API
-
특징 : 원시 데이터
-
숙박 도메인의 모든 제휴점과 제휴점의 상품, 가격 정보를 계산하여 실시간으로 조회한다.
Exhibition-Product-API
-
특징 : 가공된 데이터
-
Web 또는 앱에서 사용자의 요청에 의한 가공 데이터를 조회하는 API 서비스
-
원시 데이터는 Builder-API를 통해 전달받아 사용자의 요청에 따라 가공된 데이터를 제공한다.
이번 프로젝트의 대상은 Builder-API 라고 불리는 전시 API 서비스입니다.
그럼 대상이 되는 서비스를 확인하였으니, 왜 개선을 해야 하는지 알아보겠습니다.
2. 개선하려는 이유
이번 프로젝트의 목적은 여러가지가 있지만 주요한 3가지에 대해 말씀드리도록 하겠습니다.
하나, 낮은 버전의 Application
지난 6월 Spring Data MongoDB 취약점이 발견되었고 관련된 모든 시스템은 Spring Data MongoDB의 버전을 업그레이드 하라는 권고를 받았습니다. 다행히 우리 프로젝트에 사용된 모듈은 아니었기에 업그레이드를 진행하진 않았지만, 분석 과정에서 해당 모듈의 버전을 업그레이드 하기 위해선 Spring Boot 버전을 업그레이드 해야 했고 그에 따라 1.8 버전을 사용하는 자바의 버전 업그레이드도 불가피한 상황이었습니다.
단순히 업그레이드만 하면 문제가 없겠지만 버전업에 따라 Deprecated된 문법으로 발생할 수 있는 코드의 잠재적 오류와 Warning 포인트를 모두 체크해야 했습니다. 게다가 이 프로젝트는 10개의 크고 작은 서브 프로젝트가 연결된 구조였기에 Spring Boot 버전을 올리고 Java버전을 올리게 된다면 모든 프로젝트의 서비스를 검증해야 하는 상황이 생길 수 있었습니다.
둘, 기존 코드의 복잡성과 테스트 코드의 부재로 인한 유지보수의 어려움
-
숙박 도메인의 전시 비즈니스를 모두가 잘 알지 못했기에 명확한 코드 수정의 어려움이 있음
-
수정을 했더라도 사이드 이펙트를 예측하기 어려움
-
주석의 부재로 코드의 명확한 의도를 파악하기 어려움
-
테스트 코드의 부재로 검증의 한계가 있음
-
다단계의 복잡한 if문을 타고 가다 길을 잃기 쉬움
-
기획서는 존재하지만 기획서에 명시되어 있지 않은 내용은 PHP레거시 소스를 분석해야 했음
셋, 동시성 이슈
무엇보다 가장 큰 문제는 동시성 이슈였습니다.
동시성 이슈란?
- 여러 스레드가 동시에 같은 인스턴스의 필드 값을 변경하면서 발생하는 문제를 의미합니다.
한 가지 예를 들어 설명해보면
제휴점의 체크인-체크아웃 날짜를 계산하여 숙박일을 계산하는 로직을 담고 있는 클래스가 있습니다. 이 클래스는 싱글톤 패턴으로 생성된 하나의 Bean으로 여러 스레드에서 동시에 값을 전달하여 상품 가격을 계산합니다. 그래서 동시 접근으로 값을 변경할 경우 원자성이 보장되지 않는 값에 의해 언제든 잘못된 상품 가격 정보를 반환할 수 있는 구조였습니다.
이는 어느 날 인입된 VOC를 통해서 발견되었고 이와 같은 현상을 재현해 보려 했지만 동일한 문제는 재현되지 않았습니다. 결국 가격에 영향을 줄 수 있는 모든 위치에 로그를 심어 추적한 결과 동시성 이슈로 인한 문제라는 걸 알아낼 수 있었습니다.

동시성 이슈는 코드만 보고선 쉽게 파악하기 어려울뿐더러 개발자의 일반적인 테스트 코드만으로는 재현이 매우 어렵습니다. 또한 이러한 문제가 발생하여 VOC가 인입된다 하더라도 재현이 어려워 일시적인 문제로 가볍게 넘어갈 수도 있습니다.
기존 API 서비스는 대부분 소스가 비동기 처리를 기본으로 하고 있어 멀티 스레드에 의한 또 다른 동시성 이슈는 여전히 존재할 수 있었습니다. 이런 문제점들을 해결하고 서비스의 안정성과 유지보수의 생산성을 위해 첫 번째 프로젝트로 전시 API 서비스를 개선하기로 했습니다.
저희는 기존에 사용되던 API를 대체할 수 있는 신규 서비스를 컨버팅 하기로 결정하였습니다. 신규 서비스로 전환하는 과정에서 오류가 발생하게 되면 빠른 롤백이 중요했기 때문에 배포 전략은 블루/그린을 사용하기로 논의하였습니다. 신규 서비스에 대한 서버를 미리 구축하여 서비스를 배포하였고, 로드밸런서의 리스너와 맵핑된 타겟 그룹을 기존 API서비스에서 신규 API서비스로 변경하여 전환하기로 최종 결정 하였습니다.

블루그린 배포 전략
3. 전환 작업 시작
전환 대상 선정
가장 먼저 한 일은 현재 서비스 중인 API를 분석하는 일이었습니다.
신규 서비스로 컨버팅 하기 위한 API 개수는 총 51개였습니다.
4명의 백엔드 개발자가 컨버팅 하기엔 많은 분량이라 판단하여 사용 중인 API만 찾아 컨버팅하기로 결정하고 진짜 사용 중인 API를 찾았습니다.
서비스 개발팀에서 관리하는 모든 프로젝트 중 전시 API를 호출하는 API를 찾고, 회사 내 유관부서 담당자들에게 사용 중인 전시 API를 수소문한 결과 20개로 축소시킬 수 있었습니다. 마지막으로 Web Application Server의 Access Log를 분석하여 실제 호출되는 API만 찾아 최종 컨버팅 대상은 16개의 API로 축소시킬 수 있었습니다.
기존 API소스 리뷰를 통한 국내 숙박 도메인의 이해
프로젝트에 투입된 모든 인력은 상시 재택근무를 지향하는 회사의 방침 아래각자의 거점에서 업무를 보고 있었기 때문에 저희는 모든 회의를 협업툴 Slack의 허들 기능을 이용해 진행하였습니다. 화상으로 회의를 하며 각자의 화면을 공유하고 기존 API 코드를 기능별로 리뷰하며 비즈니스와 코드에 대한 이해도를 맞춰나갔습니다.
먼저 소스 구조에 대한 이해도를 높이는 데 어느 정도 시간이 소요되었고,
팀원 개개인이 이해하고 있는 비즈니스와 코드에 대해 리뷰하는 시간을 오랫동안 가졌습니다.
개발에 투입된 4명의 백엔드 개발자가 한 명 한 명 진행하는 리뷰를 보며 이해도를 높여갔던 과정이 어찌보면 불필요하거나 비효율적으로 보일 수 있지만 모두가 국내 숙박 도메인의 전시를 위한 비즈니스 이해도를 높일 수 있는 좋은 시간으로 기억하고 있습니다.
페어프로그래밍
저희 서비스개발팀의 운영은 페어프로그래밍을 기초로 운영되고 있습니다.
페어프로그래밍이란 두 사람이 한 짝이 되어서 같이 프로그래밍을 한다는
의미로 애자일 개발 방법론 중 하나 입니다.
기존 Jira by jira를 프로젝트 담당자 또는 비즈니스 이해도가 높은 사람이 처리하는 한편 신규 프로젝트는 몇몇 팀원이 모여 각자 개발을 하고 코드 리뷰를 거쳐서 개발을 완료하는 시스템이었습니다.
페어프로그래밍으로 팀이 운영된 지 1년이 채 지나지 않았지만 그동안 느꼈던 장단점을 프로젝트 투입인원끼리 취합해보았습니다.
장점
업무 집중도
- 업무 시간의 대부분을 페어로 진행하다보니 평소보다 더 많이 집중할 수 있었습니다.
마치 라이브 코딩
- 평소에 개발 진행할 때 프로그래밍 문법은 외워서 하지 않기 때문에 상당 부분 구글링으로 찾습니다.
그래서 코드 작성 할때 약간의 딜레이가 생기기도 하지만 특별한 문제는 되지 않았습니다.
그러나 페어프로그래밍은 코드를 함께 작성하는 시스템이므로 딜레이가 되지 않도록 자주 쓰지만
딱히 외우진 않았던 문법 들을 복습하고 써야 하는 API를 미리 찾아 놓게 되었습니다.
비즈니스 이해도
- 어렴풋이 알고 있던 숙박 상품 도메인 비즈니스를 더욱 자세히 살펴볼 수 있는 시간이었고,
페어 동료와 의견을 나누며 눈높이를 맞출 수 있는 좋은 기회였습니다.
안정감
- 혼자 개발을 진행하다보면 해결하기 어려운 문제를 자주 만나게 되고 막막하고 답이 없는것 처럼
느껴져 좌절하고 힘들 때가 많습니다. 그러나 페어프로그래밍을 진행하면서는 문제가 발생하면
함께 토론하기 위해 정리하던 중 해결책이 떠오르는 경우도 많았고, 팀원이 제가 생각지 못한 관점으로
의견을 제시해서 해결 하는 경우도 많았습니다. 이런 일을 경험하면서 문제가 생기더라도 움츠러들지
않고 일단 함께 얘기해보자라는 생각을 가지게 되었고, 실제로 많은 것을 해결할 수 있어 심리적으로
안정감이 들었습니다.
코드 품질
- 기존 레거시 코드에 설계 구조가 map의 뎁스가 깊은 자료 구조로 설정되어 있고, 실제 사용하지
않아도 객체가 초기화되는 코드가 곳곳에 존재하여 테스트 코드로 검증하기도 코드의 의미를 파악하기도
쉽지 않았습니다.그래서 페어 팀원과 많은 토론을 거쳐 개선 프로젝트에서는 데이터를 사용하는 부분은
클래스, 데이터를 찾는 부분에서는 map, 초기화는 실제 해당 객체가 필요할 때 생성하는 방식으로
개선하고 몽고 도큐먼트 데이터를 연관 있는 도큐먼트끼리 모으고 모여진 데이터로 숙박 상품 가격
계산을 위한 비즈니스 도메인을 생성하여 가격 계산 테스트 코드를 작성하여 코드 품질을 높일 수
있었습니다.
단점
생산성
- '1+1'이 '2'가 되어야 하는데 페어 초기에는 '1.5' 정도의 아웃풋이 나오는 느낌을 받았습니다.
분명히 관리 측면에서는 '2+@'를 기대할텐데 페어를 진행하는 본인도 생산성이 떨어지는 느낌을
받아들이기가 쉽지 않았습니다. “혼자했으면 지금쯤 끝났을텐데..” 라는 생각이 머릿속에 떠올랐기
때문입니다.
하지만 굳이 페어 프로그래밍의 효과에 대한 논문을 인용하지 않아도 코드 품질, 개발만족도, 안정성
등 여러 효과를 많이 느꼈고 배웠기 때문에 페어 초기의 생산성이 떨어지는 부분은 트레이드 오프가
필요하지 않을까 싶은 생각입니다.
일정 압박
- 생산과 관련된 설계, 코드 작업 등 모든 활동을 같이 하기 때문에 시간이 좀 더 들 수 밖에
없었습니다.
처음 계획했던 일정보다 지체가 되니 빨리 해야한다는 심적인 압박이 있었지만 팀장님께서 일정을
조율해주신 덕분에 초기의 적응의 시간을 보내고 난 후로는 안정감을 가지고 일을 마칠 수 있었습니다.
피곤함
- 평소 업무 시에 텐션이 높은 편은 아닙니다. 그런데 페어를 진행하다보니 분위기가 처지면 집중력이
떨어지는 경우가 많았는데 프로젝트 초기 페어 프로그래밍을 하고 퇴근 후에는 항상 녹초가 되곤
하였습니다.
장단점이 뚜렷하다고 생각된 페어프로그래밍은 서로 다른 성향과 생각을 가진 사람 두 명이 한 길로 가기 위한 일련의 활동이라고 생각될 때가 있었는데 마음이 잘 맞지 않고 자기 주장이 강한 사람이거나 아직 서로 신뢰를 쌓지 못한 팀원끼리는 함께 일하기 힘들 수 있겠구나 하는 생각이 들었습니다.
그래서 페어프로그래밍을 시작하기 전에 개발뿐만 아니라 여러 부분에서 본인의 생각이나 감정 등을 나누며 서로 알아가는 시간이 있다면 더 높은 효과를 기대할 수 있을 것 같습니다.
페어프로그래밍을 진행하며 사용했던 도구 및 방법은 다음과 같습니다.
- IntelliJ Code with Me
- 함께 코딩작업할 때 사용했던 툴이지만 자주 끊김
- Slack 허들
- 대부분의 회의는 허들을 통해 진행함
- 허들 화면 공유를 통해 각자 코드리뷰를 진행함
- Google JamBoard
- 화상 회의를 할 때 보드에 뭔가를 기록하고 싶을 때 사용
최근 몇몇 IT서비스 회사에선 흔하게 페어프로그래밍을 진행한다고 합니다만 저희 프로젝트 구성원은 모두 페어프로그래밍을 처음 경험했습니다.
그동안 설계, 개발, 문서 등의 결과물을 가지고 논의하는 식으로 업무를 해왔기 때문에 대부분은 혼자 일을 했습니다. 그래서 페어프로그래밍을 시작할 때 새로운 방식에 대한 기대감과 생산성 저하의 우려가 뒤섞인 기분이 들었습니다.
9~11월까지 약 3개월 간 레거시 코드 분석, 오브젝트 스터디, 클래스 재설계부터 코드 작성까지 함께 진행하였습니다. 서로 성향이 다른 두 사람이 함께 문제를 보고 파악하니 여러 관점으로 볼 수 있고 생각하게 되어 좋았습니다. 특히 동료와 함께 문제 해결 방안에 대해 토론을 하면서 서로의 비즈니스 이해도를 끌어올리고, 그 결과를 설계 단계부터 코드까지 반영할 수 있었습니다.
그리고 제일 시간이 많이 들었던 부분 중에 레거시 코드 분석, 클래스 설계를 할 때 예상하지 못한 엣지 케이스들로 인한 설계 변경으로 일정 지연이 있었는데 모든 과정을 페어프로그래밍 하는 동료와 함께 진행했기에 빠르게 코드를 되짚고 차근차근 테스트 코드를 작성하고 검증할 수 있었습니다.
“멀리 가려면 함께 가라” 는 말의 의미를 되새길 수 있는 시간 이었습니다.
마치며
이번 글에서는 API 서비스 개선의 이유와 개발 방식, 그리고 페어프로그래밍에 대해서 이야기해보았습니다. Part-2에서는 이번 프로젝트를 진행하며 가장 중심이 되었던 API 검증 단계에서 섀도잉을 통해 API 정확성을 검증해나가는 과정과 테스트코드에 대해서 설명하도록 하겠습니다.
끝까지 읽어주셔서 감사합니다.