오픈 소스 개발 근황
어쩌다 보니 최근 꽤 많은 오픈 소스 프로젝트를 만들게 되어서, 근황 보고 겸 진행중인 오픈 소스 프로젝트들을 글로 정리해 본다. 각 프로젝트들은 어떤 식으로든 서로 관계가 있다.
Hollo
사실 최근 내가 만들게 된 오픈 소스 프로젝트들의 시발점이 되는 게 바로 이
프로젝트이다. Elon Musk가 Twitter를 사들이고 이름을 X로 바꾸고 나서부터
원래부터 쓰던 Mastodon을 더욱 열심히 쓰게 되었는데, 국한문 혼용체로 글을 쓰다
보니 사람들이 읽기 불편하지 않을까 눈치를 보게 되었다. 그래서 Seonbi를
이용하여 국한문 혼용체를 한글전용체로 바꿔주는 기능을 Mastodon에 넣을까도
생각했으나… 나 말고는 아무도 쓸 것 같지 않은 이 기능을 Mastodon 업스트림에
넣는 것은 애초에 무리. 그러면 다운스트림 패치를 유지하며 Mastodon 서버도
스스로 운영해야만 한다는 소리인데, Mastodon이 워낙 무겁기로 유명해서
그러고 싶지가 않았다. 그래서 자가용 경량 ActivityPub 구현을 만들고자 한 게
바로 Hollo이다. 혼자 쓰는 ActivityPub 서버 소프트웨어라서 홀로
라고 이름
지었다.
개밥 먹기(dogfooding)에 성공하여 현재는 내 연합우주(fediverse) 어카운트를
Hollo로 옮겼다. 연합우주 핸들은 @hongminhee@hollo.social. 국한문 혼용체로
마음껏 글을 쓰고 있으며, 한자 위에 한글 독음이 <ruby> 태그로 달린다.
실은 개밥 먹기를 달성한 이후로는 내게 절실한 기능은 모두 구현되어서 버그 수정 등 유지보수 위주로만 하고 있다.
Fedify
앞서 이야기한 Hollo를 처음 구현할 때는 ActivityPub 구현을 바닥부터 하려고 시도했었다. 그런데 만들다 보니 ActivityPub 구현 코드가 생각보다 두껍고 할 게 많다는 생각이 들었다. 그래서 Hollo를 만들던 것을 중단하고 ActivityPub 서버 프레임워크를 만들게 된 게 Fedify이다. 만들고 나서 반년이 채 안됐을 때 Ghost로부터 자금 지원을 받게 되었고, 그 뒤로 한 동안 전업으로 Fedify 프로젝트를 하게 되기도 했다. 현재는 정보통신산업진흥원(NIPA) 산하 오픈 소스 소프트웨어 통합 지원 센터에서 주최하는 오픈 소스 컨트리뷰션 아카데미(OSSCA)의 참여형 프로젝트로 선정되어 훌륭한 멘티 분들과 함께 프로젝트를 진행하고 있다.
Fedify 이전에도 ActivityPub 서버 프레임워크가 없었던 것은 아니다. 하지만 어떤 것도 내가 필요로 하는 추상화 수준을 제공하지 않았다. 어떤 것들은 WebFinger나 서명 알고리즘 정도만 제공하는 작은 라이브러리에 가깝고, 또 어떤 것들은 거의 Mastodon과도 비교할 수 있는, 프레임워크라기 보다는 완성된 소셜 미디어 플랫폼 구현에 가까웠다. 비유하자면 HTTP 라이브러리나 WordPress 같은 CMS는 있어도, Rails나 Django에 가까운 프레임워크를 없었던 것이다.
Fedify를 만들 때 염두에 둔 목표는 이하와 같다.
- 가급적 많은 개발자들이 쓸 수 있게 한다.
- 데이터베이스나 스토리지에 무관(agnostic)해야 한다. 애플리케이션 개발자가 쓰고 싶은 데이터베이스를 쓸 수 있어야 한다.
- ActivityPub 프로토콜을 활용하는 방식에 제약이 없어야 한다. 이를테면 마이크로블로그 같은 완성된 애플리케이션의 형태를 전제하지 않는다.
- ActivityPub을 구현한다면 갖추어야 하는 모든 것들—인증, 서명, 발신함(outbox) 및 수신함(inbox) 대기열 등—일절를 제공한다.
- ActivityPub을 잘 모르는 사람도 쓸 수 있을 만큼 풍부한 문서화를 제공한다.
- 타입 안전해야 한다.
그리고 이 글을 쓰는 현재, 이상의 목표는 거진 이룬 것 같다. 결과적으로 Hollo는 Fedify 기반으로 만들어지게 되었고, 그 외에도 (아래서 다룰) Hackers’ Pub, Ghost 등이 Fedify를 써서 ActivityPub을 구현하게 되었다. 또한, 아직 완성되지는 않았지만 Kosmo, Cosmoslide 등의 프로젝트가 Fedify를 이용해 ActivityPub을 구현하고 있다.
LogTape
Fedify에 로그 체계를 추가하려고 JavaScript로 만들어진 로그 라이브러리를 찾아보았으나 내가 원하는 조건의 라이브러리가 없어서 새롭게 만들게 된 것이 LogTape이다.
내가 원하는 조건이라는 것도 크게 대단치도 않은 것이었다. 그저 Python 표준
라이브러리의 logging 모듈에 해당하는 것을 찾은 것인데, 돌이켜 생각해 보니
logging 모듈이 꽤 잘 만든 물건이었던 것 같기도 하다. 내가 바라는 조건은
다음과 같았다.
- 라이브러리에서 로그를 남기되, 애플리케이션에서 라이브러리의 로그 출력을 제어할 수 있어야 한다. 애플리케이션에서 출력 설정을 따로 하지 않는 한, 라이브러리의 로그는 어디에도 출력되어서는 안 된다.
- 로거가 계층적으로 관리되어야 한다. 상위 로거에 설치된 출력처(sink)는 하위 로거에도 적용되어야 한다.
- 출력처는 구현하기 쉬운 인터페이스여야 한다.
- 타입 안전해야 한다.
- Node.js, Deno, Bun, 에지 함수(edge functions), 웹 브라우저 등 다양한 JavaScript 런타임에서 두루 동작해야 한다.
대체로 애플리케이션이 아니라 라이브러리에서 로그를 남기기 위해 필요한 조건들이었다. 어차피 Fedify에 쓸려고 만든 것이기 때문에, 만들어 놓고 방치하고 있었는데 작년 가을 지나서부터 어쩌다 입소문이 나서 사람들이 많이 쓰게 되었다.
Hackers’ Pub
소프트웨어 개발과 관련된 글들을 올릴 블로그를 만들고 싶어서 velog를 조금 쓰게 되었는데, ActivityPub을 지원하지 않는 게 아쉬워서 velog 이슈트래커에 이슈를 남기게 되었다. 다행스럽게도 긍정적으로 검토하겠다는 답변을 받긴 했지만, 제작진 분들이 바쁘셔서 그 이후로 소식이 없었다. 결국 내가 스스로 ActivityPub을 지원하는 소프트웨어 개발자들을 위한 소셜 미디어 및 블로그 플랫폼을 만들어보자고 생각한 게 Hackers’ Pub이다.
작년 겨울에 첫 개장을 하고서 얼마 되지 않아 이재열 님께서 가입하셨는데, 초대제임에도 불구하고 이재열 님께서 이곳저곳에서 엄청나게 열정적으로 Hackers’ Pub 홍보를 해 주신 덕분에 상당히 많은 분들께서 가입하여 활동하시게 되었다. 단기적 목표는 한국에서 널리 쓰이게 되는 것이고, 나아가 중장기적 목표는 동아시아 전반과 영어권을 아우르는 것이다. 하지만 아직은 대부분의 콘텐츠가 한국어로 되어 있으며, 소수의 일본인 분들이 간헐적으로 일본어 콘텐츠를 올려 주시는 정도이다.
Fedify를 통해 ActivityPub을 구현했으므로 당연히 Hollo, Mastodon, Misskey 등과
소통이 가능하며, X처럼 단문(Note)을 쓸 수도 있고 긴 게시글(Article)을 쓸
수도 있다. 에모지 반응이나 인용처럼 Mastodon에는 없는 기능도 제공하고 있다.
그리고 Hackers’ Pub의 또 하나의 자랑거리는 안전하고 평등한 공동체를 이루기 위한 행동 강령이다. 특히 내가 가장 좋아하는 구절은 다음과 같다.
차별과 혐오에 대항하는 발언과, 차별과 혐오 자체를 동일선상에 두지 않습니다.
기술적 측면에서는, 원래는 Deno와 Fresh를 이용해서 만들었었으나, 현재는 웹 프런트엔드 개발에 조예가 깊으신 신의하 님의 도움을 받아 GraphQL과 SolidStart 기반으로 이주하고 있다.1
소스 코드는 AGPL 3.0으로 GitHub에 공개되어 있다. 실제로 꽤 많은 Hackers’ Pub 회원들께서 불편한 점을 스스로 고치는 풀 리퀘스트를 보내주고 계신다.
참고로 내 Hackers’ Pub 어카운트는 @hongminhee@hackers.pub이다.
Upyo
Hackers’ Pub을 만들면서 이메일을 발송할 일이 생겼는데, 이메일 제공 업체를
쉽게 교체할 수 있는 이메일 발송 라이브러리를 찾다가 마음에 드는 게 없어서
만들게 된 게 Upyo이다. 이름에서 알 수 있는 것처럼, 한국어 단어 우표
에서
이름을 따 왔다.
원래는 .NET 쪽의 FluentEmail 같은 걸 JavaScript 생태계에서 찾고 있었는데, 의외로 마땅한 게 없어서 놀랐다. 이메일 제공 업체를 교체하거나 다중화하는 일이 생각보다 잘 없는 걸까?
LLM 기반의 코딩 에이전트2를 본격적으로 써 본 첫 프로젝트이기도 했다. 그럼에도 아직 LLM의 역량에 기대가 그렇게 높지 않은 탓에, 설계와 초반 코딩은 스스로 했고, 나중에 트랜스포트(transport)의 종류를 늘릴 때 LLM의 도움을 많이 받았다. 만드는 데에 이틀 걸렸던 것 같다. 코딩 에이전트의 놀라운 생산성이 인상 깊었다.
내가 만든 다른 라이브러리들과 마찬가지로 Node.js, Deno, Bun, 에지 함수, 웹 브라우저 등 다양한 JavaScript 런타임을 지원하는 것도 특징이다.
Optique
Fedify는 프레임워크이기도 하지만 fedify 명령이라는 CLI 도구도 제공하는데,
기존에는 Deno 전용 CLI 프레임워크인 Cliffy를 그럭저럭 잘 쓰고 있었으나,
Deno 이외에 Node.js, Bun 등을 지원해야 하게 되면서3 Cliffy의 대안을 찾게
되었다. 그런데 이번에도 비슷한 패턴으로… 마음에 드는 걸 찾지 못했다.
사실 내 마음속에는 이미 이상에 가까운 CLI 파서 라이브러리가 존재하긴 했다. 다만 그게 optparse-applicative라는 Haskell 라이브러리였기 때문에 Fedify에서는 쓸 수 없었을 뿐이다. 이 optparse-applicative라는 라이브러리의 아이디어는 단순하다. CLI 파서도 파서이니 파서 컴비네이터(parser combinators)로 만들자는 것이다.
아무튼, 원하는 CLI 파서 라이브러리를 찾지 못했으니 스스로 만들 수밖에. 그래서 만든 게 Optique이다.
처음에는 optparse-applicative와 거의 비슷하게 포팅하려고 했지만, 아무래도 Haskell과 JavaScript는 DSL을 구성해내는 표현력에 큰 차이가 있었다. 그래서 고민하던 끝에 TypeScript 개발자들에게 이미 친숙한 Zod와 같은 유효성 검사 라이브러리의 API를 본뜨기로 했다.
Upyo 프로젝트와는 달리 LLM 코딩 에이전트는 아주 한정적으로 문서화나 테스트 코드 작성 등에 사용했고, 그 때문인지 만드는 데에는 일주일 넘게 걸렸던 것 같다.
만들고 나니 JavaScript 생태계 안에서는 꽤나 유니크한 CLI 파서 라이브러리가 만들어졌다고 자평할 수 있었다. 물론, 많은 CLI 애플리케이션이 그렇게 복잡한 옵션을 받지는 않지만, 어느 정도 규모가 있는 CLI 애플리케이션을 만든다면 Optique를 써도 후회하지 않을 것이라고 자부한다.
아, 그리고 앞서 소개한 다른 라이브러리들과 마찬가지로, Node.js, Deno, Bun, 심지어 에지 함수나 웹 브라우저에서도 동작한다. 그럴 필요가 있나 싶지만, 그저 자기만족이랄까. 다만, 덕분에 테스트 짜기는 아주 쉬운 라이브러리가 되었다.
야크 셰이빙
생각해 보니 내 오픈 소스 개발의 원동력은 야크 셰이빙(yak shaving)에서 오는 게 아닐까 싶다. Anthony Fu의 〈야크 셰이빙에 관하여〉(About Yak Shaving)라는 글을 읽은 적이 있는데, 모티베이션을 얻는 방식이 나와 아주 비슷하다는 인상을 받았다. 뭔가가 불편해서 도구를 만드려고 하면, 그걸 만드는 도중에 또 불편함을 느끼고 그걸 해결하는 도구를 만들게 된다. 그래서 원래 하려고 했던 최초의 일은 못하게 되는 경우가 많지만, 그렇다고 해서 도중에 만든 부산물들이 어디로 사라지는 것은 아니다.
나도 맨 처음으로 돌아가서 생각해 보면 결국 하고 싶었던 것은 국한문 혼용체로 연합우주에 글을 쓰고 싶었던 것인데, 이를 위해 Hollo도 만들고 Fedify도 만들고 LogTape도 만들고 Optique까지 만들게 되었다. 그러면서 하고 싶은 다른 것들이 새롭게 생겨났고, Hackers’ Pub 같은 커뮤니티를 통해 여러 귀중한 인연도 맺게 되었다. 아, 그래서 원래 하려고 했던 연합우주에서 국한문 혼용체로 글쓰기는 작년말에 달성하게 되었다! 앞서 소개한 부산물들 말고도 Mastodon이나 Misskey 등에 패치를 보내야 했긴 하지만 말이다.4
두 해 남짓한 기간에 일어난 일들인데 무척이나 재밌고 풍성한 여정이었던 것 같다. 앞으로도 당분간은 전업으로 오픈 소스 개발을 하게 될 것 같은데, 내게 주어진 복에 감사하며 분발해야겠다.
여러 이유로 Deno를 쓴 걸 후회하고 있긴 하지만, 어쩔 수 없이 Deno는 이주 후에도 계속 쓰고 있다. ↩︎
Claude Code를 썼다. ↩︎
Fedify 프레임워크 자체는 이미 Node.js, Deno, Bun, Cloudflare Workers 등을 지원하고 있긴 했지만, CLI 도구인
fedify명령만은 Deno 전용으로 만들어져 있었다. ↩︎글을 받아 보는 쪽에서도
<ruby>태그를 렌더링할 수 있어야 했기 때문이다. ↩︎