종강한 후에 학교 GDSC에서 주최하는 해커톤인 ‘동국톤’에 참여했다.

공식적으로 학교에서 열리는 첫 해커톤으로 알고 있어서, 의미도 있고 개인적인 실력도 올리고자 지원하게 되었다.


팀 빌딩 👋🏻

팀은 지원서에 작성한 내용을 기반으로 운영진 측에서 임의로 정해주었다.

팀 내에서 아는 사람은 아무도 없었다…

첫 회의 📄

첫 회의에서는 각자 아이디어를 발표하는 시간을 가졌다.

하지만 이때 내가 학교 수업 과제가 밀린 바람에 조금밖에 준비하지 못하고 발표를 해버려서, 상당히 죄송하고 부끄러운 마음이 들었다.

원래는 바로 주제를 픽스한 뒤에 진행을 하려 했는데, 모두가 만족하는 아이디어가 나오지 않아서 결국 한 번 더 회의를 진행하기로 했다.

사실 처음에는 회의가 꽤나 답답했다. 다들 처음이기도 하고 모르는 사이라 어색한 것은 둘째치고, 뭔가 중심을 잡고 끌고 나가는 사람이 없다고 느껴졌다.

난 기획자도 팀장도 아니기에 먼저 나서기도 쉽지 않았다. 하지만 두번째 회의 때부터는 내가 좀 더 적극적으로 해야할 것 같다는 생각이 들었다.

이후 회의 📄

두번째 회의때는 그래도 어느정도 아이디어를 생각해서 들어갔다.

아예 새로운 아이디어는 생각이 안나서, 팀장님이 첫 회의때 발표하신 아이디어에 내 생각을 덧붙여서 기능을 추가해 발표를 진행했다.

그리고 투표를 한 후에 내 아이디어로 프로젝트 주제가 선정되었다! 🙃

기분이 약간 좋기도 했고, 뭔가 조금 더 열심히 해야겠다는 생각도 들었다.

아무래도 본인의 생각이 담긴 주제로 프로젝트를 진행하는 것이 동기부여 면에서도 도움이 된다고 생각하는데, 이런 부분에서 팀장님의 아이디어를 디벨롭한 나의 아이디어가 선택된 것이 긍정적이라고 느꼈다.

초중반에는 기획자와 디자이너가 분위기를 조성하면서 프로젝트의 틀을 만들어주어야 할텐데, 만약 기획자가 느끼기에 선정된 주제가 정말 별로라면 ‘하기 싫다.‘는 마음이 생겨날 수도 있기 때문이다.


개발 👨🏻‍💻

공식적인 개발 기간은 12/18 ~ 12/20 이었다.

물론 다들 먼저 몰래 했을 것 같지만..

설계 🧱

API, DB, DTO 설계 등을 먼저 진행했다.

DB 설계는 내가 맡아서 했는데, 백엔드 측에서 다룰 데이터가 많이 없어서 이전에 했던 프로젝트에 비하면 아주 빠르게 끝이 났다.

API 설계는 다른 백엔드 팀원과 함께 회의를 하면서 정했다.

이번에는 /api/v1 를 모든 uri 앞에 붙이면서 진행했는데, 이렇게 하니 api와 버전 정보를 명시할 수 있어서 좋았던 것 같다.

아마 앞으로도 이런 방식으로 진행하지 않을까한다.

확실히 API 설계도 한 번 해보고 나니, 수월하게 마무리되었다.

만약 해커톤이 첫 프로젝트였다면.. 많이 힘들었을 것 같다.

개발 시작 🎬

20일에는 해커톤 당일이라, 가서 정신도 없고 발표 준비도 해야 해서 사실상 개발 기간은 이틀이었다.

우선 내가 프로젝트를 만들고, 전체적인 틀과 DB 구축을 진행했다.

DTO를 만들고, 사용 예시를 위해서 API도 일부 만들었다.

이전 프로젝트에서도 DTO를 사용하기는 했지만, 잘 모르고 썼었기 때문에 이번에는 조금 더 알아보고 가독성이 좋게 만들려고 노력했다.

그리고 MySQL 드라이버 에러로 꽤나 고생을 했던 터라.. 이번에는 그러지 않도록 유의했다.

다행히 잘 마무리해서 팀원에게 넘겨줄 수 있었다.

나머지 API 구현은 맡기고, 나는 바로 배포를 준비했다.

대면 개발 🙋🏻‍♂️

19일에는 오후부터 팀원들과 대면으로 개발을 진행했다.

캡실? 이었나 산시들이 쓰는 방을 빌려서 모였다.

처음에는 굉장히 어색했다.. 그래도 시간이 지나고 밥도 먹고 하니까 조금 편해졌던 것 같다.

난 이때 대부분의 시간을 도커와 배포에 할애했다.

이번에는 도커를 조금 더 제대로 사용해보고 싶었기 때문이다.

내가 생각한 배포 구조는 다음과 같았다.

  1. 프론트, 백 각자 도커파일을 만들고 생성한 이미지를 허브에 업로드

  2. EC2 인스턴스 내에는 도커 컴포즈 파일 하나만 넣어두고, docker-compose up 하나로 모든 애플리케이션 실행

도커 허브에 이미지를 올려두었기 때문에, 해당 이미지를 pull 해 온 다음에 컨테이너를 생성 및 실행하면 되지 않을까 하는 아이디어였다.

결론적으로는 다행히 성공했다! 아직 지식이 부족해서 수동으로 ci/cd 를 진행하기는 했지만.. 그래도 뭔가 생각만 한 게 실제로 되니 신기하고 뿌듯한 마음이었다.

하지만 단점도 있었다. 코드에 변경사항이 생기면 도커 허브에 업로드하고, 이를 다시 pull 받아 반영시켜야했는데 이 과정에서 시간이 꽤나 걸렸다.

만약 다음에도 비슷하게 진행을 한다면, 이러한 부분들을 보완하도록 노력해보아야 할 것 같다.

도커 컴포즈 파일

version: '3'
 
services:
  snowball_frontend:
    restart: always
    command: npm start
    container_name: snowball_frontend
    image: hsh111366/snowball_frontend:1.0
    ports:
      - "3000:3000"
    networks:
      - app-network
    stdin_open: true
 
  snowball_backend:
    image: hsh111366/snowball_backend:1.0
    container_name: snowball_backend
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://snowball_db:3306/snowball_db?useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true
      SPRING_DATASOURCE_USERNAME: snowball_user
      SPRING_DATASOURCE_PASSWORD: snowball_pwd
    ports:
      - "8080:8080"
    networks:
      - app-network
    depends_on:
      - snowball_db
 
  snowball_db:
    image: mysql:8.2.0
    container_name: snowball_db
    environment:
      MYSQL_ROOT_PASSWORD: 1234
      MYSQL_DATABASE: snowball_db
      MYSQL_USER: snowball_user
      MYSQL_PASSWORD: snowball_pwd
    ports:
      - "3306:3306"
    networks:
      - app-network
    volumes:
      - snowball_db_data:/var/lib/mysql
 
networks:
  app-network:
 
volumes:
  snowball_db_data:

도커 컴포즈 파일은 위처럼 작성을 했다.

프론트엔드 도커파일

FROM node:18.17.0-alpine
WORKDIR /donggukthon_2023_9_F
COPY package.json package-lock.json ./
RUN npm install 
COPY . ./
EXPOSE 3000

프론트엔드측 진행 속도가 더뎌서, 어쩌다보니 내가 프론트엔드 도커파일까지 만들었다..

그래서 결과적으로 혼자서 프론트 백 배포를 모두 진행했다.

이전 프로젝트에서는 배포도 잘 몰랐는데.. 그래도 어느정도 이해를 하고 내가 맡아서 할 수 있음에 감사함도 뿌듯함도 느꼈다.

위 파일대로 진행하니까 되기는 하는데, 매번 npm install을 하다보니 시간이 꽤나 걸렸다.. 아마 좀 더 좋은 방법이 있을 듯하다.

deploy.sh 파일

#!/bin/bash
./gradlew clean build -x test
docker buildx build --platform linux/amd64 --load --tag hsh111366/snowball_backend:1.0 .
docker push hsh111366/snowball_backend:1.0

원래 처음에는 도커 이미지를 만들고, 허브에 업로드하는 과정을 하나하나 명령어로 쳤다.

이를 본 백엔드 멘토분께서, 그러지 말고 sh파일을 하나 만들어서 실행하라고 팁을 주셨다.

그래서 위와 같이 만든 후에, 파일만 실행을 하니 자동으로 push까지 완료되었다.

만약 수동으로 ci/cd를 해야한다면 이처럼 sh파일을 만드는 방식이 유용할 것 같다!

그리고 여기서 중요하게 보아야 할 부분이 --platform linux/amd64인데, 수동으로 도커 이미지의 운영체제를 지정해주는 명령어이다.

처음에는 도커 허브에 올려둔 이미지를 받아와서 인스턴스 내에서 실행을 하는데, 자꾸 운영체제가 맞지 않는다는 에러가 발생했다.

이것 때문에 시간을 꽤나 썼는데, mac에서는 수동으로 운영체제를 지정해주어야 한다는 사실을 멘토님께 듣고 해결할 수 있었다.

노트북을 mac으로 바꾸고 나니, 내가 모르는 이런 문제들이 발생할 수가 있구나 싶었다.


해커톤 당일 🔥

당일에는 학교에 오전 7시까지 들어가야했다.

전날에 거의 2시간도 자지 못해서, 제정신이 아닌 상태로 도착했다.

들어가니 GDSC의 회장이 오프닝을 하고 있었고, 팀원들은 이미 개발에 몰두한 상태였다.

나도 겨우 합류를 해서 개발을 시작했다.

그리고 생각보다 해커톤을 잘 준비한 것 같다는 생각이 들었다. 후원사도 많았고, 진행도 큰 문제 없이 잘 이루어졌다.

이번을 시작으로 앞으로도 교내에 이런 행사들이 늘어났으면 좋겠다라는 생각이 들었다.

1차 스프린트 🏃🏻

오전 7시부터 12시까지는 1차 스프린트를 진행했다.

백엔드 API 개발까지는 거의 끝난 상태라, 나는 계속 도커를 만지면서 배포를 진행했다.

그리고 이번에는 EC2가 아니라, 구글 클라우드 플랫폼 (GCP) VM을 사용하여 배포하는 것으로 변경했다.

AWS에 비해 좀 더 쉽고 직관적인 것 같다는 느낌이 들었다.

처음에는 시간이 꽤 많이 남았다고 느껴졌다. 점심시간을 빼도 개발 종료까지는 약 9시간이 남아있었기 때문이다.

그래서 얼른 테스트를 해보면서 에러를 잡고 배포까지 끝내면 되겠다는 생각을 했다.

하지만 문제는.. 프론트 측에서 아직 화면도 다 만들지 못했기에, API 연동 자체를 시도해볼 수가 없었다.

물론 프론트에서 해주어야 할 일이 많았던 것은 맞다. 하지만 감당이 안 될 일정이라면 미리 조율을 했어야했고, 아니라면 어떻게든 끝내야 하는 게 맞다고 생각한다.

결국 점심시간 전까지는 테스트를 해보지 못 하고 끝이 났다.

점심시간 🍱

밥을 먹으면서도 개발을 했다.. 다들 그랬다.

나름 맛있는 도시락이 나왔다.

그래도 먹으면서 팀원들과 얘기를 조금 나누었다.

나는 이왕 함께 팀이 된 김에 미리 만나서 친해지기도 하면서 즐겁게 개발을 해보고 싶었는데, 이번 팀에서는 그런게 이루어지지는 못했다.

아쉬운 부분이었다.

2차 스프린트 🏃🏻

잠시 쉬는 시간을 가진 후에 마지막 개발에 들어갔다.

여기서 수많은 에러가 발생했다…

1. 소셜 로그인 에러

드디어 화면이 다 만들어지고, 이제 로그인이 잘 되는지 테스트를 해보았다.

로그인은 구글, 카카오 소셜로그인으로 진행했다.

둘 다 이전 프로젝트때처럼 스프링 시큐리티를 사용하여 백 측에서 처리했고, 이전에는 구글로만 했었는데 이번에는 카카오톡도 도전해보았다.

약간 다른 점이 있었지만, 그래도 어찌저찌 해결해서 로컬에서는 잘 돌아가는 것을 확인했다.

하지만 프론트와 붙여 테스트를 해보니 계속해서 에러가 났다.

리다이렉트 에러가 발생을 해서 문제점을 계속 찾아보았고, 결국 몇 시간을 헤맨 끝에 발견할 수 있었다.

내가 한 방식대로 하면 프론트와 통신할 필요가 없는데, 프론트 측에서는 통신하는 방식으로 진행을 했던 것이었다.

즉, 구글 or 카카오톡 소셜 로그인 창으로 바로 넘어가도록만 해주면 되는데, 그러지 않고 API 방식으로 했던 것이다.

백엔드 코드에는 문제가 없는 것 같아서, 프론트 측 코드를 뜯어보고나서야 이걸 알게 되었다..

로그인 버튼 클릭 시 리다이렉트 uri를 변경해줌으로써 해결할 수 있었다.

정말 피말리는 시간이었지다. 웃프지만 덕분에 리액트 코드도 대충 볼 수 있게 된 것 같다.

물론 프론트 측만의 잘못은 아니다. 그 방법을 사용하는 사람들이 더 많기 때문이다.

나도 OAuth가 어떤 구조로 돌아가는지 제대로 이해하고 있었다면, 더욱 빠르게 에러를 해결할 수 있었을 것이다.

그리고 다음부터는 ‘프론트와 통신하는 구조로 만들어봐야겠다.’ + ‘쿠키를 발행해 보안성도 높여야겠다.‘는 생각을 했다.

2. 카카오톡 IP 에러

구글은 잘 됐지만, 카카오톡은 여전히 문제가 있었다.

이를 해결하고자 온갖 서칭을 다 해보았지만 찾을 수가 없었다.

결국 동아줄을 잡는 심정으로 멘토분께 찾아가니 5분 안에 해결이 되었다.

카카오 개발자 홈에서 이것저것 해보다가 허용 IP를 설정을 했었는데, 이것 때문에 계속 차단이 되었던 것이다.

결국 허용 IP를 모두 지운 후에야, 해결이 되었다.

AWS에서 허용 IP를 설정하는 것처럼, 지정을 해주어야 로그인이 가능할 것이라 생각했는데 오히려 그 반대였던 것이다…

‘정말 간단한 걸로도 시간을 이렇게 날릴 수 있구나..’ 라는 생각이 들었다.

3. CORS 에러

원래 스프링부트 2.7x를 쓸 때는 문제가 없었다.

당연하다. 이전 프로젝트거를 그대로 가져왔기 때문이다.

하지만 스프링 부트 버전을 3.xx 이상으로 하고, 자바도 17이상으로 하자는 팀원의 의견에 동의를 해서 버전 업그레이드를 진행했다.

하면서 기존에 있던 소셜 로그인 코드를 일부 수정해야 했다. 이전 프로젝트에서는 시간 부족으로 도전하지 못했던 부분인데, 이번에 성공해서 기분이 좋았다.

또한 스프링 시큐리티 config 부분에서도 변경할 것이 많았다.

잘은 모르지만 어찌저찌 서칭을 해서, 돌아가게는 만들었다.

하지만 악명 높은 cors에러.. 어김없이 발생했다.

혼자서는 해결이 안돼서 또 멘토분의 도움을 받아서 해결했다.

해커톤을 하면서 거의 4번 이상은 큰 도움을 받은 것 같다.. 정말 감사했다.

몇 번 슥 보고 어떤 문제인지 파악할 수 있는 능력이 부럽기도 하고 대단해보였다.

나도 많은 경험을 쌓아서 저렇게 되고 싶다라는 생각을 했다.

4. 서버 500에러

그래도 테스트 결과가 나오는 기능까지는 구현을 마치자고 해서, API 연결을 진행해보았다.

분명히 로컬에서는 잘 되던 것이, 연동만 하면 500에러가 발생했다.

하필 500에러… 문제가 뭔지 알아내야했다.

나는 NginX 관련 문제라고 생각을 해서, 그쪽을 계속 파보았다.

하지만 잘 모르는 기술이었기 때문에 쉽게 찾을 수가 없었다.

결국 개발 시간이 끝날때까지 노력했지만 해결은 하지 못했다.

아마 인증서와 관련된 문제인 것 같은데.. 여전히 정확히 알지는 못한다..

결과 🥲

결국 대부분의 기능을 만들지 못한 채로 데모 부스를 시작하게 되었다.

프론트와 백 연결 자체가 안됐으니까, 사실상 아예 기능 구현을 못 한 것이나 마찬가지이다.

나도 많이 속상하고 지쳤지만, 디자인과 기획한테 미안한 마음이 들었다.

‘프론트 측의 개발이 좀 더 빨리 진행돼서 테스트를 좀 더 빨리 해봤더라면..’ 하는 마음이 드는 것도 사실이었다.

하지만 분명히 나의 에러 해결 능력의 부족도 이와 같은 결과를 만든 것이다.

그러므로 누구를 탓하기 보다는, 이번에 배우고 느낀 점을 토대로 앞으로 보완하는 것이 중요하겠다고 생각을 했다.


느낀 점 & 배운 점 💡

1. 일정 관리 실패

이번 프로젝트를 끝까지 완수하지 못한 것은 여러 이유가 있었겠지만, 가장 큰 것은 일정 관리를 제대로 하지 못한 부분이라고 생각한다.

내가 개발을 다했다고 해서 끝나는 게 아니다. 팀원들과 함께 속도가 맞아야 한다.

나 혼자 앞서나가서 하는 것도 좋지만, 다른 팀원들을 독려하며 같이 가는 것이 더 중요하다고 느꼈다.

원래도 혼자 하는 걸 좀 더 즐기는 성향이기는 하지만, 개발자는 그럴 수가 없기 때문이다.

기획자가 일정 관리를 잘 해주면 참 좋겠지만, 그러지 못할 때는 나라도 팀원들을 끌고 가야겠다는 생각을 했다.

2. 자기 객관화

내가 정말 많이 부족하다는 것을 느꼈다.

그래도 학기중에 나름 열심히 프로젝트를 하면서, 백엔드에 대해 조금 알게 되었다고 생각했다.

하지만 현실은 간단한 에러도 해결하지 못하는 초짜였다.

오히려 내 마음대로 잘 되지 않아서, 내가 부족한 부분이 어디인지 크게 깨닫게 된 소중한 경험이었던 것 같다.

부족한 부분을 아는 것은, 내가 공부해야 할 부분을 알게 되는 것이고, 실제로 공부를 하다보면 분명 성장하게 될 것이다.

3. 멘토

나보다 오히려 학번이 낮은 멘토에게 큰 도움을 받으며 많은 것을 느꼈다.

멘토에 대해 조금 들었는데, 스프링 공식 문서를 여러 번 정독했다고 한다.

역시 기본이 가장 중요한 것 같다.

오랜만에 사람한테 감명을 느꼈고, 친분은 전혀 없지만 나름의 롤모델로 삼게 되었다.

코드를 잘 짜는 개발자보다, 에러를 잘 잡는, 즉 문제 해결을 잘 하는 개발자가 되어야겠다는 생각이 들었다.

4. 새로운 기술 도전

지금까지는 내가 부족한 부분, 아쉬웠던 부분들만 말을 했는데 물론 해커톤을 하며 좋은 점도 많았다.

카카오톡 소셜 로그인을 구현해보았다는 점,

DTO를 조금 더 체계적으로 적용해보았다는 점,

버전 업그레이드를 진행해보았다는 점,

그동안 제대로 사용하지 못했던 도커를 실제로 배포에도 사용해보았다는 점,

EC2만이 아닌 GCP를 사용해 배포해보았다는 점 등등..

새롭게 도전할 수 있는 부분은 도전을 하려고 노력하니, 많은 것을 얻을 수 있었다.


아쉬운 마음이 컸던 해커톤인 것은 사실이나,

사용한 시간 그 이상의 많은 것을 배울 수 있었던 경험이라고 생각해 후회는 없다.

단점은 보완하고, 문제는 잘 해결해내는 개발자가 되도록 노력하자!

나름 발표도 했다 나름의 추억