개발자는 기록이 답이다
[항해플러스] 7주간의 프로젝트를 통해 배운 것 본문

드디어 7주간 항해플러스의 여정이 끝나고, 다음주 부터는 오픈소스 프로젝트에 들어가게 됩니다.
시간도 부족했고, 새로운 언어와 프레임워크를 적응하느라 처음의 다짐만큼 더 다양한 것들을 시도해보지 못한 점이 아쉬웠습니다.
하지만 이번 프로젝트로 인해 정말 배운 것도 많고, 재미있는 시간이었습니다.
회사 일정으로 인해 멘토링을 참여하지 못했던 순간에도 친절하신 팀원분들이 녹화를 해주신 덕분에 뒤늦게 시간을 쪼개서 확인할 수 있었고, 열정적인 멘토님들 덕분에 더 다양한 시각에서 개발을 바라볼 수 있게 되었습니다.
중간 발표가 끝나고 7주동안 어떤 걸 해왔는지 천천히 회고록을 작성해보겠습니다.

해당 챕터별로 매주 스프린트를 진행했습니다.
1. 시나리오 선정과 선정 이유, 그리고 TDD
저희 팀은 동물 예약 시스템 시나리오를 선택했습니다.
배달 예약 시스템 시나리오도 있었지만, 팀원 전부가 typescript와 nest.js는 처음이었습니다.
그래서 언어에 얽매여서 뒤쳐지는 것 보다 매주 과제를 수행하기 위해 상대적으로 쉬운 시나리오를 선택했습니다.
회원가입&로그인&인증 / 예약조회,등록,변경,취소 / 결제,환불,알람
모듈을 알람, 인증, 상담, 의사, 결제, 유저로 나눠서 역할을 분배해서 테스트 코드와, API를 만들었습니다.


디렉토리 구조를 간단하게 트리구조로 요약하자면 아래와 같습니다.
src
├─ __tests__ //유닛테스트 디렉토리
│ └─ moduleA
│ ├─ service.test.ts //모듈A의 서비스 테스트코드
│ └─ repository.test.ts //모듈A의 레포지토리 테스트코드
├─ module
│ ├─ moduleA
│ │ ├─ api
│ │ │ ├─ controller.ts
│ │ │ └─ dto.ts
│ │ ├─ data
│ │ │ ├─ db.ts //실제 레포지토리
│ │ │ └─ entity.ts
│ │ ├─ domain
│ │ │ ├─ model.ts
│ │ │ ├─ repository.ts //인터페이스로 구현된 레포지토리
│ │ │ └─ service.ts
│ │ ├─ error.ts
│ │ ├─ mapper.ts
│ │ └─ module.ts
│ ├─ http-exception.filter.ts
│ ├─ logger.ts
│ ├─ response.ts
│ ├─ seeder.ts
│ ├─ app.module.ts
│ ├─ app.controller.ts
│ ├─ app.service.ts
│ └─ main.ts
├─ package.json
├─ tsconfig.json
├─ .gitignore
└─ .env
TDD를 처음 접했을 때, 테스트코드와 실제 비즈니스 로직 코드가 서로 영향을 받지 않고 어떻게 구현부를 따로 구현할 수 있을지도 헤맸습니다. 멘토링 과정에서 서로 다른 구현체가 동일한 인터페이스를 구현하면 된다는 조언을 얻어서 적용했는데, 스프링에서 사용하지 않았던 모듈 개념도 헷갈렸던 것 같습니다.

또한 TDD에서 가장 익숙하지 않았던 개념은 바텀업 방식이었습니다. 즉, 설계를 먼저 하지 않고 function들을 많이 만들어서 유닛, e2e, api 연결까지 바텀업으로 올라간다는 것이었습니다.
테스트 코드 커버리지를 넓게 보고 함수를 만든다고 하지만, 도메인을 먼저 생각하지 않고 코드를 만들 수 있을지 의문이었습니다. 아직도 TDD는 개념이 어렵기도 하고 코치님들도 바텀업인지 탑다운인지 방식도 다르게 사용하시기 때문에 좀 더 자세히 알아봐야할 것 같습니다.
( 다른 조원분들에게 듣기로 Facade 패턴을 이용하면 132줄 짜리 코드도 9줄로 줄일 수 있다고 합니다 )
2. 서버 아키텍처 구성

해당 아키텍처를 직접 3시간동안 만들었는데, 처음 만들어보는 아키텍처였지만 저희 팀이 만든대로 잘 표현한것 같아서 뿌듯했습니다. 구글링하면서 다른 아키텍처는 어떻게 생겼는지 확인하고 고민하면서 만들었는데, 아키텍처를 만들면서 좀 더 저희 프로젝트에 대해 자세히 파고들 수 있는 시간을 가질 수 있었습니다.
해당 아키텍처에 대해 설명을 하자면 로컬 환경에서 mysql DB를 사용했고, typeorm, nestjs를 이용해서 프로젝트를 만들고, 깃헙으로 코드 형상 관리를 했습니다.
CICD 파이프라인에서는 도커로 프로젝트를 이미지로 만들었고, Github 브랜치 전략을 사용해 깃헙 액션으로 배포를 진행했습니다. ECR로 이미지를 PULL받고 ECS로 해당 이미지를 PUSH했습니다.


클라우드 내부에서는 CPU의 임계점 설정에 따라 AutoScaling이 되도록 구성했고, LB를 통해 A서버에서 새로운 B서버로 트래픽을 연결시켜주면서 무중단 배포가 되도록 설정했습니다.
Fargate와 RDS의 CPU, Memory의 경우 특정 임계점을 지나면 CloudWatch의 알람이 발동되어 슬랙으로 알람이 와서 장애 인지&탐지를 할 수 있도록 했습니다. 또한 저희 윈스턴을 사용해서 application level의 로그들이 CloudWatch의 로그 그룹과 로그 스트림에 쌓이게 되면 구독필터와 람다를 이용해 슬랙으로 유형별 채널로 알람이 가도록 설정했습니다.


그리고 Jmeter를 사용하여 로컬 환경에서 부하 테스트를 진행하고, 도커를 이용하여 CPU와 메모리를 조절하여 테스트를 수행했습니다. 로컬에서 CPU 사이즈가 어느 정도까지 부하를 견딜 수 있는지 확인하고, 클라우드 서버에서도 사이즈를 조절하여 부하가 발생하는 지점을 정확하게 파악하려고 했습니다. 이를 통해 임시로 설정한 임계점이 아니라 오토스케일링 설정에 적합한 조건을 파악하고, 서버의 자동 확장을 효과적으로 구현하려고 했지만 Jmeter에서 추출한 데이터를 유의미하게 사용하는 법이 익숙치 않아서 진행되지 못한 게 아쉬웠습니다.
3. 중간발표 및 멘토님들의 한마디
토요일 오후 2시부터 3시까지는 전수현 코치님의 이력서 특강이 있었고, 3시부터 제일 앞 조인 저희 조가 먼저 발표를 시작해야했기 때문에 12시 30분 부터 팀원들과 모여서 발표 준비를 했습니다. 추가적인 내용을 더 넣어서 '우리 열심히 했다!'라고 알려주고 싶었기 때문에 전날 새벽까지 PPT를 수정해서, 팀원분들 모두 점심도 못 먹고 고생해주셨던게 기억이 납니다,
저희 조에서 받은 질문을 정리해보고 추후 프로젝트를 고도화 시킬 때 반영하려고 합니다.
1. Seeder를 테스트할때 활용하셨다고 하셨는데, 어떤 용도로 사용하셨는지?
-
- Seeder를 활용하여 Mock 데이터를 사전에 미리 삽입하면, 부하테스트 시에도 동일한 데이터셋을 사용하여 일관성을 보장할 수 있습니다. 이렇게 하면 테스트 결과를 비교하거나 성능 지표를 추적할때 용이할 것이라 판단했습니다.
- Seeder를 사용하여 Mock 데이터를 정의하면, 테스트 수행 시마다 데이터를 다시 생성하거나 수정할 필요가 없으므로 테스트 속도를 향상시켜서 효율성과 생산성을 높일 수 있다고 생각했습니다. 또한, 테스트용 데이터와 실제 운영 데이터가 섞이거나 손상되는 경우를 방지할 수 있습니다.
2. 깃헙 액션을 통해서 배포하실때, 깃헙 브랜치 전략을 어떻게 활용하셨는지?
-
- 저희 조는 배포 전에 안정적인 코드를 사용하기 위해 주요 브랜치(main)를 사용했고, 개발작업을 취합할때는 개발 브랜치(develop)를 사용했습니다. 개발 브랜치로 취합하기 전에 각자 맡은 기능은 feature 브랜치로 개발을 진행했습니다.
- 깃헙 액션에서 배포를 수행할 때 main 브랜치를 바라보고 main브랜치에 PR(Pull Request)를 날려서 머지하거나 푸시하여 이벤트가 발생하면, 깃헙 액션에서 배포가 실행되었기에 Gitflow Workflow를 사용했습니다.


3. AWS로 모든 인프라를 구축하셨는데, 비용 누수가 있는지를 모니터링했는지?
-
- 비용은 얼마인지 정도만 체크했고, 실제로 비용 누수가 어디서 일어나고 있는지에 대해 정확히 파악은 못했습니다. ECS에서 제일 많은 비용이 나왔는데, 테스트를 위해 생성 및 삭제를 여러번 하기도 하고, 클라우드 환경에서 오토스케일링이 되는지 확인하기 위해 부하테스트를 진행했는데, 일정 사용량을 넘어서 금액이 많이 책정된건지 추측을 하고 있습니다.


-
- 또한 알 수 없는 누군가(해커)의 존재하지 않는 엔드포인트로 접속이 수십번 일어났던 적도 있고, 해당 공격으로 인해 CPU가 올라갔던 적도 있어서 이 사건으로 인해 사용량 초과에 대해 영향을 끼쳤을거라고 생각합니다.


4. 슬랙으로 알람 보일때 패스워드가 그대로 노출되는데, 암호화 처리를 안하신 이유가 있는지?

-
- 로깅할때 암호화 처리를 해놓은 건 생각하지 못했던 부분입니다. DB에는 인코딩해서 저장되지만, 로깅에서 조차 암호화를 해야한다는 점을 놓치고 있었습니다. 그 이유는 개발 과정에서는 프론트엔드와 API를 맞춰볼때, 요청, 응답값이 전부 다 나와야 400번대 에러가 발생해도 어떤 부분에서 익셉션이 발생했는지 인지할 수 있다고 생각했기 때문입니다. 로깅을 슬랙으로 남기는 과정에서 운영서버와 개발서버를 분리해서 로깅을 남기도록 하겠습니다.
5. esLint 이용해서 CI 쪽으로 같이 코드 리뷰를 해보셨는지?
-
- CI쪽으로 코드 개선을 못 해봤던건 아쉬웠습니다. 로깅이나 익셉션 핸들러처럼 공통으로 사용하는 부분에 대해서는 같이 코드 리뷰를 해봤지만, 각자 맡은 기능에 대해서 전체적인 코드 리뷰를 해보지 못했습니다. 수동으로 코드 리뷰하는 것보다 CI툴을 활용해서 시간도 절약하고, 코드 품질도 향상 시킬 수 있는 코드 리팩토링도 진행해보도록 하겠습니다.
4. 느낀점
정말 많은 트러블 슈팅이 있었고, 이를 통해 새로 알게 된 점이 많았는데 여러가지 변명들과 게으름으로 회고록을 많이 남기지 못한 점이 아쉽습니다. 앞으로도 시간내서 종종 그동안 배운 내용들을 정리해보려고 합니다. 매니저님께서 회고는 선택이 아니라 필수라고 매번 말씀해주셨는데, 울음 이모티콘만 날렸던 제 모습을 반성합니다.


멘토님은 총 4분이 계셨는데, 모두 다 귀중한 조언들이어서 어느 하나 놓치고 싶지 않았던 얘기들이 많았습니다. 다른 조에서는 어떤 멘토링을 받았나 궁금하기도 하고, 준비하지 않으면 그만큼 놓치는 조언들도 많다는걸 깨달았습니다. 그래도 7주동안 주니어 개발자의 한계를 넘어 더 성장할 수 있는 기회를 얻었던 것 같아서 너무 만족스럽고 좋습니다. 또한 카톡으로도 팀원분들과 정보 공유하고 그랬던게 기억이 많이 남습니다. 개발은 혼자 성장하는것보다 여러 사람들과 함께 부딪히고 소통해야 좀 더 쉽고 빠르게 성장할 수 있다고 느꼈습니다.



'항해플러스' 카테고리의 다른 글
[항해플러스] 10주간 느꼈던 내돈내산 솔직한 후기, 장점과 단점 (0) | 2023.08.22 |
---|---|
[항해플러스] 오픈소스 프로젝트 2주차에 배운 점 (0) | 2023.08.22 |
[항해플러스] 오픈소스 프로젝트 1주차에 배운 점 (0) | 2023.08.22 |