Continuous Integration: 통합 지옥을 없애는 실천 (자동 빌드·빠른 피드백)

들어가며

이 글은 Process-Essential 시리즈의 6단계입니다. 전체 지도는 Process Essential Curriculum에서 확인할 수 있습니다.

5단계 OOSE: 유스케이스 주도 개발에서는 유스케이스가 분석·설계·구현·테스트를 어떻게 하나의 흐름으로 꿰는지를 살펴봤습니다. 그런데 아무리 좋은 설계와 테스트를 갖추더라도, 여러 사람이 각자의 브랜치에서 며칠씩 작업한 코드를 한꺼번에 합치는 순간 모든 가정이 무너지곤 합니다. 이른바 통합 지옥(integration hell) 입니다. Continuous Integration(CI)은 바로 이 통합 지옥을 정면으로 없애려는 실천이며, 2단계에서 다룬 XP Explained: 변화를 끌어안는 애자일의 핵심 실천 중 하나이기도 합니다. XP가 “통합은 미루지 말고 계속, 자주 하라”고 말했던 그 원칙을 도구와 자동화로 구체화한 것이 이 단계의 주제입니다.

이 글의 길잡이는 Paul Duvall, Steve Matyas, Andrew Glover가 쓴 Continuous Integration: Improving Software Quality and Reducing Risk입니다. 이 책은 CI를 단순한 “빌드 서버 설치”가 아니라, 소프트웨어 품질을 높이고 위험을 줄이는 일상적 실천으로 정의합니다. 핵심 통찰은 단순합니다. 통합이 고통스러운 이유는 통합을 드물게 하기 때문이고, 고통스러운 일은 자주 할수록 덜 아파진다는 것입니다. 통합을 매 커밋마다 자동으로 하면, “합치는 일”은 더 이상 별도의 사건이 아니라 평범한 배경 작업이 됩니다.

그리고 이 모든 자동화·도구·실천을 한참 쌓고 나면 자연스럽게 떠오르는 질문이 있습니다. “그래서 방법론의 본질은 무엇인가?” 7단계 Essence: 방법론 감옥에서 탈출하기는 그 메타 수준의 물음으로 우리를 데려갈 것입니다. 우선은 통합 지옥을 없애는 구체적 실천부터 차근히 살펴봅시다.

📌 이 글에서 다루는 내용

🔍 핵심 주제

  • CI의 원칙: 잦은 커밋, 자동 빌드, 빠른 피드백이 왜 통합 지옥을 없애는지
  • 자동화된 빌드와 테스트: 한 명령으로 끝나는 빌드 스크립트와 자동 테스트 스위트 구성
  • CI 서버와 파이프라인: 빌드 트리거, 상태 가시화, 깨진 빌드에 대응하는 규율
  • 품질 피드백: 정적 분석·커버리지·데이터베이스 통합으로 넓히는 확장 실천
  • 배포로의 연결: CI에서 지속적 배포(Continuous Delivery)로 가는 길

CI의 원칙: 잦은 커밋, 자동 빌드, 빠른 피드백

왜 필요한가. 통합 지옥의 진짜 원인은 “변경량 × 시간”입니다. 두 개발자가 일주일간 따로 작업하면, 합칠 때 충돌할 수 있는 코드의 양과 서로의 가정이 어긋날 가능성이 폭발적으로 늘어납니다. 반면 하루에도 여러 번 작은 단위로 합치면, 충돌은 작고 원인은 명확하며 즉시 고칠 수 있습니다. CI의 모든 실천은 이 단순한 산술을 자동화로 보장하려는 것입니다.

CI는 보통 세 가지 원칙으로 요약됩니다.

  • 잦은 커밋(commit frequently): 작동하는 작은 단위가 완성될 때마다 메인라인(main/trunk)에 통합합니다. 이상적으로는 하루에 한 번 이상. 오래 살아 있는 거대 브랜치는 통합을 미루는 함정입니다.
  • 자동 빌드(automated build): 커밋이 들어오면 사람의 개입 없이 빌드가 돌아갑니다. “내 컴퓨터에서는 됐는데”라는 변명을 구조적으로 차단합니다.
  • 빠른 피드백(fast feedback): 빌드와 테스트 결과가 몇 분 안에 돌아와야 합니다. 피드백이 늦으면 개발자는 이미 다른 작업으로 넘어가 있고, 깨진 빌드의 맥락을 잃어버립니다.

구체적으로. Martin Fowler가 정리한 CI의 핵심 규칙 중 하나는 “메인라인을 절대 깨진 상태로 두지 않는다“입니다. 빌드가 깨졌다면 그것을 고치는 일이 팀의 최우선 과제가 됩니다. 새 기능을 추가하는 것보다 빨간 빌드를 초록으로 되돌리는 것이 먼저입니다. 이 규율이 있어야 “메인라인은 항상 배포 가능한 상태”라는 신뢰가 유지됩니다.

자동화된 빌드와 테스트

왜 필요한가. CI가 작동하려면 “빌드”가 사람의 손이 필요 없는, 한 번의 명령으로 재현 가능한 절차여야 합니다. IDE 버튼을 눌러야만 되는 빌드, 특정 개발자만 아는 환경 설정에 의존하는 빌드는 자동화할 수 없습니다.

개념. 좋은 CI 빌드는 다음을 포함합니다. (1) 의존성 설치, (2) 컴파일/번들, (3) 자동 테스트 스위트 실행, (4) 정적 분석·커버리지 같은 품질 측정. 이 전체가 하나의 스크립트로 묶여 있어야 합니다. 핵심은 단일 명령 빌드(single-command build) 입니다.

예를 들어 로컬에서든 CI 서버에서든 똑같이 돌아가야 하는 명령은 이런 모습입니다.

# 의존성 설치 → 빌드 → 테스트를 한 흐름으로
npm ci                 # 잠금 파일 기반의 재현 가능한 설치
npm run build          # 컴파일/번들
npm test -- --coverage # 자동 테스트 + 커버리지 측정

자동 테스트 스위트는 CI의 심장입니다. 테스트가 없으면 “빌드가 통과했다”는 말은 “컴파일이 됐다”는 뜻에 불과합니다. 빠른 피드백을 위해 테스트는 보통 계층으로 나눕니다.

  • 단위 테스트(unit test): 가장 빠르고 많아야 하는 층. 매 커밋마다 전부 실행.
  • 통합 테스트(integration test): 컴포넌트 간 연결을 검증. 단위보다 느리지만 여전히 커밋 빌드에 포함하려 노력.
  • 종단 테스트(end-to-end): 가장 느리고 깨지기 쉬운 층. 별도의 느린 단계로 분리해 빠른 피드백을 해치지 않게 합니다.

이렇게 “빠른 것 먼저, 느린 것 나중”으로 단계를 나누는 것이 뒤에서 다룰 파이프라인의 출발점입니다.

CI 서버와 파이프라인

왜 필요한가. 개발자가 매번 손으로 빌드를 돌릴 수는 없습니다. 커밋이라는 이벤트에 반응해 자동으로 빌드를 트리거하고, 결과를 모두에게 보여 주는 중립적 주체가 필요합니다. 그것이 CI 서버(혹은 GitHub Actions·GitLab CI 같은 호스티드 러너)입니다.

개념. CI 서버의 역할은 세 가지입니다.

  • 빌드 트리거(trigger): push/PR 같은 이벤트가 발생하면 자동으로 워크플로를 시작합니다.
  • 상태 가시화(visibility): 빌드가 초록인지 빨강인지를 PR 화면, 배지, 알림으로 누구나 즉시 알 수 있게 합니다.
  • 깨진 빌드 대응(broken build response): 빌드가 깨지면 책임자에게 알리고, 팀은 그것을 최우선으로 고칩니다.

구체적 예시. 아래는 체크아웃 → 설치 → 빌드 → 테스트를 수행하는 작고 일반적인 GitHub Actions 스타일 워크플로입니다.

name: CI
on:
  push:
    branches: [main]
  pull_request:

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Node
        uses: actions/setup-node@v4
        with:
          node-version: "20"

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Test (with coverage)
        run: npm test -- --coverage

      - name: Static analysis (lint)
        run: npm run lint

이 워크플로는 메인라인으로의 push와 모든 PR에서 자동으로 돌아갑니다. PR이 빨간 빌드라면 머지를 막도록 브랜치 보호 규칙을 걸면, “깨진 코드는 메인라인에 들어올 수 없다”는 원칙이 도구 수준에서 강제됩니다.

파이프라인. 여러 단계를 순서대로 엮은 것이 CI 파이프라인입니다. 앞 단계가 실패하면 뒤 단계로 넘어가지 않으므로, 빠르고 값싼 검증을 먼저 배치해 피드백 속도를 최대화합니다.

flowchart LR
    A["개발자 커밋<br/>(push / PR)"] --> B["CI 서버<br/>빌드 트리거"]
    B --> C["의존성 설치<br/>+ 컴파일"]
    C --> D["단위 테스트<br/>(빠름)"]
    D --> E["통합·종단 테스트<br/>(느림)"]
    E --> F["정적 분석<br/>+ 커버리지"]
    F --> G{"전부 통과?"}
    G -- "예 (초록)" --> H["메인라인 머지<br/>배포 후보"]
    G -- "아니오 (빨강)" --> I["팀에 알림<br/>최우선 수정"]
    I --> A

이 그림의 핵심은 화살표가 개발자에게 빠르게 되돌아온다는 점입니다. 빨간 빌드는 곧바로 알림이 되어 커밋한 사람에게 피드백되고, 그가 즉시 고친 뒤 다시 커밋하면서 루프가 닫힙니다.

품질 피드백: 정적 분석·커버리지·데이터베이스 통합

왜 필요한가. 테스트 통과만이 품질은 아닙니다. 컴파일되고 테스트가 초록이어도 코드 냄새, 보안 취약점, 검증되지 않은 영역이 숨어 있을 수 있습니다. CI는 “통합이 깨지지 않았는가”를 넘어 “품질이 어디로 가고 있는가”를 매 커밋마다 측정하는 자리로 확장됩니다.

확장 실천.

  • 정적 분석(static analysis): 린터·타입 체커·보안 스캐너를 파이프라인에 넣어, 실행 없이도 발견 가능한 문제(미사용 변수, 위험한 패턴, 알려진 취약 의존성)를 자동으로 걸러냅니다.
  • 코드 커버리지(coverage): 테스트가 실제로 어느 코드 경로를 거쳤는지 측정합니다. 커버리지는 목적이 아니라 신호입니다. 0%에 가까운 영역은 위험 지대를, 급격한 하락은 테스트 없이 추가된 코드를 알려 줍니다.
  • 데이터베이스 통합(database integration): 책 Continuous Integration이 특히 강조하는 실천입니다. 스키마와 마이그레이션 스크립트도 코드처럼 버전 관리하고, CI 빌드 안에서 깨끗한 DB를 생성·마이그레이션·시드하여 “애플리케이션 + 데이터베이스”가 함께 통합되는지를 검증합니다. 데이터베이스를 빌드 바깥의 수작업으로 두면, 통합 지옥은 데이터 계층에서 그대로 부활합니다.

이런 측정값을 PR마다 코멘트·배지로 가시화하면, 품질은 분기 말의 회고가 아니라 매 커밋의 일상적 피드백이 됩니다. 앞의 워크플로에 npm run lint 단계를 넣고 커버리지 리포트를 업로드하는 것이 바로 이 확장의 첫걸음입니다.

배포로의 연결: CI에서 Continuous Delivery로

왜 필요한가. CI로 “메인라인은 항상 빌드되고 테스트를 통과한다”는 상태를 만들었다면, 다음 질문은 자연스럽습니다. “그렇다면 왜 배포는 여전히 드물고 고통스러운가?” 통합 지옥을 없앤 논리를 그대로 배포에 적용한 것이 Continuous Delivery(CD) 입니다.

개념. CD는 CI 파이프라인을 배포 가능한 산출물(artifact) 생산과 환경 승격(promotion)까지 확장합니다.

  • Continuous Integration: 커밋마다 빌드·테스트로 메인라인을 항상 건강하게 유지.
  • Continuous Delivery: 모든 통과한 빌드를 언제든 배포 가능한 상태로 자동 준비. 실제 운영 배포는 사람의 버튼 하나로.
  • Continuous Deployment: 한 발 더 나아가, 통과한 빌드를 사람 개입 없이 운영까지 자동 배포.

핵심은 배포 절차 역시 빌드처럼 자동화되고 재현 가능한 파이프라인이라는 점입니다. CI에서 만든 단일 명령 빌드, 자동 테스트, 품질 게이트가 그대로 배포의 신뢰 기반이 됩니다. 즉 CI는 CD의 전제 조건입니다. 통합을 자주·자동으로 하지 않으면, 배포를 자주·자동으로 할 수 없습니다.

이 흐름을 한 문장으로 요약하면 이렇습니다. 잦은 통합 → 항상 초록인 메인라인 → 언제든 배포 가능한 산출물 → 버튼 하나의 릴리스. 통합 지옥을 없앤 실천이 그대로 “배포 지옥”까지 없애는 길로 이어집니다.

마무리

Continuous Integration은 “통합을 별도의 사건에서 평범한 배경 작업으로 바꾸는” 실천입니다. 잦은 커밋·자동 빌드·빠른 피드백이라는 세 원칙으로 통합 지옥의 산술을 무너뜨리고, 단일 명령 빌드와 자동 테스트 스위트로 재현 가능성을 보장하며, CI 서버와 파이프라인으로 트리거·가시화·깨진 빌드 대응을 자동화합니다. 여기에 정적 분석·커버리지·데이터베이스 통합 같은 품질 피드백을 얹고, 같은 논리를 배포까지 확장하면 Continuous Delivery가 됩니다.

지금까지 시리즈는 방법론(애자일·XP·스크럼·OOSE)과 실천(CI)을 차례로 쌓아 왔습니다. 그렇다면 이 모든 방법론과 실천을 관통하는 공통의 본질은 무엇일까요? 7단계 Essence: 방법론 감옥에서 탈출하기에서는 한 걸음 물러나, 방법론을 메타 수준에서 바라보며 “어떤 방법론을 쓰든 변하지 않는 것”을 탐구합니다.

다음 학습