
SFAM 소개4️⃣ 프로젝트 진행 방식5️⃣ InfraStructure6️⃣ Tech Stack7️⃣ ERD8️⃣ 기여한 역할9️⃣ 트러블 슈팅🧐 서비스간의 발생하는 순환참조를 어떻게 해결할 수 있을까?😲 뭐..? 확장자를 강제로 변경하면 요청이 정상적으로 수행된다고..?🧐 API 오류가 있을 때마다 매번 EC2 에서 로그를 확인하는 불편함을 어떻게 해소할까?🔟 프로젝트를 하면서 느낀 점
SFAM 소개
- 주위 사람들과 편리하고 다양한 스포츠 경기를 매칭 시켜주는 서비스입니다.
- 팀전 매치 및 다양한 종목에 대해 매치가 가능하며 채팅 및 전적관리, 경기 후기 등의 기능을 제공하여 보다 더 운동을 즐겁게 할 수 있도록 도모할 수 있습니다.
[팀구성]
프론트앤드
- 김창민(팀장), 장규범(스크럼마스터), 홍정기, 신승연
백앤드
- 김형욱(팀장), 박혜빈(스크럼마스터), 박진형(테크리더), 곽동운, 김병연
4️⃣ 프로젝트 진행 방식

- 3~4일 주기로 스프린트 및 회고를 진행하였습니다.
- 매일 14:00 ~ 19:00 코어타임을 정하여 스크럼 및 프로젝트를 진행하였습니다.
- 협업도구는 Discord, Gather, Slack, Jira, Notion 등을 사용하여 협업을 원할하게 진행하였습니다.
5️⃣ InfraStructure
[구조를 왜 이렇게 진행했나요?]
- 프로젝트를 진행할 때 배포서버와 실제 사용자에게 제공되어야 하는 프로덕션 서버가 따로 분리되어 있어야 한다고 생각했습니다.
- 따라서 서버를 2개를 나누었으며 개발 서버에서 충분히 검증 된 API만 프로덕션 서버에 배포될 수 있도록 프로젝트를 진행하였습니다.
[어떤 이점이 있었나요?]
- 가장 먼저 충분한 검증이 이루어 졌기 때문에 사용자 입장에서 믿고 사용할 수 있으므로 신뢰도가 향상되는 이점이 있었습니다.
- 그만큼 개발하는 과정에서 많은 테스트를 진행하기 때문에 혹시나 프로덕션 서버에서 버그가 발생해도 치명적인 버그 발생률을 줄일 수 있었습니다.

6️⃣ Tech Stack
[기술 스택을 이렇게 선택한 이유는 무엇인가요?]
- SpringBoot의 최신 버전을 사용함으로써 Spring Security의 WebSecurityConfig가 Deplicated 된 사실을 알게 된 적이 있었습니다. 이 과정에서 자신이 쓰고 있는 기술이 어떻게 업데이트 되고 있는지에 대한 꾸준한 관심이 필요하다는 것을 느꼈습니다.
- 따라서 개발자는 항상 최신 기술에 관심을 많이 가져야 한다고 생각하였으며 기술스택을 최신버전 위주로 선택하게 되었습니다.
[어떤 이점이 있었나요?]
- 가장 먼저 자바17을 사용함으로써 레코드와, 개선된 스위치문을 사용할 수 있었습니다.
- 레코드를 적극적으로 사용하여 코드의 간결함과 불변성의 이점을 얻을 수 있었습니다.
- 개선된 스위치문을 통해 보다 더 간결한 코드를 작성할 수 있었습니다.
- Flyway 도입으로 Database 설계가 변경 될 시 유연하게 대응할 수 있었으며 변경 이력 확인이 가능하여 편리함을 얻을 수 있었습니다.
- QueryDSL의 도입으로 동적 쿼리를 보다 더 편리하게 작성하고 코드 가독성에 대한 이점 도 얻을 수 있었습니다.
- CI/CD의 도입을 통해 자동으로 배포환경을 구축하여 백엔드 개발에 더욱 집중할 수 있게 되었습니다.

7️⃣ ERD

8️⃣ 기여한 역할
- 확장자를 강제로 변경하여 요청된 위장 파일을 걸러내기 위한 File Validator를 구현하였습니다.
- 외부 라이브러리 Apach Tika 사용을 고려하였지만 파일 시그니처의 특정 offset을 보는게 아닌 전체 파일을 읽어들여 크기가 큰 파일이 요청 될 경우 성능저하 우려가 있어 직접 Validator를 구현하였습니다.
- 배포 자동화를 위해 GitHub Action, CodeDeploy, S3를 이용하여 CI/CD를 구축하였습니다.
- 실제 서비스 상황을 가정하여 개발환경, 운영환경을 별도로 두어 각각 CI/CD를 구축하였습니다.
- 항상 지속적이고 동작 가능한 코드를 병합하는 것을 자동화하기 위해 PR Test를 도입하였습니다.
- Offset 페이징 방식이 아닌 Cusor 페이징 방식을 도입하였으며 다양한 상황에 맞게 동적쿼리를 구현하였습니다.
- 모바일 크기에 맞춘 UI 이슈로 커서 페이징 방식이 적합하다고 판단하여 적용하게 되었습니다.
- 적용 후 Offset 페이징 방식과 차이로 데이터 증가에 따라 Cursor 방식이 데이터 누락 및 성능적인 측면에서 더 좋은 효과를 낼 수 있다는 것을 알게되었습니다.
- 외부 환경으로 배포가 이루어져 로그확인의 어려움을 CloudWatch 도입으로 해결하였습니다.
- 협업 과정에서 API 오류가 발생할 경우 EC2 환경에 접속하여 로그를 확인하는 과정에 불편함이 있었습니다.
- AWS의 CloudWatch 도입하고 팀원에게 IAM 권한을 부여하여 로그를 보다 더 쉽게 확인할 수 있도록 하였습니다. 도입 후 장애에 대응하는 리소스를 줄일 수 있었습니다.
- API 명세 과정 중 요청과 응답의 흐름을 원활하게 확인하기 위해 Mermaid.js를 활용하여 시퀀스 다이어그램을 작성하였습니다.
- 팀원 간의 프로젝트 이해 상태를 동일 시 하기 위해 잦은 동기적 소통이 발생했지만 시퀀스 다이어그램 도입으로 불필요한 소통을 줄일 수 있었으며 개발에 더욱 집중할 수 있었습니다.
- API / 테스트코드 작성
- 사용자 조회 API, 팀원 초대 및 거절 API, 팀원 등록 API, 초대목록 조회 API 개발
- 컨트롤러 목 테스트 및 서비스 통합테스트 작성
- 변경관리 추적과 반복적인 시드 데이터 삽입의 불편함을 해결하기 위해 Flyway를 도입시켰습니다.
- 팀장의 역할로써 팀원들이 방향과 의지를 잃지 않도록 주도적으로 프로젝트를 진행할 수 있도록 도모하였습니다.
- 기획 및 스프린트 일정 조율, 팀원 담당 역할 할당
- 기획자로 프로젝트의 전반적인 기획 및 정책을 구성하였습니다.
- 팀장의 역할로 스프린트 일정 조율 및 각 팀원 간 역할을 스프린트 주기에 맞게 할당하였습니다.
9️⃣ 트러블 슈팅
🧐 서비스간의 발생하는 순환참조를 어떻게 해결할 수 있을까?
[문제점]
- 관련된 도메인들끼리 서로 참조하여 순환참조가 발생하는 곳이 꽤 있었습니다.
- 이것을 어떻게 매끄럽게 순환참조를 없앨 수 있을지 고민을 많이 했었습니다.
[대안]
- Facade Pattern 패턴을 도입하여 한 곳에서 서비스를 관리하도록 만들어 해결하는 방법을 생각했습니다.
- Facade Pattern로 해결하는 방법이 최선일까? 굳이 중간 Layer를 더 거치도록 해야하는가? 에 대해 의문점이 많이 생겼으며 명확한 해결 방법은 아니며 “회피”에 가깝다라는 생각이 들었습니다.
- 단순하게 서비스에서 다른 도메인의
Repository
를 참조하여 사용하는 것은 안될까? - 이 대안은 개인적으로 다른 도메인에 직접 접근이 가능한
Repository
의 참조할 수 있도록 규칙을 허용한다면 다른 서비스에서 도메인의 값이 의도치 않게 사용될 가능성이 더욱 높아지기 때문에 수정 여부나 휴먼에러 발생률이 더욱 커질 것이라 생각이 들었습니다. - 따라서 최대한 다른 서비스의
Repository
를 직접 접근하는 방법은 최대한 피하고 싶었습니다.

[해결]

팀의 규칙으로 Service마다 Giver를 따로 만들어 다른 도메인에서 필요한 서비스는 Giver를 사용하도록 정책을 정하여 순환참조를 피하도록 구성하였습니다.
[개선점]
- Giver 클래스도 더 작게 나눠서 다른 도메인에서만 필요로 하는 메서드만 사용할 수 있도록 제공하면 더 안전한 코드를 만들 수 있지 않을까 생각이 들었으며 반대로 그렇게 된다면 클래스 파일이 너무 많아져 관리가 힘들지 않을까란 생각도 들었습니다.
😲 뭐..? 확장자를 강제로 변경하면 요청이 정상적으로 수행된다고..?
[문제점]
- 사용자가 확장자를 강제로 변경하여 요청을 보내도 정상적으로 처리되는 문제점이 있었습니다.
(확장자 변경전)


(확장자 강제로 변경한다면?)


파일의 이름에는 png로 변경되었지만 실제 타입을 조회해보면 pdf 형태의 파일이라는 것을 확인할 수 있었습니다.
[대안]
- Apach Tika 라이브러리를 사용하여 요청이 들어온 확장자의 시그니처를 검증하도록 하는건 어떨까?
(근데 파일의 시그니처가 뭘까!?)
- 각 파일은 그 파일의 형태를 구분할 수 있는 유일한 식별자와 같은 시그니처 값이 존재하며 각 파일마다 시그니처의 위치와 값이 다르게 존재합니다.

- 좋은 대안이 될 수 있겠지만 Apach Tika의 경우 모든 파일을 읽어서 검증을 하고 있었으며 파일의 용량이 커짐에 따라 성능저하의 원인이 될 수 있겠다 판단이 되었습니다. 따라서 저희의 프로젝트에는 JPG, JPEG, PNG, BMP, GIF 등이였으며 모두 시그니처 Offset이 0이기 때문에 사용하지 않았습니다.
[해결]

- 따라서 직접 ENUM을 통해 확장자를 관리하고 각 확장자마다 시그니처 값을 검증할 수 있는 Values를 추가하였습니다.
of
정적 메서드를 통하여 파일의 확장자를 검증하였으며 현재 프로젝트에 지원하지 않는 확장자라면 예외를 발생시켜 요청을 수행하지 않도록 구현하였습니다.

- FileValidator를 커스텀으로 구현하여 MimeType을 통해 확장자와 그 확장자의 시그니처까지 모두 일치하는 경우에만 요청을 정상적으로 수행할 수 있도록 해결하였습니다.
[개선점]
- 마감기한에 따라 기능구현이 우선이기 때문에 검증값을 단순히 문자열로 처리를 하였습니다. 하지만 이 또한 들어온 byte값을 문자열로 한번 더 변환이 일어나기 때문에 리소스 낭비라고 판단이 되었으며 개선되어야 할 점이라고 판단되었습니다.
- 추가적으로 파일 크기에 따라 resizing을 하는 부분도 더욱 고려해야 할 수 있을 것 같습니다.
🧐 API 오류가 있을 때마다 매번 EC2 에서 로그를 확인하는 불편함을 어떻게 해소할까?
[문제점]
- 개발을 진행하면서 실제 협업이 이루어지는 서버는 EC2에서 실행되고 있기 때문에 로그를 바로바로 확인할 수 없었습니다.
- 또한 오류가 발생할 때마다 직접 EC2에 접속하여 로그를 확인하는 과정이 매우 번거로웠습니다.
[해결]
- AWS CloudWatch를 통해 로그가 관리될 수 있도록 구성하였습니다.
- 불필요하게 EC2에 접속하지 않고 바로 AWS에서 한눈에 확인할 수 있어서 매우 편리하였습니다.

🔟 프로젝트를 하면서 느낀 점
[프론트와 협업]
- 처음으로 프론트 개발자와 팀을 이뤄 프로젝트를 진행한 만큼 협업과 애자일 프로세스의 큰 흐름을 배울 수 있었습니다.
- 변화하는 요구사항에 팀원들의 프로젝트 이해도가 점점 달라지고 리소스 낭비가 심한 만큼 문서화와 비동기적 통신의 중요성을 느낄 수 있었습니다.
- 백엔드가 생각하는
Response
형태와 프론트가 생각하는Response
형태가 다르다는 것을 새로 알게 되었으며 API 개발 시 프론트의 입장에서 한번 더 생각해보는 계기가 되었습니다.
[개발]
- 단순한 API 한개라도 실무에서는 다양한 상황이 있을 수 있고 고려해야 할 점이 많다는 것을 느낄 수 있었습니다.