Sign up, Sign in 구현


issue #54

User Entity

서비스에서 필요한 uid, name, profile image만 갖고 있다.


UserRepository


Sign up

kakao에서 제공하는 API를 활용하여 사용자 인증과 정보를 받는다.





Q&A

Q. User Entity 기본 생성자 접근자를 protected로 변경한 이유는?

A. new User()을 막을 수 있어 객체의 일관성을 유지할 수 있다.
private이 아닌 protected로 설정하는 이유는 JPA에서 기본 생성자가 필요한데
protected로 제어하는 것까지 허용되기 때문이다.


Q. JPA 기본 생성자가 필요한 이유는?

A. 지연 로딩을 사용하는 경우
임시로 hibernate가 생성한 proxy 객체를 사용하게 되는데
이러한 proxy 객체는 해당 class를 상속하기 때문에 public 혹은 protected 기본 생성자가 필요하게 된다.


Q. Builder 패턴을 사용한 이유는?

A. 불필요한 Setter 생성을 방지하고 불변 객체로 만들기 위함이다.
@Builder 어노테이션을 사용하여 빌더 패턴을 적용하였고
@Builder 어노테이션을 선언하면 전체 인자를 갖는 생성자를 자동으로 만들기 때문에
@AllArgsConstructor(access=AccessLevel.PRIVATE) 접근자를 private로 만들어
외부에서 접근할 수 없도록 만들었다.


Q. 왜 Optional을 사용했는가?

A. 우선 Optional 이란 존재할 수도 있지만 안 할 수도 있는 객체
(null이 될 수도 있는 객체)를 감싸고 있는 일종의 래퍼 클래스다.

null 관련 문제 1) 런타임에서 NullPointerException 예외를 발생시킬 수 있다. 2) NPE 방어를 위해서 들어간 null 체크 로직 때문에 코드 가독성과 유지보수성이 떨어진다.

Optional로 객체를 감싸서 사용하게 되면서 NPE를 유발할 수 있는 null을 직접 다루지 않아도 된다.
실제 프로젝트에서 작성한 코드는 다음과 같다.

userRepository.findByUid(uid).orElseThrow(() -> new NotFoundException(...));


Q. ResponseEntityConstants는 왜 만들었는가?

A. api 응답에 필요한 Response 클래스를 별도로 만들어 재사용성을 높였다.


Q. Service 레이어에 인터페이스를 사용한 이유는?

A. 1) SocialAuthService 인터페이스
로그인으로 회원가입, 로그인을 진행하는데
지금 구현한 kakao 로그인을 제외하고 naver, google, facebook 등
확장성을 고려해 인터페이스를 사용했다.

또한 제네릭으로 파라미터 타입을 제한하여
회원가입, 로그인 로직에 필요한 추가 필드나 로직이 있는 경우
누구도 수정이 편리하도록 구현했다.

2) LoginService 인터페이스
현재 구현한 로그인 방식은 세션 로그인 방식이다.
KakaoAuthService.javasignIn() 메서드의 코드에서
kakao api를 활용하여 사용자 인증 과정과 세션 로그인이 필요하다.

그런데 위에서 설명한 회원가입, 로그인 방식이 확장되면
세션 로그인 코드는 계속 중복되서 나타날 것이고
만약 세션 로그인이 아닌 jwt나 spring security 등으로 변경되는 경우
많은 코드를 변경해야 한다.

LoginService 인터페이스를 구현해서
반복되는 코드를 줄이고 확장을 대비할 수 있다.