소프트웨어 개발에서 유지보수로 연결되는 지점은 소스관리/빌드/배포의 활동이 됩니다. 물론, 소스코드 수정이 발생되기는 하지만, 소스관리/빌드/배포의 활동이 주로 발생하기 마련이며, 이는 유지보수 시점에 확실한 절차와 방법을 필요로 합니다. 개발 시점에 이러한 활동을 지원하는 기법 중에 CI (Continuous Integration)가 있으며, 이는 오래 전부터 소프트웨어 개발에 있어서 위험을 줄이는 방식으로 사용되고 있었습니다.
CI 라는 용어가 직접적으로 사용되지는 않았지만, 1993년 Mattew Pittman이 쓴 'Lessons Learned in Managing Object-Oriented Development'라는 논문[참조 1]에서 "예정된 통합(scheduled integration)" 이라는 용어를 사용하고 있으며, 이는 CI를 수행할 때의 한가지 이슈에 대해 완벽한 테스트의 부족을 언급하고 있습니다. 즉, CI가 단순히 소스코드의 빌드와 배포만을 의미하지 않고 그 안에는 소스코드를 검증할 수 있는 방법이 분명 필요하다는 것을 말하고 있습니다.
코드 컴플리트(Code Complete)라는 책을 쓴 Steve McConnell은 1996년 'Daily Build and Smoke Test'[참조 2]라는 글에서 Microsoft사에서 일일 빌드 체계를 통해서 통합에 대한 위험을 격감사키고, Smoke Testing을 통해서 품질을 확보하고 있다는 내용을 언급하고 있습니다. 특히, 일일 빌드는 프로젝트에서 심장 박동(heartbeat)에 비유한 Jim MacCarthy의 말을 인용하여 일일 빌드(daily build)를 하지 않는다면, 그 프로젝트는 죽은 것과 같다고 표현하고 있습니다. 1990년대 후반부터는 XP(Extreme Programming)에서 CI를 기법으로 채용했으며(참조 : http://www.extremeprogramming.org/rules/integrateoften.html), Martin Fowler의 Continuous Integration이라는 글에서 본격적인 CI 기법에 대한 기본 원칙이 만들어지기 시작헀습니다.
이 글에서 Fowler는 자동화된 일일 빌드에 대한 기본 원칙을 다음과 같이 4가지로 설명합니다.
- 모든 소스 코드가 살아있고(현재 실행되고) 어느 누구든 현재의 소스를 접근할 수 있는 단일 지점을 유지할 것
- 빌드 프로세스를 자동화시켜서 어느 누구든 소스로부터 시스템을 빌드하는 단일 명령어를 사용할 수 있게 할 것
- 테스팅을 자동화시켜서 단일 명령어를 통해서 언제든지 시스템에 대한 건전한 테스트 수트를 실핼할 수 있게 할 것
- 누구나 현재 실행 파일을 얻으면 지금까지 최고의 실행파일을 얻었다는 확신을 하게 만들 것
위의 원칙들은 기본적으로 CI 도구들이 지원하고 있지만, CI가 단순히 도구만으로 구현할 수 있는 부분은 어디까지나 한정적이라고 보면 됩니다. 단순히 형상관리도구나 CI 도구, 테스트 프레임워크를 적용했다는 사실만 가지고는 CI를 적용한다라고 말할 수는 없다는 의미입니다.
CI를 적용하는데 있어서 주요한 부분을 자세히 살펴보면 다음과 같이 4가지 영역으로 구분을 해볼 수 있습니다.
- 형상관리 항목에 대한 선정과 형상관리 구성 방식 결정
- 단위테스트/통합테스트 방식
- 비기능 속성(품질 속성) 관리 방식
- 빌드/배포 자동화 방식
1. 형상관리는 CI를 위해 필수로 적용해야 하는 기법 중 하나
Martin Fowler도 CI에 대해 언급하면서 소스 접근에 대한 단일 지점을 거론했는데, 이와 같이 형상관리는 CI에 있어서 반드시 적용해야 하는 기법 중에 하나입니다. 국내의 대부분 기업에서 사용하는 오픈소스인 Subversion(SVN)을 비롯하여, 상용버전인 ClearCase, VSS, Harvest 등이 형상관리를 지원하는 도구입니다. 하지만, 이들 형상관리 도구를 단지 사용한다는 것이 CI의 그 전제 조건만은 아닙니다. 사용하되 다음과 같은 내용이 모두 포함되어야만 CI 적용이 가능합니다.
우선, 형상 항목을 명확하게 지정하여 관리하야 합니다. 이 형상 항목(Configuration Item)에는 개발시 필요한 내용(소스 코드, 설정 파일 등)도 포함되지만, 빌드 및 배포시 포함되어야 하는 항목들도 존재합니다. 예를 들어, 컴파일되어 바이너리 파일로 배포되는 형태의 언어라면 소스 코드는 형상 항목이 되지만, 배포 항목이 되지는 않습니다. (물론, 소스 코드를 배포한다고 해서 문제가 되지는 않지만, 물리적으로 소스코드가 배포되는 경우 보안 등을 포함하여 여러가지 이슈가 발생될 수 있습니다.) 마찬가지로 물리적인 서버에 배포할 바이너리 파일은 형상관리를 할 항목은 아니지만, 배포 항목은 포함되어야 합니다. (바이너리 파일 역시 형상 항목으로 포함시킬 수도 있지만, 이 경우에는 소스 코드와의 동기화와 같은 이슈가 발생될 수 있으며, 어느 기준[컴파일러의 버전 업그레이드 등]으로 바이너리 파일을 유지할 것인지에 대해서도 문제가 됩니다.)
형상 항목과 배포 항목을 결정했다고 하더라도 형상관리를 할 대상 항목들이 어떠한 구조(주로 패키지 구조)를 갖도록 할 것인지에 대해서도 결정이 필요합니다. 이는 배포 대상 항목과도 밀접하게 관련이 있기는 하지만, 배포 항목은 형상관리의 항목을 통해서 어떤 형태로 배포 항목을 만들 것인지는 주로 빌드나 통합 도구가 이를 대신 수행하기 때문에 형상 항목과 배포 항목을 반드시 맞출 필요는 없습니다.
하지만, 배포 항목이 본질적으로 형상 항목으로부터 만들어지기 때문에 형상항목에 대한 관리 구조는 배포 항목까지 영향을 미치게 됩니다. 자바(Java)와 같은 경우, 배포 항목의 단위가 WAR나 JAR, EAR 묶음이 되지만, 이를 형상항목에서 표시하는 방식은 참으로 다양합니다. WAR를 하나의 최상위 디렉토리에 위치하고, 그 하위에 관련 배포 항목들이 모두 위치하도록 배포 구조를 가지고 갔을 때 형상 항목들의 구조와 배포 항목들의 구조를 동일하게 구성할 수도 있지만, 성격이 다른 배포 항목들을 세분화시켜서 별도의 형상 항목의 디렉토리 구조를 형성시키고, 배포 시점에 이를 특정 규칙에 맞추어서 배포 지점에 위치시키는 방법도 있습니다. (예를 들어, js/html/css와 같은 UI 형상항목과 java와 같은 컴파일이 필요한 형상항목은 별도로 디렉토리를 분리하여 형상항목에 위치시키고, 최종적으로 WAR를 빌드하는 시점에 이를 각각 복제하여 구성하는 방식입니다. 이때, 빌드 과정은 형상항목의 구조와 배포항목의 구조를 매핑하여 변형하는 과정이 별도로 만들어져야 합니다.)
위의 이러한 과정에서 빌드/배포에 대한 자동화 방식이 다양할 수 있습니다.
2. 테스트가 없는 CI는 브레이크없는 자동차와 같지 않을까
CI를 구성하는데 있어서 빌드/배포 과정에 대한 자동화 만큼 비중을 차지하는 영역이 테스트 자동화입니다. CI가 지닌 의미를 살펴보면, 지속적으로 균일한 품질의 SW 제품을 유지하려는 목적이 들어 있습니다. 그에 대한 현실적인 대안이 바로 단위 혹은 통합테스트이며, 이는 가능한 한 자동화 과정 내에 포함되어야 합니다. 물론, 여러가지의 제약이나 프로세스, 혹은 문서들을 통해서 비자동화 방식을 채택할 수도 있습니다. 다만, 이러한 과정들은 매번의 SW 변화에 따라 그 만큼의 노력이 들어간다는 단점이 분명 존재합니다. SW의 성질 중에 하나는 시스템의 변화(업그레이드이든 환경에 대한 변화이든)는 기존의 잘 동작하던 기능을 멈추게 하려는 경향이 있다는 것입니다. [참조 3] 이러한 SW의 회귀현상을 방지하는 방법은 시스템 변경이 발생할 때마다 이전에 수행했던 테스트를 동일하게(동일 조건으로) 다시 반복하는 것입니다.
이러한 테스트 방식을 회귀 테스트(regression test)라고 하며, 이는 사람의 노력으로 수행하기에는 한정적입니다. 즉, 이러한 회귀테스트는 자동화되어야 할 대상이며, CI가 SW 변화를 가져오는 과정 내에 포함되기 때문에 반드시 CI 내 프로세스에 포함되어야 합니다. 하지만, 테스트 자동화는 늘 테스트 데이터와 다양하고 이질적인 시스템 통합이라는 문제와 함께 극복하기 어려운 난제를 가지고 있기도 합니다. 또한, 테스트를 CI에 포함시킨다면 테스트를 수행하는 시간이 결코 무시할 수 없기에 시스템 변경후 이관/배포 시간이 엄청 길어질 수 있다는 단점이 분명 존재합니다. 예를 들어, 인터페이스의 오퍼레이션 단위로 테스트를 하는데 개당 평균 1초가 걸린다면 1000개의 오퍼레이션을 테스트를 하는데 총 1000(약 17분 정도)초가 걸립니다. 17분 정도는 한번 배포하는데 인내할 수 있다고 생각할 수 있지만, 실제로는 전체 시스템의 크기가 증가할수록 그리고 소스 코드를 커버하는 테스트가 늘어날수록 더 큰 기울기로 증가할 수 있기 때문에 테스트 수행시간을 줄이는 것 역시 난제라고 할 수 있습니다.
이러한 난제를 안고 있는 테스트를 CI에 포함시켜서 수행하기는 쉽지는 않습니다. 테스트 자동화가 SW 품질을 일정하게 유지시키는데 가장 핵심이 되는 사항이기는 하지만, 현실적인 문제로 인해서 테스트 과정없이 빌드/배포만을 위한 CI를 수행하기도 합니다. 빌드/배포를 위한 CI인 경우, 테스트를 그 과정에 반드시 포함해야 할 필요는 없지만, 최소한의 대안은 필요하다고 봅니다. 예를 들어, 빌드/배포 CI 이외의 테스트 만을 위한 CI 프로세스를 별도로 만들어서 주기적으로 품질을 체크한다든지, 블랙박스 테스트가 불가하다면 화이트박스 테스트(정적 분석 도구 등)를 통해서 지속적인 품질을 체크하려는 노력은 필요하다고 봅니다. CI를 적용해볼때 먼저 빌드/배포에 대한 자동화를 고려해볼 수 있고, 그 다음 단계로 테스트 자동화 부분들도 고려해서 품질을 높이려는 시도를 해보는 것도 좋은 방법입니다. 자동차에 브레이크가 없다면 더 빨리 달릴 것 같지만, 제어하지 못하는 속도는 큰 위험을 안고 있는 것과 같기 때문에 사고 후에는 엄청난 비용을 지불해야 할 겁니다. 테스트 자동화를 CI에 포함시키는 것은 이와 같다고 보면 될 것 같습니다.
3. CI를 더 고급스럽게 만드는 방식 -지속적이고 통합된 품질 관리 체계 구축
SW의 기능적인 측면은 테스트 자동화를 통해서 위험을 제거할 수 있다고 본다면, 비기능적인 측면은 품질(측정) 관리 자동화를 통해서 위험을 제거할 수 있을 것입니다. 다소 한정적이긴 하지만 지속적으로 품질을 측정하여 이를 관리하려는 시도들은 꽤 의미가 있습니다. (SonarQube를 이용한 지속적인 품질 관리 참고) [참조 4]
SW 품질을 관리하려면 많은 노력이 필요한게 사실입니다. 이는 자동화하기가 그리 수월하지도 않으며, 자동화가 되었다고 하더라도 각 시스템마다 그 수치가 다소 다른 의미를 가질 수 있기 때문에 SW 품질에 표시되어 있는 수치를 어떤 형태로 해석할 것인지에 대해서 더 많은 고민이 필요한게 사실입니다. (LoC가 많다고 더 많은 노력이 들어간다고 볼 수 없는 경우와 같이) 대부분의 품질로 표현되는 수치는 각각의 특수한 상황을 반영하는게 사실이지만, 빅데이타와 같이 수많은 수치들이 쌓이고 이를 분석해내는 능력이 더 발전한다면 이보다도 더 현실적이고 예측가능한 수치도 없을 것입니다. 통상 운영 중인 시스템을 기반으로 새로운 시스템을 만들때 이러한 수치들을 통해서 시스템의 규모나 복잡도를 예측하는 것이 수많은 미사어구로 표현된 언어를 기반으로 예측하는 것보다 더 정확할 수도 있습니다. 하지만, 이러한 수치들은 현재 운영중인 시스템으로부터 표면화시켜서 가시화시키려면 좀더 발전적인 CI 방식을 필요로 하며, 더 많은 품질 자동화 노력을 필요로 합니다. 물론, 그 중심에는 CI가 중요한 역할을 하게 됩니다.
4. 지속적으로 변화하는 IT 서비스
요즘의 서비스(service)라는 개념은 얼마나 고객의 요구를 맞추어줄 수 있을 것인가에 좌우된다고 할 수 있습니다. 기존에는 제품을 만드는 사람과 이를 서비스로 변환하여 고객에게 제공하는 사람이 크게 나누어져서 전체 서비스 제공의 흐름을 이루었다고 보면, 이제는 고객의 변화무쌍한 요구에 기존 서비스 제공 흐름을 통해 대응하기란 쉽지 않기에 고객의 요구를 직접 특화된 서비스로 제공하고 (그것도 거의 실시간으로) 빠른 피드백을 받으려는 욕구가 강해졌습니다. 자동차 업계에서는 고객들이 자신만의 차량을 가지기를 원하는 욕구로 인해서 한 차종에 대해 다양한 색상이나 추가 옵션을 선택하게끔 하여 차량을 제공하기도 하며, 통신업계는 하루가 멀다하고 다양한 요금제들이 쏟아져나오고 있습니다. IT 서비스 역시 이러한 요구를 대응할 수 있는 개념들이 나타나기 시작했으며, 이를 Software as service 라고 합니다.
IaaS(Infrastructure-as-a-Service)는 사용자가 필요한 인프라(가상머신, 저장소, 네트워크 등)를 거의 실시간으로 확장하거나 축소가 가능하도록 하며, PaaS(Platform-as-a-Service)는 버튼 몇번 만으로도 사용자가 원하는 DBMS, 컨테이너 등을 바로 만들 수 있도록 합니다. 또한, SaaS(Software-as-a-Service)는 사용자가 만든 소프트웨어를 바로 탑재하여 서비스를 제공할 수 있게 만듭니다. 이러한 서비스들은 고객의 특화된 요구에 따라 사용량을 기준으로 계측되어 정산하도록 되어있으면서 유지보수에 대한 부담을 줄여줄 수 있습니다. 그러나, 이는 어디까지나 특정 플랫폼을 기반으로 하는 특화된 경우에 한해서입니다. 예를 들어, 스마트폰에서 제공하는 앱들을 통해 사용자가 서비스를 받도록 만드려면 해당 스마트폰의 앱에 맞는 플랫폼의 형태로 SW를 개발할 수 밖에 없습니다. 기업에서는 이러한 형태의 서비스들을 제공하여 사용자들이 이를 통해 업무를 보게끔 할 수도 있지만, 이는 여러가지 차원에서 기업의 IT 자원을 노출시킬 수 밖에 없다는 한계가 분명 있습니다.
기업은 자신만의 개발/운영 환경을 마련하고 이를 유지하고는 있지만, 이는 제품을 만드는 측과 서비스를 제공/유지하려는 측을 이분화시켜 만들기 때문에 Software as service 개념을 적용하는데 많은 제약을 가지고 있습니다. 이를 극복하려는 방식이 Devops(Development와 Operation의 합성어)이며[참조 5], 최근의 신생 IT 기업(스타업 기업)들은 적은 인원으로 유지보수를 하며, 더욱 많은 고객들에게 자신들의 입맛에 맞는 서비스를 제공하려는 시도와 노력들이 이루어지고 있습니다. 이를 실현하기는 과정에서 CI가 필요하며, 궁극적으로는 CD(Continuous Delivery)라는 개념을 이끌어내고 있습니다. 이상적으로 가능하지만, 현실적으로는 넘어야할 장애나 한계가 있습니다. 그럼에도 불구하고 이러한 노력을 하는 이유는 고객의 요구에 부응하는 IT 서비스를 제공하려는 이익이 더 크기 때문입니다.
참조
- Lessons Learned in Managing Object-Oriented Development, 1993, pp. 43-55, Matthew Pittman, http://www.computer.org/portal/web/csdl/doi?doc=doi%2F10.1109%2F52.207226
- Daily Build and Smoke Test, IEEE Software, Vol. 13, No. 4, July 1996, Steve McConnell, http://www.stevemcconnell.com/ieeesoftware/bp04.htm
- 소프트웨어 회귀 (Software regression), http://en.wikipedia.org/wiki/Software_regression
- 메트릭 기반의 소프트웨어 유지보수 노력 산정 모델에 관한 실증적 연구, 2013.12, 손문일
- Cloud and DevOps: A Marriage Made in Heaven, 2013, Jeff Sussna, http://www.infoq.com/articles/cloud-and-devops