유지보수자에게 필요한 포지는 클라이언트 기능보다 프로젝트 간 조정, 의존성 가시성, 다운스트림 테스트, 포크 네트워크, 더 안전한 CI 기본값을 제공해야 한다는 제안.
Mat Duggan은 GitHub 대체품에서 바라는 점을 정리해 두었고, 키보드 앞에 앉아 있는 사람이 기준이라면 그 목록은 꽤 타당하다. 스택형 PR, 푸시 전 피드백, 오프라인 리뷰, 느긋한 히스토리, 단계별 승인 상태. 그 글을 읽으면서 나는 거의 모든 항목이 클라이언트 문제이고, 클라이언트는 이미 그것을 해결하고 있다는 점을 계속 보게 됐다. Jujutsu는 어떤 웹 UI보다도 스택형 변경을 더 잘 다룬다. 리뷰는 에디터 안으로 옮겨가고 있다. 커밋 전 피드백은 파일이 있는 당신의 머신에서 실행되어야 한다.
내가 포지에 바라는 것은 클라이언트로 옮길 수 없는 것들이다. 왜냐하면 그것들은 둘 이상의 당사자가 관련되기 때문이다. 누가 당신에게 의존하는지, 당신이 누구에게 의존하는지, 3년 전에 포크했던 그 프로젝트에는 무슨 일이 있었는지, 원래 프로젝트가 조용해졌을 때 활발한 개발이 어디로 옮겨갔는지. 이런 것들의 거의 대부분은 단일 저장소 안에서 일어나지 않는다. 그것들은 저장소 사이의 관계에서 일어나며, GitHub는 그 부분을 수년째 거의 건드리지 않았고, 대체품을 자처하는 어느 쪽도 그 부분을 이야기하지 않고 있다.
그래서 Mat의 목록에 대한 내 버전은 대부분 프로젝트 사이의 조정에 관한 것이다. GitHub가 실제로 모델링하는 두 저장소 사이의 유일한 관계는 포크뿐인데, 2008년에는 다른 사람의 코드를 사용하는 방식이 그것을 포크하고 풀 리퀘스트를 보내는 것이었기 때문이다. 2026년에 다른 사람의 코드를 사용하는 방식은 매니페스트에 한 줄을 추가하는 것이고, 포지에는 그것에 대응하는 객체가 없다. 포지는 의존성을 Dependabot PR을 생성하는 어떤 것으로만 알고 있다. 나는 의존성도 포크가 받았던 것과 같은 대우를 받았으면 한다.
내가 라이브러리의 릴리스를 준비할 때, 포지가 내 테스트 스위트를 실행한 다음, 나에게 의존하는 프로젝트들 중 일부를 체크아웃해서 내 변경 사항에 대해 그들의 테스트 스위트도 실행해 주기를 바란다. Rust는 이것을 crater run이라고 부르며 컴파일러에만 사용한다. 이 기능은 모든 릴리스 PR에 있는 버튼이어야 한다. 지금은 태그가 푸시된 뒤에야 내가 수천 개의 다운스트림을 망가뜨렸다는 사실을 수천 개의 격앙된 티켓을 통해 알게 되는데, 포지는 의존성 그래프와 계산 자원을 모두 가진 유일한 곳이므로 그 전에 알려줄 수 있다. 사실 그 티켓들은 좋은 결과다. 더 나쁜 경우는 그들이 예전 버전을 고정해 두고 다시는 업그레이드하지 않는 것이다.
내가 다음 메이저 버전에서 더 이상 권장되지 않는 함수를 제거할 계획이라면, 오늘날 나는 그것을 아무도 실제로 깨지기 전까지 읽지 않는 변경 로그에 적거나, Seth Larson이 Python에 대해 지적했듯이 대부분 사람에게도 도달하지 않는 런타임 사용 중단 경고를 내보낸다. 나는 내 패키지가 lockfile에 들어 있는 모든 프로젝트가 기본적으로 구독하는 피드에 그것을 게시하고 싶다. 같은 채널로 “이 프로젝트는 관리자를 찾고 있습니다”, “우리는 저장소를 옮기고 있습니다”, “CVE가 있으며, 여기 수정된 버전이 있습니다”도 전달된다. GitHub는 2008년에 홈페이지에 “social coding”을 내걸었지만, 그 뒤에 구축한 소셜 계층은 사람을 팔로우하는 방식이었다. 실제로 실행하는 코드를 따라가고, lockfile로 자동 구독되는 버전이야말로 유용할 것이다.
프로젝트가 조용해지면 커뮤니티의 반응은 보통 모두가 그것을 각자 패치하거나 포크하는 것이다. 그러다 그 포크들 중 하나가 결국 탄력을 얻고, 긴 꼬리를 이루는 사용자들은 입소문과 고정된 이슈를 통해 천천히 그것을 발견한다. 포지는 이 모든 것을 볼 수 있다. 포지는 업스트림이 18개월 동안 머지하지 않았다는 것과, 세 개의 포크에 활발한 릴리스 태그와 유입되는 스타가 있다는 것을 안다. 모든 사용자가 각자 고고학 발굴을 하게 내버려 두는 대신 원래 저장소 페이지에 그 정보를 보여주고, 포크의 유지보수자들이 자신들을 프로젝트의 연속선상에 있다고 여긴다는 신호를 보낼 수 있게 하자. GitHub의 네트워크 그래프는 2010년 이래로 같은 읽기 어려운 스파게티를 보여주고 있을 뿐이고, 훨씬 더 나은 버전은 분명히 만들어지기를 기다리고 있다.
포지가 의존성을 진지하게 다루기 시작하면 패키지 레지스트리 프런트엔드가 하는 일과 겹치기 시작하고, 나는 몇 주 전에 사용자가 직접 그런 것을 설계하게 되면 무엇을 만드는지에 대한 목록으로 npmx 기능 목록을 정리해 두었다. 그중 몇 가지는 패키지 페이지 못지않게 저장소 페이지에도 속한다.
나는 이미 이것에 대해 두 번 썼다. 한 번은 lockfile 없는 패키지 관리자 같은 Actions에 대해, 또 한 번은 모두 워크플로 파일로 거슬러 올라가는 공급망 사고의 연속에 대해였다. 그래서 여기서 반복하지는 않겠다. 짧게 말하면, 포지가 호스팅하는 CI는 이제 대부분의 오픈 소스 아티팩트가 빌드되고 배포되는 곳이며, 기본값은 비공개 엔터프라이즈 저장소를 위해 설계되었다. 새로운 포지를 만드는 사람은 새로운 기본값을 고를 수 있다. 고정된 actions, 격리된 캐시, 낯선 사람이 트리거하는 워크플로는 아예 없음.
모든 포지의 모든 CI 실행은 같은 공개 레지스트리들에서 같은 패키지 집합을 다운로드하는 것으로 시작하고, 그 레지스트리들은 대부분 기부금으로 대역폭 비용을 감당하는 비영리 단체가 운영한다. npm, PyPI, RubyGems, crates.io 등 앞에 포지가 운영하는 캐싱 프록시를 두고, 그것을 기본적으로 CI 러너에 연결한다면 그 인프라의 부하를 엄청나게 덜어 줄 수 있고 레지스트리가 한나절 정도 상태가 좋지 않을 때에도 모두의 빌드가 계속 작동하게 할 수 있다. git-pkgs/proxy는 그 아이디어를 구현한 한 사례다. 포지는 이미 lockfile을 가지고 있으니, 무엇을 미리 워밍업해야 하는지도 알고 있다.
의존성 그래프와는 아무 관련이 없지만, 목록을 만드는 김에 하나 더 말하자면, 기능 요청은 문제가 아니고 질문도 문제가 아니며, 유지보수자의 받은편지함에 들어오는 모든 것을 “issue”라고 부르는 것은 누가 한마디를 입력하기도 전에 대화의 온도를 정해 버린다. 나는 이것이 인기 있는 프로젝트를 운영할 때 깔리는 전반적인 적대감에 사람들이 생각하는 것보다 더 크게 기여한다고 본다. “티켓”은 지루하고 중립적이며, 바로 그 점이 중요하다.
나는 AI, federation, enterprise permissions는 언급하지 않았다. 나는 지금 AI 이야기에 들어가고 싶지 않다. federation에 대해서는 전에 쓴 적이 있고, 어려운 부분은 이름짓기인데, 여기서 내가 그 문제를 해결할 수 있는 척하지는 않겠다. 그리고 나는 엔터프라이즈 기능에는 그냥 관심이 없다. 당신이 좋아하는 주제가 여기 없다면 아마 그 셋 중 하나일 것이다.
유지보수자에게는 누가 자신들의 다운스트림인지 알아내고, 문제가 생기기 전에 그 사람들과 이야기하고, 고립된 채가 아니라 프로젝트 경계를 넘어서 협업할 수 있도록 돕는 도구가 필요하다. 의존성 트리가 더 깊어질수록 이 일의 그 측면은 해마다 더 어려워졌지만, 그것을 도와줄 새로운 도구는 거의 없었다. 내부 코드베이스에는 알 수 없는 수천 개의 다운스트림이 없기 때문에 이런 것들에 대한 엔터프라이즈 버전도 존재하지 않으며, 따라서 혜택을 보는 유일한 사람들은 거대한 공개 의존 그래프를 떠안고도 예산이 없는 오픈 소스 유지보수자들뿐이다. 아마 그래서 GitHub가 이것을 만들지 않았을 것이다. 새로운 포지를 만드는 사람이라면 그 지점에서 시작할 수 있다.