빌드 시스템을 사용해야 하는 이유

이 페이지에서는 빌드 시스템의 정의와 기능, 빌드 시스템을 사용해야 하는 이유, 조직이 확장되기 시작할 때 컴파일러와 빌드 스크립트가 최선의 선택이 아닌 이유를 설명합니다. 이 가이드는 빌드 시스템에 대한 경험이 많지 않은 개발자를 대상으로 합니다.

빌드 시스템이란 무엇인가요?

기본적으로 모든 빌드 시스템의 목적은 간단합니다. 엔지니어가 작성한 소스 코드를 머신에서 읽을 수 있는 실행 가능한 바이너리로 변환하는 것입니다. 빌드 시스템은 인간이 작성한 코드만을 위한 것이 아니라, 머신이 테스트용 또는 프로덕션 출시용 빌드를 자동으로 생성할 수 있도록 해 줍니다. 엔지니어가 수천 명인 조직에서는 대부분의 빌드가 엔지니어가 직접 트리거하지 않고 자동으로 트리거되는 것이 일반적입니다.

그냥 컴파일러를 사용하면 안 되나요?

빌드 시스템의 필요성은 곧바로 명확하지 않을 수도 있습니다. 대부분의 엔지니어는 코딩을 배우는 동안 빌드 시스템을 사용하지 않습니다. 대부분 명령줄에서 직접 gcc 또는 javac와 같은 도구를 호출하거나 통합 개발 환경 (IDE)에서 이와 동등한 도구를 호출하는 것으로 시작합니다. 모든 소스 코드가 동일한 디렉터리에 있는 한 다음과 같은 명령어가 제대로 작동합니다.

javac *.java

이 명령어는 자바 컴파일러에 현재 디렉터리의 모든 자바 소스 파일을 바이너리 클래스 파일로 변환하도록 지시합니다. 가장 간단한 경우에는 이것만 있으면 됩니다.

그러나 코드가 확장되는 즉시 복잡성이 발생합니다. javac는 현재 디렉터리의 하위 디렉터리에서 가져올 코드를 찾을 수 있을 만큼 지능적입니다. 그러나 파일 시스템의 다른 부분 (여러 프로젝트에서 공유하는 라이브러리)에 저장된 코드는 찾을 방법이 없습니다. 또한 Java 코드를 빌드하는 방법만 알고 있습니다. 대규모 시스템은 다양한 프로그래밍 언어로 작성된 여러 조각을 이러한 부분 사이에 종속 항목으로 포함하는 경우가 많습니다. 즉, 단일 언어의 컴파일러가 전체 시스템을 빌드할 수 없음을 의미합니다.

여러 언어나 여러 컴파일 단위의 코드를 처리하게 되면 더 이상 한 단계로 코드를 빌드할 수 없습니다. 이제 코드가 무엇에 의존하는지 평가하고 각 부분에 다른 도구 세트를 사용하여 올바른 순서로 이러한 요소를 빌드해야 합니다. 종속 항목이 변경되는 경우 비활성 바이너리에 의존하지 않도록 이 프로세스를 반복해야 합니다. 크기가 균등한 코드베이스의 경우 이 프로세스는 금방 지루하고 오류가 발생하기 쉽습니다.

또한 컴파일러는 자바에서 서드 파티 JAR 파일과 같은 외부 종속 항목을 처리하는 방법에 관해 전혀 알지 못합니다. 빌드 시스템이 없으면 인터넷에서 종속 항목을 다운로드하여 하드 드라이브의 lib 폴더에 고정한 다음 이 디렉터리에서 라이브러리를 읽도록 컴파일러를 구성하여 이를 관리할 수 있습니다. 시간이 지남에 따라 이러한 외부 종속 항목의 업데이트, 버전, 소스를 유지하기가 어려워집니다.

셸 스크립트는 어떨까요?

취미 프로젝트가 컴파일러만 사용하여 빌드할 수 있을 만큼 간단하게 시작하지만 앞에서 설명한 몇 가지 문제가 발생하기 시작했다고 가정해 보겠습니다. 빌드 시스템이 필요하지 않다고 생각하고 올바른 순서로 빌드하는 몇 가지 간단한 셸 스크립트를 사용하여 지루한 작업을 자동화할 수 있습니다. 한동안은 도움이 되지만 머지않아 더 많은 문제가 발생하기 시작합니다.

  • 그러면 번거로워집니다. 시스템이 더욱 복잡해짐에 따라 실제 코드처럼 빌드 스크립트 작업에 거의 많은 시간을 소비하기 시작합니다. 셸 스크립트를 디버깅하기가 매우 까다롭고 꿀팁이 겹쳐져서 계속 늘어나고 있습니다.

  • 속도가 느립니다. 실수로 오래된 라이브러리에 의존하지 않도록 하려면 실행할 때마다 빌드 스크립트에서 모든 종속 항목을 순서대로 빌드해야 합니다. 다시 빌드해야 하는 부분을 감지하는 로직을 추가하려고 하는데 이 방식은 매우 복잡하고 스크립트에서 오류가 발생하기 쉽습니다. 또는 매번 다시 빌드해야 하는 부분을 지정하는 것을 고려하고 있다면 다시 제곱합니다.

  • 좋은 소식입니다. 이제 출시를 위한 출시가 되었습니다. 최종 빌드를 위해 jar 명령어에 전달해야 하는 모든 인수를 파악하는 것이 좋습니다. 그리고 어떻게 업로드하고 중앙 저장소로 푸시해야 하는지 잊지 마세요. 문서 업데이트를 빌드 및 푸시하고 사용자에게 알림을 전송합니다. 음, 다른 스크립트가 필요한 것 같네요...

  • 큰일이에요! 하드 드라이브가 비정상 종료되며, 이제 전체 시스템을 다시 만들어야 합니다. 모든 소스 파일을 버전 제어에 유지할 만큼 똑똑했습니다. 하지만 다운로드한 라이브러리는 어떨까요? 모두 다시 찾아 처음 다운로드했을 때와 동일한 버전인지 확인할 수 있나요? 스크립트가 특정 위치에 설치되는 특정 도구에 의존할 수 있습니다. 동일한 환경을 복원하여 스크립트가 다시 작동하도록 할 수 있나요? 컴파일러를 제대로 작동하게 만들기 위해 오래전에 설정한 모든 환경 변수는 어떻게 되나요? 그런 다음 잊고 있었나요?

  • 이러한 문제에도 불구하고 프로젝트가 성공적이라서 더 많은 엔지니어를 고용할 수 있습니다. 이제 이전 문제가 발생하는 데 재난이 필요하지 않다는 것을 알게 되었습니다. 새로운 개발자가 팀에 합류할 때마다 동일한 고통스러운 부트스트랩 프로세스를 거쳐야 합니다. 최선을 다했음에도 불구하고 각 사용자의 시스템에는 약간의 차이가 있습니다. 종종 한 사람의 컴퓨터에서 작동하는 것이 다른 사람의 컴퓨터에서는 작동하지 않으며, 매번 차이점이 어디인지 알아내기 위해 디버깅 도구 경로 또는 라이브러리 버전을 몇 시간씩 걸리게 됩니다.

  • 빌드 시스템을 자동화해야 할지 결정합니다. 이론적으로는 새 컴퓨터를 구입하고 매일 밤 크론을 사용하여 빌드 스크립트를 실행하도록 설정하기만 하면 됩니다. 여전히 고통스러운 설정 프로세스를 거쳐야 하지만 지금은 인간의 뇌로 사소한 문제를 감지하고 해결할 수 있는 이점이 없습니다. 매일 아침에 들어서면 어제 개발자가 시스템에서 작동했지만 자동화된 빌드 시스템에서는 작동하지 않아 지난밤 빌드가 실패한 것을 확인할 수 있습니다. 해결 방법은 간단하지만 너무 자주 발생하여 이러한 간단한 수정사항을 발견하고 적용하는 데 매일 많은 시간을 소비하게 됩니다.

  • 프로젝트가 커질수록 빌드가 느려지고 느려집니다. 어느 날 빌드가 완료될 때까지 기다리는 동안 휴가 중인 동료의 유휴 데스크톱을 애도하면서 바라보면서 컴퓨팅 성능 낭비를 모두 활용할 방법이 있으면 좋겠다고 생각합니다.

규모라는 전형적인 문제에 직면했습니다. 최대 1~2주 동안 최대 200줄의 코드 작업을 하는 한 개발자의 경우 (지금까지 대학을 졸업한 주니어 개발자의 전체 경험일 수 있음) 컴파일러만 있으면 됩니다. 스크립트를 사용하면 훨씬 나아질 수 있습니다. 하지만 여러 개발자와 시스템 간에 조정이 필요한 경우, 완벽한 빌드 스크립트만으로는 충분하지 않습니다. 이러한 머신의 사소한 차이점을 고려하는 것이 매우 어려우기 때문입니다. 이 시점에서 이 간단한 접근 방식은 무너지고, 이제 실제 빌드 시스템에 투자해야 할 때입니다.