시작

이전 글이 2020 첫 개인 프로젝트로 서버 개발을 공부해보고 싶었다.로 시작하는데, 서버 개발을 시작한지 얼마 안 되어서 인턴 참여 기회가 생겼다.
사실 이전 글인 서버 개발 챌린지 글은 인턴 지원하고, 코딩 테스트 이후 시작했던 활동이다. 서류-코테-면접 순으로 진행됐었고, 3개월 동안 참여했다. 코로나 때문인지 결과 발표까지의 기간이 4개월 정도 걸렸다..
원래는 이 기간에 안되면 대학원 컨택을 할 생각이었는데, 발표가 늦어서 컨택은 하지 못했다. 결과적으로 대학원 생각은 없어졌다(?)
지금은(7월) 인턴십 기간이 끝났고 학교로 돌아가야 한다(ㅠㅠ). 졸업이 꽤나 남아서 마지막 여름방학을 즐기고 있다 ^ㅁ^


과정

3개월이 그리 짧은 기간은 아니어서(실제로 내가 있던 부서는 이렇게 장기 인턴은(?) 처음이라고 하셨었다),
다양한 활동을 해볼 수 있었는데 회사에서 했던 활동은 내 소유가 아니어서 자세히 쓸 수 없다.

백엔드로 지원했었는데, 사실 백엔드를 해본 기회가 많이 없었어서 쫄았었지만.. 천사 멘토님 덕분에…ㅜㅜ(흑흑 멘토님 그립다..)… 무사히 마친 것 같다.

REST API

이전에도 REST API처럼 보이는를 만들어 봤었지만, 좀 더 RESTful하게 만들 수 있었다.
사실 이전 버드뷰 챌린지 코드 리뷰에서도 지적받은 점들이 몇 개 있었는데,

1. 코드 포맷팅

사실 지금까지는 개인 프로젝트여서 멋대로 했었는데, 포맷팅을 하는 게 나중에 볼 때도 훨씬 좋아 보였다.
버드뷰 챌린지 코드 리뷰에서는 파이썬이니까 PEP8이 아니라서 아쉬웠다는 지적을 공통적으로 받았다.
여기서는 사내 코딩 컨벤션 규칙을 따르거나 golang은 그냥 google code convention을 따랐다.

2. 일관된 에러 처리

에러 처리가 일관되지 않아서 아쉽다는 평을 공통적으로 받았는데, 지금 보면 코드를 대충 개판으로 짜서 어떤 에러는 뷰로 띄우고 어떤 에러는 http 상태 코드로 응답했었다.
이번에는 에러 처리를 상태 코드로 일관되게 맞춰주었고, 그 외에 비즈니스 에러 처리도 일관된 형태로 띄우려고 노력했다. 이후 나중에 뷰(thymeleaf)로 띄울 때에도 일관되게 하려고 노력했다.

3. URL

URL은 지적받은 부분은 아니었는데, 그 땐 API가 몇 개 없기도 했고 형태도 단순했기 때문에 신경 쓸 부분이 없었던 것 같다.
근데 만들다 보니까 너무 많아져서 만드는 나도 URL 경로가 헷갈려서 중간중간 써놓은 위키를 보면서 했다…
가끔 헷갈릴 때에는 여기를 참고했었는데, 도움이 되었던 것 같다.

Deploy

1. Dockerfile

사실 API를 만드는 과제 이전에 하나의 과제를 더 했었는데, 그 때 커스텀 도커 이미지를 만들어야 했다.
도커는 이전에 써봤었지만, 직접 Dockerfile을 작성하고, 레지스트리에 pull하는 과정을 처음해봤었는데, 생각보다 재밌었다ㅎㅎ

2. k8s, helm chart

이후 REST API 과제 시에도 배포를 했어야 했는데, helm chart와 k8s로 배포를 해야했었다..
둘 다 난생 처음 해보는 거여서 삽질을 꽤 했지만, k8s에 대한 이해를 하는 데 많은 도움이 되었다.

3. CI

젠킨스를 사용하지는 않았지만, 사내 플랫폼을 이용해 PR시나 매 PUSH 등 특정 조건마다 자동 배포를 하는 CI를 만들어 볼 수 있었다.

MySQL

MySQL도 클러스터를 이용해서 배포해 놓고 연결했는데, DB인 만큼 영속성을 위해 stateful 클러스터로 배포했다.
클러스터 설정 파일을 쓰면서 여러 이슈들이 있었는데, (master node, slave node 설정 등..) 역시 구글링이 짱이다 ^^!

이후 DB설계를… DB 수업 들던 기분으로 돌아가서 강의 자료 봐가면서 하고(사실 DB 수업이 제일 재밌었다. 정규화 재밌지만 하면 할수록 모르겠다ㅋㅋㅋ..), 설계된 대로 구현을 하려고 했으나
처음에는 JPA로 하려고 했지만, 다중 PK인 테이블이 중심이 되어서 (대충 이런 상황) 깔끔하게 JPA를 포기하고 MyBatis를 사용했다.

Dynamic Scheduler

스프링 부트로 다이나믹 스케줄러를 만들어야 했다.
정적 스케줄러는 스프링 부트에서 어노테이션으로 간단하게 만들 수 있었지만, 다이나믹은 조금 설정해줄 것들이 있어서 어려웠던 것 같다.
뒤에 OAuth2.0 설정해줬던 걸 생각하면 이걸 뭘 그렇게 어려워했는지 모르겠다..

Thymeleaf

FE를 리액트나 뷰제이에스를 쓰는 대신에 타임리프를 사용했다. 타임리프를 쓴 이유는 일단 내가 마크업이 아닌 FE를 아예 해본 적이 없었고(JS…? 잘 모름), 필요한 페이지가 얼마 안되고, 상태바나 메뉴 바 등 중복되는 부분은 thymeleaf-layout기능으로 처리할 수 있었기 때문이다.

jsp(jstl) 쓰지 않은 이유는 스프링 부트에서 서블릿 컨테이너 제약이 있댔나..? 아무튼 그래서 스프링 부트에서 타임리프를 권장했기 때문이다.

결과적으로 뷰나 리액트를 사용했으면 뒤에서 언급할 JWT 헤더를 할 수 있었을 것 같아 아쉬웠다.
또한 그 밖에 자원이 없을 때 404 페이지를 띄우는 것보다 모달 창 같은 것을 사용할 수 있지 않았을까..등의 생각이 들지만,
그만큼 타임리프에 대해 많이 배울 수 있어서 좋았다.

Logging System

사실 서버를 스프링 부트로만 짠 게 아니라 golang으로 하나 더 짰었다. golang쪽은 json방식으로 request, response를 주고받는 간단한 API 였지만, 그 만큼 중요한 정보가 왔다갔다 하므로 로그가 꼭 필요했다.

로깅 시스템은 사실 처음 구축해봤는데, 옛날에 ES 설치하는 데 애를 먹어서 겁을 먹어 그런지 괜히 더 어렵게 느껴졌던 것 같다. (왠지 키바나 대시보드도 어렵게 생겼다고 생각함)
로그를 쌓는 방법이 클러스터 구성하는 것만큼 여러 방법이 있다는 것을 처음 알아서 놀랐다.

과제를 하면서 많이 느꼈지만, 서비스의 규모에 맞추어 대응 방식을 적절히 타협하는 건 늘 어려운 것 같다.
지금은 이만큼만 자세히, 대충 이정도로만 해도 되겠지 하는 부분들이 나중에는 어떤 영향을 끼치는지 생각해야 한다는 걸 느낀 부분이었다.

지금 서비스 하는 데에 이 부분이 조금 문제가 된다는 것을 알고, 문제점을 당장 바꾸지 않더라도 나중엔 어떤 상황에 어떻게 대처해야 하는지 생각을 하고 넘어가는 것과, 아예 그 점이 문제가 되는지도 고려 하지 않고 넘어가는 것은 확실히 다르구나를 느꼈다. (잘 표현한지 모르겠다)

1. fileBeat + ELK

스프링 부트쪽에 사용한 방식이다. 비트, 로그스태시와 부트는 ningx을 리버스 프록시로 사용해 연결했고(또 한 번 배포하는데 애를 먹었다), ES와 Kibana는 사내 플랫폼을 이용했다.
각 플랫폼에 대한 이해와 설정파일 쓰기, ES에 어떻게 인덱싱을 해야하는지에 대해 배운 것 같다.
사실 유명한 친구들이니 그냥 쌓으면 알아서 해주겠지! <라고 생각했는데, 해보니 전략이 필요하구나.. 라고 생각했다

2. HTTP -> ES

golang 쪽은 조금 다르게 해보고 싶어서 REQUEST가 들어오면 바로 HTTP로 ES에 쓰고, RESPONSE도 마찬가지로 하도록 했다.
logger로 zap을 쓰고 있었는데, 음..여러가지 많은 문제가 있어서 zap을 래핑해서 사용했다.

go를 많이 써보지 않았지만, wrapping은 너무 매력적인 것 같다..

OAuth 2.0

중간 발표도 끝나고 인턴 기간이 얼마 남지 않았을 때 OAuth 2.0을 붙이기로 했다. Github을 provider로 해서 구현했고, 이후 github Enterprise로 바꾸었다.

또한 기존의 세션 방식이 아닌 JWT로 인증을 해봤으면 좋겠다고 하셔서, 해보려고 했는데, , ,
스프링 부트 시큐리티가 세션 인증 방식을 기준으로 해서 필터 커스터마이징이 조금 필요했다.
관련 설정 파일만 이해하고 짜는데 이틀정도 걸린 것 같다.. 약간 악몽 같았지만, 나중엔 더 빨리 할 수 있지…않을까^^

그렇지만, JWT는 일반적으로 헤더값으로 인증을 하는데, SSR방식으로 뷰를 구성해서 헤더를 붙이는 데에 문제가 있었다.
리액트 등에서는(다른 FE는 내가 잘 모르겠다.) 초기에 렌더링을 해주면 헤더에 붙일 수 있겠는데, 타임리프에서는 매 페이지마다 헤더값으로 붙이는 데에 한계가 있는 것 같았다.
그래서 그냥 JWT를 쿠키로 전달하기로 했고, 대신 리프레시 토큰처럼 주기를 짧게(3분이었나?) 설정했고, 이는 별 문제 없었다.

etc…

1. 코드 리뷰

혼자하는 프로젝트 위주로 경험했어서 코드 리뷰를 받는 것도 처음이어서.. 처음에 PR띄우는 게 세상 어색했다..
그치만 코드 리뷰를 받는 게 훨씬 프로젝트에 도움이 되는 것을 느꼈다. 뭔가 소통도 더 잘되고, 코드가 리팩당하는(?) 걸 보면서 내 코드의 문제점을 깨닫기도 했고, 리뷰를 위해서 코드를 더 가독성 있게 짜는 습관이 좀 든 것 같다.

2. 브랜치 관리 전략

이전에는 브랜치를 관리..한다기 보다, 깃으로 배포(헤로쿠 등)를 하기 위해 마스터에 쌓는 식으로 많이 했었는데, github flow로 브랜치를 관리해보았다.
처음에는 한 커밋이 너무 많아서 커밋을 나눠 보기도 하고, 나중에는 작은 커밋들이 너무 많이 쌓여서, 어디까지 보셨는지 기억이 안나신다고 하여 PR을 쪼개도 봤다. 나중엔 Git flow로도 해보고 싶다.

3. 테스트 코드 짜기

버드뷰 챌린지 코드 리뷰에서 테스트 코드가 없어서 아쉽다는 평이 공통적으로 많았는데, junit, BDDMockito와 go test로 테스트 코드를 짜보았다.
처음에는 뭐지..? 이렇게..하는 건가?..라는 느낌에서 나중엔 아무 생각 없이 기계적으로 테스트 코드를 짜는 나를 볼 수 있었다.

4. 도큐먼트 자세히 쓰기

나는 나름 자세히 쓴다고 위키를 썼지만, 사용자나 FE분들이 어떤 점을 궁금해 하실 것인지, 어떤 점을 더 자세히 써야 하는지를 알 수 있었다.
나도 사내 위키를 보며 뭐라고 하는 거지? 했던 경우가 있었는데, 그러는 순간 나도 위키를 더 자세히 써야함을 느꼈다ㅎㅎ..

느낀점

끝난지 일주일도 안됐는데 쓰면서 추억 여행 하는 기분이었다. 흑흑… 코로나 때문에 그린팩토리 자주 못갔었는데, 정자역 맛집 더 못가본 게 후회된다.
쓰면 쓸수록 멘토님이 일부러 짧은 시간동안 많은 걸 해볼 수 있도록 조종(?)해주신 기분이 든다. 한 분야의 도메인 깊게 파보지 않았지만, 큰 회사가 아니면 경험할 수 없는 것들을 많이 해본 것 같다.
프로젝트로만 끝날 것이 아니라 서비스를 할 때 고려해야할 것들에 대해 깊게 생각해 볼 수 있었고, 혼자서 개발하는 것이 아닌 팀워크를 할 수 있는 방법에 대해 배운 것 같아 좋았다. 아 이제 뭐하지..