지속적 통합의 이해

지속적 통합(CI)은 병합을 할 때마다 자동으로 코드베이스를 빌드하고 테스트하는 방식을 말합니다.

지속적 통합이란?

지속적 통합(CI)이란 개발 팀의 업무를 효율화하고 더욱 신뢰할 수 있는 소프트웨어를 전달할 수 있도록 지원하기 위해 설계된 DevOps 방식입니다. CI를 활용하면 변경 사항을 병합할 때마다 CI 서버가 자동으로 코드를 빌드 및 테스트하여 작업물에 관한 피드백을 빠르게 제공합니다. 이렇듯 빠르고 신뢰할 수 있는 피드백 주기를 통해 변경 사항을 더욱 빈번하게 릴리스하면서 프로덕션까지 도달하는 버그의 수를 줄일 수 있습니다.

CI가 적용되지 않은 개발

지속적 통합이 왜 필요한지를 이해하려면 지속적 통합이 없는 소프트웨어 개발은 어떤지 생각해 보면 도움이 됩니다. Git과 같은 버전 관리 시스템으로 작업한다고 가정해 보겠습니다. 여러분과 동료들은 저장소에 각자의 사본을 갖고 있고, 이를 사용해서 로컬에서 개발을 한 다음 작업을물 공유 저장소에 푸시합니다.

새로운 기능을 개발한다면 며칠 정도 작업한 다음 변경 사항을 공유합니다. 그동안 동료들도 저장소의 로컬 사본을 사용하여 기능을 개발하고 있습니다. 여러분은 작업이 완료될 때마다 변경 사항을 공유 저장소에 푸시하고 지정된 브랜치로 병합을 시작합니다. 그래야 다음 각 기능이 다른 기능과 조합되었을 때 예상대로 동작하는지 테스트할 수 있습니다.

그러나 안타깝게도 다수의 개발자가 작성한 대규모 변경 사항을 합치는 것이기 때문에 코드가 빌드되지 않을 위험이 큽니다. 여러분은 동료와 함께 시간을 써서 어떤 변경 사항 세트가 문제를 일으킨 것인지 찾아냅니다. 그런 다음에는 더 긴급한 변경 사항을 릴리스하기 위해 이러한 커밋을 되돌려버리거나 문제를 해결하기 위해 코드를 더 변경하게 됩니다.

코드가 빌드되고 나면 변경 사항의 조합으로 다양한 버그가 발생하는 것이 확인될 수 있습니다. 이번에도 각 기여자의 코드 변경 사항을 일일이 보면서 문제의 근원을 찾고, 수정하고, 다시 빌드 프로세스를 시작합니다.

CI의 필요성

지속적 통합은 변경 사항을 지정된 브랜치로 병합할 때마다 자동으로 빌드와 테스트 절차를 수행하여 이러한 프로세스의 속도를 높입니다. 이러한 절차를 자동화하면 코드베이스를 몇 주에 한 번씩 빌드하고 테스트하는 대신 몇 시간마다 더 자주 수행할 수 있습니다.

이렇게 작은 분량으로 나눠서 작업하면 코드 변경 사항에서 발생하는 문제를 빠르게 찾고 수정할 수 있습니다. 문제의 원인을 찾기 위해 수백, 수천 줄의 변경 사항을 검사하는 대신 훨씬 적은 양의 변경 사항에서 검색하면 됩니다. 이뿐만 아니라 사용자가 아직 변경 사항을 기억하기 때문에 컨텍스트가 전환되면서 생기는 부담도 없습니다.

CI는 변경 사항이 작성될 때마다 소프트웨어가 빌드되고 예상대로 동작하는 것을 확인하여 코드를 항상 배포 가능한 상태로 유지합니다. 그 결과 프로덕션으로 변경 사항을 릴리스하는 과정의 부담이 줄어들고 기능과 수정 사항을 더욱 자주 전달할 수 있게 됩니다.

지속적 통합은 기여자가 많은 대형 소프트웨어 개발 프로젝트에서 발생하는 문제를 해결하기 위해 고안되긴 했지만 개발 프로세스에 빠르게 도입하는 것이 좋습니다. 혼자 일하는 개발자라고 하더라도 적은 분량으로 작업하고 자동화 테스트를 활용하여 변경 사항을 검증하면 더 효율적으로 일하면서 코드 품질을 높일 수 있습니다.

지속적 통합

CI 모범 사례

효율적인 CI 워크플로를 만들려면 도구, 프로세스와 팀의 업무 방식을 조합해야 합니다. 그럼 하나씩 살펴보겠습니다.

버전 관리 시스템 사용

지속적 통합을 위해서는 코드베이스 전체가 소스/버전 관리 시스템에 저장되어 있어야 합니다. 여기에는 모든 소스 코드 파일, 라이브러리, 구성 파일 및 스크립트가 포함되어야 합니다. 버전 관리를 사용하면 다수의 개발자가 편리하게 동시에 작업하며 서로 변경 사항을 공유할 수 있습니다. CI 서버는 버전 관리 시스템과 통합되어 코드 변경 사항을 빌드하고 테스트합니다.

변경 사항을 자주 커밋

모든 사람이 동일한 기반 위에 있으려면 동일한 저장소에서 작업하고 변경 사항을 자주 공유해야 합니다. 공유 저장소의 CI 브랜치에 전원이 매일 커밋을 병합하도록 하는 것이 좋습니다. 더 자주 하는 것도 가능합니다. 이와 동시에 로컬 사본을 항상 공유 저장소와 동기화하여 푸시할 때마다 병합 충돌이 발생할 위험을 낮추세요.

자동화된 빌드 및 테스트

코드 변경 사항을 병합한 다음에는 솔루션을 빌드하고 린팅, 유닛 테스트, 정적 분석과 같은 일련의 검사를 진행해야 합니다. 빌드 또는 테스트를 수동으로 진행하면 시간도 많이 걸리고 오류가 발생할 수도 있어서 매일 변경 사항을 통합하는 것은 불가능하기 때문에 자동화가 필수적입니다. 빌드 도구와 자동화된 테스트 프레임워크는 모든 프로그래밍 언어에 사용할 수 있으며, CI 서버를 사용하여 자동으로 프로세스를 시작하고 다양한 단계를 조율할 수 있습니다.

실패를 신속하게 처리

지속적 통합의 이점을 활용하려면 자동화 빌드나 테스트가 실패할 경우 프로젝트에 기여하는 모든 인원이 신속하게 대응해야 합니다. 그러면 전원이 동작하지 않는 코드가 아닌 탄탄한 토대에 새로운 기능을 추가할 수 있습니다. 잘못된 빌드나 테스트를 수정하는 동안 팀원의 업무를 중지시키는 것처럼 보일 수 있지만, 자동화 CI 프로세스는 첫 결과를 몇 분 내로 제공할 수 있기 때문에 코드 변경 사항을 아직 생생하게 기억하고 있을 때 어떠한 문제든 해결할 수 있습니다.

프로세스 유지 관리

빌드와 테스트를 자동화했다면 CI 흐름을 유지 관리해야 합니다. 여기에는 새로운 코드를 작성할 때 유닛 테스트를 추가하고 피드백 루프의 속도를 유지하는 것이 포함됩니다.

저장소 모니터링, 빌드 트리거, 자동화된 테스트 실행 및 결과 대조 등의 작업을 처리하기 위해 CI 서버를 추가하면 이러한 모든 요소를 연결할 수 있어 맞춤화된 자동화 로직을 작성하는 데 드는 시간을 절약할 수 있습니다. 좋은 CI 서버는 코드 커버리지 메트릭이나 빌드 기록과 같은 추가적인 인사이트도 제공합니다.

CI의 이점

지속적 통합으로 얻을 수 있는 장점을 이해하면 팀원에게 새로운 업무 방식을 시도하도록 장려하고 새로운 프로세스를 지원하도록 이해관계자를 설득할 때 도움이 됩니다.

개인과 전체 개발 팀에게 CI는 다음의 장점이 있습니다.

  • 원활한 병합: 작은 분량으로 작업을 시작하면 병합 충돌의 수가 줄어듭니다. 다른 사람들이 푸시한 변경 사항에 맞춰 로컬 저장소를 자주 업데이트하는 것이 핵심입니다.
  • 더욱 효율적인 워크플로: 자동화된 빌드와 테스트 프로세스에서 빠르게 피드백이 전달되므로 변경 사항을 푸시하면 몇 분 내로 코드에 있는 문제에 관한 경고를 받습니다. 반면에 수동 빌드나 테스트 프로세스에 의존하면 변경 사항으로 인해 발생한 버그를 며칠 또는 몇 주가 지나도록 발견하지 못할 수 있습니다.
  • 관리가 쉬운 코드베이스: CI 프로세스가 잘 돌아가도록 자동화된 테스트 커버리지를 추가하면 코드베이스를 이해하고 관리하기가 쉬워집니다.
  • 소통과 협업 개선: 작은 분량으로 작업하고 변경 사항을 더 자주 공유하면 다른 사람이 진행 중인 작업도 확인할 수 있습니다. 따라서 동료와 기능의 설계에 관해서 논의하고, 제품 관리자와 사용 편의성 전문가에게 진행 상황을 보여주고, 필요에 따라 방향성을 바꿀 기회가 많아집니다.

지속적 통합은 더 넓은 범위의 비즈니스에도 다음과 같이 도움이 됩니다.

  • 버그 감소: 지속적 통합으로 버그가 유입되는 것을 막을 수는 없지만, 버그를 손쉽게 버그를 식별하고 해결할 수 있습니다. 그 결과 프로덕션에 버그가 릴리스되면서 사용자에게 영향을 줄 확률이 크게 줄어듭니다.
  • 빠르고 빈번한 릴리스: 빌드와 테스트 프로세스를 자동화하면 시간이 절약되고 각 과정이 일관되게 실행되어 소프트웨어 릴리스를 준비할 때 드는 수작업이 줄어듭니다. 팀이 CI 프로세스에 익숙해지면 변경 사항을 더욱 빈번하게 릴리스할 수 있습니다.

지속적 통합, 전달 및 배포에 관해서 자세히 알아보고 싶으신 경우 CI/CD의 12가지 장점에 관한 가이드를 읽어보세요.

CI의 해결 과제

지속적 통합이 개발자와 넓은 범위의 비즈니스에도 장점이 있지만 항상 환영받는 것은 아닙니다.

많은 개발 부서에서 DevOps는 작업 방식에 큰 변화를 가져오고 기존 프로세스에 문제를 제기합니다. 팀 간의 업무를 조정하고 협력의 문화를 조성하려면 의사소통이 원활해야 합니다.

이미 애자일 방법론을 따르고 있다면 피드백을 수렴하는 것의 중요성과 자율 관리형 팀의 개념이 이미 어느 정도 자리를 잡았을 것이므로 전환 과정이 일반적으로 더 용이합니다.

그렇지 않은 경우라면 CI가 중요한 변화임을 인식하고 사람들과 소통하며 작게 시작하고 이점을 보여주는 것이 CI의 장점을 동료들에게 설득하는 데 효과적일 수 있습니다.

또한 지속적 통합에는 더 현실적인 문제가 있습니다. 대형 모놀리식 애플리케이션을 개발하는 중이라면 빌드 타임이 오래 걸릴 수 있으며, 테스트 환경이 부족한 경우에는 테스트 실행을 병렬화하는 것이 어려워집니다.

지속적 통합 워크플로를 시각화하고 메트릭을 사용하여 병목 현상을 식별하면 아키텍처 변경, 추가 인프라 및 자동화된 테스트 커버리지에 대한 투자의 비용과 이득을 수량화하는 데 도움이 될 수 있습니다.

지속적 통합 시작하기

CI 워크플로를 구축하기가 엄두가 나지 않을 수 있습니다. 고려할 옵션도 많고 자동화할 것도 정말 많습니다. 다행히도 이 프로세스는 세분화하기도 쉽고 단계마다 장점이 있습니다.

다음과 같은 작업으로 시작하면 좋습니다.

  1. 작은 분량으로 작업 시작: 코드가 버전 관리 시스템에 저장되어 있다면 작은 배치로 작업하고 변경 사항을 더욱 자주 공유하여 병합 충돌을 줄일 수 있습니다. 이를 촉진하기 위해 백로그를 정리하는 동안 개발 작업을 나누는 것이 필요할 수 있습니다.
  2. 브랜치 전략 합의: 여기서 CI 흐름으로 보낼 브랜치와 변경 사항의 릴리스 방식을 결정합니다. 일반적인 선택지에는 트렁크 기반의 개발이나 GitFlow(특히 버전이 있는 소프트웨어의 경우)가 포함됩니다.
  3. 코드 작성 시 유닛 테스트 추가: 유닛 테스트가 이미 있든 백지 상태에서 시작하든, 유닛 테스트를 팀에서 사용하는 '완료의 정의'에 포함시키면 코드 커버리지가 항상 개선됩니다. 일부 자동화된 테스트라도 있는 게 없는 것보다는 낫고 몇 가지 자동화된 테스트만 사용하며 CI 연습을 시작해도 좋습니다.
  4. 점진적으로 자동화: CI 흐름의 모든 단계를 한 번에 스크립트화하려고 애쓰기보다 가장 시간이 많이 걸리거나 가장 많은 피드백을 주는 단계에 집중하세요. 준비가 되는 대로 CI 서버를 사용하여 단계를 자동화된 CI 프로세스로 묶을 수 있습니다.

CI와 CD를 모두 설정하는 방법을 자세히 알고 싶으시면 CI/CD 모범 사례 가이드를 참조하세요.

마무리

지속적 통합을 채택하면 개발 프로세스의 속도를 높이는 동시에 코드 품질을 개선하는 효과를 거둘 수 있습니다. 이러한 단계를 자동화하면 보다 효율적으로 작업하고 사용자에게 가치를 더하는 일에 집중할 수 있습니다. 그러나 지속적 통합은 CI/CD 파이프라인의 시작일 뿐입니다. 다음 단계인 지속적 전달은 릴리스 프로세스의 다음 부분에 DevOps의 원칙을 적용합니다.

TeamCity의 이점

TeamCity는 요구 사항에 맞게 설정할 수 있는 유연한 CI/CD 플랫폼입니다. Git, Perforce, Mercurial과 Subversion을 포함한 모든 주요 버전 관리 시스템을 지원하고 주요 프로그래밍 언어를 위한 빌드 및 테스트 도구를 제공합니다. 사용자는 광범위한 CI 트리거를 활용하여 지정된 브랜치로 커밋할 때마다 빌드 및 테스트 프로세스를 실행할 수 있고, 피처 브랜치에 하위 검사 세트를 실행하고, 야간 빌드를 예약하고, 팀원에게 로컬에서 CI 검사를 실행할 수 있는 옵션도 제공할 수 있습니다.

TeamCity는 피드백을 최대한 빠르게 제공하기 위해 테스트와 다른 빌드 작업을 병렬화합니다. Slack과 IDE를 통합하면 어디서 일하든 피드백을 받고, 상세한 테스트 보고서를 통해 빠르게 실패의 원인을 파악할 수 있습니다. TeamCity에는 CI 프로세스를 최적화하고 유닛 테스트 커버리지를 평가하는 데 도움이 되는 다양한 메트릭이 있습니다.

CI 프로세스를 확장하여 지속적 전달이나 배포도 포함하려는 경우에도 TeamCity에는 환경을 관리하고 배포를 자동화하는 데 필요한 모든 것이 있습니다.