logo
logo
프론트엔드
GraphQL
그래프QL은 페이스북이 2012년에 개발하여 2015년에 공개적으로 발표된 데이터 질의어이며, 필요한 데이터의 구조를 지정하여 요청 및 반환받을 수 있게 설계되어 있다.
StackOverflow 질문 수: 21189
Github Stars : ★ 20171
사용 기업
인공지능
교육
기타
모빌리티
소셜/컨텐츠
직장
패션
금융/보험
종합
이커머스
헬스케어
부동산/인테리어
여행
푸드테크
techstack-logo
슈퍼브에이아이
techstack-logo
클래스팅
techstack-logo
엔라이튼
techstack-logo
바로고
techstack-logo
당근
techstack-logo
모두싸인
techstack-logo
그린랩스
techstack-logo
버즈빌
techstack-logo
카카오스타일
techstack-logo
차이코퍼레이션
techstack-logo
42dot
techstack-logo
카카오엔터프라이즈
techstack-logo
카카오모빌리티
techstack-logo
카카오
techstack-logo
뱅크샐러드
techstack-logo
네이버
techstack-logo
네이버웹툰
techstack-logo
스포카
더 보기
기술 블로그 글
리디
RiGrid, Server Driven UI로 변화에 민첩하게 대응하기
일반적으로 서비스를 고객들에게 제공하기 위해 필요한 요소들이 있습니다. 첫 번째는 서비스 페이지로 주로 앱이나 웹의 프론트엔드에서 직접 고객들에게 보여지는 부분이고, 두 번째로 서비스 페이지를 구축하기 위한 데이터를 제공하는 백엔드가 필요합니다. 마지막으로 백엔드가 제공하는 데이터를 관리하는 콘텐츠 관리 시스템입니다.급변하는 시장 상황과 고객의 요구에 빠르게 대응하기 위해, 때로는 비즈니스 타이밍을 맞추기 위해 설계 단계에서 충분히 고려되지 못한 부분을 구현해 적용한 경험은 누구나 있을 겁니다. 이처럼 미처 고려되지 못했던 기능들이 추가되고, 급하게 구현된 코드들이 쌓이면서 기술 부채와 레거시가 증가하게 돼 결국 유지보수 비용을 증가시키는 요인이 되었습니다.미처 설계에 충분히 고려되지 못했던 부분이나 급하게 대응한 부분은 앱/웹 프론트엔드뿐만 아니라 백엔드, 콘텐츠 관리 시스템, 심지어는 데이터베이스와 인프라에 이르기까지 광범위하게 발생했습니다.특히 서비스 변화의 최전선에 있는 프론트엔드와 백엔드는 항상 최선의 선택을 해왔지만, 기술 부채와 레거시가 누적되면서 유지보수 비용 증가와 생산성 감소라는 문제에 직면하게 됐습니다. 무엇보다 프론트엔드의 UI 구성을 위한 데이터와 백엔드의 비즈니스 데이터가 강하게 결합되고, 심지어 동일한 데이터를 가지고도 프론트엔드 플랫폼별로 다른 비즈니스 로직을 구현하는 사례도 있었습니다. 이러한 문제는 서비스의 확장성과 유지 보수성을 저해하는 주요 요인이 되었습니다.리디는 앞서 언급한 문제점들을 해결하고 보다 효율적인 서비스 운영 환경을 구축하기 위해, ‘어떻게 하면 좀 더 효율적으로 서비스를 운영할 수 있을까?’라는 질문에 대한 해답을 찾기 위해 노력해왔습니다. 그리고 그 해답을 찾는 과정에서 핵심적인 문제점을 발견했습니다. 바로 비즈니스 로직 데이터와 UI 데이터의 강결합이었습니다.기존 API 의 UI 에서 사용하는 작품의 배지 표현을 위한 데이터기존 웹 Twig Book Macro에서 신간(NEW) 배지를 표현하는 코드API의 뱃지 정보와 프론트엔드 코드의 뱃지 표현 방식이 강하게 결합되면, API 스펙 변경 시마다 프론트엔드 코드를 수정해야 합니다. 이는 유지보수 및 확장성을 저하시키고, 코드 재사용성을 떨어뜨립니다. 따라서 비즈니스 로직의 데이터와 UI 데이터를 분리해 API와 프론트엔드 코드의 결합도를 낮추는 것이 중요합니다.“기다리면 무료”로 이용할 수 있는 작품을 뜻하는 배지를 노출하기 위해서는 is_wait_free: boolean 속성이 필요합니니다. 해당 배지를 추가하기 위한 API 에 property.is_wait_free 라는 응답이 더해졌고 이에 따라 여러 부분의 대응이 진행됐습니다.기존 웹 Twig Book Thumbnail Macro에서 기다리면 무료 배지를 표현하는 코드기존 웹 React Book Component 의 BookBadgeRenderer에서 기다리면 무료 배지를 표현하는 코드이렇게 “기다리면 무료”를 나타내는 배지를 표현하기 위한 비즈니스 로직 데이터와 UI 를 표현
graphql
당근
GraphQL을 이용한 QueryFacade 개발기
안녕하세요. 저는 로컬 비즈니스실에서 서버 개발자로 일하고 있는 에렌(Eren)이라고 해요. 당근을 사용해 본 적 있으신가요? 당근의 동네지도 탭에 들어가면 ‘음식점’, ‘카페/간식’ 등 카테고리별로 동네 업체를 모아볼 수 있는데요. 여기서 각 업체의 정보를 담고 있는 ‘비즈 프로필’을 저희 팀이 만들고 있어요. 저희 팀은 사람들은 믿을 만한 동네 업체를 빠르게 찾고, 동네 사장님들은 더 효과적으로 장사할 수 있도록 돕는 플랫폼을 만들고 있어요.로컬 비즈니스실의 핵심 모델은 Business Profile(업체 프로필)이에요. 다양한 카테고리의 업체 사장님들이 비즈 프로필을 효과적으로 사용하기 위해선 여러 도구가 필요해요. 그래서 저희는 상품 판매, 예약, 후기, 쿠폰, 채팅, CRM 같은 여러 기능을 계속 추가하고 있어요. 동네 사장님의 필수 채널이 되는 것을 꿈꾸는 만큼 제품의 복잡도가 빠르게 증가하고 있어요.로컬 비즈니스실은 각 도메인의 복잡한 정책을 나누기 위해 마이크로서비스 아키텍처를 지향하고 있어요. 그럼에도 도메인 자체가 상호작용할 필요가 늘어났고, 각 서비스의 데이터를 조합하는 일도 증가했어요. 특히 다음과 같은 상황에서 복잡한 데이터 조합이 필요했어요. 대표적으론 다음과 같은 경우가 있었어요.모든 정책과 연관 관계가 모이게 되는 프로필 홈 화면.정책 자체가 여러 도메인의 데이터를 기반으로 결정되는 경우.외부 서비스에 데이터를 취합하여 데이터를 제공하는 경우.서비스가 고도화되면서 도메인 간의 관계는 점점 복잡해졌어요. 트래픽 또한 1만 TPS를 뛰어넘게 되었고요. 조회해야 할 데이터 관계는 늘어나고 시스템의 부하도 증가했어요. 로컬 비즈니스실에서 조회 로직과 관련해 구체적으로 어떤 문제가 발생했고, 어떻게 해결했는지 공유하고자 글을 작성하게 되었어요. 비슷한 고민을 하고 계시는 다른 분들에게 도움이 되면 좋겠어요.로컬 비즈니스실이 마주한 문제 — Dynamic Join Aggregator로컬 비즈니스실은 객체 간의 연관 관계를 조합하기 위해 Aggregator 패턴을 사용하고 있었어요. Aggregator 패턴은 간단하게 구현하기 좋다는 장점을 가지고 있어요. 예를 들어 프로필과 프로필의 카테고리 정보가 같이 필요하다면 다음과 같은 코드를 작성할 수 있어요.// 로컬프로필 조회val businessProfiles = businessProfileRepository.findAllBy(businessProfileIds)// 카테고리 조회val categoryIds = businessProfiles.map { it.categoryId }val categories = categoryRepository.findAllBy(categoryIds).associateBy { it.id }// 하나의 Dto로 조합val dtos = businessProfiles.map { Dto( businessProfile = it, category = categories[it.categoryId] )}실제 프로덕션 코드 또한
graphql
java
nodejs
카카오스타일
내가 만든 non-null 변수에서 NullPointerException이 발생할 리가 없어!
안녕하세요, 카카오스타일 전시 UX팀의 샌즈입니다.모두들 알고 계시듯 null(널)은 값이 없음을 나타냅니다. 그리고 null 값인 객체에 접근하려고 하면 그 유명한 NullPointerException(NPE)이 발생합니다. 그런데 null 값을 가지지 않는 다고 설정한 변수에서 NPE가 발생하는 현상을 겪어 그 내용을 공유해보려고 합니다.다음은 Kotlin에서 non-null 변수를 선언한 예입니다.타입인 경우 null 값을 가질 수 있고, 으로 선언하면 null이 들어가면 안 된다는 뜻입니다. 카카오스타일에서 Kotlin 외에 사용 중인 TypeScript와 GraphQL에서도 비슷하게 설정가능합니다.non-null 변수에 null이 들어가는 현상지그재그 특가 진입시 ad_noti_status라는 필드가 ‘disagree’이면 알림 유도 UI를 제공하도록 되어 있었습니다. 이 필드 값을 반환하는 코드는 다음과 같습니다.일부 사용자가 알림 동의를 받지 않았음에도 UI가 노출되지 않아 분석을 해보니 위 코드에서 NPE가 발생하고 있었습니다.문제 재현을 위해 다음과 같이 코드를 작성해봤습니다.실행하면 다음과 같은 결과를 보여줍니다.이런 에러가 나는데는 몇가지 조건이 겹쳤습니다.잠깐! NPE는 null인 객체를 접근해야 에러가 나는 건데, user는 null이 아닌데? 맞습니다. 실제 환경에서도 user가 null이면 로그를 찍게 해봤는데 로그에 찍히는게 없었습니다.해당 서비스는 오래전에 만들어졌는데, 그 뒤로 Kotlin 버전 업그레이드를 하지 않은채 1.4.20을 사용하고 있었습니다. Kotlin을 1.5로 업그레이드 했더니 문제가 발생하지 않았습니다. (user가 null이면 당연히 NPE가 발생합니다.) when을 if로 바꿔도 문제가 발생하지 않았기 때문에 오래전 Kotlin 버전에서 when 동작에 특이한 부분이 있다고 짐작할 수 있습니다.다음은 비슷한 상황에 enum을 추가 적용해본 것입니다.Kotlin 최신 버전(2.0.0)에서 실행해본 결과입니다.when를 if의 문법적 설탕 정도로 생각했는데 동작이 조금 다른 것을 확인할 수 있습니다.Kotlin 언어에는 null과 non-null 구분이 있지만, 그 기반이 되는 JVM에서는 그런 구분이 없습니다. 그렇다보니 언어의 제약과 상관없이 내부 값이 null을 가질 가능성이 존재합니다. (TypeScript도 마찬가지기 때문에 JSON 파싱 후 값의 타입을 검증해주면 좋습니다.)위 문제를 사내에 공유했을 때 비슷한 문제가 있어서 Gson 대신 Jackson을 사용했다는 답글이 있었습니다.테스트 코드를 Jackson으로 재작성했을 때 파싱 과정에 에러가 나는 것을 확인했습니다.Kotlinx도 마찬가지로 파싱시 에러를 발생합니다.Kotlinx는 동작이 다른 부분이 하나 더 있습니다. ad_noti_status가 nullable, 즉 String?으로 선언되었을 때, Gson, Jackson은 문제가 없었지만, Kotlinx는 에러를 반환했습니다. Kotlinx는 JSON 문자열이 일
graphql
kotlin
카카오엔터테인먼트FE
마법소녀 이세계 아이돌 웹툰 런칭! BFF 장애 대응기
카카오페이지 웹 서비스는 graphql을 활용해 BFF를 운영하고 있습니다. 팀 내부에서는 graphql을 사용하는 방법에 대한 노하우들이 적립되어 DX(Developer Experience) 향상과 타 팀과의 커뮤니케이션에 많은 도움을 받으며 BFF를 사용하고 있었는데요. 유명 스트리머 우왁굳의 버추얼 걸그룹 이세계 아이돌의 웹툰이 카카오페이지에 런칭하는 날 트래픽이 3배 이상 몰리게 되며 BFF 서버의 CPU가 100%를 찍는 장애가 발생하게 됩니다. 저희가 문제를 겪으며 알아낸 해결책이 어떤 분께는 도움이 될 수 있을 것 같아 이 글을 쓰게 되었습니다. 문제를 찾아 나가며 알게 된 꿀팁들도 적어 볼 테니 재밌게 봐주셨으면 좋겠습니다.이세계 아이돌 웹툰 런칭 서비스 장애2023년 6월 21일 22시 이세계 아이돌의 웹툰 마법소녀 이세계 아이돌 이 카카오페이지와 카카오웹툰에 런칭하게 됩니다. 스트리머 우왁굳과 버추얼 아이돌 그룹 이세계 아이돌 멤버들이 트위치에서 실시간 생중계를 하며 런칭을 기다렸고, 많은 시청자들이 웹을 통해 작품에 접속하게 되면서 서버가 응답을 내려주지 못하는 장애가 일어나게 됩니다. 수분 정도 페이지가 뜨지 않는 현상이 있었고, 리소스 대비 생각보다 TPS가 안 나오고 있는 것을 발견하여 성능 개선을 우선 과제로 보고 여러 가설을 세워 문제를 찾아나가기 시작했습니다.BFF는 백엔드 API를 호출해서 응답을 가공해 클라이언트로 내려주는 역할 정도만 하고 있어서 CPU가 올라갈 만한 문제의 원인에 감이 안 오는 상황이었는데요. 저희 팀은 여러 가지 가설을 세워 문제의 원인을 찾아내고자 했습니다. 원인이 확실하게 떠오르지 않아 생각나는 대로 가설 리스트를 만들고 하나씩 넣어보며 원인을 찾아 나섰습니다. 가설을 말씀드리기 전에 일단 저희 구성도를 간단히 설명해 드리겠습니다.저희는 서비스 운영에 쿠버네티스를 활용하고 있고, 서버사이드 렌더링을 하는 next.js pod들과(인스턴스라 생각해 주시면 되겠습니다.) BFF를 담당하는 pod들이 따로 떠 있는 상황입니다. BFF에 요청이 들어오면 그에 맞는 백엔드 API를 호출하고, API 응답을 받은 후에는 클라이언트가 요청한 gql 포맷에 맞게 응답을 가공해 내려주는 작업을 진행합니다. BFF 환경은 node.js express에 apollo server를 사용해 띄우고 있었는데요. REST API로 데이터를 받아와 가공 정도만 하는 BFF 서버가 서버사이드 렌더링을 하여 html을 그려주는 next.js 서버보다 성능이 안 나오는게 이해가 안 되는 상황이었죠.제일 간단하게 생각을 해봤을 때 장애 당시 백엔드 응답이 늦어서 BFF도 응답을 내려주기까지 시간이 오래 걸려 타임아웃이 발생한 게 아닐까 하는 생각이 들었습니다. 하지만 당시 백엔드 팀의 모니터링 결과로는 응답 중에서는 특이하게 느린 응답이나 생각보다 부하가 없었다는 얘기를 전달받게 됩니다. 그렇다면 저희 쪽 BFF 서버에서 뭔가의 문제가 있는 것인데.. 정확한 확인을 위해 현 상황에서 nGrinder를 통해 부하 테
apollo
expressjs
graphql
kubernetes
nodejs
연관 기술 스택
techstack-logo
Apollo
techstack-logo
MobX
techstack-logo
Redux
techstack-logo
Relay
Copyright © 2025. Codenary All Rights Reserved.