2022 오픈소스 컨트리뷰션 아카데미 Challenges 후기
평소 여러 오픈소스 소프트웨어를 사용하면서 여러 사람이 함께 참여하는 오픈소스 방식에 매력을 느끼게 되었다. 특히, 기술은 공유 할 수록 더 발전할 수 있다는 자유 소프트웨어 정신이 좋기도 하였고 좋은 소프트웨어를 개발해준 오픈소스 커뮤니티들에 대한 감사함도 있었다.
그러면서 자연스럽게 나도 오픈소스 개발에 기여해보고 싶다는 생각을 하게되었다. 하지만 선뜻 오픈소스 개발에 뛰어들기에는 망설여졌는데, 아직 학생이라 실력이 부족한 건 아닐까 생각하기도 하였고 오픈소스 커뮤니티가 어떤 식으로 운영되는지에 대해서도 잘 몰랐기 때문이다.
그러던중 멘토의 도움을 받으며 오픈소스 기여활동을 하는 오픈소스 컨트리뷰션 아카데미에 대해 알게 되었고 오픈소스 개발에 참여해보는 좋은 기회가 될것 같아 신청을 결심하게 되었다.
아카데미 지원 (프로젝트 소개)
Yorkie
오픈소스 컨트리뷰션 아카데미에는 25개의 오픈소스 프로젝트가 있고 이중에서 기여해보고 싶은 프로젝트에 지원하는 방식으로 신청을 하게 된다. 따라서 1,2 지망을 골라 지원해야 하는데 나는 1지망 Yorkie, 2지망 Backend.AI를 골라 지원하였고 Yorkie에 붙어 활동하게 되었다!
1지망으로 지원한 Yorkie는 실시간 협업 애플리케이션 개발을 위한 분산 시스템과 SDK를 개발하는 프로젝트로 컨트리뷰션 아카데미 프로젝트 소개를 읽고 처음 알게되었다. Yorkie를 처음 보자마자 매우 큰 관심을 갖게 되었는데, 이전부터 백엔드 서버 개발과 분산 시스템에 대해 관심을 갖고 공부하고자 노력했었고 최근 Go언어에 관심이 생겨 공부하기 시작했는데 마침 Yorkie 서버가 Go언어를 사용해 구현되었기 때문이다. 그리고 Yorkie 데모를 테스트 하면서 매우 빠른 반응속도를 보고 더욱 흥미를 갖게 되었다.
하지만 기존에 주력으로 사용하던 것은 Node.js와 자바스크립트였고 Go언어는 비교적 최근에 시작해서 아직 부족하다 생각해 망설여 지기도 하였다. 그리고 아카데미 후기를 찾아보니 이미 현업에서 일하시는 분들도 많이 지원한다는 것을 보고 아직 학부 3학년인 내가 해낼 수 있을까 걱정이 들기도 했다.
그렇지만 오픈소스 기여를 해볼 수 있는 좋은 기회를 놓치기 아깝다 생각하였고 지원 시기와 실제 활동기간 사이에 긴 텀이 있어 이때 많은 공부를 하며 준비를 하기로 마음 먹었다. 그리고 실제로 이 기간동안 WiFi Positioning Server 작업을 Go언어로 포팅을 하면서 공부를 했다.
Openstack, Backend.AI
다음으로 Yorkie를 제외하고도 Openstack과 Backend.AI에도 관심이 갔었다.
특히 Openstack은 대학교 1학년때 Openstack 커뮤니티에 속한 연사분의 초청강의를 들어본적이 있기도 하였고 가상화와 분산 시스템에 매우 많은 관심이 있었기 때문이다. 특히 가상화 기술을 사용한 인프라 구축에대해 공부하고 싶다고 생각하였다. 하지만 아직 많은 공부를 해본것이 아니라 기반 지식이 부족하다고 생각하였고 Openstack 개발에 사용되는 Python에 대한 깊은 이해가 없어 지원을 보류하게 되었다. 만약 후에 기회가 된다면 반드시 오픈스택에 대해 공부하고 더 나아가 기여 또한 해보고 싶다.
Backend.AI의 경우 AI 백엔드 플랫폼을 개발하는 프로젝트이다. 플랫폼 시스템의 구조와 그 구현에 대해 공부하고 싶었기 때문에 Backend.AI 또한 프로젝트 소개에서 보자마자 관심을 갖게 되었다. 무엇보다 최근 시작한 졸업작품 프로젝트가 사진 업스케일링 플랫폼을 개발하는것을 주제로 선정했기 때문에 딥러닝을 통한 이미지 업스케일링을 공부하기 시작하면서 AI 백엔드 플랫폼이라는것이 흥미롭다고 생각했다. 따라서 Yorkie와 조율하다 최근 Go언어에 관심이 쏠리면서 2지망으로 지원하게 되었다.
발대식
Yorkie 팀의 발대식은 7월 9일 토요일에 온오프라인으로 동시에 진행되었다.
나는 오프라인으로 발대식에 참여했는데 장소는 선릉역 근처의 저스트코타워였다.
건물에 도착한뒤 출석을 체크하고 기념품과 다과를 받고 Yorkie팀의 세미나실로 이동하였다. 기념품으로 에코백과 충전기 등을 받았고 샌드위치와 쿠키, 음료수 또한 받았다!(기념품을 사진으로 남겼어야 했는데 까먹었다ㅠㅜ)
발대식은 30분 정도 진행됬던걸로 기억하고 아이스브레이킹을 위한 간단한 게임들도 같이 진행하였다. 아카데미 발대식 이후에는 팀별 발대식을 진행하였고 Yorkie 프로젝트에 대한 소개와 질답 시간을 가졌다. 팀별 발대식에서 Yorkie 프로젝트의 일부분인 Codepair를 사용해 동시편집을 하며 내용을 정리하였는데 이렇게 실제 사용되는 프로젝트에 기여할 생각을 하니 왠지 가슴이 벅차기도 했다ㅎ 발대식이 진행된 뒤에는 모두 같이 기념사진을 촬영한뒤 해산하였다.
기본 Git 교육
본격적인 컨트리뷰션 활동에 앞서 주최측에서 기본 Git 사용법에 대한 교육을 진행하였다. 교육은 총 2회 진행되었는데 둘의 내용은 같아 시간이 되는 회차에 참가하면 되는 방식이었다. 나는 발대식 바로 다음날인 7월 10일에 참여 하였고 오전 9시부터 오후 18시까지로 오전에는 기초를 배우고 오후에는 응용과 실습을 진행하였다.
내용은 처음에는 git 명령인 status, add, commit, push, pull, log 등에 대해 알아보았고 다음으로 협업을 위한 branch, checkout, remote, pull request 등에 대해 배올 수 있었다. 그런다음 이러한 브랜치를 관리하기위해 fetch를 사용해 원격지 업데이트 내용을 불러오고 merge, rebase 등을 하며 conflict를 해결하는 방법에 대해 배웠다. 마지막으로 reset, rebase -i 등과 같은 심화 기능을 배운뒤 git blame과 같이 과거 기록을 조회해 프로젝트 구조나 구현 의도를 파악하는 방법을 배울 수 있었다.
기존에도 팀 프로젝트 등을 진행하면서 어느정도 Github과 Git에 대한 사용법을 알고 있었지만 이번 교육을 통해 상세한 사용법과 실제 오픈소스 개발 과정에서의 개발 흐름에 대한것까지 배울 수 있었다. 특히, 오픈소스 프로젝트를 파악하는 여러 꿀팁과 경험에 대해 배울 수 있었고 실제 프로젝트 개발의 과정과 소통의 과정, 코드 리뷰 과정에 대해 알 수 있게된 너무 소중한 시간이었다. 다른 사람에게도 오픈소스 컨트리뷰션 아카데미에 참여한다면 꼭 기본 교육을 수강하라고 추천하고 싶었다.
Challenges 기간
기본교육이 끝나고 Challenges 기간이 시작 되었다. 오픈소스 컨트리뷰션 아카데미는 크게 두개의 기간을 가지고 진행되는데 challenges 기간과 masters 기간이 그것이다. 그 사이에는 중간발표가 있고 마지막에는 최종발표가 있다. Masters 기간은 Challenges 기간의 활동을 바탕으로 선발되어야 이어서 진행할 수 있다.
Challenges 기간이 시작되면서 Yorkie 팀은 멘티를 크게 3팀으로 나눠 진행하기로 하였고 R,G,B 3개의 팀으로 나누게 되었다. 그리고 모든 소통은 Slack을 기반으로 진행하기로 하며 Yorkie Slack에 초대되었고 활동을 시작하게 되었다.
본격적인 기여에 앞서 우선 Yorkie 프로젝트의 구현을 이해하기 위해 노력했다. Yorkie의 문서를 열심히 읽어보았고 gRPC에 대해 기존에 사용해본적이 없어 예제 코드를 제작하면서 공부를 하였다. 그리고 Yorkie의 개발환경을 구성하고 데모를 테스트해보는 시간을 가지며 여러 이슈들과 PR의 내용을 확인하며 기여를 해볼 수 있는 부분을 찾아보았다.
첫 이슈 선점 - Add --backend-snapshot-with-purging-changes
flag #288
이슈 링크: https://github.com/yorkie-team/yorkie/issues/288
그렇게 열심히 공부하던중 한 이슈에 관심이 가기 시작했고 마침 메인테이너께서 Good First Issue
라벨을 달아두셨길래 드디어 처음으로 이슈를 선점하는 코멘트를 달게되었다.
이슈에 대해 설명하자면 현재 yorkie의 구현은 모든 변경사항(change)들을 하도 빠짐없이 저장하는 방식이다. 하지만 이는 많은 저장공간을 차지하게 되기도 하고 yorkie에는 이미 특정 버전의 document를 저장하는 snapshot이라는 기능이 구현되어 있기도 하므로 이를 활용해 snapshot이 저장될때 이전의 change들을 삭제하는 옵션을 추가하자는 제안이었다.
이 이슈를 확인하면서 snapshot이 생성될때 단순히 DB에서 change들을 일괄 삭제하는 간단한 작업만 추가하면 될것이라 생각하였고 호기롭게 이슈를 선점하고 개발을 시작하였다..(이때는 아직 엄청난 난관이 있을줄은 몰랐다..)
첫 이슈 - example/index.js
stops when receiving a snapshot from the server. #347
그렇게 열심히 개발에 몰입하던 중 이상한점을 발견하게 되는데 이를 통해 처음으로 issue를 생성하게 되었다.
첫 이슈: https://github.com/yorkie-team/yorkie-js-sdk/issues/347
이상한 점은 바로 프론트에서 서버와 통신하며 수정 사항을 동기화 할때 change 자료형이 아닌 snapshot 자료형으로 수정사항을 전달받으면 작동이 멈추는 문제였다. 처음에는 위의 이슈를 개발하고 있었으니 내가 개발한 부분에서 문제가 생기는줄 알고 계속 코드를 수정하며 테스트 했는데 도저히 고쳐지지 않아 많은 고민을 하고 있었다. 그러다 번뜩 버그일 수도 있다는 생각을 하였고 테스트를 해보니 버그인것 같아 이슈를 써보기로 생각했다.
이렇게 발견한 버그에 대해 계속 테스트하며 재현 방법을 확인해 보았고 상세히 첫 이슈를 작성해 보게 되었다. 현재는 버그가 수정되어 이슈가 Closed 되었다.
첫 PR - Add --backend-snapshot-with-purging-changes
flag #370
첫 PR: https://github.com/yorkie-team/yorkie/pull/370
위에서 이슈를 선점한뒤 개발을 시작했는데 그 과정은 생각보다 쉽지 않았다..
우선 새로운 플래그가 추가되어야 하니 Yorkie에서 CLI 구현을 위해 사용한 Cobra 라이브러리를 공부해 --backend-snapshot-with-purging-changes
플래그를 추가해 주었다. 이를 위해 /server/backend/config.go
에 SnapshotWithPurgingChanges 변수도 추가해 주었다.
그런다음 /server/packs/snapshot.go
의 storeSanpshot 함수와 /server/backend/database
의 코드들을 수정해 snapshot이 생성될때 change들을 삭제하는 코드를 추가했다. 그리고 제대로 작동하는지 확인하기 위해 계속 테스트를 진행해 보았고 몇가지 문제를 발견하게 되었다.
첫번째는 위에서 적은 버그를 발견한 것이었다! 처음으로 오픈소스 프로젝트의 버그를 발견한 것이었고 열심히 버그를 확인한 뒤 떨리는 마음으로 첫 이슈를 작성하게 되었다.
두번째는 change를 삭제하도록 했더니 SyncedSeqs를 기록하는 부분에서 문제가 생긴것이다. 처음에는 단순히 change만 삭제하면 될줄 알았는데 change가 삭제되면 에러가 나는 부분이 있던것이다. 이를 해결하기 위해 처음에는 유심히 확인하지 않았던, 동기화가 일어날때 마지막으로 동기화하는 지점을 기록하는 SyncedSeqs와 관련된 코드를 열심히 확인하였다.
그 결과 문제를 찾을 수 있었는데, UpdateSyncedSeq 함수에서 SyncedSeq가 기록된 테이블을 업데이트 할때 해당 ServerSeq의 change를 호출하는 부분이 있던 것이다. 원인을 찾고 고민 끝에 동기화가 일어나기 전의 change는 삭제하면 안된다고 생각하였고 snapshot을 생성할때 change를 일괄 삭제하는 것이 아닌 SyncedSeq 테이블에 기록된 동기화가 끝난 change들만 삭제하도록 변경하였다.
이렇게 수정을 하고 테스트를 했더니 크게 문제가 없는것 같아 개발이 완료되었다고 생각했고, PR을 생성하기로 했다.
하지만 의기양양하게 PR을 열었지만 무수한 코멘트를 받게 되고 생각보다 많은 문제에 직면하게 된다..
Add --backend-snapshot-with-purging-changes
flag #370 코드 리뷰
PR을 생성하고 시간이 조금 지나서 mainter 분께서 코멘트를 달아 주셨다. 코멘트는 간단한 이야기였는데 history 명령을 실행할때도 문제가 없냐는 부분이었다.
이는 개발을 하면서 간과했던 부분이었는데, 내가 위 플래그를 개발시작하기 불과 얼마전에 새롭게 change들을 조회하는 history 명령이 업데이트 되었는데 이를 간과한 것이었다..
빠르게 수정작업을 시작하였고 admin 관련 cli 부분을 모두 확인하느라 쉽지 않았다. 특히 기존의 구현은 모든 change가 존재하는것을 전제로 해서 그런지 상당히 많은 부분을 수정해야 할것 같았고 최대한 원래 코드를 건드리지 않으면서 change가 삭제된 경우를 예외처리 하기 위해 노력했다.
결국 gRPC를 위한 proto파일까지 수정해 프로토콜에 대한 변경사항까지 추가해야 했다.
이렇게 history 명령에 대한 부분은 해결해서 푸쉬하였지만 아직 더 수정할 부분이 있었는데, 바로 test 코드를 간과한 것이었다. 평소 작은 규모의 과제 정도에서는 테스트 코드까지 작성해 테스트를 자동화 하며 테스트할 일이 없었다. 하지만 이정도의 큰 규모의 프로젝트에서는 모든 기능 하나하나에대한 테스트 코드를 작성하며 개발을 해야한다.
나는 평소 간과하고 있던 테스트에 대해 다시 깨달으며 Go언어에서 테스트 코드를 작성하는 방법을 공부하고 테스트를 만드는 작업을 시작했다.
처음에는 간단하게 예외처리만을 추가한 테스트를 생각하다가 이걸로는 부족하다 생각해 --backend-snapshot-with-purging-changes
플래그가 있을때 change가 제대로 삭제되는지, history 명령은 제대로 작동하는지 테스트를 작성했다. 이 과정에서 자료형과 관련해서 일관성이 부족한 문제를 확인할 수 있었고 이는 따로 분리해서 다루는게 좋다고 생각해 따로 이슈를 생성하였다. 이에대한 것은 아래에 자세히 서술했다.
이제 테스트도 작성했겠다 이제 개발이 완료되었다고 생각하던 때에 작업한 테스트를 푸쉬했더니 또다른 문제가 생겼다.
문제는 나의 로컬 환경에서는 테스트가 성공하는데 테스트를 푸쉬한뒤 github actions의 CI툴이 자동으로 테스트가 수행되면 테스트에 실패하는 것이었다.
이 문제는 나에게 상당한 멘붕을 느끼게 했다. 나의 로컬 환경에서는 재현이 안되는데 도저히 원인을 파악할 수 없었기 때문이다. 그래서 Yorkie Slack에 도움을 구해보기도 하고 문제 해결을 위해 계속 고민을 했다.
그러다 문득 yorkie에서 snapshot을 생성할 때는 goroutine을 사용한다는 것이 기억났고 이 문제가 타이밍 문제라는 직감이 들었다. 바로 테스트 해봤고 명시적으로 긴시간을 sleep했더니 문제가 해결되는것을 확인할 수 있었다.
추가로 몽키패치를 적용하는것이 좋겠다는 코멘트가 달렸고 처음으로 몽키패치가 뭔지에 대해 알 수 있었다.
이외에도 구현에 대한 여러 코멘트를 주고 받았고 또 수정하는 작업을 했다.
이처럼 생각보다 간단한 기능이라 생각했던것이 많은 코드를 수정해야 했고 많은 난관이 있었다. 아직 PR 또한 크리티컬한 부분을 많이 건드리기도 해서 메인으로의 merge는 보류 중이다.
메인테이너 멘토께서도 많은 부분을 건드리는 만큼 구현에 대한 토론을 제의해 주셨고 이때 이 플래그 기능의 추가에 대한 의견을 좀 더 실시간으로 나눌수 있을것 같다.
하지만 아직 개발이 완료된것은 아니어도 개발 과정에서 많은 것을 배울 수 있었다. 특히 새로운 기능을 추가할때는 이와 연관된 다른 기능들도 확인해야 하는것을 알 수 있었고, 코드 스타일을 주의해서 작성해야 한다는것도 느낄 수 있었다. 또한 테스트의 중요성을 다시한번 생각할 수 있었고 테스트를 위한 몽키패치와 같은 방법을 알 수 있었다.
비록 기능 추가 자체가 보류될 수도 있다고 생각하지만 많은 것을 배울 수 있는 의미있는 시간이었다.
두번째 이슈 및 PR - Change the data type of data inserted into the db from uint64 to int64 #379
이슈 링크: https://github.com/yorkie-team/yorkie/issues/373
PR 링크: https://github.com/yorkie-team/yorkie/issues/373
이 이슈는 위의 이슈를 작업하다가 발견하게 되었다. 이슈의 내용은 mongodb는 정수를 int64 또는 int32로만 취급해서 uint64는 int64로 변환되어 저장된다는 것을 알게 된것이다. 이러한 사실을 코멘트로 의견을 교환했더니 메인테이너께서 이를 수정하는것을 제안해 주셨다. 왜냐하면 DB에 저장되는 데이터 타입과 서버에서 다루는 데이터 타입이 다른경우 개발에 혼동을 줄 수 있으니 데이터 타입 일관성을 위해 데이터 타입을 변경할 필요가 있기 때문이다.
vscode의 검색 기능을 이용해 uint64 데이터 형중 DB에 삽입되는 데이터를 변환해 주었다. 작업 결과를 PR로 올렸고 메인테이너께서 그 사이에 생긴 업데이트로 인한 충돌 사항을 해결해 병합해 주셨다.
작업 시작은 위의 이슈를 먼저 시작하였지만 어쩌다 보니 이것이 내가 기여한 첫 작업이 되었다!!!
그리고 나도 드디어 contributor 칭호를 얻게 되었다 ^_^
중간보고 및 Masters
이것으로 Challenges 기간이 끝나게 되었다. 오픈소스 기여를 경험해볼 수 있는 정말 좋은 시간이었고 재미 또한 있었다고 생각한다. Challenges 기간이 끝나면 중간 활동 보고서를 작성해야 했기에 작성했고 Masters 기간은 선정된 멘티만 이어서 할 수 있기에 기다려야 했다.
그렇게 Masters 기간 합격자 선정을 기다리고 있었는데 어느날 멘토분께 연락이 왔다. 연락은 바로 Masters 기간동안 리드멘티를 해볼 생각이 없냐는 제의 였다!!
선뜻 리드멘티를 했다가 잘 할 수 있을까 고민도 되었지만, 리드멘티를 하기로 했다.
리드멘티 중에 한명은 중간 발표회의 발표자가 되어 발표를 해야 한다. Yorkie 팀의 리드멘티는 나를 포함해 총 두명이었는데 slack DM을 통해 연락을 하였고 우선 중간 발표회는 다른 리드멘티분께서 발표를 하기로 하였다.
그리고 중간 발표회를 위한 발표자료를 준비해야 했는데, 이는 같이 준비를 하기로 하였다. 서로 시간을 조율해 구글 미트로 같이 이야기하며 작업하기로 하였고 함께 발표자료를 작업하고 발표 스크립트를 준비했다.
중간 발표회는 8월 13일에 있었고 이로써 Challenges 기간이 완전히 종료되고 Masters 기간이 시작되었다!