본문으로 건너뛰기

일관성 있는 Agentic AI Workflow를 팀 프로젝트에 적용하는 법

· 약 20분
01010011
Sr. Software Engineer, Engineering Manager

alt text

개요

코딩 에이전트가 개발의 필수 도구가 된 지금, AI를 쓰지 않는 개발자를 찾기가 오히려 어렵다. 기업들도 이 흐름에 발맞춰 OpenAI, Claude, Gemini를 종류별로 전부 구독하며 적극적인 사용을 장려한다.

하지만 비싼 비용을 들여 AI를 구독한다고 해서 생산성이 저절로 높아지지는 않는다.
METR 리서치에 따르면 AI 코딩 도구를 사용했을 때 개발 완료 시간이 오히려 19% 증가했다는 결과도 있다. 개발자들은 20% 단축을 기대했지만, 실제로는 정반대였다.
반면, SNS에서 자주 회자되는 프로그래밍좀비라는 개발자는 AI를 활용해 350개의 앱을 개발하고 수익화에 성공했다고 한다. 중국인 개발자 EastonDev는 10,000라인 레거시 코드를 14일 만에 리팩토링하며 테스트 커버리지, 버그, 성능 지표까지 개선했다.

같은 도구를 쓰면서 왜 이런 생산성 차이가 생길까? 개인이 각자 알아서 AI를 사용하다 보면, 도구에 대한 이해도, 축적된 경험, 효과적인 활용법에 따라 결과가 천차만별이기 때문이다. AI 구독은 개인 능력의 상한선을 높여주지만, 그것이 곧 팀 전체의 생산성 향상으로 이어지지는 않는다.

이 글에서는 개인의 AI 활용 역량을 팀 전체의 역량으로 전환하는 방법을 다룬다.

LLM과 Harness의 한계

LLM의 한계는 이미 잘 알려진 내용이므로 깊이 다루지는 않겠다. 다만 트랜스포머 기반 AI에게 업무를 맡길 때 반드시 인지해야 할 본질적 한계를 짚고 넘어가보자.

1. 컨텍스트는 유한하다

아무리 컨텍스트 윈도우가 커져도, 긴 맥락이 필요한 작업에는 여전히 한계가 있다. 대규모 코드베이스 전체를 이해하거나, 수십 개 파일에 걸친 리팩토링을 한 번에 처리하기는 어렵다. 이를 해결하려면 맥락을 효과적으로 전달하는 별도의 방법을 고안해야 한다.

2. 결과물은 확률적이다

같은 프롬프트에도 매번 다른 결과가 나온다. 이는 LLM의 근본적인 생성 방식 때문이다. 창의적인 작업에서는 장점이 되지만, 일관성이 필요한 작업에서는 치명적인 단점이 된다.

3. 환각은 피할 수 없다

LLM은 자신 있는 어조로 틀린 정보를 생성한다. 코딩 맥락에서는 존재하지 않는 API를 호출하거나, deprecated된 문법을 최신인 것처럼 제안하거나, 아예 없는 라이브러리를 import하는 코드를 만들어낸다. 문제는 이런 환각이 그럴듯해 보인다는 것이다. 검증 없이 AI의 출력을 그대로 믿으면, 컴파일 에러는 그나마 다행이고 런타임에서나 확인하는 대형사고로 이어질 수 있다.

Harness: 현실적인 해결책

이러한 한계를 보완하는 여러 방법 중, 현재 가장 제품 수준의 완성도를 보여주는 것이 Harness(Tool Use 기반의 에이전트 구조)다. Claude Code, Cursor, Windsurf 같은 코딩 에이전트들이 이 방식을 채택하고 있다.

하지만 Harness에는 **유효기간**이 있다.

Bitter Lesson의 깨달음, Scaling Law는 여전히 유효하다. 어느 날 갑자기 Google이나 OpenAI의 신모델이 등장해, 팀이 공들여 구축한 Harness를 무용지물로 만들 수 있다. 실제로 예전에는 PDF에서 텍스트를 추출하려면 복잡한 파이프라인이 필요했지만, 이제는 멀티모달 모델에 이미지로 던지면 끝이다. 팀이 몇 주간 구축한 PDF 파싱 Harness가 하룻밤 사이에 레거시가 되어버리는 것이다.

그럼에도 Harness를 만들어야 하는 이유

이런 리스크에도 불구하고, 지금 당장 Harness가 제공하는 생산성 향상은 무시할 수 없다.

Harness 없이 Raw LLM만 쓰는 것과, 잘 구성된 에이전트 환경에서 작업하는 것의 생산성 격차는 이미 크게 벌어졌다. 6개월 뒤 무용지물이 될 수 있다 해도, 그 6개월간의 생산성 이득이 구축 비용을 상회한다면 만들어야 한다.

문제는 이 Harness를 개인이 아닌 팀 전체가 일관되게 사용하도록 만드는 것이다.

개인의 AI 역량 ≠ 팀의 AI 역량

AI를 잘 쓰는 개인은 많다. 하지만 그 개인이 속한 팀이 AI를 잘 쓰는가는 전혀 다른 문제다.

팀원들에게 비싼 AI 구독을 제공한다고 해서 팀 생산성이 저절로 높아지지 않는다. 개인 단위의 AI 활용이 팀 단위의 생산성으로 전환되지 못하는 데는 구조적인 이유가 있다.

1. 인간 지능이 병목이다

AI의 코드 생산 속도는 인간의 리뷰 속도를 아득히 넘어선다. ITWorld의 분석에 따르면, 이는 "조립 라인에서 한 기계만 속도를 높이고 나머지를 그대로 두면, 공장이 빨라지는 것이 아니라 처리되지 못한 작업이 쌓여갈 뿐"인 상황과 같다. 코드는 10배 빨리 생성되는데, 리뷰는 여전히 사람이 일일이 해야 한다면 결국 인간 리뷰어가 병목이 될 수 밖에 없다.

2. 검증 체계가 없다

AI가 생성한 코드를 얼마나 신뢰할 수 있는가? 코드래빗 보고서에 따르면, AI 생성 코드는 사람이 작성한 코드보다 PR당 1.7배 더 많은 이슈를 발생시킨다. 객관적인 검증 지표와 자동화된 품질 게이트 없이는, AI 결과물에 대한 확신을 가질 수 없다.

3. 숙련도 격차가 크다

누군가는 정교한 프롬프트와 최적화된 에이전트 설정으로 높은 품질의 결과물을 뽑아내지만, 누군가는 기본적인 활용에도 어려움을 겪는다. 같은 도구, 같은 구독료를 내면서도 생산성 격차는 몇 배씩 벌어진다. 이 격차를 좁히는 것은 개인의 노력만으로는 한계가 있다.

4. 경험과 노하우가 휘발된다

가장 심각한 문제다. 비슷한 업무를 하는 팀원들이 각자 비슷한 프롬프트를 만들고, 비슷한 에이전트 구성을 시도한다. 누군가 효과적인 방법을 발견해도, 그 지식은 개인에게 머문다. 슬랙에 공유한 팁은 며칠 뒤 묻히고, 노션에 정리한 가이드는 업데이트되지 않는다. AI를 잘 쓰는 경험과 노하우가 팀에 축적되지 않고 휘발된다.


이 네 가지 문제의 공통점은 무엇인가? AI 역량을 축적하고 공유할 워크플로우의 부재다.

개인의 역량에 의존하는 한, 팀 전체의 AI 활용 수준은 들쭉날쭉할 수밖에 없다. 필요한 것은 개인의 경험이 팀의 자산으로 축적되고, 검증된 워크플로우가 모든 팀원에게 일관되게 적용되는 구조다.

AI 시대, 리더가 해야 할 일

앞으로 모든 기술 리더는 개인의 경험이 팀의 자산으로 축적되는 구조를 설계해야 한다. 이것은 비단 AI Era만 해당되는 이야기가 아니다. 다만 AI 시대에는 앞서 언급한 이 문제가 첨예해졌을 뿐이다.

리더의 역할은 적극적으로 Harness를 구축하고, 이를 팀 워크플로우에 녹여내는 것이다. 다음은 이를 위한 다섯 가지 원칙이다.

1. 워크플로우 단계별로 맥락을 분리하라

하나의 거대한 프롬프트로 모든 것을 해결하려 하지 마라. 기획 검토, 설계, 구현, 테스트, 리뷰 - 각 단계는 필요로 하는 맥락이 다르다. 단계마다 적절한 컨텍스트만 전달하면 LLM의 유한한 컨텍스트 윈도우를 효율적으로 활용할 수 있고, 결과물의 품질도 높아진다.

2. 결정적 작업(Deterministic Tasks)과 비결정적 작업(Non-Deterministic Task)을 구분하라

모든 것에 LLM을 쓸 필요는 없다.

결정적 작업은 규칙 기반으로 항상 같은 결과를 내야 하는 작업이다. 린팅, 포매팅, 정적 분석, 타입 체크, 보안 스캔이 여기에 해당한다. 이런 작업에 LLM을 쓰면 불필요한 비용과 불확실성만 늘어난다. 전통적인 도구가 더 빠르고, 더 정확하고, 더 일관적이다.

비결정적 작업은 맥락 이해와 판단이 필요한 작업이다. 여기가 LLM이 진가를 발휘하는 영역이다:

  • Tidying: 변수명 개선, 불필요한 중복 제거 같은 작은 정리 작업
  • Reviewing: 잠재적 버그 탐지, 성능 이슈 지적, 컨벤션 위반 발견
  • 문서화: 코드 주석, README, API 문서, CHANGELOG 작성
  • 테스트 생성: 단위 테스트 작성, 엣지 케이스 도출, 테스트 커버리지 확장

결정적 작업은 CI 파이프라인에 맡기고, LLM은 비결정적 작업에 집중시켜라.

3. 변경 범위를 작게 유지하라

AI가 한 번에 수천 줄을 생성할 수 있다고 해서, 매번 수천 줄을 생성해야 하는 것은 아니다. 큰 변경은 리뷰어의 인지 부하를 높이고 병목을 유발한다. 충분히 검증 가능하고, 문제가 생겨도 쉽게 롤백할 수 있는 작은 단위로 변경을 쪼개야 한다.

그렇다고 무조건 작게만 유지하라는 것은 아니다. 핵심은 인지 부하 없이 자동 검증 가능한 범위를 찾는 것이다.

Kent Beck은 Tidy First?에서 리팩토링보다 작고 린팅보다는 의미 있는 'Tidying'이라는 개념을 제안한다. 예를 들어:

  • 가드 클로즈로 중첩 조건문 펼치기
  • 설명하는 변수명으로 매직 넘버 대체하기
  • 죽은 코드 제거하기
  • 함수 순서 재배치하기

이 정도 규모의 변경은 테스트만 통과하면 별도 리뷰 없이 머지해도 된다. 워크플로우를 잘 설계하면 이런 Tidying 작업을 AI가 자동으로 수행하고, 자동으로 검증하고, 자동으로 적용하는 것이 가능하다.

4. 인간 개입을 최소화할 수 있는 워크플로우를 만들어라

병목은 결국 인간이다. AI의 생산 속도를 인간의 리뷰 속도가 따라갈 수 없다면, 인간 개입을 최소화하여 AI 결과물을 검증할 수 있는 자동화된 워크플로우가 필요하다.

일반적으로 검증 워크플로우는 계층적으로 구성된다:

1차: 결정적 검증 (CI 파이프라인)

  • 린팅, 포매팅, 타입 체크 통과 여부
  • 테스트 스위트 전체 통과 여부
  • 보안 스캔, 의존성 취약점 검사

2차: 비결정적 검증 (AI 리뷰어)

  • PR이 생성되면 리뷰어 에이전트가 변경점을 분석
  • 잠재적 버그, 성능 이슈, 아키텍처 위반 탐지
  • PR 변경의 핵심 포인트 요약 및 개선 제안

3차: 범위 기반 자동 승인

  • Tidying 수준의 작은 변경 + 1차/2차 검증 통과 → 자동 머지
  • 버저닝을 유발하는 큰 변경 → 리뷰 생성

여기서 Conventional Commits 규칙이 에이전트에게 힌트를 줄 수 있다. 커밋 메시지에 feat:, fix:, refactor:, chore:, docs: 같은 타입과 !(breaking change) 표시를 강제하면, AI가 변경의 성격과 영향 범위를 명확히 판단할 수 있다.

chore: 미사용 import 제거          → 자동 머지 가능
refactor: 결제 로직 함수 분리 → AI 리뷰 후 자동 머지
feat!: 인증 API 응답 구조 변경 → 별도의 리뷰 프로세스 필요

이렇게 구성하면 버저닝을 유발하는 큰 변경이 아닌 chore, style, docs, refactor 수준의 변경은 1차/2차 검증만 통과하면 리뷰어 에이전트가 직접 머지할 수 있다. feat!, fix! 같은 breaking change나 feat 같은 의미 있는 변경만 별도의 리뷰 프로세스를 도입하면 된다.

이 워크플로우의 수준이 높아져서 다소 큰 변경마저도 리뷰 에이전트가 인간 지능 개입 없이 머지가능한 수준으로 고도화된다면 결국 대부분의 변경이 인간 개입 없이 자동으로 처리되고, 이 팀/프로젝트의 생산성은 큰 변곡점을 맞게 될 것이다.

5. 모든 개선이 팀의 자산으로 축적되게 하라

이것이 가장 중요하다.

AI 도입은 "좋은 도구를 사주면 끝나는" 문제가 아니다. 2025 DORA 리포트는 성공적인 AI 도입을 툴 문제가 아니라 시스템 문제로 정의하며, AI의 가치는 도구 그 자체보다 주변의 기술·문화적 환경에 Lock-in 된다고 말한다.

누군가 효과적인 프롬프트를 발견했다면, 그 프롬프트는 휘발되지 않고 팀 전체가 쓰는 도구에 반영되어야 한다. 누군가 실수를 방지하는 워크플로우를 만들었다면, 그 워크플로우는 개인의 습관이 아니라 팀의 시스템으로 자리 잡아야 한다.

개인이 발견한 베스트 프랙티스가 → 팀의 표준 워크플로우가 되고 → 버전 관리되며 → 지속적으로 개선되는 구조.

이 구조가 작동하려면, 조직은 명확하고 공유된 AI 스탠스(정책/기대치/허용 도구/적용 범위) 를 가져야 한다. DORA 리포트는 AI 도입의 긍정적 효과가 이런 "clear and communicated AI stance"의 존재에 의존하며, 이것이 있을 때 개인 효과와 조직 성과의 긍정적 영향이 증폭된다고 제시한다.

이것을 가능하게 하는 것이 AI 시대 리더십의 핵심 역할이다.


다음 편에서는 이 원칙들을 Claude Code의 Skills, Hooks, Plugins로 구현하는 구체적인 방법을 살펴보겠다.

Mobile Attribution in the Privacy First Era

· 약 15분
01010011
Sr. Software Engineer, Engineering Manager

alt text

개요

개인정보 보호의 중요성이 대두되면서 모바일 어트리뷰선의 패러다임은 크게 변화하였다. 과거에는 IDFA, GAID 등의 광고 식별자를 통해 명확한 측정이 가능하였으나, 사용자의 개인정보 보호를 최우선으로 하는 현대에는 더이상 Deterministic한 사용자 식별이 불가능하다.

이 글에서는 Apple의 SKAdNetwork(SKAN)와 Google의 Privacy Sandbox로 대표하는 모바일 환경의 개인정보 보호 프레임워크에 대해 설명하고, 어떻게 확률론적으로 모바일 어트리뷰선을 획득하는지에 대해 알아보겠다.

어떻게 알고 오셨어요?

1970년대, 미국 디트로이트의 자동차 판매원 '조 지라드(Joe Girard)'는 15년간 13,001대의 차를 팔아 '세계에서 가장 위대한 세일즈맨'으로 기네스북에 올랐다.

그의 성공 비결은 차를 파는 기술이 아니라, 고객을 끊임없이 만들어내는 '시스템'에 있었다. 그는 자신의 고객이 될 만한 사람을 소개해 주는 사람들을 '버드 도그(Bird Dogs, 사냥개)' 라고 불렀다. 이발사, 식당 주인, 은행원 등 주변의 모든 사람이 그의 '버드 도그'가 될 수 있었다.
그의 규칙은 간단했다. "저에게 손님을 보내주십시오. 그 손님이 차를 사면, 제가 바로 당신에게 25달러를 보내드리겠습니다."
이 시스템이 완벽하게 돌아가려면 가장 중요한 전제 조건이 있었다. 바로 "이 고객을 누가 보냈는가?" 를 한 치의 오차도 없이 파악하는 것이었다.
조 지라드는 새로운 고객이 오면 가장 먼저 "누가 당신을 제게 보냈습니까?"라고 물었다. 그리고 판매가 성사되면 장부에 꼼꼼히 기록해 두었다가, 약속한 25달러를 소개자에게 반드시 보냈다.

조 지라드의 일화와 마찬가지로 모바일 앱 서비스 생태계에서는 어떤 광고활동이나 마케팅이 고객의 유입이나 결제로 이어졌는지 추적하고 그 공로를 찾아내는데, 그 과정을 Mobile Attribution 이라고 한다.

Deterministic Attribution

Attribution을 정확히 측정하는 것은 매우 중요하다. 이 손님이 이발사의 소개를 받고 왔는지, 은행원의 소개를 받고 왔는지를 알아야 누구에게 얼마의 광고료를 줄지 판단할 수 있기 때문이다.
'이 손님은 누구의 소개를 받고 왔는가?' 이 질문에 답하기 위해 모바일 플랫폼은 Ad Network에게 다음 정보를 전달하였다.

  • IDFA (Identifier for Advertisers): Apple이 iOS 기기를 위해 제공하는, 사용자가 재설정할 수 있는 광고 식별자
  • GAID (Google Advertising ID): Google이 Google Play 서비스가 설치된 Android 기기를 위해 제공하는 광고 식별자

IDFA, GAID는 모두 사용자의 기기를 정확히 식별할 수 있는 고유의 값이다. 따라서 IDFA 와 GAID 를 알면 정확한 Mobile Attribution을 획득할 수 있다.

  1. 사용자가 광고를 클릭
  2. Ad Network는 해당 기기의 IDFA / GAID를 캡처 후 저장
  3. 사용자가 앱을 설치, 처음으로 실행
  4. 100% 정확한 사용자 유입 경로를 알 수 있는 Attribution 획득

이러한 Deterministic 한 Attribution 획득 방식으로 인해, 광고주들은 어떤 광고가 어떤 사용자를 유입시켰는지에 대한 명확한 데이터를 확보할 수 있었고, 이는 모바일 광고 생태계를 성장시키는 기반이었다. 하지만 이제 공짜점심은 끝났다. 모바일 플랫폼의 개인정보 보호 강화 기조 아래, 사용자 동의 없이 Deterministic Attribution 획득은 불가능하다. 이 글을 읽고 있는 당신도 그러겠지만, 사용자들은 더 이상 나를 특정할 수 있는 개인정보 제공에 동의하지 않는다.

Probabilistic Attribution

Apple의 ATT(AppTrackingTransparency)와 SKAN(SKAdNetwork) Framework

상술하였듯, 애플은 더 이상 사용자 동의 없이 IDFA를 제공하지 않는다.(정확히 말하면 '명시적인' 사용자 동의 없이).

empty IDFA

따라서 iOS14+ 이후부터는 기기의 IDFA 값을 가져오려면 ATT(AppTrackingTransparency) 프레임워크를 통해 반드시 명시적으로 사용자의 권한을 획득하여야 한다. 사용자가 동의를 거부하면 상기 스샷과 같이 IDFA 값은 000000~ 으로 비워진다.

이는 광고주 및 Ad Network 모두에게 치명적인 문제다. 내 광고가 누구에 의해 노출이 되었는지 명확히 알지 못하기 때문에 어느 경로를 통해 고객이 유입되었는지 파악할 수 없고, 광고 비즈니스의 대전제(어떻게 알고 오셨어요?)가 무너지게 된다.

대안으로, 애플은 개인을 특정할 수는 없는 제한된 정보를 제공하는 광고 식별자 획득 방식을 제공하는데, 그것이 SKAN(SKAdNetwork)이다.

SKAN winning flow

SKAN 의 데이터 흐름은 다음과 같다.

  1. Ad Network: 광고를 개제
  2. Ad Network: 제한된 Attribution(Postback) 수집 URL 등록
  3. 사용자: 광고를 클릭 -> 앱 설치
  4. Apple: 광고사업자가 개인 추적이 어렵도록 일정 기간 지연(~최대 144시간)
  5. Ad Network: 일정시간 경과 후 Postback 으로 캠페인 ID 및 제한된 사용자 정보(Conversion Value) 수신(IDFA 없음)

여기서 유일하게 사용자 정보를 얻어낼 수단은 CV(Conversion Value) 뿐이다. CV는 0~63 사이의 정수로 표현되는 6bit 값으로, 광고주는 64 가지 값에 매핑하여 사용자의 앱 설치 후 행동을 수집할 수 있다. 예를 들어 CV가 1이면 튜토리얼 완료, CV가 2이면 최초 인앱 구매 완료 등의 값을 사전에 정의, Postback 시점에 획득하여 사용자를 분석할 수 있다. 알고 있겠지만 6bit 는 메우 제한된 값으로, CV를 단독으로 이용하여 사용자를 특정할 방법은 없다.

말하자면 Apple 은 데이터 측정의 심판이자 유일한 처리자 역할을 자처한다. 광고주, Ad Network 는 모두 Apple 이 정해둔 엄격한 규칙 안에서 Apple이 제공하는 최종 결과물을 수동적으로 받아 해석해야 한다.

Android 의 Privacy Sandbox와 Attribution Reporting API

앞서 Apple이 모든 Attribution 획득 경로에 관여, 통제하면서 결과만 전달하는 방식과는 대조적으로, Google은 광고 생태계 참여자들이 개인정보 보호 기술을 기반으로 자체적인 프라이버시 보호 솔루션을 구축할 수 있도록 빌딩블록을 제공한다. 그 핵심 빌딩블록이 바로 Privacy Sandbox 이다.

Privacy Sandbox는 다음 3가지 핵심 목표를 갖는다.

  1. 기존의 추적 메커니즘을 대체할 새로운 개인정보 보호기술을 구축하는 것.
  2. 퍼블리셔와 개발자가 침해적인 추적 없이도 무료 온라인 컨텐츠를 계속 제공할 수 있도록 지원하는 것.
  3. 업계와의 협력을 통해 새로운 인터넷 개인정보 보호 표준을 구축하는 것.

요약하면, 개인정보를 보호하면서도 퍼블리셔와 개발자가 광고 기반 비즈니스를 지속할 수 있도록 하는 업계 표준을 만드는 것이다.

Privacy Sandbox flow

Google의 Privacy Sandbox가 기존의 Attribution 획득방식과 기술적으로 가장 크게 구별되는 부분은 사용자 디바이스 안에서 Ad Network 정보와 매칭되는 Attribution을 만들어낸다는 점이다.

디바이스 안에서 Attribution을 획득하기 때문에 광고 비즈니스 사업자는 사용자의 개인정보를 디바이스 밖으로 빼내지 넘기지 않고도 유의미한 사용자 전환 정보를 얻을 수 있다.

이렇게 사용자 단말에서 생성된 익명화된 Attribution은 Attribution Reporting API(줄여서 ARA)를 통해 수집된다.

ARA를 통해 수집되는 리포트는 크게 2가지 유형이 존재한다.

  • Event-Level Report: "어떤 광고가 전환을 유도했는가?"와 같이 제한적이지만 세분화된 정보
  • Summary Reports: "캠페인의 총매출액과 ROI는 얼마인가?"와 같이 구매 금액 등 상세한 전환 데이터를 암호화 및 집계된 형태로 제공

Event Level Report는 익명화된 개별 정보이다. 개별정보이지만 익명화 되어 있기 때문에 많은 정보가 담겨있지는 않다. Attribution 정보와 사용자 클릭, 조회 등의 이벤트를 매핑한 데이터를 제공한다. 이 리포트는 캠페인 도달율 측정이나 Attribution 집계 등의 용도로 적합하다.

반면, Summary Report는 사용자 데이터를 집계한 통계 결과물이다. 개별화된 정보는 없지만 전환가치, ROI, 사용자 세그먼트 별 캠페인 성과분석 등 깊이있는 리포트를 제공한다.

이 데이터들은 암호화된 형태(=encrypted aggregatable report)로 Ad tech platform(Appsflyer, Meta, Applovin 등등..)에게 전달되며, 이 암호화된 데이터를 기반으로 필요한 쿼리를 Cloud Trusted Execution Environment에 위치한 Aggregation Service 에 질의한다.

Cloud Trusted Execution Environment(TEE)?
TEE란 구글에서 제안하는 보안 기준을 충족하는 & 신뢰할만한 클라우드 제공자의 인프라 위에서 동작하는 격리된 환경이다. TEE의 보안 기준을 충족하면 Ad Tech Platform 기업에서 자체적으로 구축, 운영할 수 있다.

Executive Summary

지금까지 개인정보 보호의 시대에 어떻게 Mobile Attribution 을 획득할 것인가에 대한 내용을 알아보았다. 과거처럼 Deterministic하게 Attribution을 획득하던 시대는 끝났으며, 각 이해관계자들은 개인정보 보호의 시대의 Attribution 획득 방식을 준비해야 한다.

결정론적 시대의 종말: 개인정보 보호 강화로 IDFA, GAID 기반의 1:1 사용자 추적이 불가능해졌다.

확률론적 시대로의 전환: 이제는 명확한 데이터 대신, 제한된 데이터를 바탕으로 성과를 '추론'해야 한다.

Apple (SKAN)의 접근: Apple이 모든 과정을 통제하는 '블랙박스' 방식이다.

Google (샌드박스)의 접근: '온디바이스 매칭' 을 핵심으로, 광고 생태계가 활용할 수 있는 '빌딩 블록' 을 제공한다.

Ad Tech의 역할 변화: MMP, 광고 네트워크 등 Ad Tech는 암호화된 리포트를 받아, 직접 클라우드 보안 환경(TEE)에 'Aggregation Service' 를 구축하고 운영하여 데이터를 처리해야 한다.

docker-build-hang/docker-build-hang

· 약 3분

slug: docker-build-hang title:Docker build가 가끔씩 멈추는 이유는? authors: [bahamoth] tags: [alpine, docker, mtu, mss-clamping, pmtud]

CI가 가끔씩 실패를 한다.

CI가 가끔씩 실패를 한다.

이유는 alpine linux docker image를 multi-stage build할 때 간헐적으로 hang이 발생하기 때문이다.
다른 os에서는? ubuntu docker build 에서도 전혀 발생하지 않는다. 오직 hang은 alpine linux를 이용하여 apk add를 수행할 때 간헐적으로 발생한다.
곤란하게도 hang은 매번 발생하지 않는다. 10번 시도하면 4~5번 정도? 대개는 apk add gcc 를 수행할 때 걸리지만, 가끔씩 apk add python 이나 다른 package 빌드할 때도 발생은 한다.
이 현상은 퍼블릭 네트워크를 이용하는 내 개인 PC에서는 발생하지 않으며, 오직 회사의 격리된 private network에서만 발생한다.
이렇게 간헐적으로 발생하는 문제는 추적하기가 힘들다. 원인을 특정하고 정확히 재현해 내기가 어렵기 때문이다.

Maximum Transmission Unit(MTU)

그나마 우리에게 주어진 단서는 이 현상이 사내 네트워크와 연관이 있다는거다. 네트워크 관련한 설정을 이것 저것 바꾸거나 tcp packet을 캡처하는 시도를 해볼 수 있다.
네트워크 관련한 여러 가지 시도를 하였고, 그 결과 문제의 원인을 좁힐 다른 단서를 찾을 수 있었다.
docker build --network host 옵션에서는 hang이 전혀 발생하지 않는다. 문제는 docker0 bridge network를 사용할 때만 발생한다.
놀랍게도 docker0 interface의 mtu size 를 500 까지 줄였더니 증상이 사라지는 것을 발견하였다.(종전 mtu=1500, host와 동일)

지금까지의 현상을 정리하면,

  • 특정 private network 환경에서
  • docker bridge network 를 이용하여
  • alpine linux 의 apk add 명령을 수행할 때
  • 간헐적으로(4~5건 / 10회) network hang 발생

should-i-still-write-blogs-in-the-ai-era/should-i-still-write-blogs

· 약 3분

slug: should-i-still-write-blogs title: AI 시대에 여전히 블로그를써야 할까? authors: [bahamoth] tags: [AI, blog]

AI의 시대, 위기의 글쓰기 - 기술 블로그를 계속 써야 할까?

블로그에 글을 안 쓴지 3개월 가량 지났다.
다양한 생성형 AI 서비스를 접하면서 블로그에 대한 존재론적 물음이 들었달까?
내가 하루 중에 읽게 되는 컨텐츠, 그 중에서도 기술 컨텐츠의 상당한 비중은 생성형 AI로부터 나온다. 간단한 리눅스 명령어나 쉘스크립트부터 네트워크 패킷 분석이나 관련한 RFC 추적, 핫한 트랜드가 되고 있는 MCP Spec 분석과 구현까지 생성형 AI 가 내놓은

그 사이 AI 기술은 하루가 멀다하고 격변하는 시기를 거치 고 있다. 이제 누구든 코딩 문제가 생기면 구글링보다 빠르게 ChatGPT나 Claude에게 물어보는 시대가 됐다. 이제는 간단한 리눅스 명령어부터 복잡한 SQL 쿼리문, 코드 리뷰와 대체기술까지 알아서 척척 알려주니 굳이 구글링해가며 발품을 팔 이유가 없어졌다. 이쯤 되면 심각한 존재론적 회의가 든다. 이런 초월적 AI 시대에 개발 블로그를 계속 써야 할 이유가 있을까? 수많은 개발 블로그들 사이에서 내 글이 존재 의미가 있을까? 블로그는 차치하고 당장 개발자 커리어를 계속 이어갈 수는 있을까? 당장 어떤 기술 주제로 글쓰기를 시켜도 나보다 클로드가 더 많은 정보를 전달해주는 시대에

macOS에서 특정 단축어를 누를 때만 들리는 beep음 없애기

· 약 3분
01010011
Sr. Software Engineer, Engineering Manager

beep

맥북을!! 샀다!! (!! m4!! pro!! max!! 64GB!! 🎉🎉🎉)

새 맥북에 이전 맥북 설정을 마이그레이션하는 대신 처음부터 맥북을 세팅하기로 결정, 기존에 써보지 못했던 도구들도 하나 둘 알아가는 재미를 즐기고 있다. 터미널 프로그램도 iterm2에서 다른걸 써보려고 Warp를 설치했는데 아주 만족도가 높다.

그런데 황당한 문제가 발생했다. Split pane(Horizontal) 의 크기를 줄이려고 cmd + ctrl + ↓ 키를 눌렀더니,

"삑"

beep음이 들리는 것이다.

cmd + ctrl + ↓ cmd + ctrl + ↓

"삑" "삑"

희한하게도 cmd + ctrl + ↑ 키를 누를 때는 아무 소리가 나지 않았다. Warp 뭐야. 시끄럽게. 분할창 크기 조절을 얼마나 자주하는데 이러면 곤란하지. 안타깝지만 곧 나올 Ghostty 나오면 Warp는 폐기다. 라고 생각하고 무심결에 같은 단축키(cmd + ctrl + ↓)를 vs code에서 눌러봤다.

"삑"

어라? vs code에서도 beep음이 나는데? chrome에서도? 평소에 음소거 상태에서 맥북을 이용하기 때문에 & 저 단축키를 누를 일이 없어서 이런 거슬리는 소음 문제가 있다는걸 처음 알게 되었다. 찾아보니 이 문제는 2019년도부터 Warp 터미널 뿐 아니라 다른 앱에서도 여러 차례 보고된 것으로, macOS에서 제대로 키바인딩 처리를 하지 못해 발생하는 것이 원인으로 추정된다. (링크: https://issues.chromium.org/issues/41432539#comment10)

해결방법은 다음과 같다.

~/Library/KeyBindings/DefaultKeyBinding.dict 파일을 생성하고 아래와 같이 설정, 어플리케이션을 재시작하면 beep음이 꺼진 것을 확인할 수 있다.

{
"@^\UF701" = "noop:";
"@^\UF702" = "noop:";
"@^\UF703" = "noop:";
}

호랑이는 죽어서 가죽을 남기고 프로그램은 죽어서 덤프를 남긴다.

· 약 20분
01010011
Sr. Software Engineer, Engineering Manager

tiger

서론

아무리 소프트웨어를 잘 만들었더라도 구동중인 프로그램이 사용자 환경에서 비정상 종료되는 문제는 필연적이다.

속된 말로 '프로그램이 죽는' 현상이 이러한 비정상 종료에 해당하는데, 개발자 입장에서는 왜 이러한 '죽음'이 발생하는지 파악이 어렵다. 왜냐하면 개발자의 PC에서는 프로그램이 죽지 않기 때문이다.(It works on my machine)
너무도 다양한 사용자 환경은 기상천외한 문제를 일으킨다.(바닐라 아이스크림 알러지가 있는 자동차)

이러한 안타까운 죽음의 원인을 부검하기 위해, 개발자는 프로그램이 실행되었던 주변환경에 대한 다양한 정보를 수집한다. 허나 아무리 다양한 주변 정보를 수집한다 하더라도 직접적인 사인은 시체를 확인해야만 하듯, 프로그램이 비정상 종료된 원인은 크래시가 발생한 시점에 메모리에 적재된 스냅샷을 확인해야만 한다.

그렇다. 호랑이는 죽어서 가죽을 남기고 한우는 죽어서 T본 스테이크를 남기듯, 프로그램은 죽어서 메모리 덤프를 남긴다. 이 글에서는 메모리 덤프가 무엇인지 알아보고, 다양한 사용자 환경에서 덤프를 수집하고 처리하기 위해 어떤 과정들이 이뤄지는지를 알아보겠다.