Requests 3 모금, 비동기 지원 개발, 그리고 오픈소스 커뮤니티의 신뢰와 책임성에 대한 개인적 경험을 다룬 글.
[콘텐츠 경고: 이 글의 일부는 가스라이팅이나 다른 형태의 학대를 겪은 사람들에게 트리거가 될 수 있습니다]
Kenneth Reitz는 유명한 Python 개발자로, Requests 프로젝트를 만든 것으로 가장 잘 알려져 있습니다. 몇 년 전까지만 해도 저는 그와 진지하게 상호작용한 적이 전혀 없었지만, 그를 높이 평가했습니다.
저는 그의 디자인 감각과 사용성, 아름다움에 대한 강조를 좋아했습니다(지금도 좋아합니다). Requests는 소프트웨어 세계의 큰 부분을 떠받치는 핵심 인프라이며, 그가 이것을 사실은 "아트 프로젝트"라고 장난스럽게 고집하는 태도는 제 아나키스트적 공감대에 와닿았습니다. 저는 그가 자신의 정신 건강 문제를 공개적으로 다뤄 온 점도 존경했습니다(지금도 존경합니다). 제가 Trio 프로젝트를 시작할 때는 친근함과 접근성을 강조하고 싶어서, 그의 "for humans" 태그라인을 빌렸고, 문서를 그의 말을 인용하며 시작했습니다.
그러다 저는 requests에 비동기 지원을 추가하는 작업을 시작했습니다.
2017년 8월, 저는 Requests가 사용하는 기반 HTTP 라이브러리인 urllib3에 비동기 지원을 추가하는 작업을 시작했습니다. 이것은 매우 실험적인 작업이었습니다. 역사적으로 최첨단 상태는 동기 코드용 HTTP 클라이언트 라이브러리 하나, Twisted용 하나, Tornado용 하나, asyncio용 하나 등으로 나뉘어 있었고, 이들은 코드를 공유하지 않는 독립 프로젝트로 각각 유지보수되었습니다. 모두가 이것이 우스꽝스럽다는 건 알고 있지만, 고치기는 매우 어렵습니다. HTTP에 대한 깊은 전문성이 필요하고, 동시에 네트워킹에 대한 이 여러 다른 접근 방식들에 대한 이해도 필요하며, 또한 겉보기에는 양립 불가능한 API들을 어떻게 조화시킬지에 대한 영리한 아이디어도 필요합니다. 그래서 이전의 모든 시도는 실패했습니다. 그런데 저는 영리한 아이디어가 있다고 생각했고, 그래서 한번 시도해 봤습니다.
Reitz는 이 작업에 매우 큰 관심을 보였습니다. 그는 Requests에 비동기 지원이 들어가기를 아주 원했지만, 제게 말하길 자신은 이 문제들을 어떻게 해결해야 할지 몰랐기 때문입니다. 우리는 몇 차례 영상 통화와 IRC 대화를 했고, 그는 자신의 유명세를 활용해 자원봉사자를 모집해 제 쪽으로 보내려고도 했습니다. 큰 성과는 없었지만, 저는 다른 Trio 기여자 몇 명과 함께 계속 작업을 밀고 나갔습니다.

그러다 2018년 3월 7일, 그는 "Requests 3" 작업이 시작되었고, 핵심 기능은 제가 작업 중이던 네이티브 async/await 지원이 될 것이며, 이를 실현하기 위해 기부를 받고 있다고 발표했습니다.
대부분의 오픈소스 프로젝트는 모임 한 번 열기 위해 수천 달러 모으는 것도 힘겨워하지만, 이 일은 사람들을 들뜨게 만들었습니다. 그는 개인들과 Microsoft, Google, Slack 같은 대기업들로부터 기부가 쇄도했고, 모금 총액은 빠르게 약 3만 달러에 도달했습니다.
2018년 3월 15일, 그는 모금에 대해 이야기하자며 저에게 연락했습니다. 그는 이렇게 많은 돈을 가지고 무엇을 해야 할지 확신이 없다고 했습니다. 원래 목표는 컴퓨터를 사기 위한 5천 달러를 모으는 것뿐이었다고 말했습니다. 개인적으로 저는 그 5천 달러짜리 컴퓨터가 Requests와 무슨 관련이 있는지 회의적이었습니다. Requests는 작은 순수 Python 라이브러리이므로, 작업하려면 저렴한 노트북이면 충분합니다. 5천 달러는 고성능 서버나 최상급 게이밍 PC의 가격입니다. 하지만 설령 그가 그 돈 중 5천 달러를 전혀 관련 없는 컴퓨터에 쓴다 하더라도, 그것을 과거 작업에 대한 보상이라고 부를 수 있고, 그래도 모금에서 약속한 내용을 이행하는 데 쓸 약 2만 5천 달러가 남는다고 생각했습니다. 그리고 이것은 분명 멋진 새 무언가를 만들 수 있는 훌륭한 기회였습니다. 그래서 저는 컴퓨터 이야기는 꺼내지 않았습니다.
대신 저는 모금과 보조금에 대한 제 경험을 바탕으로 일반적인 조언을 했습니다. 신뢰를 유지하려면 투명성이 중요하다는 점을 강조했고, Python Software Foundation (PSF) 같은 비영리 단체와 fiscal sponsorship 관계를 설정할 것을 권했습니다. 또한 돈을 효과적으로 쓸 방법을 찾는 데 도움을 주려 했습니다. 예를 들어 저는 이미 전일제로 일하고 있었지만, 저를 도와주던 자원봉사자 중 한 명에게 계약직 일을 할 수 있는지 알아보기 위해 연락하기도 했습니다.
이 무렵 그는 우리가 진행 중이던 urllib3 작업으로 몇 가지 실험도 했는데, 이것이 "Requests Core"가 여러 HTTP 요청을 병렬로 보내는 모습을 보여주는 트윗으로 이어졌습니다. 여기서 "Requests Core"는 우리의 작업 스냅샷을 그가 포크해서 이름을 바꾼 것이었습니다. 제가 알기로 추가된 것은 기초적인 HTTP/2 지원뿐이었는데, 불행히도 (그리고 사전에 우리가 경고했음에도 불구하고) 이것은 막다른 접근 방식을 사용했기 때문에 그 코드는 쓸모가 없었습니다.
이 시점까지 우리의 상호작용에는 분명 몇 가지 이상한 점들이 있었습니다. 하지만 아시다시피, 사람들은 때로 이상하기도 합니다. 저는 개인적으로 약속하는 기능을 실제로 작업하는 사람들과 먼저 이야기하지도 않은 채 모금을 발표하지는 않았겠지만, 그래도 우리는 그 돈을 효과적으로 쓸 방법을 찾을 수 있으리라 확신했습니다. 그의 HTTP/2 코드는 쓸모없었을지 몰라도, 적어도 그는 async/await에 대한 경험을 쌓고는 있었습니다. 잘 풀릴 거라고 생각했습니다.
그 뒤 몇 달 동안에도 몇 가지 이상한 일들은 더 있었습니다. Requests 유지보수 팀의 서로 다른 구성원들이 그 돈에 무슨 일이 일어나고 있는지에 대해 매우 다른 이야기를 들었다고 보고했습니다. 하지만 큰 변화는 2018년 5월 말, 제가 UC Berkeley를 떠나 컨설팅을 시작했을 때 왔습니다. 이것은 잠재적인 윈윈처럼 보였습니다. 저는 일을 찾고 있었고 이 프로젝트에 흥미를 느끼고 있었으며, 그는 쓸 방법이 없는 돈을 들고 꼼짝 못 하는 상태였기 때문입니다. 그래서 저는 더 논의해 보기 위해 그에게 이메일을 보냈습니다.
한 달과 여러 차례의 후속 연락 끝에, 그는 마침내 답장을 했습니다. 핵심 요지는 이랬습니다.
그는 그 주에 세부 사항을 논의하기 위해 통화를 하자고 제안하며 끝맺었습니다.
저는 어안이 벙벙했습니다. 세금은 그런 식으로 작동하지 않습니다. 약속도 그런 식으로 작동하지 않습니다. 새로운 기술 스택은 공짜인데 몇 페이지 문서는 2만 8천 달러가 든다는 발상은 기괴합니다. 새 기능을 구현할 돈이 없는데, 그 이유가 구현할 돈도 없는 새 기능을 문서화하는 데 그 돈을 쓸 예정이라서라는 생각은... 전혀 말이 되지 않습니다.
그가 그 돈을 Requests를 위해 다른 방식으로 사용했다면, 저는 완전히 괜찮았을 것입니다. 저는 그 돈에 대해 아무 권리도 없었습니다. 하지만 이것은 완전히 다른 문제였습니다. 저는 극도로 우려했습니다. 그래도 프로젝트와 커뮤니티를 위해 우리가 얻을 수 있는 최선의 결과를 원했기 때문에, 소통의 선을 열어 두려 했습니다. 통화가 좋은 생각이라는 데 동의했고, 몇 가지 시간을 제안했습니다. 또한 이번에는 좀 더 강한 표현으로 그가 자신의 평판을 위험에 빠뜨리고 있다는 우려를 전했고, 돕겠다는 제안을 다시 강조하며 이렇게 썼습니다. "지금 이 순간에는 requests 3가 영영 실체화되지 않고, 대중의 인식이 '아 그래 Kenneth Reitz가 그 돈 훔쳤지'가 될 진짜 위험이 있다고 생각합니다. 저는 이 둘 중 어느 것도 일어나지 않기를 정말 바랍니다. 하지만 희망은 계획이 아닙니다. 우리에게는 계획이 필요하다고 생각합니다."
이 시점에서 그는 제 이메일에 답하지 않기 시작했고, 자신의 웹사이트에서 모금 기록과 그 대가로 무엇을 약속했는지를 담고 있던 모금 페이지를 삭제했습니다(이전 / 이후). 그는 또한 Requests문서와 자신의 블로그(이전 / 이후)를 업데이트해 삭제된 페이지에 대한 언급을 제거했습니다. 몇 달 뒤 그는 원래 URL에 새 페이지를 올렸고, 모금에 대해 질문이 있는 사람은 누구든 개인적으로 자신에게 연락하라고 요청했습니다.
그 뒤로 우리의 유일한 접촉은 그가 올해 2월 9일 갑자기 제게 보낸 이메일 한 통이었습니다. 그는 제가 이전에 한 말에 아무것도 답하지 않은 채, 자신과 제가 PSF에 공동 보조금 제안서를 써서, 그의 모금이 자금 지원 중이라고 주장하던 바로 그 일을 제가 하도록 돈을 받게 하자고 제안했습니다. 물론 이것은 시작도 할 수 없는 이야기였습니다. PSF가 다른 돈은 어디로 갔는지에 대해 까다로운 질문도 하지 않은 채 이런 것에 자금을 대줄 만큼 순진하다고는 도저히 생각되지 않습니다. 그리고 설령 그렇지 않다 하더라도, 또 우리가 어떻게든 윤리적 문제를 무시한다 하더라도, 그는 사실상 제게 우리의 평판을 함께 묶자고 요구하고 있었습니다. 그래서 그의 모금 처리 방식이 폭발하면 저 역시 연루되게 만들려 했던 것입니다. 저는 답하지 않았습니다.
오픈소스 프로젝트에서 모금을 다루는 표준 관행에 익숙하지 않은 사람도 있습니다. 그래서 비교를 위해 Python Software Foundation의 Packaging Working Group이 새 PyPI를 위한 자금 조달을 어떻게 처리했는지 설명해 보겠습니다.
이런 외부 보조금을 받는 것이 우리에게도 처음이었기 때문에, 우리는 먼저 무엇을 할지, 누가 할지에 대한 계획을 세웠고, 여기에는 계약자로 일할 수 있는 기존 기여자들을 확인하는 일도 포함되었습니다. 그런 준비가 끝난 뒤에야 우리는 자금을 신청했습니다.
그 다음 돈이 들어온 뒤에도, 우리는 그것을 그냥 넘겨주지 않았습니다. 각 계약자는 자신의 단가와 무엇을 약속하는지를 공식적으로 밝히는 몇 단락의 문서를 작성했고, 그룹이 그것을 검토한 뒤, 이메일로 짧은 투표를 진행해 승인했습니다. Working Group 구성원이었던 계약자들은 자신의 제안에 투표하지 않았습니다. 모두가 정기적으로 청구서를 제출했습니다. 그리고 전체 과정은 궁극적으로 커뮤니티가 선출한 PSF 이사회가 감독했습니다.
이것은 상당히 가벼운 절차이며 완벽무결하지도 않지만, 최소한의 투명성과 책임성을 제공합니다. 그리고 PSF는 Python 관련 프로젝트라면 어느 프로젝트에든 이런 서비스를 기꺼이 제공합니다. 예를 들어 Flask와 관련 프로젝트들의 기부금도 그들이 처리합니다.
어쩌면 Reitz는 단지 이런 일들이 보통 어떻게 처리되는지 몰랐고, 이 모든 것이 불행하지만 이해 가능한 실수였을 수도 있습니다. 하지만 저는 그 가능성이 낮다고 봅니다. Reitz가 모금을 진행하던 당시, 그는 PSF 이사회 멤버였습니다. 그리고 Packaging Working Group의 일원으로서, 그는 자신의 모금을 시작하기 몇 달 전에 이루어진 PyPI 자금 조달 투표에도 참여했습니다. 그런데도 제가 이야기해 본 PSF 직원들 중 누구도 제가 말해 주기 전까지는 그의 모금에 대해 알고 있지 못했습니다.
요약하면 이렇습니다. 그는 자신이 잘 알고 있던 표준적인 책임성 메커니즘을 피할 수 있는 모금 구조를 선택했습니다. 그는 자신이 약속한 것을 전달할 어떤 계획도, 능력도 전혀 갖고 있지 않았습니다. 그리고 제가 어쨌든 그것을 해낼 수 있는 방법을 제안했을 때, 그는 문서 작성이 얼마나 비싼지에 대한 횡설수설을 늘어놓았습니다. 사실상 Requests 3 자금을 어떻게 쓰겠다는 그의 공개적 약속은 처음부터 끝까지 거짓말이었고, 그는 이것이 문제라는 점에 대해 후회나 이해조차 보여주지 않았습니다.
이런 신뢰의 배반은 커뮤니티 전체를 해칩니다. 오픈소스를 위해 돈을 모으는 일은 원래도 충분히 어렵습니다. 이런 종류의 일은 정말로 도움이 되지 않습니다.
그리고 좀 더 개인적인 차원에서, 저는 그가 저와 상호작용한 방식이 극도로 조종적이었다고 느꼈습니다. 그는 저를 이용하려 했고, 자신의 평판을 지키기 위해 자신의 거짓말을 덮는 일에 저를 공범으로 만들려 했다고 느꼈습니다. 저는 이런 일에 동조한다는 생각 자체가 극도로 불편했지만, 그는 제가 선택할 수 있는 다른 길을 비동기 작업 자체를 포기하거나, 아니면 제게도 상당한 대가가 따를 수 있는 이 모든 이야기를 공개하는 것뿐인 상황으로 만들어 버렸습니다.
저는 무엇을 해야 할지 확신이 없어서, 더 많은 맥락을 얻기 위해 다른 커뮤니티 구성원들에게 조용히 연락하기 시작했습니다. 곧 저는 Reitz의 공개적 평판과는 달리, 그와 직접 함께 일해 본 사람과 이야기할 때마다 모두 그에 대해 심각한 불편함을 표현했고, 많은 사람들은 각자의 충격적인 이야기를 갖고 있다는 사실을 알게 되었습니다. 제 이야기는 가장 심한 축에도 들지 못했습니다. 예를 들어, Ian Stapleton Cordasco는 공개적으로 기록에 남겨도 좋다며 자원했고, 이렇게 말했습니다. "Kenneth와 이 모든 해 동안 상대해야 했던 경험 때문에, 저는 이제 python 오픈소스 소프트웨어 작업을 거의 하지 않게 되었고, 대부분 조용히 커뮤니티를 떠났습니다".
제가 특히 충격적으로 느낀 점 하나가 있습니다. 그의 장기 협업자들과 제 경험에 대해 이야기할 때마다, 그들은 즉시 제가 미쳐 가는 것이 아니라는 점을 안심시키려 들었습니다. 그러니까... 물론 저는 그 지지에 감사했습니다. 하지만 이것이 그들이 처음 하는 일이 아니라는 점은 분명했습니다. 사람들은 Reitz와 함께 일하기 시작하고 나면 언제나 자기 자신의 인식을 신뢰해도 된다는 안심이 필요해진다는 것입니다. 그의 협업자들은 이것을 너무 오래 해 와서, 이런 일이 정상처럼 느껴지는 듯했습니다. 하지만 이것은 정상이 아닙니다.
이것은 전형적인 "missing stair" 문제입니다. 내부 집단 사람들은 독성 있는 사람을 조용히 우회합니다. 외부인은 아무것도 모른 채 들어옵니다. 저는 Python 세계에서 꽤 인맥이 있는 편인데도, 아무것도 모른 채 들어왔습니다. 돌이켜 보면 몇 가지 경고 신호를 볼 수 있습니다. auteur 지위를 고집하는 태도는 이제 매력적인 괴짜 기질이라기보다, 책임은 부정하면서 공로와 권력을 차지하려는 계산된 허세처럼 보입니다. "긍정성"을 고집하는 태도는 책임 추궁을 피하려는 사람들이 흔히 쓰는 전술입니다. 하지만 저는 속았습니다.
제가 계속 생각하게 되는 것이 하나 있습니다. Requests의 비동기 기능에 대해 그와 처음 이야기했을 때, 모금 몇 달 전이었는데, 그는 이상한 말을 했습니다. 자신은 이것을 구현하는 데 완전히 저에게 의존하고 있기 때문에, 만약 제가 Requests가 AsyncIO(더 잘 알려진 경쟁자) 대신 Trio(제 라이브러리)를 기본으로 사용하라고 요구한다면, 자신은 따를 수밖에 없다고 지적한 것입니다. 저는 그것이 꺼내기에는 믿을 수 없을 만큼 이상한 이야기라고 느꼈습니다. 거의 저더러 자신을 조종하라고 요청하는 것 같았습니다. 그 당시 저는 협박이 아니라 장점으로 성공하고 싶다는 식으로 얼버무렸고, 아예 기본값을 정하지 말라고 권했습니다. 돌이켜 보면, 사기꾼들이 종종 피해자에게 사소한 비윤리적 행동을 먼저 유도해 놓고, 사기가 점점 커질수록 피해자가 빠져나가지 못한다고 느끼게 만드는 방식이 떠오릅니다.
그의 협업자들은 또한 그가 무엇을 하든 늘 그의 양극성 장애를 변명으로 들었습니다. 저는 이것이 Reitz에게도, 정신 건강 문제로 고생하는 모든 사람에게도 매우 불공정하다고 생각합니다. 질병은 누군가가 타인에게 끼친 해악이나 자신의 행동에 대한 책임을 지워 버리지 않습니다. 많은 사람들은 이런 종류의 해를 끼치지 않고도 자신의 상태를 관리하며, 실수했을 때는 우리 모두처럼 책임을 지고 바로잡습니다. 만약 누군가가 그렇게 할 수 없다면, 우리는 커뮤니티로서 연민은 가질 수 있겠지만, 그들에게 권력과 영향력을 주어서는 안 됩니다.
많은 사람들은 Reitz가 실제로 Requests 개발과 얼마나 적게 관련되어 있는지 잘 모른다고 생각합니다. 수년 동안 실제 유지보수는 거의 전적으로 다른 자원봉사자들이 해 왔습니다. PyPI의 유지보수자 목록을 보면, 그는 자기 프로젝트에 대한 PyPI 권한도 없습니다. 계속 문제를 일으켰기 때문에 실제 유지보수자들이 그의 접근 권한을 박탈하자고 고집했기 때문입니다. Requests git 저장소를 클론한 뒤 git log requests/를 실행해 보면, 누군가 라이브러리 소스 코드를 변경한 모든 시점을 볼 수 있습니다. 직접 변경했든, 다른 사람의 풀 리퀘스트를 병합했든 말입니다. Reitz가 둘 중 하나라도 마지막으로 한 것은 2017년 5월이었고, 그때 그는 약간의 공백 정리를 했습니다.
적어도 커밋 기준으로 보면, 그 이후 그의 주요 기여는 몇 가지 작은 문서 수정 병합과, 기부 링크, 광고, 거슬리는 스폰서 링크 등을 추가하여 프로젝트를 수익화하는 일로 보입니다. 이 돈은 전부 프로젝트 유지보수자들이 아니라 그의 주머니로 직접 들어갑니다.
또한 저는 그가 Requests에 대한 프리미엄 지원 계약을 판매해 온 이력이 있고, 돈은 자신이 받은 뒤 실제 작업은 무급 자원봉사자들에게 떠넘겼다는 사실도 알게 되었습니다.
저는 오픈소스로 돈을 벌려는 시도 자체에 반대하지 않습니다. 저는 이전에도 오픈소스는 충분한 투자를 거의 받지 못한다고 쓴 적이 있습니다. 제가 반대하는 것은 자원봉사자를 착취하고, 커뮤니티 구성원을 몰아내고, 후원자와 더 넓은 커뮤니티에 거짓말하는 것입니다. Reitz는 이런 모든 일을 해 온 일관된 이력을 갖고 있습니다.
저는 여기서 무엇을 해야 할지 결정하는 데 오랫동안 힘들었습니다. 작년 이후 저는 이 문제를 다른 사람들에게 이야기할 때 매우 조심하려고 노력했습니다. 거짓 소문을 퍼뜨리거나 인터넷 군중을 부추기고 싶지 않았기 때문입니다. (이 때문에 우리가 urllib3의 비동기 기능에서 하고 있던 작업에 대해서도 침묵해야 했고, 그 작업 자체를 하기도 어렵게 만들었습니다.) 그리고 이것을 공개하는 일이 제 평판과 정신 건강에 어떤 영향을 줄지 두렵습니다.
결국 저는 Python 커뮤니티와 그 구성원들을 깊이 아끼기 때문에 목소리를 내기로 했습니다. 우리 커뮤니티의 가장 두드러진 구성원 중 한 사람이 후원자에게 거리낌 없이 거짓말하고 자원봉사자에게 해를 끼치는데, 우리가 모두 아무 말 없이 그것을 넘겨 버린다면, 그것은 우리가 함께 쌓아 온 모든 것을 위험에 빠뜨립니다. 그리고 저는 많은 사람들보다 이 문제를 말할 수 있는 더 나은 위치에 있습니다.
그렇다면 이제 무슨 일이 일어날까요?
여기는 인터넷이니, 저는 이것을 명시적으로 말해야 합니다. Reitz를 괴롭히거나 학대하지 마세요. 그런 일은 결코 적절하지 않습니다. (그리고 도덕적 논거에 설득되지 않는 유형의 사람이라면, 이렇게 생각해 보세요. 그는 분명 관심을 원합니다.)
저는 Reitz가 자신이 모금한 돈과 그것이 어떻게 쓰였는지에 대해 공개적으로 설명할 것을 요구합니다.
저는 Requests 프로젝트 유지보수자들에게, 프로젝트를 보다 정상적이고 덜 역기능적인 거버넌스 모델로 전환할 것을 촉구합니다. 그의 기여를 인정하되, 그의 개인적 신화까지 받아들일 필요는 없습니다. 그의 통찰은 대체 불가능하지 않습니다. 여러분은 이 상황이 여러분과 여러분의 사용자들에게 해를 끼치고 있다는 것을 알고 있습니다. 여러분과 여러분의 사용자는 그의 자아보다 더 중요합니다.
그 외에는, 저는 제 자신의 일에 집중할 생각입니다. 저는 더 이상 Reitz를 그의 행동 결과로부터 보호하기 위해 비밀을 지키지 않을 것입니다. 다음에 무슨 일이 일어날지는 그와 더 넓은 Python 커뮤니티에 달려 있습니다.
누구든 들어 줄 사람이 필요하다면, 저는 njs@pobox.com으로 연락할 수 있습니다. 이번 주말 PyCon에서도 주변에 있을 예정입니다.