Search
📖

오픈소스에서 철 드는 이야기

subtitle
2019년 ~ 2023년, 오픈소스 활동을 하며 배우고 느낀 것
Tags
오픈소스
Created
2023/01/07
2 more properties
저의 오픈소스 활동에 대해 자유롭게 적은 글입니다.
아무것도 모르고 시작했던 마냥 재미로 시작했던 오픈소스 활동.
오픈소스 계의 천방지축이었던 내가 조금씩 철 들어가는 이야기.
사진 출처: google - 에펨코리아

오픈소스 활동들

Summernote (2019.8.15 ~ 2020.2.22): 오픈소스 시작

첫 오픈소스 활동에 신났었던 나
파이콘 2019 스프린트 행사에 참여하여 처음으로 오픈소스 활동을 시작했다. 스프린트가 뭔지도 몰랐었는데 maintainer와 직접 만나 프로젝트에 기여할 수 있다는 설명을 보고 신청했다.
코딩을 시작한 지 얼마 되지도 않았고 오픈소스에 기여하는 법도 잘 몰랐지만 summernote maintainer 분께서 친절하게 알려주셔서 비교적 쉽게 시작할 수 있었다. 내가 summernote에 했던 기여들은 여기서 확인할 수 있다.
파이콘 행사 이후에는 종종 서울 스프린트에 참여해 PR을 올리곤 했다. 지금은 행사가 중단된 듯 싶은데 혹시나 하는 마음에 가끔씩 홈페이지에 들어가 새로운 행사가 있는지 확인해보곤 한다.
지금에서야 PR을 보니 내가 올렸던 PR들을 제대로 follow up하지 않고 일부 PR은 테스트가 안되어 있는 것도 보여서 스스로 부끄럽다는 생각이 들었다. 내 코드가 반영되면 해당 오픈소스를 사용하는 모두가 영향을 받는데 나는 오픈소스 활동을 그저 재미, 보람으로만 느꼈던 것 같다.
아직까지 그렇게 영향력 있는 기여를 해보진 못했지만 지금까지 느낀 바에 의하면 오픈소스 활동을 할 때는 그 이상의 책임감이 꼭 필요하다고 생각한다.

Shopify/Graphql-design-tutorial (2019.09.10 ~ 2021.03.01)

2019년 8월 26일에 첫 직장에 입사했다. 우리 회사는 한창 Django, Angularjs, Coffeescript 등의 기술을 Node.js, GraphQL, Typescript로 마이그레이션하는 작업을 하고 있었다. CTO님은 이런 상황 설명과 함께 GraphQL 스키마를 설계하는 방법에 대한 reference로 shopify의 graphql-design-tutorial을 소개해주셨다.
GraphQL을 써본 적도 없고 스키마를 설계해본 적은 더더욱 없었지만 당시 summernote로 인해 오픈소스 기여에 재미를 느끼고 있었기 때문에 '번역'해서 기여해보자는 생각이 들었다.
오픈소스 문서 번역의 좋은 점은 한국어로 자연스럽게 번역하기 위해 문장 하나하나 주의 깊게 보게 된다는 것이다. 즉, 기여도 하면서 공부도 할 수 있다. 많은 기술 서적을 번역하고 출판한 개발자 '윤인성'님이 이런 공부법의 좋은 예인 것 같다.
첫 PR을 올렸을 때 Shopify 개발자분이 흔쾌히 merge해주셨고 그 이후로 몇몇 한국 개발자분들이 오타, 오역을 고쳐주셨다. 내 기여에 다른 사람의 기여도 추가되니 진짜 함께 만들어간다는 느낌이 들었고 조금 신났었던 것 같다.
그 이후 graphql-design-tutorial은 내 기억 속에서 잊혀졌다. 1년이 지나고 새로운 개발자분들이 들어왔는데 다른 팀에서 내가 번역한 문서를 추천해주고 있다는 소리를 들었다. graphql을 잘 모르던 시기에 번역한 거라 잘못된 정보가 있을까 간담이 서늘해졌다. 또 어색한 번역투도 남들에게 보여주기에 부끄러워서 다시 다듬어야겠다는 생각이 들었다.
그래서 오랜만에 다시 꺼내 문서에서 업데이트된 부분도 반영하고 번역투나 오역을 수정해서 다시 PR을 올렸다. 오픈소스 활동을 하면 부끄러움 반, 책임감 반으로 인해 전에 기여했던 것도 다시 보게 되는 일이 생기는 것 같다.

오픈소스 스터디 (2019.10. ~ 2019.12)

깨달음1: 실력이 없다면 스터디를 주최하지 말자.
깨달음2: 실제 사용하고 있는 오픈소스에 기여하자.
입사한지 얼마 안 되었던 시절, 개발자로서 빨리 성장하고 싶어서 어떤 방법이 있을까 생각해보다가 summernote maintainer님의 조언대로 서울 스프린트가 아니더라도 스스로 오픈소스에 기여할만한 기회를 만들고자 했다.
개발자 카페에서 스터디원들을 모아 mattermost, summernote 등 오픈소스에 기여하는 모임을 만들었다. 관악구에서 첫 모임을 가졌는데 오픈소스에 기여가 처음이신 분들을 온보딩시켜드리고 윈도우 노트북에 환경 구축을 해드리는 것부터가 스터디의 첫 고비였다.
스터디에 잘 나오지 않는 사람들도 있어서 처음에는 5명으로 시작했다가 3명만 남았다. 그래도 다행히 그 중 한분은 mattermost에 기여하셨던 것 같다(원래도 armeria에 기여하시던 분이라 스스로도 잘하시는 분이었다). 정작 나는 실력도 없는 상태에서 주변 챙기기에 바빠 제대로 기여하지도 못했다. 또한 실무에서 쓰지 않는 프로젝트에 계속해서 관심을 갖고 기여하는 것도 어려웠고 흥미도 점점 떨어져 갔다.
무책임하지만 스터디원들에게 더 이상 진행할 수 없을 것 같다고 말씀드리고 스터디를 해산시켰다. 이때 커리어나 성장을 위해 오픈소스에 기여하는 것에 회의감을 갖게 됐다. 그래서 그 이후로는 필요에 따라 실무에서 사용하는 오픈소스에 기여하고자 했다.

Marmelabl/React-Admin: 첫 Reject

실무에서 react-admin을 사용하다가 DateInput에서 input 값을 검증하는 데 불편한 점이 있어 validator를 추가하는 PR을 올렸다. 이 PR을 통해서도 오픈소스의 좋은 점, 그리고 스스로 반성해야할 점을 찾을 수 있었다.
좋은점
1. 프로젝트 owner인 fzaninotto가 내 PR을 보고 직접 코드 리뷰를 해준다.
date validator를 쓸 때 date-fns 라이브러리를 썼는데 fzaninotto는 Intl로도 충분하다고 말씀해주셨다. 아무 생각 없이 라이브러리를 사용해 외부 의존성을 높이기보다, 내장된 API로도 충분히 구현할 수 있다면 내장 API를 사용하는 것이 좋다. 특히 오픈소스 프로젝트에서는.
반성해야 할 점
1. contribute하기 전 먼저 이슈를 제기해 프로젝트에 정말 필요한 기능인지 공감을 얻어야 했었다.
다짜고짜 PR을 올리니 owner와 maintainer가 이 기능이 왜 필요한지 물었고, 기존 코드만으로도 충분히 구현 가능하다고 하니 스스로 이 기능이 정말 필요한 것인지 의문이 들었다.
2. PR을 던지고 그 이후에 계속 follow-up하지 않았다.
react admin에서 나의 행동은 어쩌면 무례한 것 같기도 하다. 다짜고짜 PR을 올리고, owner와 maintainer가 댓글을 다는 데도 follow-up하지도 않았다. 내가 마지막 댓글을 달고 한 달뒤에 댓글이 달려 모르긴 했지만 그래도 그분들의 시간을 뺏은 것 같아 아쉽다.
프로젝트 maintainer와 contributor가 서로 시간 낭비 하지 않으려면 1. contributor가 contribute 문서를 잘 따르고 2. PR을 날리기 전 issue 제기부터하고 3. 내가 올린 PR을 계속 follow-up하는 것을 잊지 말아야한다.
부족한 점이 많았는 데도 불구하고 바로 close 시키지 않고 코드 리뷰도 해주고 개선 사항을 알려줬던 owner, maintainer분께 죄송하면서도 감사하다.
회사에서 개발 콘텐츠를 스크레이핑할 때 open-graph-scraper를 많이 이용했다. 종종 brunch나 slideshare처럼 커스텀 meta tag를 쓰는 경우가 있는데 custom meta tag가 type에 없어 ts-ignore를 해주거나 any 타입으로 추가해줬어야 했다.
그런데 크롤링해오는 사이트가 점점 늘어나면서 custom meta tag를 쓰는 곳도 많아졌고 ts-ignore 사용도 지양하기 위해 처음으로 외부 라이브러리 타입을 직접 추가해보았다.
open-graph-scraper에 CustomMetaTag 인터페이스를 추가하는 간단한 작업이었는데, 이 PR을 통해 처음으로 type을 테스트하는 작업도 해보았다. type도 테스트할 수 있는지 몰랐는데 테스트까지 직접하게 됐다. 오픈소스를 보다보면 내가 모르는 게 아직 너무 많다는 생각이 든다.
어쨌든 테스트를 하는데 이상하게 한 번에 통과하는 것이었다. 혹시나 싶어서 일부로 틀린 테스트를 작성해봤는데 문제 없이 통과했다. 테스트가 이상하다는 것을 감지하고 다른 라이브러리의 타입 테스트 파일을 봤는데 expectType이 아닌 ExpectType 으로 쓰는 것을 발견했다.
단순한 오타에 의한 버그였음을 발견하고 테스트 오류까지 수정해 PR을 올렸다. 원 author인 ffflorian 이 승인을 해줘서 merge가 된 상태고, 이런 오타 실수에 대해 dtslint에서 아무런 에러도 뱉지 않는 것에 대해 이슈를 남겼다. 아직까지 아무도 내 이슈에 대해 관심이 없다. 흑흑.

Typeorm: mongodb 버그 PR (2022.08)

배경
회사에서 typeorm@0.2.41 버전을 사용하다가 peer dependency를 맞추기 위해 ^0.3.0버전으로 올렸다. db는 mongodb를 사용하고 있었는데 나중에 데이터를 확인해보니 쿼리가 엉뚱하게 들어가고 있었다. (이것때문에 서버가 난리가 났다 ㅂㄷㅂㄷ)
분명 typeorm findXXX 메서드의 인터페이스에 맞게 넣어줬는데 where절이 왜 안먹히는 걸까 고민했다. nestjs와 typeorm 샘플 코드를 보아도 똑같이 따라해보았는데 데이터는 이상하게 나왔다.
컴파일 된 typeorm 코드에서 직접 콘솔을 찍어가며 확인해보았고 코드를 따라가면서 문제의 원인을 파악할 수 있었다.
문제 원인 및 해결
간단히 설명하면, DeletedDateColumn이 있는 entity에 쿼리할 때, soft deleted 데이터를 필터링하는 쿼리문이 기존 쿼리문을 덮어씌우면서 데이터가 잘못 필터링되는 오류가 있었다. 쿼리가 덮어씌워지지 않도록 하는 코드를 작성해 PR을 올렸다.
그리고 해당 코드의 테스트를 위해 DeletedDateColumn이 붙은 entity를 추가하여 find 메서드 쿼리 테스트를 작성했다. 만약 이전에 DeletedDateColumn 분기를 추가한 사람이 해당 코드를 커버하는 테스트를 추가했다면 이런 버그가 안생겼을 텐데. 테스트의 중요성을 다시 한번 깨닫는다. 이 이슈덕분에(?) 회사 코드에도 mongo-memory-server로 데이터를 정상적으로 쿼리하는지 판단하는 테스트도 추가했다.
typeorm 테스트 팁
typeorm 테스트를 할 때는 변경 사항이 생길 때마다 전체 코드를 빌드한 후 테스트를 돌려야 한다. 만약 변경사항이 자주 발생한다면 그냥 컴파일된 코드에서 바로바로 고쳐서 npm run test-fast로 실행하는 게 빠르다.
그리고 테스트가 너무 많으니 describe.only나 it.only를 사용해 특정 테스트만 실행하자. (grep 옵션으로도 테스트 필터링이 가능하다)
이번 PR을 통해서 느낀점
mongodb는 repository나 entity manager 코드가 따로 작성되어있어서 RDB (Mysql, postgresql, …) 코드를 전부 테스트하지 않아도 되서 편했던 것 같다. 스택오버플로우나 다른 블로그들을 보니 기존에 많은 사람들이 겪었던 문제 같은데 얼른 머지되서 해결 되었으면 좋겠다. (지금은 머지가 되었다!)
반성
처음에는 원인을 알 수 없어서 그냥 0.2.41 버전으로 내려서 사용하려 했는데, 동료분 중 한분이 ‘임시처리죠?’, ‘원인이 뭐에요? 궁금하지 않아요?’라고 말씀하셔서 회피하지 않고 문제 해결에 파고들 수 있었다.
오픈소스에 대한 신뢰가 커서 ‘내가 뭔가 잘못했겠지’, ‘나중에 해결해야지'라고 해결을 미루려고 했는데 이번 이슈를 통해서 오픈소스 코드에도 실수가 있을 수 있다는 걸 깨달았고 또 해결을 미루려고 했던 내 자신도 반성하게 됐다.
그리고 문제가 되었던 서버의 데이터를 의존하고 있던 서버들도 영향을 받았었는데, 팀 리드분이 장애가 생겨도 영향을 받지 않도록 의존성을 제거하자고 제안해주셨다. 나는 문제가 되었던 서버를 해결하는 데에만 집중했었는데, 다음에 똑같은 문제가 일어나지 않도록 방지책을 생각하시는 모습에서 또 한번 반성했다.
내가 많이 부족하지만 그래도 동료분들이 계셔서 많이 배우고 성장하는 것 같다. 감사링.

pnpm: pnpm patch edit-dir 옵션 추가(22.09)

5304
pull
이번 PR도 실무에서 pnpm patch를 사용하다가 기여하게 되었다.
pnpm patch <packageName@version> 이 어떻게 돌아가는지 원리를 간단히 설명하면, 입력 받은 패키지 버전의 소스를 npm에서 가져온다. 그 다음 임시 폴더를 만들어 user, source 두 하위 폴더에 패키지 소스를 넣는다.
개발자는 user 폴더의 패키지 소스를 수정한 후 pnpm commit 커맨드를 실행되면 pnpm은 user와 source 폴더에 있는 패키지 소스를 비교하여 diff를 감지하고 프로젝트 폴더에 patch 파일을 기록한다.
이미 패치된 패키지를 다시 한 번 패치하려면 기존에 수정했던 user 폴더의 패키지 소스를 수정해야 한다.
그런데 기존 pnpm patch 는 아래와 같이 패치 패키지 소스를 복잡한 임시 경로에 만들어 다시 패치할 때 접근하기 어려운 불편함이 있었다.
> pnpm patch @types/jest You can now edit the following folder: /private/var/folders/hl/s51yjywn6hj4v0w_mhrv8l540000gn/T/828d303a78782154638821e9da7d97b5/user
Shell
복사
그래서 issue를 올렸는데, 메인테이너인 지코찬(zkochan)이 동의하여 PR을 올리게 되었다.
옵션 이름 때문에 잠시 실랑이가 있었지만(지코찬 고집 좀 있으신 듯) 결국 그의 뜻대로 --edit-dir 로 이름 짓게 되었다. --path 가 훨씬 낫지 않나? 하지만 괜히 나도 고집 부려서 PR 클로즈 당할까봐 고분고분 말을 들었다..
pnpm patch는 7버전부터 사용 가능하고, 내가 만든 옵션은 7.11버전에 추가되었다.
pnpm document에도 작고 커엽게 추가되었다.

influxdb-light: write query options 추가 (2023.1.7 토)

influxdb-light 는 influxdb api를 쉽게 사용할 수 있게 만든 가벼운 라이브러리이다.
하지만 너무 가벼운 나머지 write api에 필요한 추가 옵션들이 빠져있었다.
write v1 api
export interface WriteV1QueryParams { precision?: 'n' | 'u' | 'ms' | 's' | 'm' | 'h' /** password */ p?: string /** username */ u?: string /** retention policy */ rp?:string consistency?:'any' | 'one' | 'quorum' | 'all' }
TypeScript
복사
precision은 write payload의 timestamp에 대한 단위를 나타낸다. timestamp에 ms 단위의 숫자를 넘겼다면 precision도 ms로 넘겨줘야 write query가 정상적으로 동작한다.(그렇지 않으면 DB에 적재되지 않는다.)
p, u는 인증 정보
rp: retention policy. 공식 document에 따르면 데이터베이스에 해당 데이터를 얼마 동안이나 유지할 것인지에 대한 옵션이다. autogen 이 기본값인데 ‘영구적으로 유지’하겠다는 의미이다.
consistency: 검색해도 안나옴.. 내 생각에는 클러스터 환경에서 해당 데이터를 어떤 노드들에 배치할 것인지에 대한 옵션 같다. all로 설정하면 클러스터 내 모든 노드에 해당 데이터가 쌓일 것 같은 느낌적인 느낌.
write v2 api
write v2 api에는 precision 옵션만 추가해주면 되었다.
influxDB 관련 용어들
오픈소스 기여 활동을 할 수록 배우는 게 많아진다. 코드에 대해서 배우는 것도 있지만 큰 프로젝트 안에서 협업하는 방법과 태도에 대해 더 많이 배운 것 같다. 오픈소스에서는 프로젝트 관리자가 만들어놓은 contribute 문서를 잘 따르고, 기여하기 전 먼저 이슈를 제기해 프로젝트에 정말 필요한 기능인지 물어보고, PR을 올린 후에도 계속 follow-up하는 등 협업하는 자세와 태도, 절차가 중요한 것 같다.
오픈소스 활동이 더 추가되면 이 문서도 계속 업데이트 될 것이다.
팔로팔로미