프로덕트

아티클

전체 보기
문정호

문정호

프로덕트에서 다크모드를 추구하면 안되는 걸까? (1)

no-answer.png

프로덕트 개발에 있어서 노답 삼형제같은 존재들이 있습니다.

  1. 다크 모드

  2. 국제화, 현지화

  3. 반응형 디자인

이 무서운 친구들은 처음부터 적용하면 할만하지만 이미 있는 프로덕트에 적용하는 것은 디자이너, 개발자 모두에게 악몽과도 같은 일입니다. 몇 개의 포스팅 걸쳐 이러한 문제를 해결할 수 있는 효과적인 전략들을 소개합니다. 그 첫 시작은 다크모드 입니다.

다크모드

tailwind-dark-mode.png

다크 모드는 사용자 경험을 향상시키는데 핵심적인 역할을 합니다. 이는 눈의 피로를 줄이고, 배터리 소비를 낮추며, 시각적으로 매력적인 환경을 제공합니다.

그러나 디자인 시스템에서 다크 모드를 구현하는 것은 복잡하고 시간이 많이 소요될 수 있습니다. 특히, Figma와 같은 디자인 도구를 사용해 수동으로 색상을 조정하는 작업은 번거롭고 수정하기 어려울 수 있습니다.

컬러 네이밍

color-naming.png

컬러 네이밍에는 세 가지 주요 접근 방식이 있습니다: Atomic, Semantic, Contextual.

  1. Atomic 방식은 컬러의 색상(Hue)과 명도(Shade)를 이름에 직접 포함시키는 방법입니다. 예를 들어, 'blue-600', 'emerald-600'와 같은 이름이 여기에 해당합니다. 이 접근법은 컬러를 명확하게 식별하는 데 도움이 됩니다.

  2. Semantic 방식은 컬러의 의도를 반영하여 이름을 붙이는 방법입니다. 예를 들어, 'enabled', 'success'과 같은 이름이 이 방식에 해당합니다. 이 방식은 컬러가 전달하고자 하는 메시지나 역할에 초점을 맞춥니다.

  3. Contextual 방식은 컬러의 사용 상황에 따라 이름을 정하는 방법입니다. 'bg-enabled', 'text-success'처럼 컬러 사용처를 기반으로 명명합니다.

이러한 방식으로 정의된 컬러는 디자인 토큰으로 활용됩니다. 디자인 토큰은 색상, 글꼴, 간격 등과 같은 디자인 관련 값들을 정의하는 데 사용됩니다.

디자인 토큰

design-token.png

단일 네이밍 방식으로 정의된 디자인 토큰은 협업 과정에서 신뢰할 수 있는 단일 정보 소스(Single Source of Truth)를 제공하며, 소통을 용이하게 합니다. 그러나, 이는 각 분야의 생산성을 제한할 수 있습니다.

예를 들어, '#2563eb'라는 컬러를 사용하기 위해 모든 사용자가 'blue-600' 토큰을 사용하는 것보다 아래와 같이 각자의 사용 영역에 맞는 토큰을 사용하는 것이 더욱 효과적일 수 있습니다.

  • BI/BX 디자이너는 Atomic 방식으로 네이밍 된 'blue-600' 토큰을 사용합니다.

  • UI/UX 디자이너는 Semantic 방식으로 네이밍 된 'enabled' 토큰을 사용합니다.

  • 개발자는 Contextual 방식으로 네이밍 된 'bg-enabled' 토큰을 사용합니다.

Google Material, Adobe Spectrum 과 같은 디자인시스템에서는 디자인 토큰을 계층으로 나누어 추상화 시켜 디자인토큰을 더 유연하게 관리할 수 있도록 합니다.

계층적 분류

hierarchical-deisgn-token.png

Google Material 디자인시스템에서는 디자인 토큰을 세 가지 계층으로 분류합니다: Reference Token, System Token, Component Token.

  1. Reference Token은 기본 값을 표현합니다. 컬러의 이름을 그 색상의 실제 특성(예: 색상명과 명도)을 바탕으로 짓는 Atomic 방식에 해당됩니다.

  2. System Token은 Reference Token를 참조합니다. 컬러의 명칭을 그 사용 목적이나 의미(예: 기본 컬러, 강조 컬러)에 따라 정하는 Semantic 방식에 해당됩니다.

  3. Component Token은 System Token을 참조합니다. 컬러의 사용처(예: 텍스트의 기본 색, 에러 메시지의 배경색)에 따라 이름을 정하는 Contextual 방식에 해당됩니다.

이렇게 디자인 토큰의 계층에 컬러 네이밍 전략을 매칭 시킨다면 사용영역에 따라 컬러를 어떻게 구분하고 사용할 지에 대한 명확한 가이드라인을 제시할 수 있습니다.

다크모드 적용

dark-mode-1.png

다크 모드를 구현하는 간단한 방법은 Shade 전환입니다. 예를 들어, shade가 50부터 950까지 정의된 색상에 대해 light 모드에서 'blue-600'을 사용했다면, dark 모드에서는 500을 기준으로 Shade가 전환된 'blue-400'을 정의하면 됩니다.

그러나 디자인 도구나 개발 IDE에서 Light와 Dark 모드의 컬러 토큰을 수동으로 설정하는 것은 반복적이고 수정하기 어렵습니다.

dark-mode-2.png

Reference Token 관점에서는 Light와 Dark 모드를 구별할 필요가 있지만 System Token 이상의 위계에서는 Light와 Dark 모드를 구별할 필요가 없습니다.

System Token이 각각 Light와 Dark 모드에 해당하는 Reference Token을 참조하고 사용한다면 우리는 모드에 따른 컬러 토큰을 일일이 수동으로 설정할 필요가 없을 것입니다. Light, Dark, 그 이상의 모드에서도 말이죠.

다음 글에서는

  • Figma에서 Local Variable을 통해 컬러 토큰을 생성하고 Light와 Dark 모드를 설정할 수 있도록 방법,

  • Local Variable로 설정한 컴포넌트를 React.js/Next.js 환경의 Code syntax로 변경할 수 있는 방법,

  • Tailwindcss를 통해 Component Token을 자동으로 정의하는 방법에 대해 설명 드리겠습니다.

13
1

포스트

전체 보기
문정호

문정호

김대리. 너무 GA4 이벤트? 사용하지 마세요.


GA4 이벤트를 코드에 직접 심으면 측정할 게 늘어날 때마다 배포를 해야 합니다.

기능은 다 만들었는데 이벤트 심느라 배포가 밀리고, 그렇게 심어도 마케팅이 보고 싶은 데이터는 빠져 있어서 다음 배포로 밀리는 경우가 있습니다.

슈퍼인턴에서 코드에서 직접 넣던 event를 지우고 GTM을 설정하였습니다. E2E를 활용해 상호작용 가능한 모든 요소를 측정하게 만든 과정을 공유합니다.

1. E2E 셀렉터 재활용

GTM이 클릭을 잡으려면 요소를 가리켜야 하는데, 클래스나 구조로 가리키면 디자인이나 기능이 바뀔 때 이벤트가 끊겨 한참 뒤에 알아차립니다.

E2E에서 버튼이나 입력창 같은 상호작용 요소를 찾아 조작하는데, 측정하고 싶은 것도 정확히 그 요소입니다. 교집합 덕분에 어트리뷰트(data-testid)가 이미 다 붙어 있었고, 새로 만들 규칙도 없었습니다.

Component Click 태그 하나로 흩어져 있던 클릭 측정을 일원화했습니다. 클릭을 전부 이 태그가 받고 element_id로 구분하여, 버튼이 늘어도 별도의 설정이 필요 없습니다. E2E도 같은 어트리뷰트를 쓰니 누락이 생기면 테스트에서 잡아냅니다.

2. dataLayer는 브라우저가 못 보는 것만

요소 클릭만 쌓으면 어떤 버튼이 몇 번 눌렸는지까지만 나옵니다. GA4에서 퍼널을 그리거나 신규·기존 코호트를 비교하려면 누른 사람이 누구인지가 붙어야 합니다. 그 정보는 서버에 있으니 dataLayer로 내려줍니다.

  • 전역 사용자 속성: 식별 정보, 상태값, 코호트, 활동 구간
  • BFF 패턴: 서버가 모아 내려주고 클라이언트는 한 번만 push
  • 주의사항: 값 종류 500개 초과 시 GA4가 (other)로 처리

그래서 가입일은 날짜가 아니라 월로, 지원 건수는 숫자가 아니라 구간으로 넘깁니다.

3. 커버 안 되는 건 커스텀

클릭 트리거는 무엇을 눌렀는지까지만 알려줍니다. 어디까지 진행했는지, 그래서 결과가 무엇인지는 클릭만으론 알 수 없습니다.

진입과 진행 단계는 page_view 경로 규칙으로 잡습니다. 완료는 뷰로 세면 결과 화면을 다시 열어본 사람까지 섞여 완료율이 100%를 넘어가니, 완료된 순간에만 코드가 맞춤 이벤트를 한 번 보냅니다.

슈퍼인턴에선 가입과 로그인은 동일 버튼으로 다른 기능을 수행합니다. 이렇게 클릭으로 알기 어려운 이벤트도 맞춤 이벤트로 보냅니다. OAuth 리다이렉트 구간은 서버에서 돌아 dataLayer 접근이 안 되니, 쿠키로 넘기고 도착 페이지가 읽어 소비합니다.

4. Claude Code로 강제

이미 상호작용 가능한 모든 요소를 테스트 하도록 E2E 테스트 하네스가 적용되어 있습니다. 측정에 필요한 게 개발 흐름에 이미 있었기 때문에 하네스만 추가했습니다.

  • 검사 스크립트: 어트리뷰트가 빠진 상호작용 요소를 전부 찾아냄
  • 커밋 훅: Claude Code가 커밋할 때 돌려서 빠진 게 있으면 차단
  • 예외 주석: 측정 안 할 요소는 주석 한 줄로 제외

GTM은 러닝커브가 있어 처음 세팅하기가 어렵습니다. 또한 개발에서 마케팅의 언어로 데이터를 풀 수 있도록 논의가 선행되어야 합니다. 조직에 GTM 도입이 필요하시다면 편하게 프로필 링크로 DM 주세요.

공채가 활발한 지금, 슈퍼인턴은 사내 MCP부터 GTM까지 데이터 기반 채용 서비스로 발전하고 있습니다. 채용 홍보를 맡기고 싶으시다면 biz@superpasshr.com으로 연락 주세요!

슈퍼인턴

우리 기업에 딱 맞는 주니어 인재 채용

1
0
문정호

문정호

그만 물어봐! 사내 MCP로 "데이터 민주화" 하기


"이번 달 지원자 몇 명이에요?" 데이터를 보려면 늘 개발자인 저를 거쳐야 했습니다.

마케터나 기획자분이 SQL을 쓸 줄 알아도 마찬가지였습니다. 조직 내 암묵지들 때문에 제대로 된 데이터를 뽑기 어려운 경우가 빈번하게 일어났습니다.
그래서 사내 DB를 AI가 직접 조회하는 MCP 서버를 만들었지만, 조직이 실제로 쓰는 MCP가 되기까지는 생각보다 멀었습니다.
MCP 배포 이후 2주동안 그 거리를 좁히면서 배운 3가지를 공유합니다.

1. MCP 구현

MCP SDK로 만들었습니다. 읽기 전용을 두 겹으로 강제했습니다.

  • 앱단: SQL 파서로 단일 SELECT만 통과
  • DB단: 계정 자체가 SELECT 권한만 보유

앱 가드를 우회해도 DB가 거부합니다.
다만 서로 다른 RDBMS라 직접적인 크로스 DB 조인은 불가능합니다. 대신 인터페이스를 통일해서 LLM이 두 번 쿼리해 직접 합치도록 했습니다.
MySQL과 PostgreSQL은 생각보다 많이 다릅니다.
커넥션 풀, 드라이버별 응답 형태, 타임아웃과 오류 체계가 전부 달라서 이걸 하나로 추상화하는 게 실제 작업의 대부분이었습니다.

2. 암묵지의 형식지화

조직과 서비스가 커지면 암묵지가 쌓입니다. AI에게는 이걸 초등학생에게 설명하듯 자세히 알려줘야 합니다.
예를 들어 앱스토어 이벤트용 캠페인과 CRM 캠페인은 데이터 구조가 전혀 다른데 둘 다 campaign이라는 이름을 씁니다.
AI는 이걸 구분할 능력이 없습니다. 그래서 데이터를 요청하면 심심찮게 의도하지 않은 결과가 나옵니다.
문제는 에러가 안 난다는 것입니다. 조용히 틀린 숫자가 나옵니다.

  • 커밋 시점: Claude Code hooks가 "스키마 바꿨는데 가이드도 고쳤냐"를 확인
  • CI 시점: 테스트 가드가 "그 내용이 실제 스키마와 맞냐"를 검증
  • 두 층이 짝입니다. 훅은 고쳤는지만, 테스트는 맞는지를 봅니다

도메인 지식을 통째로 주면 컨텍스트를 다 먹습니다. 그래서 맥락을 크기에 따라 대-중-소 목차의 트리 구조로 나눴습니다.
AI가 목차를 먼저 읽고 필요한 절만 골라 열도록 해서, 판별력은 살리고 컨텍스트는 아끼는 구조입니다.

3. 권한 관리

데이터를 여는 일과 개인정보를 지키는 일은 같이 가야 합니다. 개인정보보호법의 통계 작성, 과학적 연구, 기록 보존 목적에 맞춰 해시를 통한 가명화 처리를 했습니다.

  • 기본적으로 우리 조직 계정만 허용하고, 그중 admin만 전체를 볼 수 있습니다
  • 나머지 구성원은 가명화된 테이블만 조회됩니다
  • DB 계정 자체를 분리해서, 앱단에 SQL 인젝션이 들어와도 가명화된 것만 접근 가능합니다

가명 데이터도 개인정보라 GDPR을 준하기 위해 감사 로그를 남깁니다.
모든 호출을 누가 언제 어떻게 어떤 결과를 받았는지 구조화 로그에 기록해 사후 추적이 가능하도록 했습니다.

이제 개발자가 아니어도 직접 묻습니다. 저를 거치지 않아도 됩니다.
만들고 보니 그동안 흐린 눈 했던 도메인 문서화도 함께 해결됐고, 직접 처리하던 가명화도 자동화되었습니다.

사내 데이터를 AI에게 열어보려는 분들께 권합니다. 도구보다 "우리가 아는 것을 정리하는 일"이 먼저였습니다. 궁금하신 분들은 편하게 링크드인 DM 주세요!

슈퍼인턴

우리 기업에 딱 맞는 주니어 인재 채용

2
0