배달의민족 Flutter 도입과 아키텍처 설계 교훈

배달의민족은 주문접수 채널에서 Flutter를 도입하여 멀티 플랫폼 대응력을 높이고, Clean Architecture를 통해 효율적인 코드 관리를 실현했습니다. 이 글에서는 Flutter 도입과 아키텍처 설계의 과정에서 얻은 교훈을 바탕으로, 변화하는 비즈니스 요구에 맞추기 위한 혁신적인 접근을 소개합니다. 또한, 이러한 경험이 다른 기업이나 개발자에게도 유용한 전략이 될 수 있도록 공유하고자 합니다. Flutter 도입으로 인한 혁신적인 변화 배달의민족은 Flutter 도입을 통해 플랫폼 전환과 유지보수 측면에서 큰 혁신을 이루었습니다. 기존의 Windows, Android, iOS 플랫폼에 추가하여 macOS와 다양한 Android 디바이스로까지 확장할 필요성을 느꼈습니다. Flutter의 도움으로 단일 코드베이스에 의해 멀티 플랫폼을 동시에 지원할 수 있게 되었고, 이를 통해 개발자 수를 줄이고 생산성을 향상시킬 수 있었습니다. 개발자들은 각 플랫폼에 대해 반복적으로 구현할 필요가 없어졌고, 버그 수정이나 기능 변경 시에도 이전에 비해 적은 시간에 모든 플랫폼에 적용할 수 있게 되었습니다. Flutter의 도입은 크로스 플랫폼 반응형 UI 구현을 가능하게 하여, 사용자 경험의 일관성을 높였습니다. 이제 파트너들은 다양한 OS 환경에서 동일한 경험을 하게 되므로, 학습 비용도 줄어들고, 혼란이 줄어드는 장점을 경험하고 있습니다. 이러한 변화는 단순히 기술적인 접근방식이 아닌, 사업의 방향성을 전환하는 계기로 작용했습니다. 파트너사들이 원하는 효율적인 주문 관리 시스템을 제공하기 위해, 기존의 네이티브 아키텍처에서 벗어나 새로운 기술 스택으로 과감히 옮겨갔습니다. Firebase와 같은 클라우드 서비스를 활용하여 실시간 데이터 업데이트와 동기화가 가능하게 되었고, Flutter의 강점을 극대화하여 사용자 친화적인 UI/UX도 구현됐습니다. 이로 인해 즉각적인 피드백을 수렴할 수 있는 구조가 마련됐습니다. 결국 Flutter의 도입은 배달의...

Spring Cache와 Redis에서의 record 직렬화 오류 해결


최근에 많은 개발자들이 Spring Cache와 Redis를 활용한 프로젝트를 진행하면서, record와 GenericJackson2JsonRedisSerializer 조합에서 발생하는 직렬화 오류에 대한 문제를 경험하고 있습니다. 이 글에서는 Spring Cache와 Redis에서 record 직렬화 오류의 원인과 해결 방법에 대해 심층적으로 알아보겠습니다. 특정 직렬화 방식이 다른 결과를 초래할 수 있는 만큼, 그 해결책을 제시하여 안정적인 캐시 환경을 제공하고자 합니다.

Spring Cache와 Redis에서의 직렬화 오류 원인

Spring Cache는 어노테이션 기반으로 캐싱을 지원하는 기능입니다. Redis는 이러한 캐시 데이터를 저장하는 데 사용됩니다. 그러나 record 데이터 클래스를 Serialize할 때, GenericJackson2JsonRedisSerializer의 구현에서 발생하는 문제로 인해 오류가 발생하게 됩니다. 이 문제는 종종 첫 번째 데이터 요청은 성공하지만 두 번째 요청에서 특정 예외가 발생하는 형태로 나타납니다.


제공된 예시 코드에서, record인 UserRecord를 정의하고 해당 객체를 Redis에 캐시하는 서비스를 구현할 수 있습니다. 첫 번째 요청에서는 사용자가 원하는 데이터를 정상적으로 받지만, 캐시된 데이터에서 두 번째 요청 시, 역직렬화 과정에서 타입 정보가 누락되면서, InvalidTypeIdException이 발생하는 예외가 뜹니다. 이는 GenericJackson2JsonRedisSerializer가 Jackson의 ObjectMapper를 통해 직렬화하던 과정에서 발생하는 문제로, record가 final 타입이기 때문에, 해당 타입의 정보가 JSON에 포함되지 않기 때문입니다.


일반적으로 직렬화할 때는 특정 클래스의 타입 정보가 필수적입니다. Jackson의 기본 설정에 따르면, final 타입인 record에는 기본적으로 '@class' 정보가 없어 이를 바탕으로 역직렬화하는 과정에서 문제가 발생합니다. 이러한 예외는 개발자가 컴파일 단계에서 눈치 채기 어려운 런타임에서만 발생하므로 예방하기 더욱 힘든 문제입니다. 따라서, 직렬화 과정에서 모든 데이터의 타입 정보를 포함시킬 수 있는 방법을 모색하는 것이 필요합니다.

효율적인 해결 방안 모색

직렬화 오류 문제를 해결하는 첫 번째 방법으로는 기존 코드를 수정하여 데이터 클래스의 타입 정보를 JSON에 포함시키는 것입니다. 구체적으로, ObjectMapper를 커스터마이즈하여 record나 final 클래스를 포함하더라도 타입 정보를 자동으로 추가하도록 설정할 수 있습니다. 예를 들어, Custom TypeResolver를 활용하여 구체적으로 record 타입일 경우에만 타입 정보를 추가하도록 하면, 이 문제를 해결할 수 있습니다.


특히, Spring Data Redis의 GenericJackson2JsonRedisSerializer의 운용 중요성을 인식하고, 해당 직렬화기 내에서 타입 해결 로직을 명확히 합리화해야 합니다. 직렬화할 때 ObjectMapper가 쓰이는 구조이므로, 기본 타입 결정 설정을 수정해야 합니다. 이를 통해 JSON의 형식을 정의할 때 record에 대한 특별한 대우를 해줄 수 있습니다. 전에 제시된 해결 방법을 적용하면, 역직렬화 과정에서 JSON 안에 모든 필요한 정보가 포함되어 문제없이 객체를 재생성할 수 있습니다.


또한, 이와 같은 해결 방법을 적용한 후에는 충분히 테스트를 거친 상태에서 배포를 진행해야 합니다. 특히 테스트 환경에서 다양한 케이스에 대해 검증한 후, 실제 배포로 이어가야 하며, 이전에 캐시한 데이터와의 충돌을 피하기 위해 새로운 cacheName을 설정하는 것도 고려해야 합니다.

변화에 대한 지속적 검증

직렬화 및 역직렬화 설정을 마친 후, 여러 케이스에 대해 충분한 테스트를 통해 검증한 결과, 변경된 설정이 정상적으로 동작하며 문제를 효과적으로 해결하는 것으로 확인되었습니다. 이처럼 JSON 직렬화 과정에서 record 타입을 잘 처리한다면, 효율적으로 Redis의 캐시를 관리할 수 있습니다.


주목할 점은 최적화된 설정이 많을수록 개발자에게 실수할 여지가 줄어드는 만큼, 초기 구현 단계에서 더욱 신경 써야 한다는 것입니다. 위에서 다룬 내용처럼 개선된 serializer를 통해 타입 정보의 부재로 인해 발생하는 문제를 근본적으로 해결할 수 있으며, 이는 향후 유사한 문제를 다른 프로젝트에서 접했을 때 더욱 유용한 교훈이 될 것입니다.


결론적으로, 이번 문제는 간단하게 ‘record가 직렬화되지 않는다’는 단순한 오류가 아닌, 외부 라이브러리와의 호환성 문제로 인한 것임을 부각합니다. 따라서, 두 라이브러리의 기본 설계를 이해하고, 지속적인 검증과 테스트를 통해 실질적인 문제 해결을 도모하는 것이 중요합니다. 이러한 경험은 향후 유사한 문제를 해결하는 데 큰 도움이 될 것입니다.

이 블로그의 인기 게시물

우아한형제들의 실시간 알림 혁신: SSE(Server-Sent Events)로 이룬 효율성과 안정성

우아한 디버깅 툴 개선으로 QA 업무 효율화

물어보새의 진화와 지식 공유 확장