스프린트 1이 끝나고 스프린트 2가 찾아왔다.
저번 스프린트에는 팀 규칙과 팀 문화, 협업에 익숙해지느라 API 구현을 적게 가져갔기 때문에, 이번에는 조금 달리기러 했다!
스프린트 1에서는 아래와 같은 기능들을 구현했다.
스프린트 2에서는 스프린트 1에 구현해놓은 기능에 더해, 아래와 같은 기능들을 구현하기로 했다.
이번 UI도 팀원 7명 모두 함께 디자인했다.
로그인, 회원 가입은 모두가 알아야 하는 기능이라고 생각해서, 백엔드 5명이서 몹 프로그래밍을 했다.
우리는 익명 커뮤니티이기 때문에, 어떻게 익명을 보장할지 고민을 많이 했다. 오랜 회의 끝에 도출한 결론은 우아한 테크코스 크루임을 인증하는데 사용하는 이메일을 회원 정보 table에 보관하지 않기로 했다.
우아한 테크코스 크루임을 인증할 때 쓰이는 이메일을 단방향으로 해싱해서 ticket이라는 테이블에 SERIAL_NUMBE라는 컬럼으로 저장했다. USED는 중복 가입을 방지하기 위한 컬럼이다.
여기서 사용한 SERIAL_NUMBER 값. 즉, 이메일은 아래와 같이 회원 정보 테이블에 저장되지 않는다.
NICKNAME, PASSWORD, USERNAME은 모두 사용자가 자유롭게 설정할 수 있는 값이다. 우리가 이 값을 보았을 때, 어떤 크루인지 식별할 수 없다. 데모데이 때, NICKNAME을 통해서 누군지 추측할 수 있지 않냐는 피드백이 있었지만, 저기에 적힌 NICKNAME은 실제 우아한테크코스에서 사용하는 닉네임이 아니라고 정의하고 개발하였는데, 크루들에게 혼란을 줄 수 있고 크루들이 저기에 자신의 진짜 닉네임을 적으면 익명성이 보장되지 않기 때문에 어떠한 장치를 마련해야 할 것 같다.
우아한 테크코스 크루임을 인증하기 위해서, 이메일 인증 방식을 사용하기로 했다.
이메일 인증은 MailSender를 사용하였다.
팀 기술블로그 : https://sokdak-sokdak.tistory.com/3 (토르가 정리한 Spring에서 이메일 보내기)
개인 블로그 : https://velog.io/@byeongju/스프링에서-메일-보내기 (스프링에서 메일 보내는 방법을 간단히 정리)
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나 추후의 유지보수 및 성능 개선에서 더 토의해보고 해결할 예정이다.
Response에 Session을 전달해도 해당 Session을 브라우저에 저장할 수 없는 문제가 데모 이틀 전 밤에 발생하였다. 우리가 추측하는 이유는 크롬 브라우저, HTTP 환경(HTTPS x)에서 Session을 저장 할 수 없는 것이었다.
우리는 해당 이슈에 아래와 같이 대처하기로 했다.
데모 발표 준비를 해야하는 크리스(나)는 Session을 Token으로 빠르게 전환하고 데모 발표 준비를 한다.
크리스를 제외한 백엔드 4명(헌치, 토르, 이스트, 조시)은 Https를 구현한다.
이를 결정한 것은 데모 1일 전 10시 30분이었고, 팀원들은 Https를 처음 적용해보았기 때문에 Https를 하루 만에 구현하지 못하였다(하지만 팀원들은 정말 많은 노력들을 했다!!!). 당장 다음 날 데모를 해야하기 때문에 Token을 구현한 브랜치를 머지시키기로 했다.
API 변경 공유는 정말 정말 필수적인 것이다. 백엔드 5명이 몹프로그래밍을 하다가 API 변경이 불가피한 상황이 있었다. 따라서, 우리는 일단 API를 변경해두고 나중에 프론트엔드에 전달하기로 했다.
하지만, 5명 중 누구도 변경 사실을 프론트엔드에게 전달하지 못했고, 테스트 중에 장애가 발생하였다.
반성하였고.. 아래와 같은 솔루션을 정했다.
진짜.. 협업에서 다시는 발생하지 않아야 하는 문제이다.
이번에 무비와 둘이서 데모를 했다. 스프린트 1 때, 조시와 토르가 데모 준비를 하루 전에 하고 성공적으로 데모를 했다. 따라서, 우리도 데모 하루 전에 16시부터 데모 준비를 시작했다. 하지만, 스프린트 1에서는 api가 3개여서 기능이 많이 없어서 데모 준비가 빨랐던 것이었다. 무비와 데모 전날 새벽 2시 30분 까지 데모 준비를 했다.
따라서 팀원들과 아래와 같은 규칙을 정했다.
그렇게 데모 데이가 찾아왔다.
긴장도 많이 했지만, 팀원들이 엄청 응원해줬기 때문에 준비한 것보다 더 잘해낼 수 있었던 것 같다.
사실 긴장을 조금 해서, 엄청 만족스러운 발표는 아니었지만 나름 뿌듯하다!
더 잘할 수 있었을텐데
라는 아쉬움은 역시 남았고, 다음 번에 조금 더 개선해서 데모데이에 발표하는 기회를 갖고 싶다
는 생각을 했다.
(회고는 매주 하는데, 몰아서 정리)
데모가 끝나고 팀 회고를 진행했다.