때는 24년 12월 20일 금요일, 나는 드디어 기초 프로젝트 과제 팀을 배정받았다. 그리고 뉴스피드를 만들라는 과제를 부여받고, 사실상 본격적인 팀 프로젝트를 처음 해 보았다.
대학 시절에도 이런저런 프로젝트를 만들기는 했으나 Spring Boot를 사용한 본격적인 프로젝트는 처음이었기에 파트 분배부터 어려움이 있었다.
우리는 SNS의 백엔드 구조와 유사한 형태로 프로젝트를 시작하게 되었다. 필수 과제는 대표적으로 사용자 파트, 게시글 파트, 친구 파트, 로그인 파트로 나뉘어져 있었다.
사다리타기로 두 명씩 짝지어서 각자 크게 사용자와 로그인, 게시글과 친구 파트를 가지고 페어코딩을 시작했다. 온라인 환경이었기 때문에 두 사람끼리 모여서 하루 온전히 코딩에 집중을 해야했다.
사실 코드를 짜는 것 자체는 큰 문제가 없었다. 그러나 코드를 짜는 스타일이 각자 너무 달랐다. 나는 일단 코드를 짜고 그 후에 수정을 하는 것을 좋아했으나 나와 짝이 된 팀원 분은 생각하고 코드를 짜면서 신경을 많이 쓰시고 신중한 편이었기 때문이다. 처음에는 의견 충돌으로 인해 여러가지 이야기를 하다가 결국 튜터님에게 이런 상황에 대한 질문을 하게 되었다. 처음에는 우리가 서로 정확히 모르는 분야에 대해 서로 주장하는 바가 달랐기 때문에 생긴 문제라고 생각했는데 대부분의 문제는 정답이 없는 문제였다.
같이 코딩하는 내내 크고 작은 의견 충돌이 있었는데 오늘의 예시를 들어보면 다음과 같다.
ResponseDto의 역할이 유사한데 굳이 회원가입과 사용자 관리를 분리해야 하나요?
- 나
- 나중에 유지보수를 생각해 보면 서로 다르게 관리하는 게 맞다고 생각합니다.
- 팀원분
- 현재 상황의 코드에서는 거의 동일한 형태를 가지고 있기 때문에 한 개로 관리해도 된다고 생각합니다.
우리는 이 이야기를 갖고 제 3자에게 물어보았고, 유지보수 측면에는 내 말이 맞긴 하지만, 현재 구현해야하는 프로젝트에서는 굳이 그렇게 나누지 않아도 될 거 같다는 의견을 받았다. 이러한 의견충돌 등을 해결하면서 튜터님에게도 건강한 토론을 하는 것이 좋다는 의견을 받았다. 그래서 결론적으로 해당 ResponseDto는 역할에 따른 이름을 부여하는 것을로 마무리를 짓게 되었다.
솔직히 의견 충돌이 이렇게 많이 날 줄 몰랐기 때문에 처음에는 당황했지만 며칠 해보니 이 경험이 각자에게 재산이 될 수 있는 좋은 경험이 될 수 있을 것이라고 생각 된다.
나와 페어 팀원 분은 함께 사용자와 로그인 필터를 관리하는 부분을 만들었는데 금요일에 사용자 생성, 수정, 조회, 삭제 등을 예외처리 빼고 틀만 작성하고 필터도 대충 예전에 쓰던 필터를 씌워서 틀만 작성한 후에 올렸었다.
그런데 네 명이 쓰는 버전 이슈인지, 쿼리Dsl의 문제인지 자꾸만 트러블이 발생했다. 왜냐하면 우리 파트는 하나하나 코드를 작성해서 생성 수정 삭제 조회를 만들었는데 다른 팀원 분들은 쿼리Dsl을 이용해서 코드를 작성하셨기 때문이다. 그 부분에서 무슨 일인지 pull만 하면 실행이 제대로 안되는 것이다.
그리고 찾아보니 버전 문제가 맞았다.
Setting에서 이 부분을 고쳐주니 버전 문제는 해결이 되었다. 그리고 다른 팀원 분의 도움을 받아 프로젝트에 .gitignore을 사용하여 지속적으로 생기는 문제를 해결할 수 있었다.
어찌보면 기본적인 문제인데 4명이 데이터베이스에서 다 다른 아이디와 비밀번호를 사용하고 있었고 그러다보니 파일을 pull 할 때마다 application.properties를 변경해야 하는 문제가 발생했다.
처음에는 그 문제인 줄도 모르고 어디서 에러가 났는지 오래 찾았는데 결국 긴 에러코드를 가지고 gpt선생님에게 물어본 결과 아이디와 비밀번호가 다르다는 걸 알게되었다.
나는 바보가 분명하다
그런데 월요일 아침, 주말 사이에 컨플릭트가 났다.
알고보니 팀원 분 중 한 분이 실수로 풀리퀘스트가 남아있는 상태에서 본인의 코드를 머지해버린 것이었다. 이 부분은 나도 예전에 겪었던 적 있었던 문제라서 공감이 갔다. 그 때는 컨플릭트 난 코드를 깃허브 내부에서 고쳤었는데 이번에는 인텔리제이를 이용하여 로컬에서 컨플릭트를 수정한 뒤 풀리퀘스트를 날릴 수 있도록 열심히 배웠다.
나는 본래 코드를 짜면서 분리라는 걸 제대로 해 본 적이 없다. 자랑은 아니지만 Restfull한 코드 작성 경험이 없는 것이다. 그런데 이번에 공부를 하며 프로젝트를 작성해보니 그 부분을 튜터님에게 피드백 받게 되었다.
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findUserByEmail(String email);
// TODO: 서비스에서 에러 처리
default User findUserByEmailOrElseThrow(String email){
return findUserByEmail(email).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Does not exist email" + email));
}
default User findByIdOrElseThrow(Long id) {
return findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Does not exist id = " + id));
}
boolean existsUserByEmail(String email);
이런 식으로 레포지토리에서 예외처리를 했던 부분이 있었다. 그런데 그 부분은 exceptionHandler를 사용해서 고쳐보라는 피드백을 받은 것이다. 그래서 현재의 레포지토리는 리팩토링하여 아래의 형태가 되었다.
public interface UserRepository extends JpaRepository<User, Long> {
/*
주석처리된 부분은 유저 이름으로 호출할 필요가 있으시면 쓰세욥
*/
//Optional<User> findUserByName(String username);
Optional<User> findUserByEmail(String email);
boolean existsUserByEmail(String email);
}
솔직히 이게 훨씬 역할에 잘 들어맞는다고 생각한다. 그리고 현재 예외처리에 대한 핸들러에 대해서는 다른 팀원 분이 담당하여 해 주고 계시기 때문에 아직 여기에 기록하기는 어렵다.
나의 역할은 현재 필수구현 과제에서 기본적인 사용자 생성, 조회, 수정, 삭제, 로그인 필터에 대한 틀이라고 할 수 있는 소스코드를 구현하였고, 비밀번호 암호화에 대한 부분 등을 가져와서 넣어놓은 것 정도라고 할 수 있다.
사실 내가 구현한 코드는 완전 정말.. 대충 구현해놓은 껍데기 같은 거라서 그 껍데기를 토대로 다른 팀원분들이 열심히 콘크리트를 발라주셔서 나는 큰 도움을 받고 있는 것 같다. 그리고 각자 코드를 작성할 때는 화면을 공유해서 보면서 어떠한 식으로 코드를 작성하고 수정하면 좋을지 논의를 하면서 작성하고 있다.
로그인 필터 부분의 예외처리 부분이나 사용자 수정, 삭제를 할 때는 다른 팀원 분께서 많이 해 주셨다.
그리하여, 오늘 필수 구현과제를 어찌어찌 우리 파트를 끝내고, 다른 파트들은 다른 두 분이 구현해주신 것들을 보면서 공부를 열심히 해볼 예정이다.