본문으로 건너뛰기

© 2026 Molayo

GeekNews헤드라인2026. 06. 12. 13:53

소프트웨어 재사용을 줄여라

요약

이 글은 소프트웨어의 의존성 관리 및 재사용성에 대한 다양한 관점을 논하며, 콘텐츠 해시 기반의 패키지 관리 시스템을 제안합니다. 이는 소스 코드를 벤더링하고 재사용 가능한 소프트웨어를 만드는 좋은 절충안으로 평가됩니다. 하지만 실제 구현 시 발생하는 복잡성과 기업 규모에 따른 정책적 한계점도 함께 지적합니다.

핵심 포인트

  • 콘텐츠 해시 기반 패키지 관리 방식은 의존성 관리에 효과적인 대안이 될 수 있습니다.
  • 의존성을 벤더링하는 것은 비용을 증가시키지만, 안정성을 높이는 장점이 있습니다.
  • 대규모 기업 환경에서는 기술적 해결책 외에 조직 규모와 정책적 결정이 중요합니다.

Zig 패키지 관리자는 꽤 괜찮은 절충안이라고 봄
모든 패키지가 콘텐츠 해시로 고정돼서 기본적으로 잠금 파일이 있는 셈이고, “상위 저장소가 갑자기 악성으로 바뀌는” 문제는 피하면서도 “상위 저장소가 사라지는” 문제는 남아 있음
다만 전역/로컬 캐시가 모두 있고 콘텐츠 해시 기반이라, 상위 저장소가 사라지면 로컬 사본의 tarball을 필요한 곳에 던져 넣으면 됨
“소스를 벤더링하기”와 “단순하고 재사용 가능한 소프트웨어” 사이의 좋은 절충으로 보임

그 방식을 모든 소프트웨어로 확장할 수도 있고 꽤 멋질 것 같음
모든 소스를 콘텐츠 주소 지정 저장소에 두고, 각 프로그램은 입력들의 해시를 바탕으로 해시하면 됨

대체로 동의하지만, 그 구성을 어떻게 공격할 수 있을지는 조금 궁금함
아마 잠금 파일을 수정하거나 해시 충돌을 찾아야 할 텐데, 둘 다 쉬워 보이진 않음
다만 cargo 생태계에 익숙하다 보니 완전히 마음에 들지는 않음. 의존성을 올리면 그 전이 의존성들도 별다른 말 없이 함께 올라가는 경향이 있고, 의미적 버전 범위에 맞는 다른 것들도 같이 바뀌기 때문임

“공급망 공격”이라고 하기엔, 제안과 대가가 있는 서명된 계약이 없으니 공급망은 아니라고 봄
별개로, 의존성이 아래에서 바뀌지 않게 보장한다는 관점에서는 해시가 들어간 잠금 파일이나 Go의 최소 버전 선택 방식이 의존성 벤더링과 동일함
벤더링에는 마찰이 생긴다는 차이는 이해하지만, 극단으로 가면 직접 구현하거나 더 나쁘게는 의존성을 즉흥 생성 코드로 만들게 되므로, 도메인 전문가가 작성하고 충분히 검증된 소프트웨어를 쓰는 편이 낫다고 봄
Facebook에서 이쪽 일을 했는데, 그곳의 서드파티 의존성 관리는 누구에게도 권하고 싶지 않음. 특정 Rust 크레이트의 직접 의존성은 fbsource 전체에서 의미적 버전이 호환되지 않는 버전이 동시에 최대 두 개까지만 허용됨. 의존성을 업데이트하려면 fbsource 전체를 업데이트하는 부담을 떠안아야 함
Facebook에는 맞는 방식일 수 있지만, 특별히 훌륭하거나 지속 가능하다고 보긴 어려움

궁금한데 왜 “최대 두 개”인지 모르겠음. 예전 버전에서 새 버전으로 점진적 마이그레이션을 하기 위해서인가?
“특별히 훌륭하거나 지속 가능하지 않다”는 건 정책 자체보다는 규모의 함수에 가깝다고 의심함. 여러 버전을 허용하면 또 다른 문제가 생기는데, TypeScript를 제외한 대부분의 현대 언어가 주로 또는 전적으로 명목적 타입을 쓰기 때문에, 깨지는 변경마다 “semver trick”을 쓰지 않으면 버전 간 타입 재사용이 막힘
Log4Shell 때는 버전이 많고 여러 곳에 흩어진 회사들이, 버전 수가 적거나 고정해 둔 회사들보다 업그레이드에 더 고생했던 기억이 뚜렷함

맞음, 그럼 의존성 공격이라고 부르면 되겠음 <3

The Third Networking Truth에 따르면 “충분한 추진력이 있으면 돼지도 잘 난다. 하지만 그것이 꼭 좋은 생각이라는 뜻은 아니다”
Google/Facebook 같은 곳에서 인용되는 많은 관행은 그 회사들이 충분한 추진력을 투입할 수 있기 때문에만 작동함
예를 들어 그런 곳 중 일부는 모노레포와 의존성 관련 선택을 지원하기 위해, 내가 다니는 회사 전체 인원보다 더 큰 팀을 붙이는 걸 알고 있음. 그들은 감당할 수 있지만, 우리 대부분은 감당하기 어려움

좋은 견해임. “모든 의존성을 벤더링하면 의존성을 쓰는 비용이 올라간다”는 점에 강하게 동의함
다만 libcurl을 복사해 붙여 넣지는 말아야 함. 대부분의 라이브러리에는 괜찮은 전략이지만, 적대적 입력을 다루는 C 프로그램에는 좋은 조언이 아님. 운영체제가 libcurl을 안전하게 유지하는 것보다 더 잘할 수는 없음
한 번도 생각 못 했던 점은 apt 같은 최종 사용자용 패키지 관리자가 먼저 나오고, 언어 수준 패키지 관리자가 나중에 나온 게 적어도 조금 이상하다는 것임
이게 실제로 많은 문제를 일으켰다고 봄. 2000년대 초반 rubygems를 보면 프로젝트별 관리가 아니라 시스템 전체 설치가 기본인 식으로 “Ruby용 apt”를 만들려 했던 게 꽤 명확함. 그 실수의 피해를 되돌리는 데 bundler를 추가하며 수십 년이 걸렸지만, 처음부터 프로젝트 격리 필요성을 인정했다면 bundler는 필요 없었을 것임
Python은 아직도 이 혼란을 수습 중이고, Perl도 아마 그럴 것 같지만 자세히는 모름

그러니까 한계는 있긴 한 셈임 :-) 정확히 어디에 선을 그을지가 어려울 뿐임
역사적으로 패키지 관리자는 원래 시스템을 빌드하는 방식이었고, 그런 시스템에는 여러 사용자, 데스크톱 환경, 함께 동작하는 많은 소프트웨어가 있었음
소프트웨어 빌드에는 시간과 메모리가 많이 들었고, 디스크와 RAM에 비해 소프트웨어가 아주 많았으니 라이브러리 재사용이 중요했음
웹앱이 부상하면서 중요한 컴퓨터 대부분은 평생 소수의 프로그램만 돌리는 서버가 됐고, 디스크와 RAM이 충분히 싸져서 코드 바이너리 크기는 덜 중요해짐
시스템을 만드는 도구들은 시대 변화에 그만큼 따라가지 못했고, 그래서 소프트웨어를 만드는 대부분의 사람은 공유 라이브러리가 많은 거대한 상호연결 시스템이 아니라 단일 프로그램을 잘 만드는 도구만 필요로 하게 됨
이 역사와 나란히 “C에는 제대로 된 모듈 시스템이 없다”는 흐름도 있지만, 여기서는 덜 중요함

틀릴 수도 있지만, 복사해 온 의존성에 버그가 있어도 스캐너가 감지하지 못하는 단점이 있을 것 같음
그렇다면 원래라면 알림을 받았을 잠재 문제가 조용히 남아 있을 수 있음

이런 스캐너들이 만들어내는 오탐 수를 보면 오히려 장점일 수도 있음
스캐너는 문제가 될 수 있는 것을 보여주는 데는 매우 유용하지만, 스캐너가 문제라고 생각했으나 실제로는 아닌 것을 고치느라 예정된 일을 갑자기 미루게 만들 때는 매우 골치 아픔

제안대로 소프트웨어에 모든 의존성을 포함하고, 상위 소스 관리를 git 저장소에 복사해 커밋하고, 수작업이 지겨우면 빌드 도구가 자동화하게 만들면, 결국 한 바퀴 돌아서 다시 서드파티 소프트웨어를 보지 않고 포함하는 셈 아닌가?

계속 읽어보면, 빌드 시스템에서 의미적 버전이나 “서로 다른 두 코드가 같게 동작해야 한다”는 개념을 버리고 모든 버전 번호를 서로 고유하고 무관한 것으로 다뤄도 같은 효과를 낼 수 있다고 함
하지만 그 방식은 의존성이 사라지거나 변조되는 문제, 또는 누군가 패키지 내용을 다른 방식으로 손대는 문제를 해결하지 못함. 최적화에 가깝고, 내 생각엔 성급한 최적화임. 언젠가 그렇게 갈 수는 있겠지만 시작점으로 삼으면 안 됨

AI 자동 생성 콘텐츠

본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0