2023.03.27 (월) ~ 2023.04.07 (금) _ (6주간 진행)
SSAFY 8기 2학기 특화 프로젝트 - 빅데이터 분산 도메인 PUNPUN 푼푼히
결식아동, 결식아동이란 보호자의 식사 제공이 어려운 저소득층 결식 우려 아동을 의미하며 전국 약 30만 어린이가 존재합니다.
이 아동들은 급식카드를 지원 받아 식사를 해결에 도움을 받습니다. 하지만, 급식카드의 가맹점이 많지 않으며 한정적입니다. 또한, 편의점에서 끼니를 때우는 편이라고 합니다.
또한, 급식카드로 인하여 눈치를 보거나 편하게 식사를 할 수 없는 상황이 현실이라, 많은 뉴스들이 말하고 있습니다. 그러나 먼저 나서서 급식카드 없이 식사를 제공한다고 종이에 써서 가게 앞에 붙여놓는 식당들도 있습니다.
이러한 상황에서 개발자로서 저희가 무엇을 할 수 있을까 라는 점에서 고민을 시작하였습니다.
이러한 고민 끝으로 저희 PUNPUN(푼푼히) 서비스를 개발하였습니다.
"결식 아동이 편하게 밥을 먹을 수 있도록" - 저희의 슬로건입니다.
저희가 제공하는
- 후원과 나눔을 통하여 결식 아동이 식사를 할 수 있도록 돕는 식당 예약 시스템
- 제한적인 식사 선택이 아닌 아동이 원하는 것을 행복하게 먹을 수 있도록 하는 서비스
- 직접 가게를 찾아가지 않고 식사 여부를 확인해 예약하여 아동에게 편리함을 제공하는 서비스
입니다.
나의 위치 위경도를 기준으로 300M
내의 가게를 검색하는 기능을 개발하던 도중 속도에 대한 이슈로 분산 처리에 대한 필요성을 느끼게 되었습니다.
200만건의 데이터에서 모든 가게를 조회해서 자바 내부에서 필터링을 진행할 경우 55s
의 시간이 걸렸습니다. 기능의 속도에 대한 개선이 필요하다고 생각하였고, 프로젝트에 사용할 수 있는 공유 hadoop
+ spark cluster
를 대여받아서 이를 통해 분산처리를 해보았습니다. 하지만, 성능은 최대 2s
까지 줄일 수 있었으나 다른 프로젝트에서 많이 사용하는 시간대에선 최대 2min
까지 늘어나서 사실 사용하기 어렵다고 판단하여 postgres db
의 extension
중에 haversine
공식을 통해 거리를 계산해주는 함수가 있다는 것을 알게 되었고 이를 통해 결과를 구해보니 3s
대의 안정적인 속도를 기대할 수 있었습니다.
추후 더 좋은 성능을 끌어올리고 싶다면 연산이 필요한 store
정보만 가지고 db sharding
을 통해서 데이터를 분리해서 성능 향상을 해볼 수 있을 것 같습니다.
아동이 예약을 하면 해당 예약을 요청, 승인 과정에서 알람(문자)이 가는 기능이 있습니다.
만약, 알림을 보내는 기능이 예약 서비스 내부에 존재한다면 알림을 보내는 것을 실패할 경우, 예약의 트랜잭션이 롤백 될 수 있습니다. 그러하면 알림을 보내지 못하였을 뿐인데, 예약까지 실패하는 상황이 됩니다. 분리가 된다면 예약과 알림을 따로 관리할 수 있습니다. 또한, 예약에 대한 다른 기능을 추가할 때도 예약에 대한 이벤트를 수신하면 예약에 대한 서비스 로직을 변경하지 않고 보다 편하게 다른 서비스를 추가할 수 있습니다.
Spring
을 통하여 예약 관련 서비스가 수행되면 이벤트를 생성하여 kafka
에 전송합니다. 이벤트를 저장하는 공간을 바라보던 go
로 된 알람 서버가 해당 이벤트를 consume
한 후에 별도의 서비스로 문자 알림을 발송합니다.
go
를 사용한 이유는 경량 스레드인 고루틴을 사용해서 병렬적인 처리를 쉽게 할 수 있으며, 가벼운 언어이기 때문에 요청이 많아져도 많이 버틸 수 있을 것이라고 기대하였기 때문입니다.
FrontEnd와 BackEnd 혹은 PostMan, Swagger와 BackEnd간의 통신을 통해서만 결과를 확인 할 수 있는 것이 아닌 Test Code
를 사용해서 의도한 대로 정확히 작동하는지 검증할 수 있습니다.
- 개발 과정 중 예상치 못한 문제를 미리 발견할 수 있습니다.
- 코드 변경 시, 변경 부분으로 인한 영향도를 쉽게 파악할 수 있습니다.
- 테스트 코드를 통해 동작하는 방식 및 결과 확인이 가능합니다.
- 소형 테스트에 속하는 테스트이다.
- 클래스 범주 내에서 작은 단위 (함수)의 기능에 대한 유효성을 검증하는 테스트이다.
- 단위 테스트는 매우 간단하고 명확하며 빠르게 실행된다는 특징이있다.
- 하나의 함수에 대한 하나 이상의 테스트가 존재할 수 있고, 각각의 조건에 대한 유효성을 검증한다.
- 이렇게 작성된 테스트가 많을수록 해당 로직에 대한 신뢰도가 높아질 수 있다.
- 또한, 작게 쪼개진 단위 테스트는 해당 로직이 어떤 역할을 하는지 쉽게 파악할 수 있다.
이러한 이유로 단위 테스트를 진행하였습니다.
👏🏻 테스트 진행에 있어 좋았던 점
Entity를 변경 시 변경 비지니스 Login 변경 시 변경된 범위를 알고 수정하기 좋았습니다.
예상하지 못한 곳의 에러를 잡아낼 수 있었습니다.
테스트 케이스를 고려하면서 예외 처리의 경우의 수를 더 생각할 수 있었습니다.
🥲 테스트 진행에 있어 아쉬웠던 점
단위 테스트를 선택하였지만, 통합 테스트도 필요한가? 그러면 어느 부분에 있어 씅리까라는 의문이 있었습니다.
커버리지를 100% 달성하기 위해서는 외부 라이브러리를 사용하거나 시큐리티 등의 테스트 진행에 대한 지식의 부족함이 아쉬웠습니다.
다음에는 커버리지를 더 높히고 이미 진행한 부분에 대해서는 엣지 케이스들에 대하여 더 검증하고 싶습니다.
Backend - Spring
- InteliJ IDE
- Springboot Gradle 6.8.3
- Java jdk 11
- Spring Data JPA
- querydsl JPA 5.0.0
- Spring oauth2 client
- Spring Security
- jjwt 0.2
- Spring validation
- Spring web
- Spring Kafka
- Spring devtools
- junit5
- gson 2.8.9
- lombok
- springfox-boot-starter 3.0.0
- springfox-swagger-ui 3.0.0
- spring Cloud aws 2.2.6
Backend - DB
- h2
- postgresql
- Amazon S3
CI/CD
- AWS EC2
- Ubuntu 20.04
- Docker 20.10.23
Frontend - React
- Visual Studio Code IDE
- Nodejs 18.12.1
- React 18.2.0
- jquery 3.5.16
- typescript 4.9.5
- TailwindCss
- sweetalert2 11.3.10
- axios 1.2.3
ECT
- kafka
- jenkins
- go
추후 추가 예정
- GitLab , GitHub 및 exec 파일 참조