JUINTINATION

카카오테크 부트캠프 2기 - 5주차(해커톤 후기) 본문

카카오테크 부트캠프

카카오테크 부트캠프 2기 - 5주차(해커톤 후기)

DEOKJAE KWON 2025. 3. 1. 12:03
반응형

정신없는 하루하루가 지나가니 어느덧 3월이 되었다. 5주차는 월요일만 수업이 진행되었고, 나머지 화수목금은 사실상 해커톤 기간이었는데, 그래서 카카오테크 부트캠프 후기를.. 적어보려고 한다.

팀빌딩

화요일은 아이디어톤 및 팀빌딩을 진행했다. 각 팀은 6명(풀스택 2, 클라우드 2, 인공지능 2)을 원칙으로 구성되며,  주제는 LLM을 활용한 AI 기반 서비스 개발 프로젝트였다. 나는 LLM 관련 지식이 별로 없기도 하고, 사실상 과제하느라 바빠서 아이디어톤은 참가하지 않았지만 다른 분들의 아이디어 발표를 듣고 어느 팀에 들어갈지 생각하는 시간을 가졌다.

미리 디스코드에서 팀원을 모두 구한 팀도 있고, 클라우드 과정에 백엔드 개발을 할 줄 아시는 분들이 많아서 사실상 백엔드의 수요가 적을 것이라는 생각이 들었다. 그래서 뭔가 팀빌딩을 할 때 내심 아무나 나한테 "저희 팀에 들어오실래요?"를 해주길 원했는데.. 역시 그런 일은 없었고, " LLM 기반 연습 문제 생성 서비스"를 주제로 하는 팀에 지원해서 들어갔다.

아이디어 회의

사실 PDF를 입력해서 연습 문제를 만들어 준다는 내용과 완전히 동일한 주제로 하는 다른 팀이 하나 더 있어서 걱정을 했는데, 이건 회의를 통해 차별점을 만들면 될 것 같다고 생각을 했다. 그래서 우리 팀만의 차별점은 "PDF 뿐만 아니라 다른 확장자의 파일(mp3 등)을 입력해도 연습 문제를 만들어 준다"는 내용으로 가기로 결정했다.

또한 피그마를 통한 UI/UX 회의도 진행했는데, 프론트엔드 파트를 맡는 팀원 mini와 로그인 기능을 구현할지 말지에 대한 얘기가 많이 오갔다. 기능적으론 로그인 기능을 구현하는 것이 무조건 맞는데, MVP(Minimum Viable Product)만 만들면 되는 해커톤 특성상 굳이 만들 이유가 없는 것도 맞았다.

그런데 우리 아이디어 특성상 DB 테이블은 회원(Member) 테이블과 연습 문제(Quiz) 테이블, 이렇게 딱 2개만 필요해서 해커톤 기간동안 맡을 역할이 너무 없을 것 같기도 하고, 이전에 만들어둔 로그인 관련 API 서버도 있어서 금방 끝날 것이라고 생각해서 결국 회의 끝에 로그인 기능까지 구현하기로 했다.

트러블슈팅

생각보다 개발 관련 문제는 너무 빨리 생겼다. 내가 지금까지 구현한 모든 프로젝트는 페이지네이션을 백엔드 API 서버에서 처리하고, 웹 애플리케이션에서는 해당 PageResponseDTO만 받고 그대로 출력하는 방식을 사용했는데, mini는 전체 DTO를 받아서 자체적으로 처리하는 방식만 사용한 것이다. 사실 이건 내가 할 일이 줄어드는 것이라 상관이 없어서 그렇게 하기로 결정했다.

 

이전에 작성해둔 코드를 한 번씩 읽어보고 로그인 API 서버를 만들어서 배포를 하려고 했다. 클라우드 쪽에서 CI/CD를 구현했다고 해서 테스트해보는데 잘 안 되는 듯 했다. 그런데 생각보다 시간이 많이 남은 것 같다는 느낌이 들지 않아서 급하게 스프링 서버는 내가 기존에 해봤던 엘라스틱빈스톡으로 배포를 진행하기로 했다. 그런데 왜인지는 모르겠지만 AWS 엘라스틱빈스톡 conf 파일과 함께 프로젝트 배포하기 글에서 사용한 방법이 작동하지 않았다. 어쨌든 문제 원인을 분석하고 해결하는 것보다 그냥 매번 엘라스틱빈스톡 EC2 환경에 들어가서 직접 conf 파일을 수정해서 413 Request Entity Too Large 오류를 예방하기로 했다.

 

인공지능 파트가 생각보다 일찍 끝나서 중간에 백엔드 서버 개발을 일시 중단하고, 바로 FastAPI 서버를 만들고 배포하려고 했다. 개발을 구글 코랩 환경에서 진행했는데 생각해보니 이 노트북 형식의 파일들을 어떻게 배포할지에 대한 생각을 해본적이 없다. 어쨌든 파이썬 파일들이니 코드를 모두 옮기기 전에 requirements.txt 파일을 만들어서 EC2 환경에 먼저 설치해보려고 하는데, 역시 파이썬.. 라이브러리 설치 도중에 문제가 진짜 말 그대로 마구마구 발생했다. 그래서 코랩에서 Ngrok을 사용하면 매번 재부팅마다 url 주소가 바뀌긴 하지만 일단 배포는 된다고 해서 진행해봤다. 매번 엘라스틱빈스톡 환경의 AI_SERVER_URL을 바꾸고, 매번 conf 파일을 수정해야 한다는 귀찮은 과정만 제외하면 괜찮은 방법이었다.

그러다가 클라우드 쪽에서 설치가 안 되는 라이브러리를 제외한 필수 기능만 넣은 FastAPI 서버 배포에 성공해서 해당 서버를 고정적으로 사용하기로 했다.

 

이렇게 FastAPI 배포에 성공했지만, 개인적으로 다가온 문제가 있었다. 어떤 Quiz에 대한 응답이 다음과 같은 형태로 온다.

{
    "id": {id},
    "mno": {mno},
    "title": {title},
    "problem": {problem},
    "answer": {answer},
    "explanation": {explanation}
}

문제가 모두 단답형 또는 주관식 형태로 온다면 해당 DTO를 처리하는 과정에는 기존과 같은 방법을 사용해도 전혀 문제가 없다. 그런데 객관식으로 보기를 받을 때 문제가 생긴다. 이런 경우에는 어떤 Quiz에 대한 응답이 다음과 같은 형태로 온다.

{
    "id": {id},
    "mno": {mno},
    "title": {title},
    "problem": {problem},
    "answer": {answer},
    "choices": {
        "A": {choice_a},
        "B": {choice_b},
        "C": {choice_c},
        "D": {choice_d},
        "E": {choice_e},
    },
    "explanation": {explanation}
}

choices는 key-value 형태로 와서 QuizDTO의 choices 필드를 다음과 같이 Map으로 구현했다.

package com.quizwhale.apiserver.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.Map;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class QuizDTO {

    private Long qno, mno;

    private int id;

    private String title, problem, answer, explanation;

    private Map<String, String> choices;

    private boolean isCorrect;

}

이렇게 되면 이 DTO를 기반으로 엔티티를 JPA로 설계했을 때 자동으로 데이터베이스에 quiz_choices 테이블이 추가로 생성되며, 하나의 Quiz 데이터를 가져오면 보기에 대한 5개(보기의 개수)의 결과가 나온다는 문제가 있다. 물론 하나의 요청에 대한 응답이 여러 개가 나와서 오류가 발생하며 서버가 다운된다는 심각한 문제와 함께.. @Transactional 어노테이션을 사용하면 쉽게 해결할 수 있었으나, 데이터베이스에 여러 번 접근하기 때문에 추후에 기능 확장성을 고려했을 때 성능적으로 오버헤드가 생길 수 있기 때문에 나는 쿼리문을 작성해서 한 번에 가져오고 싶었다.

다른 할 일이 많아서 오래 고민해보진 않았지만, 결국 Member, Choices와 동시에 연관관계를 갖는 하나의 Quiz를 받는 쿼리문을 작성하지 못 했고, 시간상 일단 @Transactional 어노테이션을 사용하기로 했다.

모든 일정이 끝나고 좀 여유로운 지금에서야 고민해본 방법인데, QueryDSL을 사용하면 해결할 수 있지 않을까 싶다. 아직도 끝내지 못 한 4주차 과제를 일찍 끝내면 도전해볼까 한다.

 

이외에도 FastAPI 서버에 대한 응답이 영어가 아니라면 Request Timeout 에러가 발생한다던지, 에러 핸들링 처리를 제대로 하지 않아서 무조건 500 에러가 발생한다던지 하는 여러 문제가 있었고, 어찌저찌 해결했던 것 같다.

해커톤 결과

결론부터 얘기하자면, 본선 진출에 실패했다. 물론 25개 팀 중에서 6개의 팀만 올라가는 것이라 어려운 것이 맞지만, 2박 3일동안 팀원들과 너무 고생하면서 만들었기에 아쉬움이 크게 남았던 것은 사실이었다. 특히 우리와 같은 주제였던 다른 팀이 본선에 진출해서 살짝 배아프다는 느낌도 있었다. 이런 감정을 안 가지려고 노력하는데, 나도 어쩔 수 없는 사람인가보다.

그래도 다행인 것은 쓸데없이 날린 시간이 정말 하나도 없어서 "아.. 이렇게 말고 이렇게 할걸.." 이런 생각이 전혀 들지 않아서 후회가 하나도 남지 않았다. 나 뿐만 아니라 다른 모든 팀원들도 이렇게 생각하는 것 같아서 너무 기쁘고 뿌듯하다는 생각이다.

 

이렇게 아쉽다는 감정을 뒤로하고 본선 발표를 모여서 감상하는데.. "와.. 저게 겨우 며칠만에 나온 퀄리티라고?" 라는 생각이 저절로 들었다. 진짜 솔직히 얘기하자면, 작년에 1년동안 팀원들과 진행해서 좋은 결과를 만들어낸 CapEasy 프로젝트보다 고작 며칠동안 만든 다른 팀들의 결과물이 훨씬 좋다고 느껴졌다. 이런 말 하긴 좀 그렇지만.. 벽이 느껴졌다. 그래서 너무 설레고(?) 좋았던 것 같다. "우리가 저렇게 강한 팀들과 같이 경쟁한 것이구나" 하는 안도감, "나도 언젠가 저렇게 며칠만에 멋진 결과를 만들고 싶다" 하는 설렘이 동시에 들기도 했다.


결론

"카카오 대표이사 상" 이라는 워딩이 너무 탐나서 4등을 목표로 진행했지만, 본선 진출에도 실패하고 벽을 느껴버린 2박 3일동안의 해커톤이 끝이 났다. 시간 가는 줄 모르고 코딩을 한지가 얼마 만인가.. 너무 즐겁고 뿌듯한 기간이었다는 생각이 든다. 특히 목요일에는 새벽까지 하다가 이제 집에서 가서 자면 금요일 아침에 일어날 자신이 없어서 집에 가서 씻기만 하고 돌아와서 오피스에서 자기도 했다.

그리고 팀원들도 너무 좋은 사람들 뿐이어서 좋았고, 오프라인 기간에 마주치면 웃으면서 인사할 친구들이 생겨서 너무 기쁘고 설렌다. 모두들 너무 고생 많았고, 이 기간동안 느낀 감정을 끝까지 기억하며 열심히 살아가야겠다는 생각이 들었다.

반응형
Comments