logo
기술 블로그
logo
데이터가 세상을 지배하는 시대 : 두 번의 대전환
요즘에 데이터 플랫폼 구축과 관련된 프로젝트를 시작하고 있습니다.데이터에 대해 다시 한 번 정리를 해 봐야 겠다는 생각을 하였고, 데이터의 히스토리를 다시 머리속으로 떠 올리고 자료도 확인해 보면서 정리해 보기로 했습니다.2000년대 초부터 시작하는 데이터, 구체적으로는 빅데이터의 시대 출현부터 기억을 되살려 보았고,그 이후에도 2010년대 초, 2020년대 초로 이어지면서 변화를 일으키고 있다는 사실을 확인하게 되었습니다.현재 우리는 데이터가 가장 중요한 자원으로 여겨지는 시대를 살고 있습니다.2000년대 초반부터 지금까지, 빅데이터와 인공지능의 발전은 기술 산업뿐 아니라 우리의 일상생활을 근본적으로 변화시켰습니다.이 글에서는 지난 20여 년간 일어난 두 번의 중요한 기술적 대전환을 살펴보며, 데이터가 현대 사회의 핵심 동력이 된 과정을 알아보겠습니다.첫 번째 대전환 : 빅데이터의 탄생과 성장 (2001-2010)2001년, 가트너의 애널리스트 더그 레이니는 데이터의 특성을 설명하는 '3V' 개념을 최초로 제시했습니다.그 이전까지 데이터는 단순히 컴퓨터에 저장된 정보였지만, 레이니의 개념은 데이터를 바라보는 관점을 완전히 전환시켰습니다.• None Volume(양): 전통적인 데이터베이스로는 처리할 수 없는 방대한 규모의 데이터• None Velocity(속도): 데이터가 생성되고 처리되는 빠른 속도• None Variety(다양성): 정형, 반정형, 비정형 등 다양한 형태의 데이터이 시기는 고요한 바다에 거대한 파도가 일기 시작하는 듯했습니다. 아직 그 파도의 정확한 크기를 예측하지 못했지만, 변화의 조짐은 분명했습니다.2005년, 아마존은 사용자의 클릭스트림 데이터 분석을 통해 추천 시스템의 정확도를 35% 향상시켰습니다.이는 데이터를 활용한 비즈니스 혁신의 대표적인 성공 사례가 되었고, 오늘날 우리가 당연하게 여기는 "이 상품을 구매한 사람들이 함께 구매한 상품" 추천 기능의 시초가 되었습니다.2008년, 유럽입자물리연구소(CERN)는 대형 하드론 충돌기(LHC) 실험에서 초당 1페타바이트(PB)의 데이터를 처리할 수 있는 시스템을 구축했습니다.이는 당시로서는 상상하기 어려운 데이터 처리 규모로, 빅데이터 기술이 과학 연구의 새로운 지평을 연 순간이었습니다.같은 해, 구글은 검색 데이터를 활용한 '구글 독감 트렌드'를 발표했습니다.사용자들의 검색어를 분석해 독감 유행을 예측하는 이 시스템은 빅데이터의 잠재력을 보여주는 혁신적인 사례였습니다.그러나 이후 예측 정확도에 문제가 발생하면서 데이터의 품질과 정제의 중요성이 부각되기 시작했습니다.빅데이터 인프라의 발전이 시기에 하둡(Hadoop)과 MapReduce 같은 분산 처리 기술이 등장하면서 대규모 데이터 처리의 새로운 지평이 열렸습니다.2006년 야후에서 시작된 하둡은 빅데이터 처리의 핵심 도구로 자리 잡았고, 기업들은 이전에는 엄두도 내지 못했던 규모의 데이터를 저장하고 분석할 수 있게 되었습니다.첫 번째 대전환의 시기는 데이터의 양적 폭발이 특징이었습니다.마치 미지의 대륙을 탐
SK텔레콤
·
2일 전
logo
여기어때 시스템 아이콘 개선기
김제린(Riny) / Visual graphic Designer아래 이미지에서 어떤 문장이 더 읽기 쉬워 보이시나요?디지털 환경에서 일관된 디자인 언어는 사용자 경험을 높이는 중요한 요소인데요, 여러 서체가 섞였을 때 가독성이 떨어지는 것처럼 시스템 아이콘에서도 일관된 그래픽 스타일을 유지하는 게 중요하죠. 시스템 아이콘은 디지털 인터페이스에서 기능이나 상태를 시각적으로 나타내는 그래픽 요소로, 사용자가 빠르게 이해하고 조작할 수 있도록 돕는 역할을 해요.하지만 기존 시스템 아이콘들은 각기 다른 스타일로 디자인되어 가독성이나 통일성 면에서 아쉬움이 있었어요. 2024년 하반기 앱 6.0 업데이트를 맞아 UI 디자인이 새롭게 개편되었는데요, 여기어때의 브랜드 아이덴티티를 반영한 일관된 그래픽 규칙을 수립하고, 가독성을 높이기 위한 시스템 아이콘 개선한 과정을 공유하고자 해요.시스템 아이콘이란?먼저 본격적으로 이야기를 하기에 앞서 시스템 아이콘이란 무엇인지 알아볼게요. 사실 시스템 아이콘은 단순한 그림이 아닙니다. 앞서 말씀드렸듯 디지털 제품에서 사용자가 기능이나 상태를 빠르게 인식할 수 있도록 돕는 중요한 시각적 도구예요. 내비게이션, 버튼, 상태 표시 등 여러 UI 요소에 적용되어 사용자 경험을 매끄럽게 만들어주는 핵심 요소입니다.그럼 시스템 아이콘의 역할은 무엇일까요?이처럼 시스템 아이콘은 단순히 장식적인 요소가 아니에요. 오히려 사용자 경험을 향상시키고, 제품 내에서 가독성과 접근성을 높이는 중요한 디자인 자산이죠. 그래픽 규칙이 명확하게 설정된 일관성 있는 아이콘은 브랜드 아이덴티티를 강화하고, 사용자에게는 더욱 직관적인 경험을 제공할 수 있게 돼요.기존 아이콘의 문제점시스템 아이콘은 제품의 일관성을 유지하는 중요한 요소이지만, 기존 아이콘들은 그래픽적인 통일성이 부족했어요. 이는 사용자 경험을 저해할 뿐만 아니라, 브랜드 아이덴티티를 일관되게 전달하는 데도 어려움을 만들었어요.이렇듯 기존 시스템 아이콘들은 각기 다른 스타일과 규칙으로 제작되어 디자인 일관성이 부족했어요. 대표적인 문제점은 다음과 같아요.또한, 기존 아이콘의 문제는 앱 6.0 업데이트를 통해 해결할 필요성이 더욱 커졌어요. 홈 화면부터 UI, 배너, 버튼 등 제품에서 전반적인 요소가 대규모 업데이트 되었는데, 이 과정에서 시스템 아이콘 또한 새로운 디자인 방향성에 맞춰 개선해야 할 필요성이 대두되었죠.이처럼 제품의 시각적 정체성을 확립하고, 사용자 경험을 향상시키기 위해 새로운 그래픽 규칙을 적용한 시스템 아이콘 업데이트가 필수적이었어요.해결 방법 ① 브랜드 아이덴티티 반영하기시스템 아이콘을 개선하면서 가장 중요한 목표는 여기어때의 브랜드 아이덴티티를 반영하는 것이었어요. 기존 아이콘들은 스타일이 일관되지 않아 브랜드의 시각적 정체성이 명확하지 않았고, 이를 해결하기 위해 여기어때 로고의 특징을 시스템 아이콘에 녹여내는 방향으로 디자인을 진행했죠.여기어때의 로고는 한글 로고타입으로, 폰트를 분석해 보면 윗면은 원형의 형태, 밑면은 사각형의 형태를 가지고 있어요. 이
여기어때컴퍼니
·
2일 전
logo
Android SharedFlow, StateFlow 도입기
안녕하세요, 현대오토에버에서 내비게이션 개발 업무를 하고 있는 김혜성입니다.이번에 Android 기반의 새로운 내비게이션 엔진을 도입하면서 관련 로직을  Kotlin으로 개발하게 되었습니다.해당 프로젝트에서는 비즈니스 로직과 UI 로직을 별도의 repository로 개발하고 있습니다. 따라서 비즈니스 로직에는 Android UI 생명 주기와 직접적으로 관련된 데이터는 필요하지 않았고, 오히려 Android에 대한 의존성을 최대한 배제하여 개발한다면 추후 다른 플랫폼에서도 기존 로직을 그대로 사용할 수 있을 것 같았습니다.이런 점을 염두에 두고 보니 프로젝트 초기에 작성된 코드의 LiveData가 눈에 띄었고 이를 모두 SharedFlow와 StateFlow로 대체하기로 했습니다.LiveDataAndroid 공식 문서에 따르면 LiveData는 observer 패턴을 따르는 데이터 홀더 클래스인데, 데이터 관찰 시 특정 Lifecycle 객체를 파라미터로 넘겨 주어 해당 Lifecycle의 상태에 따라 관찰을 시작하거나 끝낼 수 있습니다.UI와 함께 개발할 때는 이런 점이 메모리 관리 측면에서 편리하지만 LiveData는 기본적으로 main 스레드에서 처리되기 때문에 비즈니스 로직만 개발하는 경우에는 이런 점이 오히려 좋지 않습니다. 또한 아키텍처 측면에서는 불필요하게 Android에 대한 의존성을 갖게 됩니다.이를 대체하기 위해 사용할 수 있는 것이 Kotlin의 Flow입니다.FlowFlow는 Kotlin의 공식 라이브러리인 kotlinx.coroutines에서 제공하는 클래스입니다. Kotlin 공식 문서에 따르면 Flow는 비동기적으로 계산된 값들을 반환하기 위해 만들어진 타입입니다.Flow가 LiveData와 구분되는 또 다른 특징이 바로 다양한 중간 연산자와 종단 연산자를 지원한다는 점입니다. 우선 중간 연산자로는 다음과 같은 것들이 있습니다.map: 해당 요소를 다른 형태로 변환transform: 해당 요소에 대해 함수 호출 등 복잡한 처리 가능take: 설정한 횟수에 이르면 플로우 실행 취소그리고 종단 연산자로는 다음과 같은 것들이 있습니다.collect: 가장 기본적인 종단 연산자로, Flow를 수집launchIn: Flow를 특정 CoroutineScope 내에서 수집toList, toSet: Collection으로 변환first: 첫 번째 값만 기다린 후 반환single: Flow가 종료되기를 기다린 후 하나의 값 반환reduce: 모든 요소를 더하여 하나의 값 반환fold: 초기값에 모든 요소를 더하여 하나의 값 반환Kotlin의 Collection 함수와 동일한 역할을 하는 익숙한 연산자가 많아서 다양하게 활용할 수 있습니다. 그리고 Flow는 LiveData의 MediatorLiveData보다 비교적 간단하게 데이터를 결합할 수 있습니다.zip: 두 Flow에서 모두 새로운 값이 생산되면 그때 1:1로 쌍을 이루어 방출combine: 두 Flow 중 하나라도 새로운 값이 생산되면 가장 최신 값끼리 쌍을 이루어 방출merge: 여러 Flow를 하나의 Flow로 만들어서 먼저 생산되는 것부터 방출하지만 Flow는 cold stream이기 때문에 실제 애플리케이션 개발에서는 이의 하위 타입인 StateFlow와 SharedFlow를 주로 사용하고 있습니다.SharedFlowSharedFlow는 Flow를 상속한 인터페이스로, 초기값이 없어도 됩니다. 새로운 구독자가 생기면 그 구독자가 구독을 시작한 이후에 새로 업데이트된 값부터 알림을 받기 때문에 이벤트 처리에 적합하고 replay 옵션에 따라 이전 데이터를 캐싱할 수 있습니다.private val _hasArrived = MutableSharedFlow(replay = 1)val hasArrived: SharedFlow = _hasArrived.asSharedFlow()// (코루틴 내에서) 데이터 생산_hasArrived.emit(true)// (코루틴 내에서) 데이터 구독(수집)hasArrived.collect { // 도착 여부에 따른 처리}// 캐싱된 데이터에 접근hasArrived.replayCache.firstOrNull()emit()은 suspend fun이기 때문에 코루틴 내에서만 호출할 수 있습니다. 하지만 tryEmit()을 사용하면 기다리지 않고 즉시 반환되게 할 수 있습니다. 이때는 onBufferOverflow 옵션에 따라 동작하게 됩니다.BufferOverflow.SUSPEND: MutableSharedFlow의 버퍼 오버플로우 시 기본 정책으로, 버퍼에 자리가 날 때까지 기다림BufferOverflow.DROP_OLDEST: 버퍼에서 가장 오래된 값을 제거하고 새로운 값을 즉시 추가함BufferOverflow.DROP_LATEST: 새로운 값을 추가하지 않고 버퍼를 유지함BufferOverflow.SUSPEND일 때는 일반적인 emit()처럼 동작하고 false를 반환합니다. 그리고 나머지 설정값은 캐시나 버퍼가 있을 때만 가능하므로 replay나 extraBufferCapacity 옵션을 1 이상의 값으로 설정해야 합니다.launchIn을 사용하면 다음과 같이 간단한 형태로 구독할 수 있습니다.hasArrived .onEach { /* 도착 여부에 따른 처리 */ } .launchIn(coroutineScope)StateFlowStateFlow는 SharedFlow의 구현체로, 항상 한 가지 값(상태)을 갖고 있어야 해서 초기값이 필요합니다. 새로운 구독자에게 현재 상태를 즉시 알리고 이후에 새로 업데이트된 상태를 알리기 때문에 UI 업데이트 용도로 사용할 수 있습니다.private val _isAlertShowing = MutableStateFlow(false)val isAlertShowing: StateFlow = _isAlertShowing.asStateFlow()launch { // (코루틴 내에서) 데이터 생산 _isAlertShowing.emit(true)}launch { // (코루틴 내에서) 데이터 구독(수집) isAlertShowing.collect {
현대자동차그룹
·
2일 전
logo
Istio Ambient 도입 후기
도입 배경안녕하세요. 중고나라 DevOps 엔지니어 조상현, 김지헌입니다.복잡한 아키텍처를 개선하며, 자원 효율화를 위해 새롭게 도입한 Istio Ambient Mode에 대해 공유하려 합니다.중고나라는 회사의 성장과 함께 서비스 트래픽이 증가하면서 네트워크 관리의 중요성이 더욱 커졌습니다. 이를 해결하기 위해 Istio를 도입하여 서비스 메쉬를 구축했지만, 기존 Istio Sidecar Mode 기반 아키텍처는 몇 가지 한계를 보였습니다.Why Ambient Mode?간단하게 기존의 Sidecar Mode 형태의 아키텍처를 간단하게 소개하면 아래와 같습니다.큰 특징으로는 각 Pod마다 Envoy proxy를 Sidecar로 주입하여 트래픽을 전달하는 방식입니다.하지만 Sidecar Mode는 리소스 사용량 증가와 운영 복잡도 같은 문제를 야기했습니다.리소스 증가각 Pod마다 Envoy Proxy를 Sidecar로 주입하므로, 각 Pod의 컨테이너 개수는 (애플리케이션 컨테이너 1개 + Sidecar Proxy 컨테이너 1개)로 총 2개가 됩니다.따라서 Pod 수가 증가할수록 CPU와 Memory 사용량(요청량)이 크게 증가했고, 이는 전체적인 인프라 비용 증가로 이어졌습니다.2. 운영 복잡도Pod에 문제가 발생했을 때, 애플리케이션 컨테이너의 문제인지 Envoy Proxy의 문제인지 즉시 구분하기 어려웠습니다.Envoy Proxy와 애플리케이션이 강하게 결합(Coupling)된 형태여서, 하나의 문제로 인해 전체 Pod의 장애로 확대되는 경우가 많았습니다.저희는 이러한 문제를 해결하기 위해 새롭게 출시한 Ambient Mode로 전환하는 결정을 내렸습니다.새롭게 도입한 Ambient Mode 아키텍처를 간단하게 소개하면 아래와 같습니다.Ambient Mode는 기존의 Sidecar Mode와 달리, Envoy Proxy Sidecar의 역할을 Layer 4(ztunnel)와 Layer 7(waypoint)로 분리하여 네트워크 트래픽을 처리하는 방식으로 모든 pod 간 통신은 ztunnel 을 통하고, L7 기반 로직 처리 필요 시 waypoint 를 경유합니다. 이러한 구조적 변화로 인해 인프라 운영이 더욱 가볍고 효율적으로 설계되었습니다.key point는 아래와 같습니다.리소스 절감Pod마다 Envoy Proxy Sidecar가 존재하지 않으므로 CPU와 Memory 사용량(요청량)이 감소하였고, 더 적은 Worker Node로 동일한 트래픽을 처리할 수 있게 되었습니다.2. 운영 단순화Istio의 정책을 별도의 Proxy(ztunnel, waypoint)로 관리하여, 네트워크 정책 적용과 디버깅이 더욱 간편해졌습니다.애플리케이션을 Service Mesh에 포함하거나 제외할 때, 애플리케이션 Pod 재시작할 필요가 없습니다.Istio 버전을 업그레이드 할 때, 애플리케이션 Pod를 재시작할 필요가 없습니다.물론 Ambient Mode 전환 과정에서 기존 Sidecar Mode와의 호환성을 고려해야 했으며, 트래픽 라우팅 및 보안 정책이 기대한 대로 동작하는지 충분한 테스트가 필요했습니다.다음으로, Ambient Mode 전환 과정에서 맞닥뜨린 문제와 이를 어떻게 해결했는지, 그리고 현재 운영 방식에 대해 더 자세히 풀어보겠습니다!도입 과정Helm + Argo를 통한 Istio Ambient Mode 설치초기에 Istio를 도입할 당시, 중고나라는 Istio Operator를 활용하여 배포 및 운영을 진행하였습니다.그러나 Istio 1.18 버전 이후 Operator 기반의 방식이 Deprecated됨에 따라, 기존 방식으로는 더 이상 업그레이드가 불가능한 상황이 되었습니다.이에 따라 다양한 배포 방법을 검토하였으며, 잦은 업그레이드, 커스텀 설정, GitOps 등 유연한 운영이 가능한 방법을 찾고자 하였습니다.그 결과, Helm을 활용하여 환경별 세부 설정을 커스텀하고, Argo CD 기반의 GitOps 배포 방식을 도입하여 지속적인 운영 및 유지보수를 최적화하기로 결정하였습니다Kubernetes Gateway API 도입기존에는 Istio Gateway를 사용하여 트래픽을 관리하였지만, Gateway API를 도입한 이유는 다음과 같습니다.Istio 측에서 Gateway API를 향후 표준으로 자리 잡을 것이라고 언급했습니다.(참고 문서)Waypoint 트래픽을 세밀하게 제어하기 위해 Gateway API의 HTTPRoute 리소스를 활용할 필요가 있었습니다.이에 따라 기존의 VirtualService 및 DestinationRule 설정을 HTTPRoute 기반으로 재구성하였습니다.또한, Argo Rollout Controller 설치 시 gatewayAPI plugin을 같이 생성하고 Argo Rollout 의 트래픽 라우팅 방식도 기존 trafficRouting.istio에서 trafficRouting.plugins을 활용하는 방식으로 변경하여, Gateway API를 통해 트래픽을 분배할 수 있도록 수정하였습니다. (참고 문서1, 참고 문서2) trafficRouting: plugins: argoproj-labs/gatewayAPI: namespace: {{ .Release.Namespace }} httpRoute: {{ .Release.Name }}-httproute하지만 아직 HTTPRoute에서는 VirtualService, DestinationRule에서 제공하는 트래픽 관리 설정을 완벽하게 지원하지 않습니다.!! 예를 들어 Fault Injection 등은 아직 제공하지 않아 꼭 해당 기능이 필요한 상황이라면 Gateway API의 도입을 신중하게 검토해야합니다!!Ztunnel ProxyConfigAmbient Mode를 도입하면서 가장 큰 변화 중 하나는 L4 트래픽을 처리하는 ztunnel이 등장했다는 점입니다.그렇다면, 기존에 Istiod가 관리하던 ProxyConfig 설정이 ztunnel에도 그대로 적용될까요? 정답은 아니오 입니다.ztunnel은 Envoy 기반이 아니라 독립적인 L4 터널링 컴포넌트입니다.즉, 기존 ProxyConfi
중고나라
·
3일 전
logo
Redis와 클라이언트 캐시 간 데이터 동기화 기술 - Redis Client Caching 살펴보기
Redis는 In memory 기반의 데이터베이스로 빠른 읽기/쓰기 성능과 다양한 자료구조로 데이터베이스 캐시로 많이 사용되고 있습니다.만약 Redis 에 저장한 데이터가 빈번하게 변경되지 않지만 payload 사이즈가 커서 매번 Redis에서 값을 가져오는 것이 비효율적인 경우,클라이언트 캐시를 사용하기도 합니다. 하지만 클라이언트 캐시가 항상 최신 데이터를 가지고 있지 않을 수 있습니다.이런 경우 클라이언트 캐시와 Redis 의 데이터를 동기화 하는 것이 필요합니다.쉬운 방법으로는 Local cache의 Expiration을 설정하여 일정 시간이 지나면 Redis의 값을 읽어서 동기화하는 방법도 있습니다.이 방법은 캐시의 데이터가 즉시 동기화되지 않아도 무방한 경우 단순하고 효과적인 방법이기도 합니다.하지만 Redis의 데이터가 변경되는 것을 즉시 Notification을 받아서 Local Cache를 Redis와 동기화할 수 있으면 어떨까요?이 글에서는 Redis Client Caching 을 사용하여 클라이언트 캐시와 Redis 의 데이터를 동기화 하는 방법을 설명합니다.Redis Client Caching 은 Redis 의 데이터를 클라이언트 캐시에 저장하고 동기화 하는 기법입니다.먼저 Local Cache를 사용하는 기본적인 방법부터 알아보고 이후 Redis Client Caching 을 사용하는 방법을 알아보겠습니다.Redis에서 매번 값을 읽으면 불필요한 Network I/O가 발생하고 Redis의 자원을 비효율적으로 사용하게 되거나 서비스의 Latency를 증가시키게 됩니다.이런 문제를 해결하기 위해서는 클라이언트 캐시를 사용하는 것이 필요합니다.위그림은 Local Cache의 기본적인 동작을 설명하고 있습니다.여기서는 하나의 클라이언트가 Redis에서 값을 가져와서 Local cache를 참조하도록 설계되었는데,만약 다른 클라이언트에서 foo 값을 변경하면 Local cache의 값과 Redis의 값이 다르게 됩니다.이런 경우 클라이언트는 다시 Redis에서 값을 가져와서 동기화해야 합니다.클라이언트A가 값을 변경하면 Redis는 해당 값의 Invalidation 여부를 클라이언트B에게 알립니다.클라이언트B는 이 메시지를 받으면 Redis에서 값을 읽어 Local cache를 갱신합니다. 이런 방식으로 클라이언트 캐시와 Redis의 데이터를 동기화 할 수 있습니다.이렇게 Invalidation 메시지를 받아서 동기화하는 방식이 Redis Client Caching 입니다.Redis Client Caching 은 크게 두 가지 모드로 동작합니다.이 모드에서 Redis 서버는 클라이언트A가 관심있는 key가 어떤 것인지 기억합니다.클라이언트A가 관심있는 key가 변경되면 Redis 서버는 클라이언트A에게 Invalidation 메시지를 보냅니다.이 모드는 클라이언트가 관심있는 key가 적은 경우 유용하지만, 서버의 메모리를 사용한다는 점을 유념해야 합니다.이 모드에서는 클라이언트가 어떤 key를 관심있는지 명시적으로 알려야
SK텔레콤
·
3일 전
logo
구글처럼 복잡한 권한 쉽게 관리하기 feat. GraphQL
안녕하세요. 당근 알림 경험팀에서 프론트엔드 엔지니어로 일하고 있는 딜런(Dylan.lee)이라고 해요.알림 경험팀은 당근 사용자들뿐만 아니라 당근 구성원들의 알림 경험(Notification Experiences)을 책임져요. 사용자가 그동안 받은 알림을 모아볼 수 있는 알림함부터 당근 구성원이 알림을 간편하게 발송할 수 있는 알림 센터까지, 알림과 관련된 다양한 서비스를 만들고 있죠.알림 센터와 같은 서비스를 만들다 보면 필연적으로 인증과 인가를 다루게 돼요. 알림 센터는 다양한 소속의 당근 구성원들이 사용하기 때문에, 민감한 정보는 외부에 노출되지 않도록 소속에 따라 권한을 분리해야 하죠. 또한 마케팅성 알림은 마케팅 팀의 승인이 있는 경우에만 발송할 수 있어야 하고요.이렇게 서비스가 복잡해지고 기능이 고도화될수록 인증과 관련된 코드가 길어지고 복잡해지는 문제가 생겼어요. 이번 글에서는 권한을 선언적으로 관리하며 코드의 복잡성을 효과적으로 개선한 방법을 소개해 드리려고 해요.역할을 기반으로 권한을 관리한다면?알림 센터에서는 사용자에게 발송되는 알림 내용을 템플릿 형태로 관리해요. 이것을 알림 시나리오라고 하는데요. 당근의 모든 구성원은 여기에 접근 권한을 갖고 있지만 외부 협력사는 볼 수 없어야 해요. 이러한 권한은 단순했기 때문에 간단한 분기만으로도 관리할 수 있었어요.const canAccess = (user, entity) => { if (entity === "scenarioPage" && user.company === "daangn") return true; return false;}그러다 권한 정책이 업데이트되었어요. 외부 협력사 직원이더라도 특정 이메일 값을 갖는 사용자라면, 알림 시나리오 페이지에 접근 권한을 가지도록 수정이 필요했어요. 그래서 저는 allow list를 만들어 관리했어요.const allowList = ["john@external.com"];const canAccess = (user, entity) => { if (entity === "scenarioPage" && (user.company === "daangn" || allowList.includes(user.email))) return true; return false;}그러다가 새로운 기능이 추가되었어요. 마케팅성 알림을 발송하기 전에는 마케팅팀에게 리뷰를 요청하고, 마케팅팀이 승인할 때만 발송할 수 있어야 했죠.const allowList = ["john@external.com"];const canAccess = (user, entity) => { if (entity === "scenarioPage" && (user.company === "daangn" || allowList.includes(user.email))) return true; if (entity === "approveButton" && user.team === "marketing") return true; return false;}이번엔 알림 경험팀에 특수한 권한을 부여
당근
·
3일 전
기술 블로그 더 보기
Copyright © 2025. Codenary All Rights Reserved.