TIL 리팩토링

sally·2023년 2월 21일
0

프로젝트

목록 보기
5/5

TIL

찝찝하니 힘든 하루였던거 같다.

어제 댓글 달기 구현이 포스트하고 유사하여, 좀 더 흥미로운 걸 찾아다녔다.

User

  • JWT 토큰 필터 구현하면서 인증 객체
  • 캐시에 저장 되는 객체
  • 컨트롤러에서 인증객체로서 캐스팅 되어 id 등 전달

Redis에 저장하기 위해 @JsonIgnore 를 추가 된 부분 ?

  • 스프링 시큐리티의 인증 타입 위해 AuthenticatedPrincipal 구현부
  • @Getter 에 맞춰 저장되다 보니 중복된 내용이 캐싱에 저장되는 걸 막기 위해서
  • getter 롬복은 쓰고 .. 머 그런 (당시 좀 빠듯하게 열심히 했던 거지만, 엉망인거 같네요)

SRP 위반 ? 보다는 사실 분리 해볼까? ㅎㅎ


실수 1. 쌓인 생각들이 많았다.

내가 레거시...

  • Post 와 Comment 구현하면서 인증객체가 가진 role 뿐이지만, 노출을 최소화 하면서 구현하자 생각으로 Member DTO 이용

  • User는 인증 객체로만 인지 되었고

    • 컨트롤러 계층에서 Authentication 으로만 이용하게 선을 그으면 어떻까?
    • 도메인까지는 연결하지 말자
    • 캐싱도 동시성 이슈 등 생각하면 여러곳에서 조회 요청보다 토큰 필터로서 앞에서만 요청하는게 적당해 보였다.
      • UserService 의 loadUserByUserName() ➜ getThatIfMember() 로 변경
  • 서비스에서 연관관계로 조회해올 때 UserEntity 에서 role 까지 가져오는 로직이 필요 ?

    • 현재는 없다, 생겨도 분리할 거 같다.
    • role 이 시스템에서 권한 등 관련 있다면 노출하지 않는게 좋지 않을까 생각
    • 필요없는 데이터는 줄이는 방향으로 해보자
      • 이 방향은 JPA에서 view 개념의 PostView, CommentView 를 이용하면서
      • 별도의 Member 타입으로의 반환을 생각하게 했다.

실수2. 불분명한 ?

내가 딱 하나 기억하는, 마틴파울러님이 리팩토링은 ... 확실할 때 ~

두 부분을 각각 분리해 봤다.

AuthenticatedPrincipal → SecurityUser
Redis → User

컨트롤러에서 SprignSecurity 의 Authentication 타입 2가지 이용

  • AuthenticatedPrincipal 의 getName()
  • User 로 타입 캐스팅 통한 getId() 등

(이때쯤부터 시야가 좁아진 거 같다.)
AuthenticatedPrincipal 을 구현한 SecurityUser 자체로 getName() 은 변동사항 없었지만,
User 로의 타입 캐스팅이 문제였다.

SecurityUser securityUser = (SecurityUser)authentication.getPrincipal();
securityUser.toUser().getId();

.toUser().getId(); 괜히 쓰고 싶지 않은 코드 였다…..

우선 SecurityUser.class 타입으로 형변환하고 싶다는 의미를 담아 메서드 분리하니

Class 타입으로 전달 됐다. (IDE ❤️)
clazz.cast(obj) 💕 통해서 형변환 했지만, User로의 반환이 계속 고민

IDE로 두근 대던 심장은 금세 두통이 됐다 …
캐스팅을 여러 컨트롤러에서 해줘야 하기 때문에, 클래스 분리가 좋을 거 같은데 …
정의를 어떻게 내려야 할지 …. ( 이럴 때 클래스명 짓기는 더 어렵다. )

private User toUserFrom(
		Authentication authentication,
		Class<SecurityUser> clazz, 
        Class<User> userClass) {
	SecurityUser securityUser = clazz.cast(authentication);
	return securityUser.toUser();
}
  • 내가 다른 컨트롤러 만들면 어떻게 쓸까?
    • 2번 째 스텝이 고민 중이었고, 다른 컨트롤러가 생길 것 같다.
    • 클래스로 정적 메서드 통해 toUserForm() 그대로 사용이 좋아 보였는데, 좀만 더 세분화 해볼까 싶었다. 🔙

공통화는 좀더 나중에 ?

제네릭을 이용해서 util 성으로 분리

컨트롤러에서 호출시

User user = TypeCastingUtil.fromAndSecTo(authentication, SecurityUser.class, User.class);

TypeCastingUtils

public static <E, T> E fromAndSecTo(Object obj, Class<T> clazz, Class<E> secClass) {
	return secClass.cast(fromAndTo(obj, clazz));
}

public static <T> T fromAndTo(Object obj, Class<T> clazz) {
	return clazz.cast(obj);  // need to object,  TODO ClassCastException
}

( 나는 혼자 왜 이러고 있을까... )
컴파일 오류 집착하다가 실제 동작이 어떻게 되는지는 놓치고, 그렇게 실행하면서 에러가 발생했다.

  • 앞서 메서드에서, SecurityUser 내부의 User 반환 위해 toUser() 메서드 사용한 걸, 그냥 clazz.cast(obj) 를 이용했던 탓이다.
    • 그냥 SecurityUser 에서 만족 하거나 …
      • …. 처음과 똑같다. …
    • 타입을 넘겨주거나 ← 이거라도 해봐야 겠다. 🔙

User 를 Redis 저장 위해 쓰던 @Getter 를 AuthenticationUser 로

  • User는 캐시용, SecurityUser는 시큐리티용

컨트롤러에서 TypeCastingUtils 호출부분 toAuthenticationUser 메서드로 분리

private AuthenticationUser toAuthenticationUser(Authentication authentication) {
	return TypeCastingUtils.fromAndSecTo(
				authentication.getPrincipal(),
				SecurityUser.class,
				AuthenticationUser.class);
}

AuthenticationUser으로 추상화 하면서, 메서드명이 맘에 걸리는 TypeCastingUtils fromAndSecTo 사용하지 말까 생각이 들었지만,

private AuthenticationUser toAuthenticationUser(Authentication authentication) {
		SecurityUser securityUser = TypeCastingUtils.fromAndTo(authentication.getPrincipal(), SecurityUser.class);
		return (AuthenticationUser)securityUser;
}
  • 이왕... 제네릭의 컴파일 안정성을 생각해보면, 제네릭 이용한 형변환 방식을 적용하는게 좋지 않을까 생각했습니다.

SecurityUser 가 좀 찝찝

코드로 보면 그냥 더 찝찝

  • 간편하게 @Getter 쓰던 부분이 늘어난게 눈으로 보이니 ... (전이 적절했었을 수도-)
public class SecurityUser implements AuthenticatedPrincipal, AuthenticationUser {

P.S. SecurityUserSec ...

SecurityUser 가 여러 메서드 정의를 하게 된게 아닌가, 줄여볼까 싶어서 상속받아 구현 해봤습니다.

코드는 훨씬 간편해집니다.

public class SecurityUserSec extends User implements AuthenticatedPrincipal {
	@Override
	public String getName() {
		return super.getNickname();
	}
}

캐스팅 전달 파라미터도 기존보다 간편 (이상한 메서드명 안써도 된다)

AuthenticationUser user = TypeCastingUtils.fromAndTo(authentication.getPrincipal(), AuthenticationUser.class);

그렇지만 ...
User 를 상속 받는건, 어쨌든 캐싱으로 저장할 객체의 모든 역할까지 상속 받는 거고,
AuthenticationUser을 구현하는게 더 좋지 않을까 생각했습니다.

TIL … 찝찝하니.. 쉬어야 겠다.


GitHub

profile
sally의 법칙을 따르는 bug Duck

0개의 댓글