개요
- 개발 프로세스 중 가장 고통스러운 통합과정을 자동화하는 방법.
- 프로젝트의 복잡도가 증가하고 여러 사람이 협업하는 과정이 필요하다면, 통합의 비용이 기하급수적으로 증가하기 때문.
- 사실은 그저 작업을 자주 자주 통합하는 것이라고 봐도 무방함.
- 결함이 발생하는 시점과 고쳐지는 시점의 간격을 줄이고, 신속하게 피드백을 제공.
- 리팩토링, 테스트 주도 개발과 잘 어울림.
- 변경 부분이 기존 부분과 잘 융합하여 작동되는걸 쉽게 확인해보게 도와주는 안전망
시작하기
변경할 때마다 소프트웨어를 빌드하기
- 빌드: 컴파일보다 큰 개념. 컴파일, 테스트, 검사, 배포 등의 과정을 모두 포함하며 소프트웨어가 하나의 단위로 작동하는지 확인하는 과정
순서
- 소스코드 커밋, CI 서버가 변경사항이 없는지 계속해서 확인.
- CI서버가 변경 내역 감지. 최신 소스코드 복사본을 가져와서 빌드스크립트를 실행하고 통합 시도.
- 이메일 등으로 빌드 결과 내보냄
- 다시 새로운 변화에 대해서 감시
자주 빌드하여 얻을 수 있는 해답
- 모든 소프트웨어 컴포넌트가 함께 작동하는가
- 코드 복잡도가 얼마나 되는가
- 팀이 코딩 표준을 잘 지키는가
- 코드의 테스트 커버리지가 얼마나 되는가
- 가장 최근의 변경 사항 적용 후 모든 테스트가 성공했는가
- 마지막 배포에 문제가 없었는가
CI의 특징
- 버전 관리 저장소 연결
- 자동 빌드
- 피드백 메커니즘
- 소스코드 변경 내역 통합 프로세스
기본 요소
- 컴파일, 데이터베이스 통합
- 테스트
- 검사
- 배포
- 문서화 및 피드백
지속적인 통합 도입하기
CI가 지닌 가치
- 위험을 줄여줌
- 결함 조기 발견 및 수정
- 소프트웨어 건강 상태 측정
- 가정을 줄일 수 있음
- 반복적인 수작업을 줄여줌
- 언제 어느 때라도 배포 가능한 소프트웨어를 만들어줌
- 프로젝트 가시성을 높여줌
- 효과적인 의사결정
- 추세 인지
- 개발 팀이 자신의 제품에 자신감을 가지게 해줌
프로세스 자동화
- 식별하기
- 빌드
- 공유하기
- 지속적으로 돌아가게 만들기
CI 적용 단계
- 새로운 프로젝트의 시작과 동시에
CI와 다른 개발 실천 방법
- 개발자 테스트
- 코딩 표준 준수
- 리팩토링
- 작은 릴리즈
- 공동 소유권
실천 방법
- 코드를 자주 커밋
- 조금씩 바꾸기
- 각 작업이 끝날 때 마다 커밋
- 깨진 코드는 커밋하지 않기
- 빌드가 깨지면 즉시 고치기
- 자동화된 개발자 테스트 작성
- 테스트와 검사는 모두 통과해야함
- 개인 빌드를 먼저 돌리기
- 깨진 코드는 가져오지 않기
위험 줄이기
위험 요소들
- 배포 가능한 소프트웨어의 부재
- 깨끗한 빌드 전용 서버가 따로 있어야 한다.
뒤늦은 결함 발견
- 테스트 커버리지 체크
- 프로젝트 가시성의 부재
- 현재 상황에 대한 공유
- 저품질의 소프트웨어
- 코딩 표준 준수
- 중복 코드
- 아키텍쳐 준수
변경과 동시에 소프트웨어 빌드하기
빌드를 자동화하기
명령어 하나로 빌드를 수행하기
- IDE에 의존하지 말고, 단 하나의 명령어로 빌드되게끔 할 것.
소프트웨어 자산을 중앙 집중화 하기
- 외부 소스 저장소 사용
빨리 실패하는 빌드를 만들기
- 컴포넌트 통합
- 단위 테스트
- 기타 무거운 프로세스
환경에 독립적으로 빌드 되도록 하기
- properties, profile 등만 수정하면 되도록.
빌드 유형
개인 빌드
- 컴파일
- 단위 테스트
통합 빌드
- 컴포넌트
- 시스템
- 성능 테스트
- 코딩 표준 준수
- 코드 복잡도
- 코드 커버릿지
릴리즈 빌드
- 인수 테스트
- 설치 매체
- 품질 보증
빌드 메커니즘
- 주문형
- 시간 기반
- 변경사항 감시
- 이벤트 주도
전용 통합 빌드 머신 사용
- 충분한 하드웨어
- 모든 소프트웨어 자산을 두기
- 깨끗한 환경
CI 서버 사용
빌드 시간 단축
빌드 메트릭 수집, 분석 및 개선
- 컴파일 시간, 줄 수, 검사 개수 및 유형, 어셈블리 생성 시간, 테스트 실행 시간 등
전용 빌드 머신 사용
테스트 성능 개선
지속적인 테스트
- 객체 수준에서 신뢰도를 보장할 수 있어야 한다.
단위 테스트 자동화하기
- 의존성이 있는 어떤 클래스를 테스트 할 때, Mock 클래스 등을 쓰지 않고 파일 시스템이나 데이터베이스같은 외부 개체에 의존하면 그건 컴포넌트 테스트.
- 단위 테스트는 외부 의존성에 전혀 기대지 않아야 함. 왜냐하면 테스트에 걸리는 시간이 길어지므로.
컴포넌트 테스트 자동화하기
- 시스템의 일부를 검증
- 외부 의존성이 필요할 수 있음.
- 상호작용하여 예상된 총체적 행동을 생산해내는지 검증해야함.
- 단위테스트에 비해서 오래 걸리는 경향이 있음.
시스템 테스트 자동화하기
- 전체 시스템을 실행시킴.
- 완전히 설치된 시스템 필요.
- 기능 테스트와는 근본적으로 다름.
기능 테스트 자동화하기
- 클라이언트의 관점에서 테스트.
- 인수 테스트라 하기도 함.
결함 검사용 테스트 작성하기
- 결함 주도적 방식의 시나리오 사용
- assert를 적절하게 이용하기 어렵다.
- 테스트 케이스가 실패하지 않게 되었다고 해서 제대로 동작하는 것은 아니다.
- 그러나 테스트 케이스에서 더이상 문제가 없으므로 지나치려는 경향이 있다.
- 지속적인 예방 개발
- 결함을 고치고, 재발하는걸 막으며, 변화된 행동까지 검증하게끔 이끈다.
컴포넌트 테스트를 반복할 수 있게 만들기
테스트 케이스 하나에 assert 하나로 제한하기
지속적인 검사
- 정적 분석 도구를 활용하라 (기존 사람의 분석과 같이 사용하는 것이 더 효율적)
- 검사 주기는 짧을 수록 좋음.
- 결함을 조기에 발견하고 수정할 가능성이 높아짐
- 코드 메트릭을 검사
- 순환 복잡도 수
- 설계와 연관된 의존성 메트릭 (구심성 결합도, 원심성 결합도, 불안정성)
- 코드 심사
- 코딩 규약
- 아키텍쳐
- 중복 코드 줄이기
- 코드 커버리지 평가
- 코드 커버리지 테스트의 부하가 크기 때문에 성능 테스트나 부하 테스트와 병행하지 말 것