종속 항목 관리

문제 신고 소스 보기 1박 · 7.2 · 7.1 · 7.0 · 6.5 · 6.4

이전 페이지를 살펴보면 한 가지 주제가 계속 반복됩니다. 자체 코드는 상당히 간단하지만 종속 항목을 관리하는 것은 더 어려워집니다 온갖 종류의 종속 항목이 있습니다. 작업에 종속되지 않도록 해야 합니다 (예: '버전을 온전히 처리되어야 하고 때로는 아티팩트에 종속된 문제 (예: 최신 버전의 컴퓨터 비전 라이브러리를 설치해야 함'). 때로는 코드베이스의 다른 부분에 내부 종속 항목이 있습니다. 다른 팀이 소유한 코드나 데이터에 외부 종속 항목이 있는 경우가 있습니다. 이러한 권한을 부여할 수 있습니다. 그러나 어쨌든 "나는 '필요할 것 같아서'라는 생각은 '이거 먹고 싶은데?'라는 생각이 종속 항목 관리는 아마도 가장 중요한 부분일 겁니다 빌드 시스템의 기본적인 작업을 담당합니다

모듈 및 종속 항목 처리

Bazel과 같은 아티팩트 기반 빌드 시스템을 사용하는 프로젝트는 집합으로 나뉩니다. 모듈 중 BUILD를 통해 서로에 대한 종속 항목을 표현하는 모듈 할 수 있습니다. 이러한 모듈과 종속 항목을 올바르게 구성하면 빌드 시스템의 성능과 빌드에 필요한 작업량 모두에 할 수 있습니다

세분화된 모듈 및 1:1:1 규칙 사용

아티팩트 기반 빌드를 구성할 때 가장 먼저 제기되는 질문은 개별 모듈에 포함되어야 하는 기능의 양을 결정합니다. Bazel에서 모듈은 다음과 같이 빌드 가능한 단위를 지정하는 대상으로 표현됩니다. java_library 또는 go_binary입니다. 한 극단으로는 전체 프로젝트가 하나의 BUILD 파일을 루트에 배치하여 단일 모듈에 포함되는지 해당 프로젝트의 모든 소스 파일을 재귀적으로 결합하는 과정입니다. 다른 쪽 극단적으로 거의 모든 소스 파일을 자체 모듈로 만들 수 있으므로 각 파일이 종속된 모든 파일을 BUILD 파일에 나열하도록 요구합니다.

대부분의 프로젝트는 이러한 극단적인 상황 사이에 있으며, 선택에는 성능과 유지관리 사이에서 절충점을 찾아야 합니다. 단일 모듈을 사용하여 즉, 전체 프로젝트에서 BUILD 파일을 터치할 필요가 없다는 의미일 수 있습니다. 빌드 시스템이 반드시 외부 종속 항목을 항상 한 번에 전체 프로젝트를 빌드합니다 즉, 한 번에 여러 개의 빌드의 일부를 병렬 처리 또는 배포하거나 확인할 수 있습니다 이와 반대로 파일당 단일 모듈은 빌드 시스템입니다. 빌드의 캐싱 및 예약 단계에서 최대 유연성이 있지만 엔지니어가 종속 항목 목록을 유지관리하는 데 더 많은 노력을 들여야 어떤 파일이 어느 것을 참조하는지 변경합니다.

정확한 세부사항은 언어에 따라 다르며 종종 Google은 비교적 크기가 작은 모듈을 선호하는 경향이 있음 일반적으로 작업 기반 빌드 시스템에서 작성합니다 일반적인 프로덕션 바이너리는 Google은 종종 수만 개의 표적과 적당한 규모의 팀 코드베이스 내에 수백 개의 타겟을 소유할 수 있습니다. 언어 기본적으로 각 디렉터리는 패키징이라는 강력한 개념이 내장되어 있으며, 단일 패키지, 타겟, BUILD 파일 (또 다른 빌드 시스템인 Pants)을 포함합니다. 1:1:1 규칙이라고 합니다. 패키징이 취약한 언어 규칙은 BUILD 파일당 여러 타겟을 정의하는 경우가 많습니다.

소규모 빌드 대상의 이점은 실제로 대규모로 표시되기 시작합니다. 분산 빌드가 빨라지고 대상을 다시 빌드할 필요성이 줄어듭니다. 이러한 장점은 테스트가 진행되면 더욱 설득력이 있으며, 대상이 세분화되면 빌드 시스템이 훨씬 더 스마트하게 빌드되고 특정 테스트의 영향을 받을 수 있는 제한된 테스트 하위 집합만 실행 있습니다. Google은 더 적은 수의 광고를 사용할 때 얻을 수 있는 시스템적 이점을 믿기 때문에 Google은 이러한 단점을 완화하는 데 몇 가지 진전을 이루었습니다. 개발자에게 부담을 주지 않도록 BUILD 파일을 자동으로 관리하는 도구를 제공합니다.

이러한 도구 중 일부(예: buildifier, buildozer)는 다음에서 사용할 수 있습니다. Bazel buildtools 디렉터리

모듈 가시성 최소화

Bazel 및 기타 빌드 시스템을 사용하면 각 대상이 가시성을 지정할 수 있습니다 속성이 있어야 합니다. 비공개 표적 자체 BUILD 파일 내에서만 참조할 수 있습니다. 이 표적은 더 광범위한 명시적으로 정의된 BUILD 파일 목록의 타겟에 대한 공개 상태 작업공간의 모든 표적에 대해 공개 가시성을 확보합니다.

대부분의 프로그래밍 언어와 마찬가지로 일반적으로 공개 상태를 최소화하는 것이 가장 좋습니다. 개선할 수 있습니다 일반적으로 Google 팀은 다음과 같은 경우에만 타겟을 공개합니다. 이러한 대상은 Google의 모든 팀에서 사용할 수 있는 널리 사용되는 라이브러리를 나타냅니다. 코드를 사용하기 전에 다른 사람의 협조가 필요한 팀은 고객 대상의 허용 목록을 대상의 공개 상태로 유지합니다. 각 팀의 내부 구현 타겟은 디렉터리로만 제한됩니다. 및 대부분의 BUILD 파일에는 팀에서 소유하지 않은 비공개입니다.

종속 항목 관리

모듈은 서로 참조할 수 있어야 합니다. 시스템의 단점을 세분화된 모듈로 세분화할 수 있다는 것은 종속 항목을 관리해야 한다는 점입니다. (도구가 이를 자동화하는 데 도움이 될 수 있음) 표현하기 종속 항목은 일반적으로 BUILD 파일에 있는 콘텐츠의 대부분이 됩니다.

내부 종속 항목

세분화된 모듈로 분류된 대규모 프로젝트에서 대부분의 종속 항목은 내부에 있을 가능성이 높습니다. 즉, 동일한 클러스터에 정의되고 빌드된 다른 타겟에 소스 저장소입니다 내부 종속 항목은 사전 빌드된 아티팩트로 다운로드되는 대신 소스에서 빌드되는 것을 실행할 수 있습니다 이것은 또한 포드에 대한 '버전'의 개념이 내부 종속 항목 - 대상과 모든 내부 종속 항목은 항상 리포지토리의 동일한 커밋/버전에서 빌드됩니다. 반드시 해야 할 한 가지 문제는 내부 종속 항목과 관련하여 신중하게 처리해야 하는 것은 전이 종속 항목 (그림 1) 타겟 A가 타겟 B에 종속되어 있다고 가정해 보겠습니다 공통 라이브러리 타겟 C에 종속됩니다. A를 타겟팅해야 클래스를 사용할 수 있음 아니면 대상 C에서 정의되나요?

전이 종속 항목

그림 1. 전이 종속 항목

기본 도구에 관한 한, 여기에는 아무런 문제가 없습니다. 둘 다 B와 C는 빌드될 때 대상 A에 링크되므로 C는 A에 알려져 있습니다. Bazel은 수년 동안 이것을 허용했지만, Google이 성장함에 따라 문제가 관찰되기 시작했습니다 B가 리팩터링되어 더 이상 C에 의존해야 했습니다. C에 대한 B의 종속 항목이 제거되면 B의 종속 항목을 통해 C를 사용한 타겟이 중단됩니다. 효과적으로, 표적의 종속 항목이 공개 계약의 일부가 되었으며 변경할 수 있습니다. 즉, 시간이 지남에 따라 종속 항목이 누적되고 Google 점차 느려지기 시작했습니다

Google은 결국 '엄격한 전이적' 종속 항목 모드'를 요청하는 것입니다. 이 모드에서 Bazel은 대상이 참조하지 않고 기호를 참조할 수 있으며, 그렇게 하면 자동으로 삽입하는데 사용할 수 있는 셸 명령과 종속됩니다. 이 변경사항을 Google의 전체 코드베이스와 수백만 개의 빌드 대상을 리팩터링하여 수년간의 노력이 필요했지만 그만한 가치가 있었습니다. 우리 빌드는 타겟에 불필요한 종속 항목이 적기 때문에 훨씬 더 빨라졌습니다. 엔지니어는 애플리케이션 코드에 대한 걱정 없이 그것에 의존하는 표적을 파괴하는 것에 대해 이야기했습니다.

늘 그렇듯이 엄격한 전이 종속 항목을 적용하면 장단점이 있습니다. 덕분에 자주 사용되는 라이브러리가 나열되어야 하므로 빌드 파일이 더 상세해집니다. 우연히 가져오는 것이 아니라 많은 곳에서 명시적으로 가져오는 것이 좋으며, BUILD 파일에 종속 항목을 추가하는 데 더 많은 노력을 들여야 합니다. 이후 이러한 반복 업무를 줄여주기 때문에 개발자 없이 종속 항목을 BUILD 파일에 추가 개입하지 않습니다. 그러나 이러한 도구가 없더라도, Google은 코드베이스가 확장되므로 그만한 가치가 있습니다. BUILD 파일에 종속 항목을 명시적으로 추가합니다. 일회성 비용이지만 암시적 전이 종속 항목을 처리할 경우 계속 문제가 발생할 수 있습니다 바젤 엄격한 전이 종속 항목 적용 기본적으로 사용됩니다

외부 종속 항목

종속 항목이 내부가 아닌 경우 외부 종속 항목이어야 합니다. 외부 종속 항목은 빌드 시스템 외부에서 빌드 및 저장된 아티팩트에 대한 것입니다. 이 종속 항목을 아티팩트 저장소에서 직접 가져옵니다 (일반적으로 액세스 가능). 소스에서 빌드되지 않고 있는 그대로 사용됩니다. 다음 중 하나 외부 종속 항목과 내부 종속 항목의 가장 큰 차이점은 외부 종속 항목에 버전이 있고 이러한 버전은 외부 종속 항목과 상관없이 프로젝트의 소스 코드를 저장하는 데 사용됩니다

종속 항목 자동 관리와 수동 종속 항목 관리 비교

빌드 시스템에서 외부 종속 항목의 버전을 관리할 수 있음 선택할 수 있습니다 수동으로 관리하는 경우 buildfile은 아티팩트 저장소에서 다운로드하려는 버전을 명시적으로 나열한 것입니다. 종종 다음과 같이 의미론적 버전 문자열을 사용합니다. 1.1.4 형식으로 입력하세요. 자동으로 관리되는 경우 소스 파일은 빌드 시스템이 항상 최신 버전을 다운로드합니다. 대상 예를 들어 Gradle은 종속 항목 버전을 '1.+'로 선언하여 종속 항목의 모든 부 버전 또는 패치 버전이 허용될 수 있는 한 메이저 버전은 1입니다

자동 관리형 종속 항목은 소규모 프로젝트에 편리할 수 있지만 보통 규모가 크지 않은 프로젝트에서 재해를 일으킬 수 있는 엔지니어가 둘 이상 되는 것입니다. 자동 확장 시스템의 문제는 관리형 종속 항목 버전을 사용하면 버전이 배포되는 시점을 제어할 수 이(가) 업데이트되었습니다. 외부 서드파티가 수익을 창출하는 것을 방지할 수 있는 방법은 없습니다. 의미론적 버전 관리를 사용한다고 주장하는 경우에도) 어떤 날은 잘 작동하다가 다음 날엔 고장날 수 있으며 변경된 것을 쉽게 감지할 수 있는 방법이 없습니다. 작동 상태로 롤백할 수 있습니다 빌드가 중단되지 않더라도 추적이 불가능한 미묘한 동작이나 실적 변동일 수 있습니다.

반면에 수동으로 관리하는 종속 항목에는 소스를 변경해야 하므로 쉽게 검색 및 롤백될 수 있으며 이전 버전의 저장소를 확인하여 이전 종속 항목으로 빌드합니다. Bazel을 사용하려면 모든 종속 항목의 버전을 수동으로 지정해야 합니다. 짝수 중간 규모라면 수동 버전 관리의 오버헤드는 충분히 그만한 가치가 있습니다. 안정성이 향상됩니다.

단일 버전 규칙

라이브러리의 다른 버전은 일반적으로 다른 아티팩트로 표현됩니다. 이론상 동일한 외부 버전이 서로 다른 버전이 종속 항목을 서로 다른 이름으로 빌드 시스템에서 선언할 수 없습니다. 이렇게 하면 각 대상은 원하는 종속 항목 버전을 선택할 수 있습니다. 사용합니다 이것은 실제로 많은 문제를 발생시키므로 Google은 엄격한 단일 버전 규칙 코드베이스에 있는 모든 서드 파티 종속 항목에 적용됩니다.

여러 버전을 허용할 때 발생하는 가장 큰 문제는 다이아몬드 종속 항목임 있습니다. 타겟 A가 타겟 B와 외부 서버의 v1에 종속된다고 가정하면 있습니다. 타겟 B가 나중에 리팩터링되어 동일한 v2의 종속 항목을 추가하는 경우 외부 라이브러리, 이제 타겟 A가 2에 암시적으로 의존하므로 타겟 A가 중단됩니다. 여러 버전을 생성할 수 있습니다 사실, 페이지에 태그를 추가하는 것은 대상에서 여러 버전이 있는 서드 파티 라이브러리로의 새로운 종속 항목 왜냐하면 해당 타겟의 사용자가 이미 다른 목표에 있습니다. 단일 버전 규칙을 따르다 보면 이러한 충돌이 대상은 서드 파티 라이브러리, 기존 종속 항목에 대한 종속 항목을 추가합니다. 이미 같은 버전을 사용하게 될 것이므로 행복하게 공존할 수 있습니다.

전이 외부 종속 항목

외부 종속 항목의 전이 종속 항목을 처리하는 방법은 다음과 같습니다. 특히 어렵습니다 Maven Central과 같은 많은 아티팩트 저장소는 다른 아티팩트의 특정 버전에 대한 종속 항목을 변경할 수 있습니다 Maven 또는 Gradle과 같은 빌드 도구는 종종 각 버전을 재귀적으로 기본적으로 전이 종속 항목이 포함됩니다. 즉, 단일 종속 항목을 프로젝트에서 수십 개의 아티팩트가 합계입니다.

이는 매우 편리합니다. 새 라이브러리에 종속 항목을 추가할 때 라이브러리의 전이 종속 항목을 각각 추적해야 하는 큰 어려움이 있습니다. 모두 수동으로 추가할 수 있습니다 하지만 큰 단점도 있습니다. 동일한 서드 파티 라이브러리의 서로 다른 버전에 종속될 수 있습니다. 전략은 반드시 단일 버전 규칙을 위반하고 다이아몬드로 이끄는 것입니다. 종속 항목 문제일 수 있습니다. 타겟이 같은 종속 항목의 다른 버전이 있다면 어떤 버전을 사용하게 될지 get입니다. 즉, 외부 종속 항목을 업데이트하면 겉으로 보기에는 새 버전이 새 버전을 가져오기 시작하면 코드베이스 전체에서 버전이 충돌할 수 있음을 의미합니다

따라서 Bazel은 전이 종속 항목을 자동으로 다운로드하지 않습니다. 안타깝게도 만병통치약은 없습니다. Bazel의 대안은 해당 저장소의 모든 외부 저장소가 나열된 종속 항목 및 해당 종속 항목에 사용되는 명시적 버전을 저장소 다행히 Bazel은 코드를 자동으로 생성할 수 있는 Maven 집합의 전이 종속 항목이 포함된 파일을 생성합니다. 아티팩트를 생성합니다. 이 도구를 한 번 실행하여 초기 WORKSPACE 파일을 생성할 수 있습니다. 해당 파일을 수동으로 업데이트하여 버전을 조정할 수 있습니다. 지정할 수도 있습니다

다시 한번 말씀드리지만, 선택은 편의성과 확장성 중 하나입니다. S 사이즈 프로젝트에서 전이 종속 항목 관리에 대해 걱정할 필요가 없는 것을 선호할 수 있음 자동 트랜스젠더를 사용하지 않아도 될 수 있습니다. 종속 항목이 포함됩니다 이 전략은 조직이 관심을 갖기 때문에 늘어나고 충돌과 예상치 못한 결과가 점점 더 합니다. 규모가 더 큰 경우 종속 항목을 수동으로 관리하는 비용이 훨씬 많이 듭니다. 자동 종속 항목으로 인해 발생하는 문제를 처리하는 비용보다 저렴함 관리할 수 있습니다

외부 종속 항목을 사용하여 빌드 결과 캐싱

외부 종속 항목은 대체로 서드 파티에서 제공합니다. 안정화된 버전의 라이브러리를 제공할 수 있습니다. 다소 유용함 조직은 또한 자체 코드 중 일부를 사용하여 다른 코드 조각이 이 아티팩트를 서드 파티가 아닌 더 효율적입니다 이렇게 하면 이론적으로 아티팩트가 생성된 경우 빌드 속도를 높일 수 빌드는 느리지만 다운로드도 빠릅니다

그러나 이는 많은 오버헤드와 복잡성을 초래합니다. 이러한 아티팩트 각각을 빌드하고 이를 최신 상태로 유지해야 하며, 클라이언트는 최신 버전으로 업데이트합니다. 또한 디버깅이 훨씬 더 어려워집니다. 시스템의 나머지 부분이 빌드될 수 있는 더 이상 소스 트리의 일관된 뷰가 없습니다.

빌드하는 데 시간이 오래 걸리는 아티팩트 문제를 해결하는 더 좋은 방법은 원격 캐싱을 지원하는 빌드 시스템을 사용해야 합니다. 이러한 빌드 시스템이 모든 빌드의 결과 아티팩트를 특정 위치에 저장 엔지니어가 공유하는 아티팩트이므로 개발자가 빌드 시스템은 자동으로 애플리케이션을 빌드하는 대신 사용할 수 있습니다 이렇게 하면 아티팩트에 직접 종속되도록 하면서 빌드가 항상 동일한 소스에서 빌드된 것처럼 일관성이 있어야 합니다. 이것은 Google 내부에서 사용하는 전략이며, Bazel은 Google 내부에서 사용하는 있습니다.

외부 종속 항목의 보안 및 안정성

서드 파티 소스의 아티팩트에 의존하는 것은 본질적으로 위험합니다. 여기에는 가용성 위험은 여전히 제3자 소스 (아티팩트 저장소 등)가 다운로드할 수 없는 경우에는 전체 빌드가 중단될 수도 있기 때문입니다. 외부 종속 항목이 포함되어 있습니다 또한 보안 위험이 있습니다. 서드 파티 시스템이 참조된 기존 IP 주소를 대체하여 임의의 코드를 삽입할 수 있도록 하는 코드 조각입니다. 넣으세요. 이 두 가지 문제는 개발자가 생성한 아티팩트를 미러링하여 제어하는 서버에 종속되며 빌드 시스템의 액세스를 차단하여 Maven Central과 같은 서드 파티 아티팩트 저장소에 적합합니다 단점은 이러한 미러는 유지관리에 노력과 리소스가 필요하므로 프로젝트의 규모에 따라 달라질 수 있습니다 또한 보안 문제는 각 객체의 해시를 요구하여 약간의 오버헤드로 완전히 방지할 수 있습니다. 소스 저장소에 지정된 서드 파티 아티팩트로 인해 빌드가 오류가 발생할 수 있습니다 또 다른 대안은 프로젝트의 종속 항목을 벤더링하는 것입니다. 프로젝트에서 종속 항목을 공급업체의 종속 항목과 함께 소스 제어에 체크인하여 프로젝트의 소스 코드를 소스 또는 바이너리로 제공합니다. 이는 사실상 프로젝트의 모든 외부 종속 항목이 내부 종속 항목과 함께 종속 항목이 포함됩니다 Google은 이 접근 방식을 내부적으로 사용하여 모든 서드 파티를 Google 전체에서 참조되는 라이브러리를 루트의 third_party 디렉터리에 저장합니다. 소스 트리의 한 유형입니다. 하지만 이 방법은 Google이 소스 제어 시스템은 대규모 모노레포를 처리하도록 맞춤 구축되었기 때문에 벤더링이 모든 조직에 옵션이 있는 것은 아닙니다.