9osari.log
← 목록으로

[리팩토링] UserEntity SRP/DIP 위반과 해결

User 엔티티의 문제점

엔티티는 도메인 모델이자 비즈니스 로직과 상태만 가져야 한다. 하지만 기존 코드는 SRP와 DIP를 위반하고 있었다.

public static User register(UserDto dto, UserValidator validator, PasswordEncoder passwordEncoder) {
    validator.RegisterValidate(dto.getUsername(), dto.getEmail());

    Username username = new Username(dto.getUsername());
    Email email = new Email(dto.getEmail());
    String encodedPassword = passwordEncoder.encode(dto.getPassword()); // 암호화
    Password password = new Password(encodedPassword); // 암호화된 값으로 생성
    Nickname nickname = new Nickname(dto.getNickname());
    Phone phone = new Phone(dto.getPhone());

    return new User(username, email, password, nickname, phone);
}

DIP(의존성 역전 원칙) 위반
도메인 계층의 User가 인프라 계층의 PasswordEncoder(기술 서비스) 에 의존한다. 즉 도메인 모델이 애플리케이션 계층을 참조해 DIP를 위반했다.

SRP 위반
User는 도메인 객체인데 암호화(PasswordEncoder) 책임 까지 가지고있다..
User는 ‘사용자 도메인 규칙 관리’ 책임만 가져야 한다.

// 도메인 계층의 User가 외부 계층에 의존
User → PasswordEncoder (인프라 계층)

정적 팩토리 메서드 사용은 맞는데, 팩토리 메서드를 두는 위치가 문제. “도메인 엔티티 안에 둘지? 애플리케이션 계층으로 올릴지?”

엔티티는 비즈니스 상태와 행위만 가져야 한다

리팩터링

엔티티는 비지니스 로직에 집중 해야한다.

public static User of(Username username, Email email, Password password, Nickname nickname, Phone phone) {
    return new User(username, email, password, nickname, phone);
}

편의를 위해 UserFactory 클래스를 만들었다.

public class UserFactory {
  public static User createFromPrimitives(String username, String email, String encodedPassword, String nickname, String phone) {
      return User.of(
              new Username(username),
              new Email(email),
              new Password(encodedPassword),
              new Nickname(nickname),
              new Phone(phone)
      );
  }
}

애플리케이션 서비스에서 책임 조율

@Override
public void registerUser(UserDto userDto) {
    //암호화
    String encryptedPassword = passwordEncoder.encode(userDto.getPassword());

		//순수 팩토리 사용
    User user = UserFactory.createFromPrimitives(
            userDto.getUsername(),
            userDto.getEmail(),
            encryptedPassword,
            userDto.getNickname(),
            userDto.getPhone()
    );
    
    //저장
    userRepository.save(user);
}
···
← PREV [DDD] 도메인 주도 설계란 무엇인가 NEXT → [리팩토링] 레거시 코드와 SRP