우아한테크코스 Level3 스프린트 2 회고

공병주(Chris)·2022년 7월 26일
1

스프린트 1이 끝나고 스프린트 2가 찾아왔다.

저번 스프린트에는 팀 규칙과 팀 문화, 협업에 익숙해지느라 API 구현을 적게 가져갔기 때문에, 이번에는 조금 달리기러 했다!

구현할 기능

스프린트 1에서는 아래와 같은 기능들을 구현했다.

  • 게시글 작성
  • 게시글 목록 조회
  • 게시글 상세 조회

스프린트 2에서는 스프린트 1에 구현해놓은 기능에 더해, 아래와 같은 기능들을 구현하기로 했다.

  • 회원가입
  • 로그인
  • 게시글 수정
  • 게시글 삭제
  • 게시글 좋아요
  • 댓글 작성
  • 댓글 조회
  • 게시글 해시태그

디자인

이번 UI도 팀원 7명 모두 함께 디자인했다.

로그인/회원 가입

로그인, 회원 가입은 모두가 알아야 하는 기능이라고 생각해서, 백엔드 5명이서 몹 프로그래밍을 했다.

어떻게 익명성을 보장할 것인가?

우리는 익명 커뮤니티이기 때문에, 어떻게 익명을 보장할지 고민을 많이 했다. 오랜 회의 끝에 도출한 결론은 우아한 테크코스 크루임을 인증하는데 사용하는 이메일을 회원 정보 table에 보관하지 않기로 했다.

우아한 테크코스 크루임을 인증할 때 쓰이는 이메일을 단방향으로 해싱해서 ticket이라는 테이블에 SERIAL_NUMBE라는 컬럼으로 저장했다. USED는 중복 가입을 방지하기 위한 컬럼이다.

여기서 사용한 SERIAL_NUMBER 값. 즉, 이메일은 아래와 같이 회원 정보 테이블에 저장되지 않는다.

NICKNAME, PASSWORD, USERNAME은 모두 사용자가 자유롭게 설정할 수 있는 값이다. 우리가 이 값을 보았을 때, 어떤 크루인지 식별할 수 없다. 데모데이 때, NICKNAME을 통해서 누군지 추측할 수 있지 않냐는 피드백이 있었지만, 저기에 적힌 NICKNAME은 실제 우아한테크코스에서 사용하는 닉네임이 아니라고 정의하고 개발하였는데, 크루들에게 혼란을 줄 수 있고 크루들이 저기에 자신의 진짜 닉네임을 적으면 익명성이 보장되지 않기 때문에 어떠한 장치를 마련해야 할 것 같다.

Email 인증 (SMTP)

우아한 테크코스 크루임을 인증하기 위해서, 이메일 인증 방식을 사용하기로 했다.

이메일 인증은 MailSender를 사용하였다.

팀 기술블로그 : https://sokdak-sokdak.tistory.com/3 (토르가 정리한 Spring에서 이메일 보내기)

개인 블로그 : https://velog.io/@byeongju/스프링에서-메일-보내기 (스프링에서 메일 보내는 방법을 간단히 정리)

Transaction이 우리가 원하는대로 동작하지 않았던 문제

SMTP를 통해 이메일을 전송하는 것이 오래 걸리기 때문에, Transaction에 이메일을 보내는 로직이 포함되면 Transaction을 너무 오래 잡게 될 것이라고 판단되어, 아래와 같이 진입메서드에 트랜잭션을 걸지 않고, 내부 메서드에만 트랜잭션을 걸었다.

public void sendCodeToValidUser(EmailRequest emailRequest) {
    String serialNumber = encryptor.encrypt(emailRequest.getEmail());
    authService.validateSignUpMember(serialNumber);

    String authCode = saveAuthCode(serialNumber);
    sendEmail(emailRequest, authCode);
}

@Transactional
protected String saveAuthCode(String serialNumber) {
    authCodeRepository.deleteAllBySerialNumber(serialNumber); //1
    String authCode = authCodeGenerator.generate();
    authCodeRepository.save(new AuthCode(authCode, serialNumber)); //2
    return authCode;
}

private void sendEmail(EmailRequest emailRequest, String authCode) {
    emailSender.send(emailRequest.getEmail(), authCode);
}

위와 같이 코드를 @Transactional을 거니까, sendCodeToValidUser 메서드가 호출 되었을 때, 1이라고 표시한 Line은 실행되지 않아서, DB에서 데이터를 삭제가 되지 않았고, 2라고 표시한 Line은 실행되어서 DB에 데이터가 저장은 되었다.

토르가 트랜잭션 문제인 것 같다고 운을 띄웠고, 옛날에 지인이 DataJpaRepository의 save 메서드에는 @Transactional이 걸려있다고 말했던 것이 떠올라서, 아래의 링크와 같이 원인을 찾을 수 있었다.

개인 블로그 : https://velog.io/@byeongju/Transactional이-왜-안되지

일단, sendCodeToValidUser 메서드(진입메서드)에 Transactional을 걸어서 해결했다. 하지만, 본질적으로 우리는 이메일을 보내는 로직을 Transactional에서 분리시키고 싶었는데 이는 해결하지 못했다.

일단, 이메일을 전송하는 Service 객체를 분리해서, Controller에서 두개의 메서드를 호출하자는 의견이 나왔는데, 스프린트 3나 추후의 유지보수 및 성능 개선에서 더 토의해보고 해결할 예정이다.

Session을 브라우저에 저장할 수 없다고..?

Response에 Session을 전달해도 해당 Session을 브라우저에 저장할 수 없는 문제가 데모 이틀 전 밤에 발생하였다. 우리가 추측하는 이유는 크롬 브라우저, HTTP 환경(HTTPS x)에서 Session을 저장 할 수 없는 것이었다.

우리는 해당 이슈에 아래와 같이 대처하기로 했다.

  • 데모 발표 준비를 해야하는 크리스(나)는 Session을 Token으로 빠르게 전환하고 데모 발표 준비를 한다.

  • 크리스를 제외한 백엔드 4명(헌치, 토르, 이스트, 조시)은 Https를 구현한다.

    이를 결정한 것은 데모 1일 전 10시 30분이었고, 팀원들은 Https를 처음 적용해보았기 때문에 Https를 하루 만에 구현하지 못하였다(하지만 팀원들은 정말 많은 노력들을 했다!!!). 당장 다음 날 데모를 해야하기 때문에 Token을 구현한 브랜치를 머지시키기로 했다.

해당 이슈에 대해 팀원들과 내가 느낀점

  • 프론트와의 연결을 데모 2일 전에 처음해봐서 이슈 확인을 늦게 했기 때문에, 이슈를 처리할 수 있는 시간이 부족했다. 주기적으로 프론트와의 연결을 해보자.
  • 하지만 이슈를 처리하는 방식은 좋았다. 모두가 Https 구현을 하지 않고, 혹시 Https가 구현되지 않을 상황을 대비해서 Token을 사용한 안전 장치를 마련한 판단이 좋았다. 물론 궁극적으로 Https를 구현해야하지만, 빠르게 대처해야하는 상황에서는 위와 같이 분업을 하는 것도 좋겠다.

백엔드에서 API를 수정했지만, 프론트에서 인지하지 못함

API 변경 공유는 정말 정말 필수적인 것이다. 백엔드 5명이 몹프로그래밍을 하다가 API 변경이 불가피한 상황이 있었다. 따라서, 우리는 일단 API를 변경해두고 나중에 프론트엔드에 전달하기로 했다.

하지만, 5명 중 누구도 변경 사실을 프론트엔드에게 전달하지 못했고, 테스트 중에 장애가 발생하였다.

반성하였고.. 아래와 같은 솔루션을 정했다.

  • Notion의 API 페이지가 변경되었을 때, 팀 슬랙에 알림이 가는 장치 마련
  • API를 임의로 수정하지말고, 반드시 반대 진영의 컨펌을 받고 변경

진짜.. 협업에서 다시는 발생하지 않아야 하는 문제이다.

데모 준비는 빨리

이번에 무비와 둘이서 데모를 했다. 스프린트 1 때, 조시와 토르가 데모 준비를 하루 전에 하고 성공적으로 데모를 했다. 따라서, 우리도 데모 하루 전에 16시부터 데모 준비를 시작했다. 하지만, 스프린트 1에서는 api가 3개여서 기능이 많이 없어서 데모 준비가 빨랐던 것이었다. 무비와 데모 전날 새벽 2시 30분 까지 데모 준비를 했다.

따라서 팀원들과 아래와 같은 규칙을 정했다.

  • 데모 준비는 적어도 데모 2일 전 저녁부터 하자.

데모 데이

그렇게 데모 데이가 찾아왔다.

긴장도 많이 했지만, 팀원들이 엄청 응원해줬기 때문에 준비한 것보다 더 잘해낼 수 있었던 것 같다.

사실 긴장을 조금 해서, 엄청 만족스러운 발표는 아니었지만 나름 뿌듯하다!

더 잘할 수 있었을텐데 라는 아쉬움은 역시 남았고, 다음 번에 조금 더 개선해서 데모데이에 발표하는 기회를 갖고 싶다는 생각을 했다.

팀 회고

(회고는 매주 하는데, 몰아서 정리)

데모가 끝나고 팀 회고를 진행했다.

우리가 잘한 점

  • 목표한 기능들을 다 구현했다.
  • 모든 팀원이 헌신적이고, 적극적으로 스프린트에 참여하였다.
  • 세션에서 문제가 발생했을 때, Https 구현하면서 만약을 대비해서 Token을 구현해둔 판단이 좋았다.
  • 지난 스프린트 때, 프론트가 거의 매일 저녁까지 개발하였는데 이번에는 프론트의 체력/스트레스 관리가 비교적 잘되었다.

우리가 잘 해내지 못한 점과 액션플랜

  • 데모데이 준비가 촉박했다.
    • 데모데이 준비는 적어도 데모 하루 전 아침부터 준비하자.
  • 깃허브 충돌 : dev 브랜치에 push를 한 것과 dev/be에서 분기한 브랜치의 코드가 충돌했다. 발생하지 않았을 수 있는 충돌이다.
    • dev 브랜치에 push를 못하도록 막고 dev/be, dev/fe에서 dev로 머지시키자.
  • 발생한 일들과 논의에 대한 문서화가 부족했다
    • 문서화 및 기록을 습관화하자. 또한, 토론 및 논의가 생긴다면 github Discussion을 활용하자.
  • session 구현은 1주차에 완료되었지만, session 문제를 2주차인 데모 2일 전에 발견했다.
    • 일주일에 두번 프론트, 백엔드 연결을 시도하자.
  • 칸반보드가 너무 복잡하다
    • 칸반을 Fe-Dev, Be-Dev, 공통 논의 사항으로 나누자.
  • dev 환경에 더미 데이터를 구축하지 못했다.
    • 더미 데이터를 구축해두자
  • 백엔드는 몹 프로그래밍을 1주일동안 해서 개발 속도가 더뎠다.
    • 4주 중, 3주를 몹 프로그래밍으로 1주를 페어로 구현해보았으니까, 1인 단위로 개발 후 코드 리뷰하는 방식을 적용해보자.
  • 기능 개발에 쫓겨 코드 품질과 테스트 커버리지가 좋지 않다.
    • 1인 단위 개발로 전환하면 해결될 것이다. 리팩토링을 진행하고 테스트 커버리지를 높이자.
  • 진행 상황 공유가 잘 되지 않는다.
    • 데일리 미팅 때, 진행 상황과 오늘 할 일을 공유하자. 또한, 체크아웃 데일리를 15분 정도 하면서 진행 상황을 다시 공유하자.
  • PR 단위가 너무 크다.
    • 이슈와 PR을 기능 단위로 쪼개자.

0개의 댓글