안드로이드 개발자의 서버 개발기

Image not Found

안녕하세요. 곽서현입니다. 저는 버즈빌에서 안드로이드 개발자로 일하고 있습니다. 이번 글에서는 제가 서버 개발을 시작하면서 겪었던 시행착오와 제가 서버 개발에 적용할 수 있도록 해준 버즈빌의 가이드에 대한 소개를 해보려고 합니다. 주니어 개발자를 온보딩 시키거나 타직군에서 넘어오는 경우 어떻게 실무에 적응 시킬 수 있는지 고민하시는 분들에게 도움이 되길 바랍니다.

0. Motivation

안드로이드 개발을 하고 있는 제가 이번에 서버 개발을 하게 된 이유는 모든 회사가 항상 겪고 있는 고질병인 리소스 부족이었습니다. 물론 서버 개발할 사람이 부족하니 “너가 해!” 해서 이렇게 된 것은 당연히 아닙니다. 개발해야 할 일이 생겼고 마침 서버 개발을 하고 싶었던 제가 일을 맡게 되었습니다. 신규 서비스를 개발 중인 저희 팀은 안드로이드 개발자 2명, 디자이너 1명, PM 1명으로 이루어진, 작지만 전형적인 스타트업 같은 팀입니다. 팀에서 실험적인 기능 하나를 기획했지만 서버를 개발할 서버 엔지니어가 없었습니다. 하지만 우리 팀은 저를 포함하여 당장 이 기능을 런칭해서 데이터를 보고 싶어하는 조급한 이들로 이루어져 있었기에 ‘안되면 내가 하지 뭐’ 라는 단순한 생각으로 시작하게 되었습니다. 서버 개발을 만만하게 본 것은 아니었지만, 예상 사용자 수가 DAU의 10% 정도로 작은 기능 - 물론 바람은 더 높습니다만 - 이었기 때문에, 기존 서버 개발자분들의 도움을 받는다면 가능할 것 같았습니다. 버즈빌에서는 빠르게 개발하고 빠르게 테스트해 보는 문화를 장려하기 때문에 난데없이 안드로이드 개발자가 서버 개발을 한다고 했을 때 말리는 사람은 아무도 없었습니다.

다른 직군에서 보면 개발자는 다 똑같이 까만 화면에 알록달록한 글씨를 타이핑하는 사람들이겠지만 사실 개발 분야는 꽤 다양하게 나누어져 있고 분야 간 이동도 적습니다. 하지만 개발자들은 자기 서비스를 처음부터 끝까지 자기 손으로 만들어 보고 싶다는 욕구를 다들 조금씩은 가지고 있기 마련입니다. 지난여름 회사 내의 개발자와 디자이너들과 새로운 서비스를 만들어 보는 모임을 만들었는데 (버즈빌에는 스터디 활동이 정말 활발합니다. 요새는 코로나 때문에 못 모이고 있네요.) 거기서 go project와 react를 써볼 일이 있었고 꽤 재밌었습니다. 버즈빌에서는 개발자들의 자기 개발을 적극적으로 지원하고 있고, 개발자가 원한다면 다양한 직무를 맡을 수 있도록 장려하고 있습니다.

1. 시작하기

일단 제가 서버개발을 시작한다고 하니 서버 개발자 한분이 도와주시겠다고 했습니다. 그리고 저에게 가이드 문서를 주셨습니다. 처음 써보는 것들이 많아 명확히 이해하진 못했지만, 전체적인 개발 플로우를 익힐 수 있었습니다.

다음은 버즈빌 서버 개발을 하면서 쓴 툴, 언어들입니다.

  • Visual Studio Code
  • Go
  • Docker, docker compose
  • cookiecutter
  • swagger
  • kubectl

Design Canvas

자, 이제 서버 개발을 해 봅시다. 그런데 잠깐, 바로 코딩하는 게 아니네요? 첫 번째 할 일은 디자인 캔버스 작성입니다. 버즈빌에서는 마이크로서비스 아키텍처를 지향하고 있고 신규 서비스는 새로운 마이크로 서비스로 만들어 배포하고 있습니다. 새로운 서비스 작성자는 해당 서비스가 왜 필요하고 어떤 기능을 하는지 등을 포함한 디자인 캔버스를 작성한 후, 다른 서버 개발자, PM 분들과 함께 리뷰를 진행합니다. 다음은 디자인 캔버스에 포함되는 사항입니다.

  • 서비스 목적
  • 이 서비스에서 다루는 범위 / 다루지 않는 범위
  • API
  • 마일스톤
  • dependency가 있는 다른 서비스
  • 예상 request e.g. high throughput

디자인 캔버스를 작성함으로써 마이크로 서비스의 목적과 범위를 명확히 하고 작성자와 팀 간에 무엇을 어떻게 만들지 합의를 보게 됩니다. 팀 내에서 다 같이 기획을 했기 때문에 범위를 정하는 건 수월했는데, request 예상은 어떻게 해야 할지 감을 잡기 힘들어서 다른 분들이 작성하신 디자인 캔버스를 많이 참고했습니다.

디자인 캔버스를 작성하고 저 포함 5명 정도의 사람을 모아 리뷰를 진행했습니다. 디자인 캔버스의 리뷰에는 이 서비스를 왜 만들어야 하는지 뿐 아니라 model 이름과 db schema에 대한 대략적인 방향까지 포함됩니다. 수정을 거쳐 드디어 통과됐습니다!

API 설계

그다음 단계는 디자인 캔버스를 통해 합의한 API를 protobuf 로 작성해야 합니다. protobuf란 grpc로 통신하기 위해 필요한 API를 작성하는 방식입니다. protobuf 나 API first approach 같은 부분은 버즈빌의 수요 데브 세미나에서 여러 번 다루어졌던 주제라 당황스러운 내용은 없었습니다. 버즈빌은 protobuf로 작성되는 API를 하나의 리포에서 관리합니다. pr이 마스터에 머지되면 해당 패키지에 있는 API는 swagger를 통해 protobuf 와 java로 된 http클라이언트로 빌드하고 배포합니다. 그럼 안드로이드에서는 http 클라이언트를 가져다 쓰면 되니, 안드로이드 쪽에서 API 관련 코드를 작성하는 수고가 없어집니다. API가 작성되면 가져다 쓰던 안드로이드 개발자 시절에는 별생각 없었는데 직접 API를 작성해 보니 생각해야 할 게 꽤 많네요. 그래도 봐 오던 게 있으니 부딪혀 봅니다. 서당개 삼년이면 풍월을 읊는다고 남들이 어떻게 하는지 잘 관찰하는 것도 자신의 성장에 큰 도움이 됩니다. 그리고 풍월을 잘 읊으려면 좋은 서당에 있어야겠죠?

  • API 이름이 간결하고 의미를 잘 전달하는가
  • 리소스 이름이 restful한가
  • 앱에서 호출하는 API 인지, 내부용 API 인지
  • 불필요하게 중북된 리소스는 없는지

API를 작성하면서 좋았던 것은 클라이언트 개발자 입장에서 어떤 API를 호출해서 어떤 기능을 수행하고, 화면이 어떻게 구성될지, 어떻게 바뀔지 그려볼 수 있다는 점이었습니다. protobuf 함수 이름은 디자인 캔버스 작성할 때 이미 합의를 했기 때문에 별문제 없었는데 restful한 리소스 이름 정하는 게 고민이 됐습니다. 애매한 지점이 있을 때 일단 pr을 만들고 리뷰어 분과 논의해서 정했습니다. 몇번의 핑퐁 끝에 API 작성도 클리어했습니다.

3. Go project 개발

Bootstrap

이제 진짜 go project를 시작할 준비가 되었습니다! 뭐든지 부트스트랩이 가장 헷갈리잖아요? 어디서부터 시작하지? 하는 것이 처음 도전할 때 가장 큰 허들 일 것 같아요. 안드로이드 개발은 대체로 Android Studio를 설치하면 준비가 완료되지만 서버 개발은 뭐부터 해야 할지 막막했습니다. 하지만 버즈빌에서는 처음 해보는 사람이 당황하지 않도록 템플릿이 준비되어 있습니다. 버즈빌 개발팀에서 cookiecutter를 이용해 프로젝트 템플릿을 미리 설정해 두었고 저는 템플릿을 이용해 리소스 이름, 패키지 이름, 프로젝트 이름만 넣으면 go project를 생성할 수 있었습니다. cookiecutter는 프로젝트 템플릿을 설정할 수 있는 유틸리티입니다. 프로젝트를 열어 보면 cmd, internal 패키지와 그 아래 usecase, repo, entity 파일, 그리고 go mod와 docker compose yml 까지 다 들어있네요! 저는 정해진 위치에 필요한 로직만 추가하면 됩니다. 참고로 IDE는 VSCode를 사용했고 docker compose를 이용해 devcontainer를 띄워 그 위에서 작업했습니다. VSCode의 Remote Container extension을 이용해 컨테이너 내부에 개발 환경을 설정할 수 있습니다. (여기서 자세히) docker compose는 개발용 환경설정 및 개발에 필요한 database를 도커에 만들어주는 등 컨테이너 실행에 필요한 옵션을 관리해 주는 역할을 합니다.

Presentation layer development

cookiecutter로 생성된 고 프로젝트는 presentation layer, domain layer, data layer로 나누어져 있고 각각의 이름은 server, usecase, repo 입니다. 개발자 마다 다르겠지만 저는 server 부터 작업을 했습니다. repo는 가장 마지막에 작업했고 따라서 local db 세팅도 가장 나중에 했습니다. presentation layer의 작업은 크게 많지는 않았습니다. protobuf를 미리 정해 놓았기 때문에 API에 맞도록 코드를 작성하면 됩니다. cookiecutter로 main 함수의 대부분이 설정되어 있기 때문에 첫 pr은 비교적 쉽게 날릴 수 있었습니다.

Test

pr을 보내기 전에 먼저 잘 돌아가는지 테스트를 해봐야겠죠? docker-compose.test.yml을 만들고 docker 설정을 해주면 test환경을 만들어 줄 수 있습니다. 서버를 실제 띄워 본 것은 아니고 테스트를 작성해서 검증했습니다. TDD로 개발하는 게 정말 편하기도 했지만 이래도 되는 걸까 하는 마음이 동시에 들었습니다. 안드로이드에서는 integration test가 시간이 오래 걸려서 디바이스에 직접 실행해 보는 것이 더 편합니다. 물론 안드로이드 팀에서도 테스트를 중요시하고 있지만 integration test, ui test가 느리고 힘들기도 하기 때문에 디바이스 한번 켜보지 않고 이 코드는 잘 돌아간다고 쉽게 말하기는 힘들 것 같습니다. 그래서 TDD가 서버 개발에 있어서 가장 적응이 안 되면서도 가장 편하다고 생각했던 부분이었습니다.

테스트를 처음 돌리기까지 많은 삽질이 있었습니다. docker를 실행시키고 vscode에서 test 환경의 docker image를 빌드해서 그 위에서 작업했는데 이런 개념에 익숙해지는데 시간이 걸렸습니다. 그래도 최근에 만들어진 다른 마이크로 서비스들이 제가 작업하는 것과 비슷한 환경으로 개발되었기 때문에 참고할 수 있는 것이 정말 감사했습니다.

Pull request

모든 팀의 PR이 그렇겠지만 서버팀에 보낸 PR에서도 다른 개발자분들이 많은 꿀팁을 전수해 주셨습니다. error 핸들링은 어떻게 할지, 컨벤션이 어떤 건지 등등 다양한 의견이 있습니다. 저희 팀에 주니어분이 오시면 저도 더 상세하게 리뷰를 해야겠다는 생각도 듭니다.

그리고 첫번째 pr이라고 축하도 받았습니다!

참고로 커피는 아직 못 받았습니다. 하하.

Domain, Data layer development

이제 domain layer와 data layer 작업만 남았네요. domain layer 작업을 마치고 마지막 data layer 작업을 위해 도커로 db를 세팅했는데 정말 편했습니다. db 설정이 몇 줄 설정만 가지고 된다는 게 정말 좋네요. 디비로 mysql을 설정해 놓았는데 orm을 뭘 쓸지, migration은 어떻게 할지 정해야 합니다. 당시 서버팀에서 gorm과 migrate에서 다른 툴로 옮겨 가려고 실험할 때라 모든 서비스가 사용하는 툴이 통일되어 있진 않았는데 논의 끝에 raw SQL과 goose를 쓰기로 일단 합의가 되었습니다. raw SQL은 딱히 더 알아야 할 툴이 없는 것은 편했고 SQL을 다 작성해 주자니 귀찮은 면도 있었습니다. 여기에 대해서는 개발자 분마다 생각이 다를 것 같습니다.

repo 작업까지 마치고 pr에 대한 리뷰를 받아보니 제가 작업하면서 이게 도메인 로직인지 아닌지에 대한 고민이 좀 부족했구나 하는 것이 느껴졌습니다. 예를 들어 모델을 데이터베이스에서 가져오는 작업을 수행하는데, 가져올 때 없으면 생성하고 있으면 저장된 걸 꺼내오는 로직을, 저는 데이터 레이어에서 할 일이라고 생각했습니다. 그런데 리뷰해주신 분과 얘기하다 보니 그건 도메인 레이어로 보는 것이 맞는 것 같았습니다. Upsert를 하는 과정에서 데이터 레이어의 interface가 지저분해진 면도 있었고요. 그 부분을 도메인 레이어로 옮기니 데이터 레이어가 한결 깔끔해집니다! interface에서 GetLotteryTicket 이 세 가지 interface로 분리되었지만, implementation에서는 정리가 더 잘 되었습니다. 도메인 로직을 잘 분리하는 것은 안드로이드 개발에서도 중요한 부분이기 때문에 이번에 이렇게 더 배우게 되어 좋았습니다. 안드로이드는 뷰까지 가세해 코드가 더 복잡하고 코드의 양이 훨씬 많아서 레이어를 나누는 부분에 있어서 더 신중하게 고민해야겠다는 생각이 듭니다.

| Before

type Repo interface {
	GetLotteryTicket(accountID int64, appID int64, lotteryKey string) (*LotteryTicket, error)
}

| After

type Repo interface {
	GetLotteryTicket(accountID int64, lotteryID int64) (*LotteryTicket, error)
	GetLotteryByKey(key string) (*Lottery, error)
	SaveLottery(lottery *Lottery) error
}

4. Deployment

마지막으로 배포는 제가 거의 신경을 쓰지 않았는데, 그 이유는 버즈빌의 devops 팀에서 다 알아서 해주셨기 때문입니다.(고마워요 ㅠㅠ) CI설정, production/staging db 세팅 등 코드가 실제 배포되기까지의 수많은 일을 담당해 주셨는데 이 부분에서 좋았던 점은 많은 부분이 템플릿화가 되어 있어서 각 서비스에 맞게 조금씩만 수정해 주면 처음부터 세팅하지 않아도 된다는 점이었습니다. 그러고 보면 서버 개발의 많은 부분이 템플릿화가 되어 있어서 휴먼에러를 최대한 줄여주고 있습니다. 이런 점은 서버 개발을 하면서 큰 도움이 되었습니다. 이 모든 것은 셋업해주신 버즈빌 개발자분들 만세!

5. 회고

좋았던 점

작업을 하면서 가장 감사했던 부분은 다른 개발자분들의 리뷰와 관심이었습니다. 특히 제가 작업한 서비스와 전혀 관계없는 개발자분도 이렇게 주말 동안 저의 코드를 읽고 직접 pr까지 보내주셨습니다. 비록 merge는 되지 못했지만, 덕분에 go로 작업하는 부분에 힌트를 많이 얻을 수 있었습니다.

좋았던 점 하나를 더 꼽자면 서버 개발, 배포 과정과 로그를 볼 수 있는 방법들을 알게 되었다는 점입니다. 나중에 안드로이드 개발하다가 뭔가 버그가 있는 것 같을 때 간단한 트러블슈팅 정도는 할 수 있게 된 것 같아 뿌듯하네요. 다른 서비스들에도 PR 날려보고 싶어졌습니다.

힘들었던 점

서버 개발을 하면서 힘들었던 점은 인프라 권한을 받는다거나 데이터베이스 마이그레이션 하는 툴은 따로 설치해야 한다거나 하는 식의 미리 설정해 둬야 하는 부분이 많다는 점이었습니다. 컨플루언스로 정리가 잘 되어 있어서 따라 하는 데 큰 무리는 없었지만, 간혹 막히면 막막해졌습니다. 문서에는 트러블슈팅이 함께 들어가면 좋을 것 같습니다.

그래서 앞으로는?

한동안 클라이언트 개발만 하다가 오랜만에 서버 작업을 하니 개인적으로 꽤 재밌는 시간이었습니다. 속도가 아주 빨랐다고는 할 수 없지만 그래도 계획한 시간과 크게 틀어지진 않았던 것으로도 만족합니다. 오지랖일 수도 있지만, 팀에서 필요한 서비스가 있다면 제가 하겠다고 해볼 수 있을 것 같습니다. 회사 내의 여러 개발자분과 협업하고 배울 수 있는 시간은 뭐든 소중합니다. 앞으로 또 기획부터 개발, 배포까지 혼자서 하게 될 일이 또 있을지 모르겠지만 또 하게 된다면 이번 배움을 바탕으로 더 잘 할 수 있을 것 같습니다. 그러려면 이번에 겪었던 일들을 문서로 잘 정리해 두어야겠죠. 정리된 문서는 개발팀 내부에 공유할 예정입니다.

서버 개발자분이 안드로이드 개발을 맡게 되시거나 주니어 개발자분이 팀에 합류하게 될 때 잘 해드려야겠다는 생각도 듭니다. 문서정리도 중요하지만, 같이 일하고 서비스를 만들어나가는 느낌을 받는 게 좋았거든요. 개발팀은 드라이하게 일한다는 생각을 할 수도 있겠지만 개발팀의 문화가 개발자 개개인에게 큰 영향을 주기도 합니다. 하고 싶은 게 있을 때 해보라고 기회를 주고 서로에게 배우려는 문화가 있는 조직에서 일하게 되어 다행이라는 생각이 듭니다.

You May Also Like

버즈빌, 아마도 당신이 원하던 회사!

지원하기