[회고] 2024 SSAFY 공통 프로젝트 - "Speechless" 회고

insukL·2024년 2월 18일
0

회고

목록 보기
1/3
post-thumbnail

서론

2024년 1월부터 2월까지 약 6주간 SSAFY 2학기 공통 프로젝트를 진행했다. 블로깅 자체를 프로젝트를 시작하면서 시작했기 때문에, 몇 번의 프로젝트를 했지만 회고를 처음 남겨보면 좋겠다는 생각이 들었다.

프로젝트 주소

SSAFY 첫 프로젝트

주제

어느 팀이든 팀장과 발표자를 선정하는 과정이 제일 힘들다고 생각한다. 실제로 간단히 업무 분장을 하는 과정에서 발표자를 선정하는 과정이 제일 오래 걸렸다. 주제 선정하면서 이 부분이 묘하게 웃겨 생각났고, 이 불편함 아닌 불편함에서 기안하며 우리 팀은 발표, 면접을 연습할 수 있는 플랫폼이라는 주제를 선정했다.

진짜로 아래의 문구를 기획 배경으로 내걸며 프로젝트를 시작했다.

팀 프로젝트를 진행하면서 다른 역할은 분담이 쉽게 이뤄졌으나 다들 발표는 꺼려하는 문제가 있었습니다. 그래서 문득 저희 같은 사람들을 위한 프로젝트를 만들어 발표에 자신감을 얻을 수 있으면 좋겠다고 생각해 프로젝트를 시작했습니다.

프로젝트 진행

프로젝트를 진행하면서 자기소개서, 면접 연습 정보, GPT를 활용한 질문 및 피드백 생성과 관련한 API를 담당했다.

JPA 사용하기

프로젝트에 들어가기 앞서 제일 큰 문제는 JPA를 제대로 이해한 인원이 없다는 점이었다. 나는 이전 프로젝트를 진행하면서 JPA를 간단하게만 써본 상황이고 다른 BE 인원은 처음 사용하는 프로젝트였다. 이에 JPA 공부를 진행했지만..

어느 정도 예상했지만 JPA를 알고 쓰기엔 양이 너무 많았고, 전부 알고 시작하기엔 6주 프로젝트의 대부분을 JPA 공부로 사용하게 생겼기에 공부와 개발을 병행했다. 그러면서 당연히 생각 못한 오류도 엄청나게 나왔다.

에러 1. 영속성 전파 문제

제일 먼저 JPA를 다루면서 맞닥뜨린 문제는 영속성 전파로 인한 문제였다. 자기소개서와 자기소개서 문항을 1:N 관계로 유지하고 있었는데 이를 한 번에 Insert하려 했다. 이를 한 번에 Entity 객체로 전환하고 이를 Persist하려 했다. 하지만 Entity 설계를 제대로 하지 않아 영속성이 전파되면서 그대로 자기소개서 문항 엔티티들이 연관 관계 매핑이 되지 않아서 그대로 에러가 발생했다.

영속성에 대해 알고 있어서 각각의 엔티티에 우선 매핑하고 저장함으로 해당 문제를 해결했지만, 문제는 해당 문제가 나한테만 발생하진 않았다는 점이다.

발표에 대해 여러 명이 참가하면서 참가 정보를 저장하고 있었는데, 참가 정보를 저장하면 발표 그룹에 대한 정보가 같이 삭제되는 문제가 있었다. 찾아보니 cascadeType을 ALL로 지정해뒀는데, 삭제하면서 관련된 엔티티가 모두 영속화되면서 그룹 엔티티도 같이 삭제한 듯 싶었다. cascadeType을 PERSIST로 수정해서 해결했는데, 미리 공부해두고 비슷한 문제를 겪으면서 문제를 빨리 파악하지 못했다면 시간을 많이 쓸 수도 있던 문제였다.

에러 2. 연관 관계 문제

한 번은 로그인하고 자기소개서를 작성했는데, 다른 사람의 자기소개서가 모두 보이는 문제가 있었다. JPA를 통해서 SQL은 올바르게 생성했는데, 출력되는 데이터에 문제가 있으니 로직 확인을 그만두고 데이터를 확인했다. 문제는 자기소개서의 회원 FK 부분이 NULL로 설정되어 있었고, 전부 NULL이니 당연히 다른 사람의 자기소개서도 확인할 수 있었다.

데이터에서 어느 부분이 문제인지 확인하고, 이를 바탕으로 매핑이 제대로 이뤄지지 않는다는 결론을 내렸다. 그래서 로직을 다시 확인하면서 연관 관계의 주인을 확인하지 않은 것을 알았다. 로그인한 회원을 확인하고, 회원에 자기소개서를 추가했었다. 하지만 1:N 관계에서 연관 관계의 주인은 N측에 있고, ManyToOne인 자기소개서 엔티티엔 유저에 대한 정보가 매핑되지 않으면서 해당 문제가 발생했다.

그래서 연관 관계에 대해 편의 메소드를 작성했다. 회원 측 엔티티에 자기소개서를 입력하면 자기소개서에도 회원 측 엔티티가 매핑되도록 작성하니, 그제서야 데이터에 회원 FK가 올바르게 입력됐다.

두 문제 모두 JPA에 대한 기본기가 부족해서 생긴 문제였다. 문제가 생긴 원인은 공부한 부분을 잊고 설계를 진행한 점이고, 문제를 해결한 부분도 공부한 부분이 떠올라서 해결했다. 기술을 적용함에 있어 작동 배경 등 기본기를 충실히 익혀야 한다는 걸 배웠다.

openVidu

발표 연습은 여러 사람이 모여서 진행하고, 면접에선 발음 평가를 위해 서버 측에도 음성 데이터가 필요했기 때문에 WebRTC를 사용했다. 하지만 시간이 적고 서버 중간에 미디어 서버 구현을 위해 비교적 쉽게 사용할 수 있는 openVidu를 사용했는데, 여기도 문제가 있었다.

비동기 처리해주세요

서비스 중 입력한 자기소개서에 대해서 GPT API를 통해 질문을 생성하고, 이에 답변을 진행하면 답변을 STT로 변환하여 다시 피드백을 받아오는 기능이 있다. 여기서 문제는 GPT가 요청에 텍스트를 받아 이를 인식하고 반환하는 요청을 로컬에서 테스트하면서 약 15초 가량 걸렸다.

FE에서 Request를 걸어두고 15초보다 더 걸릴지도 모르는데, 오래 연결을 유지하는 것은 timeout을 길게 잡아야 하는 등 우려가 있다는 의견을 나눴다. 이에 메소드 자체를 비동기로 진행하자고 이야기해서 개발을 진행했다. @Async를 통해서 메소드를 비동기로 작동하도록 구성한 것은 좋았으나, 이제 생성한 질문과 피드백을 보내주는 것에 어려움이 있었다.

다행이 이미 면접 내에 카메라 정보를 받아와야 했기 때문에 카메라 영상을 전송하기 위해 소켓 연결이 이뤄져 있었다. 그래서 이미 연결된 openVidu의 signal 기능을 이용해서 결과 메시지를 보내서 해결했다.

에러 3. 비동기 Transaction 문제

메소드 내 로직을 비동기로 작동 시키면서 @Async를 처음 사용해봤는데, 이 과정에서 Transaction에 접근할 수 없다는 문제가 생겼다. 찾아보니 @Async는 별도의 스레드를 생성하여 해당 스레드에서 비동기적으로 로직을 진행하는데, 별도의 스레드로 복사하는 과정에서 Transaction이 닫히는 문제였다.

다행히 복잡하게 로직이 얽혀있는 것이 아니라 GPT 요청 후 메시지 전송의 과정을 Util과 Service로 분리해두었기 때문에 @Transactional을 붙여 새로운 Transaction을 생성하는 것으로 해결했다.

에러 4. JAVA 인증서 오류

 sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

Transaction 문제는 해결했으나 openVidu 서버로 요청을 보내는 과정에서 위 에러가 발생했다. 찾아보니 신뢰할 수 있는 인증서를 찾을 수 없는 문제라고 했다.

인프라 구성을 담당한 팀원과 이야기해봤지만, openVidu 구성 시 인증서를 등록했다고 했다. 실제로 openVidu에 해당하는 포트로 접근하면 Https 접근이 가능한 것을 확인했다.

해당 문제를 해결하면서 밤을 샜는데, 이 뒤에도 몇 번 밤을 샜지만 이 문제에서 2번째로 밤을 샜다. 관련 정보를 한참 찾은 결과 JAVA 내에서 다른 서버로 Https 연결을 요청할 경우 인증서를 등록해야 한다는 문제였다. 결국 openVidu 포트로 접속해 이미 등록된 인증서를 가져와 keytools를 가지고 JAVA에 인증서를 추가하고 문제가 해결됐다.

openVidu와 관련된 두 에러는 전혀 모르는 곳에서 발생한 에러라 시간을 많이 들였는데, 다시금 에러를 가지고 정보를 찾아보는 과정을 경험할 수 있었다.

Gerrit

프로젝트를 진행하면서 Gerrit을 사용했다. PR을 바탕으로 한 리뷰에 익숙했었는데, 커밋 단위로 리뷰를 하다보니 적응이 잘 안됐다. 나중에 알고 보니 우리 반에서 우리 팀만 Gerrit을 사용했다. ㅋㅋ..

서기

위에서 에러 이야기만 가득하지만, 개발 이외에도 기획, 문서화를 모두 진행했기 때문에 개발 이외에도 업무 분장이 필요했다. 나는 회의록 기록 등 문서화와 관련된 부분을 담당했다.

전부 내가 작성한 것은 아니지만, 필요한 문서가 있으면 최대한 공유를 위해 노션으로 페이지를 구성하고 이를 최신화하기 위해 힘썼다.

프로젝트 문서 정리 뿐만 아니라 기술 이해가 덜 된 팀원을 위해 기술에 대해서 알려주기도 했는데, 이 과정에서 팀원이 글 정리가 잘 되어 있다고 블로깅을 한 번 해보는 것은 어떻냐고 했다. 이전부터 공부한 기술을 한 곳에 모아두고 싶었고, 생각만 하고 있었는데 권유 받은 김에 블로깅을 시작했다.

프로젝트 마무리

생각보다 마지막까지 몰려서 내가 담당한 API의 개발이 끝났기 때문에 남아있는 일을 정리하고 담당자 설정 및 진행도 확인을 진행했다. 일종의 PM 역할을 일주일 간 맡은 셈인데, 발표 자료도 만들어야 했기 때문에 생각보다 체력 소모가 컸다. 하루는 하루종일 책상 근처를 돌아다니며 남은 진행도를 확인했는데, 이 이야기를 했더니 내 성격에 다른 사람을 쪼았다며 구경 갔어야 했다고 했다.

그래도 일주일 간 남아있는 작업 중 가능한 것과 불가능한 것을 확인하고 중간 중간 방향을 확인하니 확실히 작업 속도가 빠른 것이 보였다. 결과적으로 개발 마무리 및 문서 작업은 당초 제출일보다 하루 일찍 끝났기 때문에 다른 팀은 밤도 샌다고 했는데, 우리 팀은 밤은 새지 않고 프로젝트를 마무리할 수 있었다.

솔직히 처음부터 PM 역할을 도맡아서, 편하게 말해서 쪼았다면 좀 더 계획한 기능을 더 만들고 더 기능에 충실한 프로젝트를 만들 수 있었을까?

우여곡절 끝에 프로젝트를 완성했다.

결과적으로 프로젝트는 우수 프로젝트가 됐다. 못만들지 않았을까 많이 걱정했는데, 생각보다 결과가 좋게 나와서 다행이라고 생각한다.

후기

프로젝트 회고

초기 설계

프로젝트를 마무리하고 회고를 진행하면서 초기 설계가 부실했다는 말이 제일 많이 나왔다. 위에 작성한 큼직한 에러 이외에도 다른 사람이 발생 시킨 문제도 있고, 자잘한 충돌도 많았다.

자잘한 문제..?

  • JWT Payload 내 유저 이메일 저장
    - PK를 통해 인덱스를 사용하기 위해 PK 저장으로 수정
  • DB 설계 시 자료형 설정
  • 히스토리성 컬럼 정규화
  • 파일 데이터 저장

하지만 이런 문제 이외에도 Validation이나 기능에 접근하기 위한 사용자의 플로우 등 기획 당시 정했어야 하는 부분을 기술을 모른다는 이야기로 많이 유예했다. 결과적으로 나중에 모두가 바쁜 상태에서 다시 의견을 모으고 결정을 내려야 하면서 시간이 배로 들었다.

뿐만 아니라 짧은 개발 기간에 비해 업무 분담이 제대로 이뤄지지 않으면서 개발이 병렬적으로 진행되지 못했다. 그러면서 특정 기능 개발을 기다리거나 다음으로 무엇을 해야 할지 몰라 결과적으로 기능 개발 자체는 굉장히 빠듯하게 진행됐다.

어디까지 정해야 하는가

초기 설계 문제를 겪으면서 든 생각은 '맞닥뜨리는 문제에 대해 어디까지 정해야 하는가?'였다. 새로운 기술을 사용하면 당연히 어떤 Request와 Response, DB Schema가 필요한지 아무도 모른다. 자주 나온 이야기로 '우린 디자이너가 아니다', '우린 DA, DBA가 아니다'였는데, 이런 부분을 전부 나중에 알고 나면 정하자고 유예하면 너무 오랜 시간이 걸린다.

내가 프로젝트를 하면서 고민한 결과는 책임만 질 수 있으면 된다는 것이다. 확실하지 않은 부분을 정하려니 책임이 필요하고, 그 책임을 지기 싫어 미적지근하게 정하게 된다. 하지만 이렇게 정한 부분은 더 큰 문제가 되고, 더 복잡한 문제만 떠안게 된다. 간단하게 책임을 지자. 수정이 필요하면 수정하고, 새로 구성해야 하면 새로 만들면 된다.

나는 얼마나 못난가

프로젝트가 끝나고 느낀 다른 점은 우리는 우리가 얼마나 못난지 알아야 한다는 점이다. 서로 서로가 얼마나 못난지 알아야 프로젝트 일정 관리가 훨씬 편해진다. 부끄러워 하기보단 자신이 얼마나 할 수 있는지, 얼마나 못하는지 당당하게 밝혀야 한다.

이번 프로젝트의 경우에 나는 대충 어림잡아 잘하겠지 하고 업무량을 산정했다. 하지만 생각보다 팀원별로 알고 있는 지식이나 기술이 제각각이었고, 이미 산정된 업무량에 비해 우리팀의 인력은 모자람이 보였다. 그 뒤에 다시 공부하면서 진도를 각각 맞추기엔 일정에 어려움이 컸다.

물론 내가 다 잘하면 괜찮겠지만 못났으니까. 얼마나 못났는지 알아야겠다.

나의 후기

6주하면서 밤도 새고, 새로운 기술도 보면서 고생했는데, 결과가 잘 나와서 다행이다. 그렇지만 기간이 너무 짧아서 아쉬운 부분이 있다. 좀 더 개선하면 좋지만, 다음 프로젝트가 다시 시작되기 때문에 어떤 부분을 가져가고 어떤 부분을 버릴지 고민하는 시간이 필요하다고 생각된다.

인기 글 캐싱

프로젝트의 메인 페이지에 인기글을 가져오는 부분이 있어서 매번 요청을 바탕으로 가져오는 부분이 있다. 시간이 부족해 추가적인 시스템 구조를 추가하지 못해서 극단적으로 MySQL만 쓰는 프로젝트가 되었는데, 매번 MySQL에서 가져오는 것을 Redis로 캐싱해주면 좋았을 거라 생각한다.

데이터 모델링에 대한 관점

초기 설계가 부족했고, 데이터나 엔티티에 대한 설계가 부족했다. 그래서 DB가 자주 수정되면서 오류가 종종 발생했는데, 이에 데이터 모델링에 관해서 공부해 보고 싶다는 생각이 들었다. 물론 DA만큼의 데이터 모델링 능력을 갖추기엔 부족하겠지만, 모형화를 바탕으로 탄탄한 애플리케이션을 구성하고 싶다는 맘이 들었다.

다음으로 할 일

데이터베이스 공부

최근에 어플리케이션에서 데이터베이스 쪽으로 많이 관심을 가지고 있는데, 조금씩 공부를 시작해야겠다. 데이터베이스 구조에 대한 공부나 데이터 모델링에 대해 관심이 간다. 아래 책을 가지고 공부할까 생각만 가지고 있는데, 짬짬히 진행하면 좋을 것 같다.

친절한 SQL 튜닝
핵심 데이터 모델링
Real MySQL

빅데이터를 건들게 되면서 NoSQL을 사용하는 것도 고려가 필요할 것 같다. MongoDB 완벽 가이드를 가지고 공부할 생각인데, 조금 걱정이 되긴 한다.

대용량 데이터 공부

다음 프로젝트의 주제를 빅데이터(분산)으로 정했는데, 확정인지 모르겠다. 해당 주제로 된다면 내가 원해서 고른 주제인 만큼 공부를 많이 해야겠다. 대용량를 다루는 프로젝트를 할 일이 별로 없는데, 이번에 기회가 되었으니 관련 기술을 공부해야겠다.

공부할 책은 아래 책을 고려하고 있는데, 과연 저 책들을 빨리 읽을 수 있을지 모르겠다..

하둡 완벽 가이드
실전 카프카 개발부터 운영까지

profile
데이터를 소중히 여기는 개발자가 되고 싶습니다

0개의 댓글