Posts 돈두댓 프로젝트 회고
Post
Cancel

돈두댓 프로젝트 회고

프로젝트 정리

시작하게된 계기

올해에 복학을 하게 되면서 여러 사람들과 협업하면서 서비스를 만들어보는 경험을 하고싶어서 멋쟁이 사자처럼 대학 연합 동아리에 백엔드 포지션으로 가입하게 되었다. 여름 방학에 멋쟁이 사자처럼의 모든 학교들이 모여 해커톤을 하게 되어 참가하게 되었는데, ‘현대인들의 건강관리를 위한 IT서비스’라는 주제로 프로젝트를 시작하게 되었다.

주제 선정 배경

주제는 멋쟁이 사자처럼 중앙 운영진에서 주어졌지만 이미 건강관리에 대한 IT서비스들이 너무 않아서 아이디어 기획에 어려움이 있었다. 또한 해커톤의 특성상 개발에 사용할 수 있는 시간이 많지 않다는 것까지 고려해야했다. 여러 번의 아이디어 회의 끝에, 평소에 거북목, 척추측만 등 현대인들이 달고 사는 문제들을 해결하고 싶어서 습관적으로 하게 되는 안 좋은 요소들을 개선할 수 있도록 도와주는 서비스를 만들어보고자 하였다. 그 결과 내가 해야할 것과 한 것에 대해 기록하는 TODO리스트의 반대 개념으로 하지 말아야 할 습관에 대해 기록하는 NOT-TODO리스트 라는 서비스를 구현해보기로 하였다.

프로젝트 과정

다행히도 같은 팀에 다른 동아리에서 협업을 많이 경험해본 팀원이 있어서 협업하는 법을 많이 배울 수 있었고, 현업과는 많이 다르겠지만 처음으로 기획부터 배포까지 체계적인 단계를 거치며 진행하게 되었다. 아이디어를 기획하고 언제든지 수정사항을 공유할 수 있도록 노션에 기능 명세서와 API명세서를 작성한 뒤에 개발을 시작했다.

지난번 프로젝트에서 미흡했던 점을 보완하고 싶어서 해당 내용들에 대해 학습을 하고 기능을 구현하였다. 특히 AWS와 Github Actions는 앞으로도 많이 사용하게 될 것 같아서 이 부분을 공부하는 데에 기능을 구현하는 것보다 더 오랜 시간을 쓴 것 같다.

API명세서 작성

API명세서를 처음 작성해봤지만 프론트엔드와 백엔드가 기능 구현을 하는 단계에서 교집합에 해당하는 부분이기 때문에 문서만으로 최대한 모든 걸 설명할 수 있도록 작성했다. 처음이라 익숙하지 않았던 탓에 팀원들에게 많이 물어보면서 작성해나갔다. API명세서를 작성해놓으니 프론트와 소통을 할 때에 문서를 기반으로 원활하게 소통을 할 수 있었고, 변경사항이 발생할 때마다 반영하여 기능 구현을 할 때에도 유의해야 할 점을 잊지 않고 잘 구현할 수 있었던 것 같다.

여러 테이블의 사용과 연결

기능을 구현하기 위해서 데이터베이스에서 여러 개의 테이블을 사용해야 했다. 당연하게도 거의 모든 서비스들이 한 개의 테이블만 가지고 동작하지 않겠지만 처음으로 여러 개의 테이블을 사용하여 개발을 진행하게 되어서 어려움이 많았다. 데이블과 객체를 매핑하는 것은 테이블이 하나일 때와 동일하기 때문에 어려움이 없었지만 연관관계를 설정하는 부분이 어려웠다. 핑계지만 개발기간이 짧았고 ORM을 학습하고 구현하기에는 시간이 부족할 것 같다고 생각했다. 지난번 프로젝트에서 그랬던 것처럼 이해는 나중으로 미루고 일단 사용한 뒤에 공부를 통해 이해할 수도 있었지만 아무래도 서비스의 동작과 직결되어있는 부분이라서 잘못된 사용으로 성능 저하나 기능 오류가 생길까봐 무서웠다. 그래서 일단 연관관계를 설정하지 않고 서비스 레이어에서 필요한 객체를 그때그때 호출하여 사용하는 방식으로 구현하였다. 이 부분은 나중에 혼자서라도 공부하고 리팩토링 해야겠다고 생각했다.

통합 배포 시도

작년에도 멋사 중앙 해커톤에 참가했던 동아리원들이 해커톤 장소에 많은 사람이 오기 때문에 네트워크 상태가 좋지 않아서 미리 서비스 동작 환경을 만들어 놓아야한다고 조언해주었다. 그래서 배포환경에서의 동작을 테스트 하기 위한 용도로 간단한 기능 한 두 개만 만들어 놓고 배포부터 시작하게 되었다. 지난번 프로젝트에서 AWS와 Github Actions에 대해 이해하지 않고 사용했던 것이 아쉬움으로 남아서 이번에는 제대로 공부하고 사용하기로 했다.

공부를 하다가 프론트엔드의 빌드 결과물을 스프링의 정적 리소스로 포함시켜서 한꺼번에 빌드하고 실행하는 방법에 대해 알게 되었다. 한꺼번에 빌드를 해서 배포하면 프론트엔드와 백엔드의 http통신이 외부로 노출되지 않아서 보안적인 측면에서 더 좋을 것 같았고 네트워크에 의한 지연도 줄어들 것 같아서 통합 배포를 하는 방식으로 진행해보려고 하였다. 각 파트의 스켈레톤 프로젝트를 이용하여 빌드하고 jar파일 실행으로 리액트 화면을 띄우는 것은 성공했지만, 통합 배포 환경에서 리액트로 구현된 정적 리소스에 http호출 결과를 반환하는 방법에 대해 자료를 찾을 수 없었다. 그래서 결국 프론트엔드와 백엔드를 분리하여 배포하는 방법으로 다시 되돌아오긴 했지만 GIthub Actions를 이용하여 다른 외부 레포지토리에 접근하고 한 번에 빌드하는 방법을 해볼 수 있어서 유익한 경험이었다.

스프링 시큐리티와 JWT

서비스가 개인의 NOT-TODO리스트를 관리하는 기능을 제공하는 만큼 서비스 이용자를 식별 할 수 있는 수단이 필요했다. 이왕 이렇게 된거 스프링 시큐리티와 JWT를 이용하여 로그인, 로그아웃 기능을 구현하기로 결정했다. 스프링 시큐리티라는 프레임워크를 사용하는 방법이 기존에 스프링을 이용하여 기능을 구현하는 방법과 많이 달라서 이해하는 데에 오래걸렸던 것 같다. 하지만 관련 자료가 많아서 비교적 어렵지 않게 구현까지 해낼 수 있었다. 하지만 스프링 시큐리티와 Refresh 토큰으로 Access 토큰을 재발급하는 과정까지는 구현하지 못했다. 이 부분도 핑계지만 해커톤이라는 특성상 개발 기간이 너무 짧아서 공부를 할 시간이 부족했다. 그래도 IT서비스의 거의 필수라고 할 수 있는 로그인 기능을 구현했다는 것에 의의를 둘 수 있을 것 같다.

프로젝트 결과

해커톤이라는 특성상 개발 기간이 길지 않았고, 충분한 학습이 이루어지지 않은 채로 진행된 프로젝트지만 얻은 것도 많았던것 같다. 일단 의도했던 모든 기능들이 정상적으로 동작했다. 구현 과정에서 어려움을 겪었던 부분중 하나인 날짜별 습관을 조회하는 부분에서, 사용자는 이론상 무한대의 날짜를 선택해서 자신의 습관을 볼 수 있기 때문에 어떻게 범위가 없는 날짜에 대한 데이터를 보여줘야할지 고민되었다. 처음에는 습관정보를 저장하는 테이블에 습관 기록에 대한 타임스탬프를 계속 기록하는 방식으로 구현할 예정이었지만 기록을 담당하는 테이블을 분리하고 습관 등록 날짜와 극복 여부에 대한 정보를 이용하여 특정 날짜에 대한 습관 정보를 요청받으면 습관 등록 일자보다 요청 날자가 뒤에 있고 극복으로 등록되지 않은 습관을 반환하는 방식으로 잘 해결할 수 있었다.

개인적으로 생각했을 때 저번 프로젝트는 내가 공부한 내용들을 처음 적용해 봤다는 의의는 있지만 다른 사람들에게 보여주기는 조금 부끄러운 정도였다면, 이번 프로젝트는 그래도 보여줄 수는 있는 정도라고 생각이 들었다. 물론 코드는 좀 많이 신경 써서 작성하는 습관이 필요한 것 같다. 다음에는 예외처리, 테스트코드 등에 대해 공부해서 조금 더 가독성, 신뢰성 있는 코드를 짜는 방법에 대해 공부해 봐야겠다고 생각했다.

느낀점

좋았던 점

앞선 프로젝트에서 아쉬움으로 남았던 AWS와 Github Actions에 대해 사전에 먼저 학습하고 프로젝트를 진행했다는 점이 좋았다. 이미 한 번 해본 경험을 떠올리며 그 땐 왜 그렇게 했는지 이해하고 이번엔 어떻게 사용 해야할지에 대해서도 생각하며 공부할 수 있었다. 학습을 통해 이해하고 사용하니 더 빠르게 환경구축을 할 수 있었다. 또한 인터넷에서 찾은 자료 그대로 사용하는 단계에서 그치지 않고 우리 프로젝트에 맞게 원하는 대로 변형하여 사용할 수 있게 되었다. AWS로 배포하기 위한 각각의 구성 요소들과 해당 요소들이 어떤 역할을 하는지 까지 이해하고 사용할 수 있었다. Github Actions도 yml을 이용한 파이프라인 작성을 통해 어떤 방식으로 동작하는지 알게 되었다. 비록 프론트엔드와 백엔드를 하나의 파일로 배포하는 데에는 실패했지만 check out기능으로 다양한 repository에 접근하여 빌드와 배포를 수행하는 방법을 배울 수 있었다. 그리고 그 과정에서 쉘 스크립트에 대해서도 익숙해질 수 있었다.

이번 프로젝트는 프론트엔드와의 협업으로 진행되면서 처음으로 기능 명세서와 API명세서를 작성하고 개발을 시작하게 되었다. API명세서를 작성해놓으니 프론트와 소통을 할 때에 문서를 기반으로 원활하게 소통을 할 수 있었고, 변경사항이 발생할 때마다 반영하여 기능 구현을 할 때에도 유의해야 할 점을 잊지 않고 잘 구현할 수 있었다. 프로젝트가 끝난 지금도 API명세서 작성이 많이 서툴다고 생각하지만 점차 익숙해진다면 좋은 의사소통 도구가 되어줄 것 같다.

API명세서 뿐만 아니라 처음으로 프론트엔드와의 협업도 처음 경험하게 되었다. 서비스를 함께 개발해 나가면서 처음엔 프론트엔드와의 소통이 익숙하지 않아서 원활하지 못했지만 점차 익숙해지며 개발에 속도가 붙는 것을 느끼게 되었다. 그 과정에서 예전에 플러터로 프론트엔드 경험을 해본 것이 많은 도움이 되었던 것 같다. 물론 내가 경험한 것은 웹이 아닌 앱이지만 생각보다 리액트를 이용한 웹 프톤트앤드 개발과 일맥상통한 부분이 많았다. 협업을 진행하면서 같은 기능에 대해서도 다른 관점으로 바라보면 엄청난 차이가 있을 수 있다는 것도 알게 되었고 소프트 스킬의 중요성도 몸소 체감할 수 있었다. 이번 경험으로 의사소통 능력도 많이 향상된 것 같다는 느낌이 들었고, 무엇보다 함께 일하면 좋은 개발자가 되고 싶다는 생각도 하게 되었다.

JWT를 사용하여 로그인 기능을 구현해본 것도 만족스러웠다. 비록 만료기간이 긴 access토큰만 구현했지만 스스로가 실제 서비스를 만들 수 있는 개발자에 더 가까워진 느낌이었다. JWT를 공부하면서 자연스레 스프링 시큐리티의 필터체인이 하는 역할과 어떤 방식으로 동작하는 지에 대해서도 알 수 있었다. 아직 정말 완벽하게 알고 있는 것 같지는 않아서 조금 더 공부가 필요하겠지만 이번 경험이 다음에 다시 공부할 때에 많은 도움이 될 것 같다.

개발을 진행하면서 날짜별 습관을 조회하는 부분에서, 범위가 정해지지 않은 데이터를 반환하는 방법에 대해서도 고민하게 되었다. 데이터베이스에 범위가 없는 날짜와 같은 데이터를 저장하는 것은 불가능하기 때문에 처음에는 구현할 수 없는 기능을 정의한 것은 아닌지 생각했다. 하지만 isContaining()같은 함수처럼 굳이 어떤 결과를 반환하기 위해서는 데이터베이스에 해당 데이터가 꼭 있어야 하는 것만은 아니라는 것을 알게 되었다. 그래서 습관 체크 기록에 대한 테이블을 분리하고 습관 등록 날짜와 극복 여부에 대한 정보를 이용하여 특정 날짜에 대한 습관 정보를 요청받으면 습관 등록 일자보다 요청 날자가 뒤에 있고 극복으로 등록되지 않은 습관을 반환하는 방식으로 해결할 수 있었다. 이 기능을 구현하면서 문제를 조금 더 다양항 관점으로 해석해 볼 필요가 있겠다는 생각이 들었고, 해결 방법이 생각났다고 해서 끝내지 말고 조금 더 나은 방법을 찾아보는 자세가 필요하다는 것을 느꼈다.

아쉬웠던 점

이번 프로젝트에서 JWT를 이용하여 로그인 기능을 구현하였지만 refresh토큰을 이용한 토큰 재발급까지는 구현하지 못했다. 회원 관리를 위한 기능 구현만을 위해서는 access토큰만으로 충분하지만 보안적인 측면에서는 좋지 않다는 것을 알고 있기 때문에 다음번에는 refresh토큰까지 제대로 공부해서 로그인 기능을 구현해 보아야겠다고 생각했다.

또한 처음으로 여러 개의 테이블을 사용하게 되었다. 이번 프로젝트에서는 사용된 테이블의 개수가 많지 않았고 연결된 형태가 복잡한 편이 아니었기 때문에 연관관계를 설정하지 않고도 기능을 구현할 수 있었다. 하지만 연관관계없이 서로 관련된 엔티티를 조회하기 위해서는 repository를 자주 호출해야 했고 연관성을 나타낼 수 있는 식별자에 대한 테이터를 엔티티마다 추가해주어야 했다. 저번 프로젝트에서도 JPA에 대한 공부의 필요성을 느꼈지만 이제는 정말 개강, 계절학기 핑계로 미루지 말고 JPA를 공부해야겠다고 느꼈다.

그리고 이번 프로젝트에서는 기능 구현에 급급해서 좋은 코드를 작성하지 못한 것 같다. 물론 작성된 코드가 해야하는 가장 큰 역할은 원하는대로 동작하는 것이지만 같은 파트와의 협업과 유지보수를 위해서 조금 더 가독성을 높여야겠다고 생각했다. 또한 기능에 신뢰성을 높이기 위해서도 예외처리와 검증 과정이 필요함을 느꼈다. 개발하는 도중에 System.out.print()로 값을 검증하고 일부는 http 상태코드로 에러 종류를 구분하기는 했지만 테스트 코드와 예외처리로 기능들의 신뢰도를 높였다면 더 좋았을 것 같다는 아쉬움이 남았다. 개발 과정에서 주석으로 가독성을 높이는 방법과 예외처리, 테스트코드 등에 대해 공부해서 조금 더 가독성, 신뢰성 있는 코드를 짜는 방법에 대해 공부해 봐야겠다고 생각했다.


프로젝트 링크 :

notion-dontdothat

https://github.com/Goodbap

This post is licensed under CC BY 4.0 by the author.

S3에 파일 업로드 하기

JPA 헷갈리는 개념들 정리