한 줄 정의

지속적 배포(CD)란 완성된 변경을 한꺼번에 모아 크게 내보내는 대신, 작은 변경을 자주·자동으로 프로덕션까지 흘려보내 릴리스 한 번의 위험과 비용을 최소로 줄이는 방식입니다.

쉽게 말하면

CD는 정시에 출발하는 지하철 과 같습니다.

월 1회 운행하는 전세 버스라면 모두가 한 차에 욱여타려 하고, 한 번 놓치면 한 달을 기다려야 하니 출발 직전은 아수라장입니다(거대 릴리스). 반면 5분마다 오는 지하철은 이번 칸을 놓쳐도 곧 다음 칸이 오니, 무리해서 탈 이유도 한 번의 사고가 치명적일 이유도 없습니다.

핵심은 한 번의 배포에 거는 판돈을 잘게 쪼개는 것 입니다. 자주 출발할수록 한 번에 실리는 변경이 적어, 사고 가능성도 사고가 났을 때 뒤져야 할 범위도 줄어듭니다. 그래서 직관과 반대로 “빠를수록 안전하다”가 성립합니다.

왜 중요한가?

소프트웨어의 가치는 서브밋 시점이 아니라 사용자가 그 기능을 쓸 때 실현됩니다. 처음부터 완벽한 소프트웨어는 없고, 확실한 건 출시 후에도 계속 고쳐야 한다는 사실뿐입니다. 코드 완성과 사용자 피드백 사이의 시간을 줄일수록, 즉 자주 내보낼수록 진행 중인 작업의 비용과 헛수고할 위험이 줄어듭니다.

이게 안 되면 악순환에 빠집니다. 릴리스 비용이 커지면 ‘본능적으로’ 주기를 늦춰 안정성을 확보하려 하지만, 그렇게 번 안도감은 잠깐일 뿐 길게 보면 팀 속도가 느려지고 위험 회피적인(그래서 가치도 낮은) 기능만 선호하게 됩니다. 결국 배우고 반복할 여지가 없는 옛 계획 중심 개발로 회귀합니다.

핵심 내용

CD가 지향하는 6가지 가치

모든 팀이 곧바로 완전한 CD에 도달하긴 어렵습니다. 그래서 최종 목표로 가는 길에 독립적으로 취할 수 있는 가치들 에 집중합니다.

가치핵심
민첩성자주, 작게 릴리스한다
자동화잦은 릴리스에 따라붙는 반복 작업을 줄이거나 없앤다
격리모듈화된 아키텍처로 변경을 격리해 문제를 쉽게 해결한다
신뢰성비정상 종료·지연시간 같은 상태 지표를 측정·개선한다
데이터 중심 의사결정A/B 실험으로 지표를 비교해 품질을 높인다
단계적 출시모두에게 동시에 내보내지 않고 소수 사용자부터 이용해보게 한다

'배포하지 않더라도' 배포 가능하게

이 장의 가장 값진 통찰입니다. 실제로 프로덕션에 내보내지 않더라도, 언제든 배포가 가능한 상태로 빌드해두는 것 만으로 엄청난 가치가 생깁니다. 모든 변경이 QA 파이프라인을 거쳐 자동으로 배포 가능한 형태가 되면, “더 자주 릴리스해도 되겠다”는 자신감이 싹트고, 이 자신감 자체가 팀의 속도를 끌어올립니다.

규모가 커지면 — 속도는 팀 스포츠다

팀이 작을 땐 변경이 일정한 속도로 코드베이스에 도달합니다. 하지만 팀이 커지고 하위 팀으로 쪼개지면, 서로의 발을 밟지 않으려 브랜치를 따서 따로 작업하는 안티패턴 이 고개를 듭니다. 나중에 통합하거나 범인을 찾을 때 고생이 시작됩니다.

구글의 처방은 모든 팀이 같은 코드베이스의 헤드에서 개발 하되, CI 테스트·자동 롤백·범인 찾기 같은 안전망으로 떠받치는 것입니다. 거대 모놀리식이던 유튜브가 릴리스마다 빌드 경찰·릴리스 매니저가 고통을 분담하고 50시간짜리 수동 회귀 테스트를 거치던 지옥에서 벗어난 결정적 투자는 마이크로서비스 아키텍처로의 전환 이었습니다.

단기 안정 대신 장기 아키텍처에 투자하라

릴리스 비용이 오를 때 주기를 늦춰 안정화 기간을 버는 건 함정입니다. 정답은 비용을 줄이고 규율을 강화하며 위험에 점진적으로 대응하는 것 — 즉 눈앞의 안정이 아니라 장기 아키텍처 개선 에 투자하는 것입니다.

플래그 가드로 변경을 격리한다

제품이 커지면 성숙도가 다른 여러 기능이 하나의 바이너리에 공존하게 됩니다. 플래그 가드(flag guard) 는 기능 단위로 코드를 켜고 끄는 기법으로, 빌드 도구가 릴리스용 빌드에서는 미완성 기능을 아예 제외해 최종 사용자가 피해 입지 않게 막아줍니다.

한 걸음 더 나아가, 바이너리에 기존 기능 코드와 새 기능 코드를 모두 넣고 플래그가 새 코드로 가는 길목만 막게 할 수 있습니다. 준비가 끝나면 다음 릴리스에서 길목을 바꿔 새 기능을 데뷔시키고, 문제가 생기면 바이너리 재배포 없이 플래그 값만 동적으로 바꿔 즉시 되돌립니다.

flowchart LR
    R["요청"] --> F{"플래그 ON?"}
    F -->|off| OLD["기존 기능 코드"]
    F -->|on| NEW["새 기능 코드"]

이 능력은 제품 출시 시점을 언론 공개 시점과 분리 해줍니다. 코드가 바이너리에 먼저 들어가도 플래그로 막아두면 보도자료 발표 전 유출 위험이 크게 줄기 때문입니다.

플래그는 만능이 아니다

난독화가 부실하면 막아둔 코드도 분석당할 수 있고, 모든 기능을 플래그로 숨기면 코드가 지나치게 복잡해집니다. 플래그 설정 변경도 점진적이어야 하므로(모든 고객을 한 번에 바꾸지 않기) 설정을 안전하게 관리하는 설정 서비스 를 함께 둡니다.

릴리스 열차 — 완벽주의를 버리고 정시에

예측 가능한 릴리스 주기를 위해 두 가지 트레이드오프를 프로세스에 녹여냅니다.

완벽한 바이너리는 없다

수십~수백 명이 거대한 기능을 독립적으로 개발해 통합하는 빌드는 완벽할 수 없습니다. 모든 버그를 고치는 대신, KPI와 명확한 문턱값 으로 “이 정도면 출시”를 판단합니다. SRE의 오차 예산(error budget) 처럼 허용 오차가 얼마나 남았는지를 근거로 속도와 안정성 사이를 절충하는 것입니다.

다만 데이터가 기준을 무조건 이긴다는 뜻은 아닙니다. 필리핀의 한 작은 섬 방언으로 검색하면 빈 페이지가 나오는 버그가 있었는데, 검색 부문 선임 부사장의 답은 “섬이 아무리 작아도 정확한 검색 결과를 안정적으로 내어줘야 한다”였습니다. 그래서 주요 릴리스를 미루고 버그를 고쳤습니다.

릴리스 시한을 지켜라

“열차 시간에 늦으면 기다리지 않고 출발한다.” 시한이 지나면 아무리 애원해도 이번 릴리스에 끼워주지 않습니다. 자주 출발하는 열차에서는 한 번 놓쳐도 몇 시간 뒤 다음 열차를 타면 되므로, 이 규율이 매주 개발자의 멘탈을 붙들고 릴리스 엔지니어의 워라밸을 지켜줍니다. (NBA 계약 같은 ‘드물게’ 예외는 있습니다.)

동적 배포 — 쓰일 기능만 내보낸다

성공한 소프트웨어는 사라지기 전에 팽창(bloat) 을 겪습니다. 특히 모바일 앱이라면 고객은 쓰지도 않는 기능에 저장 공간·다운로드 시간·데이터 비용을 허비합니다. 해법은 만드는 빈도와 받는 빈도를 분리 하는 것입니다.

  • CD가 잘 돌면 매일·매시간 ‘만들’ 수 있되, 사용자가 실제로 ‘받을’ 시점은 의식적으로 선택합니다.
  • 동적 배포 로 각 고객에게 의미 있는 코드만 작게 구성한 바이너리를 내보내, 기기 자원 효율을 높입니다.

여기에 데이터로 더 일찍 결정 하는 원칙이 더해집니다. 클라이언트 시장의 다양성은 문제가 아니라 현실이므로, 종합 테스트가 불가능하면 대표 테스트를 목표로 하고 사용자 기반을 조금씩 늘려가며 단계적 출시(staged rollout) 합니다.

흥미로운 발견은, 제품에 아무 변경이 없어도 그저 업데이트를 푸시하기만 하면 사용자 지표가 통계적으로 달라진다 는 것입니다. 그래서 거대 앱에서는 배포 자체에도 A/B 테스트를 씁니다 — 한쪽엔 새 바이너리를, 다른 쪽엔 직전과 똑같은 바이너리를 다시 배포(대조군)해 지표를 비교합니다. 가드레일 지표가 흔들리지 않음을 확인하는 즉시 더 많은 사용자에게 신버전을 확대해 릴리스를 최단 기간에 끝냅니다. 사용자가 적어 A/B가 부담스러우면, 새 기능을 모두 플래그로 막아둔 변경 중립적 릴리스 로 배포 자체의 안정성만 검증합니다.

비교 / 트레이드오프

’빠를수록 안전하다’는 어떻게 성립하는가
통념 (느릴수록 안전)현실 (빠를수록 안전)
주기를 늦춰 충분히 테스트하면 안정적이다릴리스 사이 변경이 적을수록 문제 원인 찾기가 쉽다
한 번에 크게 내보내는 게 효율적이다직전 ‘좋은’ 상태와의 차이가 작아 살펴볼 범위가 좁다
사고가 무서우니 변경을 모은다가장 빠르고 안전한 복구는 거의 항상 롤백, 자주 배포하면 롤백 단위도 작다

안정적인 제품과 빠른 개발은 대척점에 있지 않습니다. 오히려 더 작게 변경해 자주 배포하는 제품이 품질도 좋고 시장 변화에도 빠르게 적응하며, 릴리스별 비용까지 낮아 한 번 놓쳐도 손해가 없습니다.

내 생각

  • ‘빠를수록 안전하다’는 트렁크 기반 개발 + 피처 플래그의 논리적 귀결이다. 배포 단위를 잘게 쪼개면 한 릴리스의 blast radius가 줄고 롤백도 싸진다. 이게 “느릴수록 안전”이라는 직관을 뒤집는 핵심이다.

  • 플래그 가드 = LaunchDarkly·Unleash, 그리고 ‘deploy ≠ release’. 코드를 프로덕션에 내보내는 것(deploy)과 사용자에게 켜는 것(release)을 분리하는 게 다크 런치·카나리·단계적 출시의 공통 토대다.

  • ‘만들기 빈도 vs 받기 빈도 분리’가 이 장의 가장 실무적인 한 줄이다. 매일 빌드·배포 가능 상태를 유지하되 실제 노출은 의식적으로 고른다 — 우리가 CD 파이프라인에서 매번 마주하는 결정이다.

  • ‘업데이트만 해도 지표가 변한다’는 경험칙이 무섭다. 배포 A/B에 대조군(같은 바이너리 재배포)을 두는 이유 — 변화의 원인이 새 기능인지 단순 업데이트 노이즈인지 가르지 못하면 데이터에 속는다.

관련 개념