내 생애 첫 제대로 된 프로젝트가 끝이 났다..

사실 전에는 코딩테스트 문제만 주구장창 풀고, 강의만 몇 번 들어본 개발자라고 부르기도 뭐한 사람이었다고 생각한다.

물론 지금도 너무너무 부족한 부분이 많고, 배울 점이 많지만 그래도 백엔드를 맡아 개발을 해봤다라고 말할 정도까지는 성장한 것 같다.

어떤 점에서 어떻게 성장을 했는지 한 번 적어서 기록해보려고 한다.


팀 빌딩 👋🏻

가장 중요하면서도 걱정이 되었던 팀 빌딩.

과연 나 정도의 실력이랑 같이 하고픈 사람이 있을까..? 싶었지만

열심히 이력서를 작성한 결과 실력 있는 두 팀에서 연락이 먼저 왔다!

처음에는 오지 않아서 내가 먼저해야하나 싶었는데.. 안도하면서도 기분이 좋았다.

지금 보면 많이 부끄러운 이력서이기는하다.

프로젝트 경험은 사실 없다시피하고, 개인 학습이 대부분이었다.

강의를 들으며 따라쳐 본 토이 프로젝트를 가지고, 기능 구현이 가능하다는 식으로 작성했다.

그 때는 그렇게 해야할 만큼 간절했던 것 같다.

그나마 백준 플래티넘 등급이 내세울만 했는데, 이 또한 웹개발에 큰 의미가 있지는 않았다.

아마 다른 사람보다 조금 더 정성스럽게 만들고, 1일 1커밋을 꾸준히 진행하고 있는 점에서

함께 해도 괜찮지 않을까라는 생각이 들지 않았나 싶다.

이런 점을 보면 역시 부족하고 어떤 것을 해야할 지 모를 때는, 뭐라도 하나 꾸준히 붙잡고 해나가는 게 하나의 강점이 될 수 있지 않나 싶다.

요즘에는 이러한 부분이 많이 줄은 것 같아 아쉽다.. 프로젝트가 끝난 후로 1일 1커밋에 대한 의미를 잃어서 하지 않았는데 다시 해야겠다는 생각이 든다.

꼭 누군가에게 보여주기라기보다는 개인적인 동기부여에서 말이다!


회의 📃

사실 회의때마다 고통과 긴장의 연속이었다.

왜냐면 잘 모르는 부분인데, 어느정도 ‘아는 척’을 해야했기 때문이다..

물론 지금와서는 바보같은 행동이었다고 생각하지만, 그 때는 내 진짜 실력이 까발려지고 싶지 않았다.

그래서 무작정 된다고, 할 수 있다고만 말을 했다.

이게 결론적으로 나를 많이 성장시키기도, 힘들게 하기도 한 것 같다.

프로젝트를 해봤다면 정말 간단하고 당연한 대화인데도, 나는 하나하나 무슨 뜻인지 생각하고 찾아봐야했다. 그리고 나에게 어떤 것을 물어볼까 긴장도 됐다.

‘왜 그렇게 쫄았을까.’

생각해보면, 두 팀원 모두 나보다 월등한 실력을 가지고 있다고 생각했기 때문이다.

물론 여러 프로젝트를 경험해보고, 잘하는 사람들인 것은 맞으나 결국 그냥 같은 대학생이었다.

팀원들도 모르는 것이 많았고, 함께 처음해보는 것도 많이 있었다.

그렇기에 프로젝트를 점차 진행하면서 이러한 긴장감은 많이 해소가 되었고, 조금 더 편안하게 소통을 진행할 수 있었다.

모든 것이 처음은 어렵다. 어려운 처음을 잘 헤쳐나가서 다행이라고 생각한다.


프로젝트 소개 📅

프로젝트 과정을 소개하기 전에, 간단하게 프로젝트에 대한 소개가 필요할 것 같다.

‘동국대학교 교내에 있는 공지사항 사이트를 통합해서 공지사항을 학생들에게 보여주고, 이를 캘린더로 일정관리할 수 있게 하는 프로젝트’라고 말할 수 있겠다.

프로젝트명은 동국대’학’교 공지’사’항 ‘통’합 ‘달’력에서 한 글자씩 뽑아서,

‘학사통달’로 지었다. 대학에서의 학사를 통달하자는 의미도 담아보았다.

프로젝트명도 내가 고민해서 만들었는데.. 이런 걸 보면 이번 학기 정말 프로젝트에 많은 시간을 쏟기는 한 것 같다.

아래 깃허브 리드미에 설명을 자세하게 작성해두었다.

https://github.com/bbbang105/2023-2-OSSProj-ZIIO-4


DB 설계 🧱

DB 설계라 하면 학교 데이터베이스 수업에서 스키마를 정말 간단하게 짜본 것이 다였다.

이러한 상태로 1학기 동안 진행할 프로젝트를 설계해야한다니… 정말 막막했다.

구글링을 정말 많이 해봤다. 그리고 프로젝트에 필요할 테이블이 어떤 것인지 고민해보았다.

그 결과 아래와 같이 ERD를 작성했다.

당연히 틀린 부분도 많을 것이다. 하지만 아는 범위 내에서는 최선을 다했다고 생각을 한다.

막상 프로젝트를 해보니 코드를 짜는 것보다, 이런 설계가 더 중요하다고 느꼈다.

데이터베이스 공부에 시간을 더 투자해야될 것 같다.

카테고리 🗂️

제일 많이 고민한 부분이 카테고리였다.

대분류 - 중분류 - 소분류로 나누어야했는데, 어떻게 해야 상위 카테고리를 선택해도 하위 카테고리까지 검색되게 할 지 고민을 했다.

그래서 생각해낸 게 각 분류별로 3글자씩, 총 9글자의 카테고리 아이디를 부여하는 것이었다.

이런식으로 말이다.

‘000’은 필요없는 부분이기 때문에, 이를 제거한 숫자를 부모 카테고리 ID라고 칭했다.

예를 들어서 문과대학의 ID는 ‘101101000’이기 때문에, 부모 카테고리 ID는 ‘000’을 제거한 ‘101101’이 된다.

그렇기에 만약 사용자가 문과대학의 공지사항을 모두 검색해보고 싶다면, 카테고리 ID가 ‘101101’로 시작하는 모든 공지사항을 보내주는 식으로 구현을 진행했다.

검색하고자 하는 키워드가 존재한다면, 해당 키워드가 제목에 포함된 공지사항들만을 반환했다.

이렇게 하니 카테고리 ID와 키워드만 받고, 사용자가 원하는 공지사항들을 화면에 보여줄 수 있도록 구현할 수 있었다.

마이페이지

캘린더에 표시할 각 사용자의 일정 정보를 저장한 테이블을 마이페이지라고 명칭했다.

테이블 하나로 모든 작업을 처리했는데, 그렇게 하니 효율성이 많이 떨어지는 것을 느꼈다.

이번에는 당연히 조인 이런건 건들여보지도 못했는데..

다음에는 DB 설계에 더 시간을 많이 쏟아서 효율성을 높여보아야 전반적인 프로젝트의 퀄리티가 올라갈 것 같다!


API 설계 📝

API가 대체 뭔데… 웹 개발을 할 때 가장 중요한 것이 API이다.

그리고 이 API를 잘 짜고 프론트와 소통을 문제 없이 하기 위해서는 API 설계를 잘 해놔야한다.

API는 애플리케이션 프로그램 인터페이스이다.

애플리케이션은 고유한 기능을 가진 모든 소프트웨어이고, 인터페이스는 추상적인 계약이라고 볼 수 있다.

즉, 이를 웹 개발 관점에서 본다면 프론트와 백 간에서 소통을 하기 위한 약속이라고 간단히 표현할 수 있을 것 같다.

최종 결과물부터 보자면, 나는 아래와 같이 API 명세서를 작성했다.

지금 보면 물론 수정할 것이 많아 보이지만… 그 때는 정말 며칠을 써서 고민한 결과물이었다.

당연히 처음이었기 때문에, 어떻게 시작해야될지도 몰랐다. 애초에 이게 왜 필요하고, 어떤 걸 작성해야하는지도 모르는 정도였다.

그래서 구글링을 미친듯이 하면서 레퍼런스를 찾아보았다. 어느 한 블로그에서 괜찮은 템플릿을 발견해서 사용을 했고, 사람들이 작성한 것을 보면서 하나하나 적어나갔다.

기획자가 없이 개발자들끼리 프로젝트를 진행했기 때문에, 기능도 명확히 정해져있지않아서 골머리를 앓았다.

각 페이지마다 어떤 기능이 필요하고, 어떤 데이터를 주고 받아야하는지 등을 모두 혼자 판단하여 작성해나갔다.

DTO도 아래처럼 적어나갔다.

물론 이는 계속 수정을 해나가서 괜찮아진 것이고… API 명세서 수정만 정말 여러 번 해나간 것 같다.

기능을 구현하면서 필요없는 API들도 뺐고, uri도 조금씩 수정을 진행했다.

이러한 과정을 거치면서,

  1. 프론트-백 간에 데이터 통신이 필요한 부분인가?
  2. uri가 직관적이면서 컨벤션에 맞는가?
  3. DTO는 적절하게 작성되어있는가?
  4. 예외처리와 에러코드에 대한 생각을 했는가?
  5. 팀원들이 보기에도 이해가 잘 되는 문서인가?

등등을 끊임없이 고민하면서 성장할 수 있었다.

한 번 해보고 나니 이후 프로젝트에서는 훨씬 수월하게 작성하고 소통할 수 있게 되었다.

프론트에서 어떤 식으로 사용을 하고 통신하는지 알게 되었기 때문에, 어떻게 만들어주어야 좋을지도 알게 되었다.

개인적으로 혼자 처음부터 고생하며 만들어봐서 정말 많이 성장한 부분이라고 생각한다!


크롤링 🕸️

이번 프로젝트에서 빼놓을 수 없는 기능이 크롤링이었다.

애초에 64개의 웹사이트에서 공지사항을 끌어와서 데이터베이스를 구축해야하는 것이라.. 핵심 기능이었다.

당연히! 크롤링도 처음 구현해보았다. 자바로 해야 했기에, Jsoup을 사용했다.

웹사이트마다 HTML구조가 같으면 좋았겠으나.. 당연히 달랐기 때문에 6가지의 클래스를 만들어서 크롤링을 진행했다.

하나는 모든 크롤러를 관리하는 목적의 크롤러 매니저로 아래와 같이 만들었다.

네이밍이 길기는 한데, 최대한 축약하지 않으려고 의도적으로 작명했다.

처음에 크롤링이 잘 되어서 콘솔에 정상적으로 출력될 때는 정말 기분이 좋았다. 그리고 끌어온 데이터들을 적절하게 가공해서 DB에 저장했다.

매 번 크롤링마다 2500~3000개 정도의 공지사항을 자동으로 가져오고 가공하여 DB를 업데이트했다.

매우 큰 데이터셋은 아니지만, 그래도 교내 프로젝트 단위에서 꽤 많은 데이터를 만져본 것은 의미있었다고 생각한다!


기능 구현 ⚒️

사실 모든 기능을 말하면 너무 길어질 것 같기에.. 기능에 대한 얘기는 패스하려고 한다.

구현하면서 느낀 것은, API 구현하는 것은 생각보다 어렵지 않다는 것이었다.

물론 Chat GPT의 도움을 많이 받기는 했지만.. 구조가 어느정도 다 짜여져 있기에 몇 번 해보면 다 비슷하게 만들어낼 수 있었다.

정말 중요한 것은 예외처리와 적절한 에러코드를 반환하는 것이었다.

API 요청이 들어올 때,

  1. 형식에 맞지 않는 데이터를 보냈는가?
  2. 없는 데이터를 찾고 있는가?
  3. 중복된 작업을 하려고 하는가?
  4. 권한이 있는가?
  5. 그 외 무수히 많은 예외…

등등을 고려해주어야 했다.

그렇기 때문에 전역으로 예외를 처리해주며 이러한 예외들을 잡고 적절한 에러코드를 반환해주었다.

전역 예외 처리 또한 당연히 처음이기에, 형식이 통일화되지 않아서 마음에는 들지 않지만 그래도 구현했다는 점에 의미를 두고 싶다.

다음에 프로젝트를 하게 된다면, 기능 구현을 하기 전에

  1. DB 설계
  2. API 설계
  3. DTO 설계
  4. 예외 처리
  5. 테스트 코드 작성

을 먼저 해줘야 수월하게 진행이 되겠다라는 생각이 들었다.

로그인 기능 🔑

다른 건 몰라도 로그인 기능 하나는 얘기를 하고 넘어가야할 것 같다.

소셜 로그인으로 구글 로그인만 진행하도록 구현했는데, 많은 시간을 쏟은 부분이었다.

여러 가지 방법이 있는데, 이 프로젝트에서는 백에서 모든 과정을 처리해서 로그인을 진행시키는 방식으로 진행했다.

https://chb2005.tistory.com/182

해당 블로그를 많이 참고해서 구현했다.

구글 API 콘솔에서 설정도 해보고, 사용자 정보를 토큰으로 받아와서 추출하고, 이를 다시 JWT 토큰으로 만들어서 uri에 쿼리 파라미터로 프론트 측에서 보내주었다.

사실 보안적인 부분에서 좋은 방법은 아니었던 것 같다.

프론트와 함께 로그인 기능을 구현하고, 쿠키를 사용해서 보안성을 높이는 게 좋은 것은 맞으나, 한정된 시간 내에서는 최선의 방법이었던 것 같다.

보완해야할 부분이 있다는 것은, 어찌보면 더 성장할 수 있다는 것이니 긍정적인 부분이다!


배포 🔛

배포에 대해서도 얘기할 것이 정말 많다..

가장 삽질을 많이 한 도커에 대해서 먼저 얘기해보려고 한다.

도커 🐳

프론트 측에서 서버를 켜고 개발을 하고 싶다는 요청이 날라왔다.

나는 아무것도 모르기 때문에, 당연히 알겠다고 했고 이는 도커를 통해서 할 수 있는 부분이었다.

도커를 오픈소스 실습에서 써보기는 했지만, 이렇게 프로젝트에서 쓰는 것은 처음이었다.

프론트 분이 보내주신 도커 컴포즈 파일을 토대로, 백엔드 도커파일과 도커 컴포즈 파일을 작성해나갔다.

당연히 에러들을 엄청나게 많이 만났다. 도커는 또 새로운 세상이었기 때문에 근본적으로 이해가 부족한 상태에서는 잘 될리가 없었다.

잘 되던 MySQL 연결이 안되고.. 실행이 안되고.. 고래 사진만 보아도 속이 안좋을 정도였다.

결국 모든 에러들을 해결을 하면서, 도커에 대한 꽤나 깊은 학습을 강제로 할 수 있었다.

이제 프론트가 VsCode에서 서버를 열고 개발을 진행할 수 있게 되었다.

하지만 이제 문제는 DB였다. 당연히 내 로컬에만 있는 DB니까 프론트에는 없다.

지금이야 당연한 거지만 이때만 해도 이해를 못했다.

도커 볼륨을 사용해서 할 수는 없을까? 라는 생각에 빠져서 고집을 좀 오래 부렸다.

결론적으로 도커 볼륨’만’ 사용해서는 팀원들과 DB를 공유할 수 없었다. 볼륨 또는 DB 자체를 클라우드에 올려야 함께 사용할 수 있었다. 이런 간단한 사실 하나를 이해하는데에도 며칠이 걸렸다.

도커를 계속 사용해서 배포하는 데에도 이용하고 싶었지만, 결국 포기하고 DB를 AWS RDS에 올리는 방식으로 변경해서 진행했다.

이번 프로젝트에서 아쉬운 부분이었다고 생각한다.

EC2 📦

AWS EC2 인스턴스를 만들고 사용하는 방법 자체는 간단했다. 그래서 백엔드 배포까지는 생각보다 쉽게 마칠 수 있었다.

하지만 문제는 프론트와 이를 연결하는 것이었다.

맨 처음에는 프론트는 Vercel로 배포하고, 백엔드는 EC2로 배포를 했다. 통신이 제대로 안됐다.

Vercel은 https를 사용하고, EC2는 기본적으로 http를 사용하기 때문이었다.

그래서 두번째로는 EC2에 프론트와 백을 모두 담아 배포하기로 결정했다. 메모리 초과가 발생했다. 프리티어니까 당연한 결과였다.

프론트는 빌드 파일만 EC2에 넣어 배포하는 방식으로 해결을 했다. 하지만 이번에는 구글 소셜 로그인에서 문제가 생겼다.

왜냐하면 구글 소셜 로그인이 로컬호스트를 제외하고는, https만 사용해야 액세스를 허용해주는 것으로 변경되었기 때문이다.

정확히 변경된지는 모른다. 하지만 다른 개발자분들이 가장 최근에 했을 때만 해도 인스턴스 도메인으로도 되었던 것이 지금은 안된다..

그래서 최종적으로는, 도메인을 구매해서 백엔드 인스턴스에 적용을 하고, 프론트는 다시 Vercel을 사용해서 연결에 성공했다.

지금 보면 참 이런 삽질이 없다고 생각이 들기는 한데, 당시에는 처절했다..

앞으로는 굳이 백에서 도메인을 구입하지 않고 SSL 인증서를 발급해서 https를 적용시키거나, EC2에서 함께 배포하는 방식으로 진행할 것 같다.

그래도 삽질한 만큼 배포 과정에 대해서도 정말 많이 배울 수 있는 순간이었다!


정리

느낀 점은 위에 적은 것들을 빼고도 사실 너무너무 많다.

매순간 새로웠고, 고통스러웠고, 뿌듯했고, 노력했다.

프로젝트 하나 끝낸거에 왜이렇게 유난이냐고 생각할 수도 있지만, 백엔드 개발자를 목표로 하고 있는 나에게는 정말로 의미가 있는 작업이었다고 생각한다.

비록 미완성인 부분도 존재했지만, 사람들 앞에서 만든 결과물을 실시간으로 선보였을 때의 뿌듯함은 이루말할 수 없을 것 같다.

프로젝트가 끝나고, 자기 객관화를 하기 위해서 팀원들에게 나의 피드백을 요청했다.

쓴소리를 원했지만, 듣지는 못했고 ‘열정 있다.‘라는 말을 들을 수 있었다.

내가 봐도 이 프로젝트에는 많은 열정을 쏟았던 것 같다.

이것이 물론 성장에는 도움을 주었지만, 다른 여러 부분에서는 좋지 않게 작용하기도 하였다.

그렇기에 앞으로는 이번처럼 프로젝트에 모든 것을 갈아넣으며 진행하지는 않을 것 같다.

하지만 열정 하나는 개발자 인생이 끝날 때까지 함께 들고 가고 싶은 마음이다!

🔥