반응형

1. 개요

 스프링이 어떻게 성격이 비슷한 여러 종류의 기술을 추상화하고 사용할 수 있는지에 대한 서비스 추상화 방법을 여러 기능을 추가해보면서 알아본다.


2. 사용자 레벨 관리 기능 추가

 사용자의 활동 내역을 참고해서 레벨을 조정해 주는 요구사항이 추가되었다. 상세 내용은 다음과 같다.

더보기

1. 사용자의 레벨은 BASIC, SILVER, GOLD 세가지이다.

2. 사용자가 처음 가입하면 BASIC 레벨이 되며 이후 활동에 따라 한단계씩 업그레이드 된다.

3. 가입 후 50회 이상 로그인을 하면 BASIC에서 SILVER 레벨이 된다.

4. SILVER 레벨이면서 30번 이상 추천을 받으면 GOLD 레벨이 된다.

5. 사용자의 레벨 변경 작업은 일정한 주기를 가지고 일괄적으로 진행된다. 작업 전에는 조건을 충족하더라도 레벨의 변경이 일어나지 않는다.

 

2.1. 상수는 Enum 클래스로

 Level은 상수로 관리해야 하므로 상수 관리에 적합한 Enum 클래스로 관리한다. 교재에서는 DB에 정수 형태로 저장하기 위해 value 필드를 만들어 BASIC은 1, SILVER는 2, GOLD는 3으로 관리하고 있다.

 

public enum Level{
	GOLD(3),
    SILVER(2),
    BASIC(1);
    
    private final int value;
    
    Level(int value){
    	this.value = value;
    }
    
    public int intValue(){ // DB 저장 시 값을 가져오기 위한 메서드
    	return value;
    }
    
    public static Level valueOf(int value){ // value 값으로 레벨을 조회하는 메서드
        switch (value){
            case 1 : return BASIC;
            case 2 : return SILVER;
            case 3 : return GOLD;
            default: throw new AssertionError("Unknown value : "+value);
        }
    }
}

 

2.2. User 필드 추가

 유저의 레벨 관리를 위해 Level 타입의 멤버필드를 User 클래스에 추가한다. 또한 로그인, 추천 횟수 정보를 담을 login, recommend 도 추가한다.

public class User {

    private String id;
    private String name;
    private String password;
    private Level level;
    private int login;
    private int recommend;

    public User(String id, String name, String password, Level level, int login, int recommend){
        this.id = id;
        this.name = name;
        this.password = password;
        this.level = level;
        this.login = login;
        this.recommend = recommend;
    }
    
    // getter, setter
}

 

2.3. 비지니스 로직은 Service로 관리

 레벨 변경 작업은 레벨을 업그레이드 하기 위한 조건들을 체크하는 비지니스성 작업이다. 이러한 비지니스 로직은 Service 클래스로 관리해야한다. DAO 클래스는 DB 데이터를 가져오고 조작하는 작업을 담당한다. 만약 비지니스 로직 중 DB를 접근해야 하는 부분이 있다면, Service 클래스에서 DAO 클래스를 참조하는 형태가 되어야 한다. 테스트 코드도 구현한다고 가정하면 아래와 같은 형태의 UML로 구성된다.

Service를 추가한 UML

 

 구현을 위해 UserService 클래스를 생성하고 조건을 체크하여 레벨을 업그레이드하는 upgradeLevels() 메서드를 생성하였다.

public class UserService {

    private IUserDao userDao;

    public void setUserDao(IUserDao userDao){ // userDao DI를 위한 메서드
        this.userDao = userDao;
    }

    public void upgradeLevels() {
        
        // 구현해야하는 비지니스 로직
        
    }

}

 

2.4. upgradeLevels() 구현

 레벨 업에 대한 비지니스 로직을 upgradeLevels() 메서드 안에 녹였지만 if, else if 구문 내용에 여러 관심이 섞여버리는 문제점이 있다.

 1) 현재 레벨을 체크하는 user.getLevel() == Level.BASIC, user.getLevel() == Level.SILVER, 그와 함께 레벨 업 조건을 체크하는 user.getLogin() >= 50, user.getRecommend() >= 30.

 2) user의 레벨 값을 변경하는 user.setLevel().

 3) userDao.update(user) 호출 여부를 체크하는 changed.

하나의 조건문 안에 여러 관심들이 섞여있다. 이를 분리하는 것이 좋아보인다.

public void upgradeLevels(){

    List<User> users = userDao.getAll();
     
     for(User user : users){
     
     	Boolean changed = false;
        
     	if(user.getLevel() == Level.BASIC && user.getLogin() >= 50){
	    user.setLevel(Level.SILVER);
            changed = true;
        }else if(user.getLevel() == Level.SILVER && user.getRecommend() >= 30){
 	    user.setLevel(Level.GOLD);
            changed = true;
        }
        
        if(changed){
	    userDao.update(user);
        }
     }
}

 

2.5. upgradeLevels() 리팩토링

 기존 메서드는 자주 변경될 가능성이 있는 구체적인 내용추상적인 로직의 흐름과 함께 섞여있다.

 

 * 추상적인 로직 - userDao.getAll(), userDao.update()

 * 구체적인 내용 - 레벨 체크, 레벨 변경 등과 같은 비지니스 로직

 

구체적인 내용을 메서드화 하여 추상적으로 만들어보자.

...

    public void upgradeLevels() {
        List<User> users = userDao.getAll();

        for(User user : users) {
            if (canUpgradeLevel(user)) { // 업그레이드 가능 여부 체크
                upgradeLevel(user); // 업그레이드 처리
            }
        }
    }

 

이제 추상화한 메서드인 canUpgradeLevel과 upgradeLevel의 비지니스 로직을 구현한다.

    private static final int MIN_LOGIN_COUNT_FOR_SILVER = 50;

    private static final int MIN_RECOMMEND_FOR_GOLD = 30;
    
    private boolean canUpgradeLevel(User user){
        Level currentLevel = user.getLevel();

        switch(currentLevel){
            case BASIC: return (user.getLogin() >= MIN_LOGIN_COUNT_FOR_SILVER);
            case SILVER: return (user.getRecommend() >= MIN_RECOMMEND_FOR_GOLD);
            case GOLD: return false;
            default: throw new IllegalArgumentException("Unknown Level :"+currentLevel);
        }
    }
    
    private void upgradeLevel(User user){
	    if(user.getLevel() == Level.BASIC) user.setLevel(Level.SILVER);
	    else if(user.getLevel() == Level.SILVER) user.setLevel(Level.GOLD);
	    userDao.update(user);
    }

  canUpgradeLevel은 레벨 업 조건을 만족하는지 체크한다. 이전과는 다르게 switch case 문을 사용해 현재 사용자 레벨 체크와 레벨업 조건 체크를 분리하였다. 그리고 알수없는 레벨 값이 들어왔을 때에는 예외처리도 하고 있다.

 upgradeLevel은 레벨 업 작업을 담당하는데 이 부분도 추상적인 로직과 비지니스 로직이 섞여있다. 유저의 레벨을 체크하는 부분, 유저의 레벨을 수정자 메서드로 set하는 부분이다.

 또다른 문제점도 있다. 알수없는 레벨에 대한 예외 처리가 되어 있지 않으며, 레벨이 늘어나면 if문도 점점 늘어날 수 있다는 것이다.

 

2.6. upgradeLevel 리팩토링

1) 레벨 관리는 Level에서. (= 자기의 일은 스스로하자)

 '다음 레벨 조회'에 대한 책임을 가진 클래스가 없기에 레벨 업을 위해 다음 레벨을 조회하는 로직이 if문 내 하드코딩으로 구현되어있다. 이에 대한 책임은 Level에서 갖도록 해야한다. 한단계 높은 레벨을 뽑아내는건 UserService가 하는것보다 Level 스스로 하는게 낫기 때문이다. 이제 다음 단계의 레벨이 무엇인지를 찾기 위해 if 조건식을 만들어서 비지니스 로직에 담을 필요가 없다.

public enum Level {

    GOLD(3, null),
    SILVER(2, GOLD),
    BASIC(1, SILVER);

    private final int value;
    private final Level nextLevel;

    Level(int value, Level nextLevel){
        this.value = value;
        this.nextLevel = nextLevel;
    }
    
    public Level getNextLevel(){
    	return this.nextLevel;
    }
    ...
}

 

 

2) User의 변경 책임은 User에서 (= 자기의 일은 스스로하자)

 User의 내부 정보를 변경하기 위해 UserService에서 user.setLevel()을 호출하고 있지만, 앞서 Level과 마찬가지로 User의 정보가 변경되는 것은 User 스스로 다루는 게 적절하다. UserService가 레벨 업그레이드 시에 user의 어떤 필드를 수정하는 로직을 갖고 있기보다는, User에게 레벨 업그레이드를 요청하는 편이 낫다.

public class User {

    ... 
    public void upgradeLevel(){
        Level nextLevel = this.level.getNextLevel();
        if(nextLevel == null){
            throw new IllegalStateException(this.level +"은 업그레이드가 불가능합니다.");
        }
        this.level = nextLevel;
    }
}

 

3) upgradeLevel() 리팩토링

 위 두가지를 적용한 후 upgradeLevel() 메서드를 리팩토링하니 훨씬 간결하고 추상적인 메서드가 되었다.

// before
    private void upgradeLevel(User user){
	    if(user.getLevel() == Level.BASIC) user.setLevel(Level.SILVER);
	    else if(user.getLevel() == Level.SILVER) user.setLevel(Level.GOLD);
	    userDao.update(user);
    }


// after
    private void upgradeLevel(User user) {
        user.upgradeLevel();
        userDao.update(user);
    }

 

 이제 오브젝트와 메서드가 자기 몫의 책임을 맡아 처리하는 구조로 만들어졌음을 확인할 수 있다. UserService, User, Level이 내부 정보를 다룰 때는 자신이 처리하고, 외부 정보가 필요할 때에는 외부로 작업을 요청하는 구조이다. 

 객체지향적인 코드는 다른 오브젝트의 데이터를 가져와서 작업하는게 아니라 데이터를 갖고있는 오브젝트에게 요청하는 것이고 이는 객체지향 프로그래밍의 가장 기본이 되는 원리이다.


3. 유연한 레벨 업그레이드 정책

 레벨 업그레이드 정책을 유연하게 변경할 수 있도록 구현하는 실습을 진행하였다. 기본은 현행을 유지하되 이벤트 기간에는 레벨업 정책을 다르게 적용할 수 있도록 말이다. 필자는 아래와 같은 요구사항을 자체적으로 수립하였고 실습을 진행하였다.

더보기

이벤트 기간에 대해서는 아래와 같은 정책이 적용되도록 한다.

1. BASIC -> SILVER 레벨업 시 로그인 횟수 50번에서 30번으로 하향한다.

2. SILVER -> GOLD 레벨업 시 추천 횟수 30번에서 20번으로 하향한다.

3. 이벤트 기간에 한해 GOLD에서 PLATINUM으로 레벨업 가능하며 조건은 추천 횟수 100번이다.

 

3.1. UserLevelUpgradePolicy 인터페이스 구현

전략 패턴을 사용하기 위해 UserLevelUpgradePolicy 인터페이스를 구현하였다. 패키지는 뭘로할까 고민하다가 Service에서 사용되는 하나의 정책 속성이라고 생각하여 attribute라는 패키지를 만들어 구성하였다. 업그레이드 기능과 연관된 메서드인 canUpgradeLevel()과 upgradeLevel() 메서드를 인터페이스 메서드로 구성하였다.

public interface UserLevelUpgradePolicy {
    
    boolean canUpgradeLevel(User user);

    void upgradeLevel(User user);
}

 

3.2. 기본 레벨 업그레이드 정책 클래스 구현

 UserLevelUpgradePolicy 를 상속받은 DefaultUserLevelUpgradePolicy 클래스를 만들고, 구현했던 로직을 이관시켰다. 레벨 업 조건이 바뀌었으므로 상수 값을 수정하였고, UserDao DI를 위한 수정자 메서드 추가, canUpgradeLevel에는 새롭게 추가될 등급인 PLATINUM도 추가하였다.

 기본 정책에서 PLATINUM 레벨은 추가되지 않지만, 이벤트 기간 후 다시 기본 정책으로 돌아왔을 때 아래 클래스를 사용하게 될텐데, 이때 PLATINUM 조건이 없다면 canUpgradeLevel 메서드에서 예외가 발생할 것이기 때문에 해당 레벨도 switch 문에 추가하였다. 

public class DefaultUserLevelUpgradePolicy implements UserLevelUpgradePolicy{

    private IUserDao userDao;

    private static final int MIN_LOGIN_COUNT_FOR_SILVER = 50;

    private static final int MIN_RECOMMEND_FOR_GOLD = 30;
    
    public void setUserDao(IUserDao userDao){
        this.userDao = userDao;
    }

    public boolean canUpgradeLevel(User user){
        Level currentLevel = user.getLevel();

        switch(currentLevel){
            case BASIC: return (user.getLogin() >= MIN_LOGIN_COUNT_FOR_SILVER);
            case SILVER: return (user.getRecommend() >= MIN_RECOMMEND_FOR_GOLD);
            case GOLD:
            case PLATINUM:
                return false;
            default: throw new IllegalArgumentException("Unknown Level :"+currentLevel);
        }
    }

    public void upgradeLevel(User user) {
        user.upgradeLevel();
        userDao.update(user);
    }
}

 

 

3.3. 이벤트 레벨 업그레이드 정책 클래스 구현

 UserLevelUpgradePolicy 를 상속받은 EventUserLevelUpgradePolicy 클래스를 만들었다. 레벨 업 조건이 바뀌었으므로 상수 값을 수정하였고, UserDao DI를 위한 수정자 메서드 추가, canUpgradeLevel에는 새롭게 추가될 등급인 PLATINUM도 추가하였다. 

public class EventUserLevelUpgradePolicy implements UserLevelUpgradePolicy{

    private IUserDao userDao;


    private static final int MIN_LOGIN_COUNT_FOR_SILVER = 30;
    private static final int MIN_RECOMMEND_FOR_GOLD = 20;
    private static final int MIN_RECOMMEND_FOR_PLATINUM = 100;

    public void setUserDao(IUserDao userDao){
        this.userDao = userDao;
    }

    public boolean canUpgradeLevel(User user){
        Level currentLevel = user.getLevel();

        switch(currentLevel){
            case BASIC: return (user.getLogin() >= MIN_LOGIN_COUNT_FOR_SILVER);
            case SILVER: return (user.getRecommend() >= MIN_RECOMMEND_FOR_GOLD);
            case GOLD: return (user.getRecommend() >= MIN_RECOMMEND_FOR_PLATINUM);
            case PLATINUM: return false;

            default: throw new IllegalArgumentException("Unknown Level :"+currentLevel);
        }
    }

    public void upgradeLevel(User user) {
        user.upgradeLevel();
        userDao.update(user);
    }

 

3.4. DI 설정 정보 수정

 DI 설정 정보를 관리하는 DaoFactory 클래스에 UserLevelUpgradePolicy에 대한 Bean을 생성하고, UserService에서 이를 DI 받도록 구성하였다. 이제 이벤트 기간에는 UserLevelUpgradePolicy의 구현체 클래스를 EventUserLevelUpgradePolicy로 설정하면 된다.

@Configuration
public class DaoFactory {
    @Bean
    public UserDaoJdbc userDao(){
        UserDaoJdbc userDaoJdbc = new UserDaoJdbc();
        userDaoJdbc.setDataSource(dataSource());
        return userDaoJdbc;
    }

    @Bean
    public DataSource dataSource(){
        SimpleDriverDataSource dataSource = new SimpleDriverDataSource();

        dataSource.setDriverClass(com.mysql.jdbc.Driver.class);
        dataSource.setUrl("jdbc:mysql://localhost/xxx");
        dataSource.setUsername("test");
        dataSource.setPassword("test");

        return dataSource;
    }

    @Bean
    public UserService userService(){
        UserService userService = new UserService();
        userService.setUserDao(userDao());
        userService.setUserLevelUpgradePolicy(userLevelUpgradePolicy());
        return userService;
    }

    @Bean
    public UserLevelUpgradePolicy userLevelUpgradePolicy(){
        DefaultUserLevelUpgradePolicy policy = new DefaultUserLevelUpgradePolicy();
        policy.setUserDao(userDao());
        return policy;
    }
}

 

3.5. 테스트 코드

UserLevelUpgradePolicy 구현체에 대한 테스트 코드는 각각 생성하였다. 레벨업 조건이 다르기 때문에 테스트 픽스처와 조건 상수 수정이 필요했기 때문이다.

UserService에 대한 테스트 코드는 UserLevelUpgradePolicy 구현체에 따라 결과가 달라지므로 테스트 메서드 레벨에서 UserLevelUpgradePolicy 구현체를 분리하도록 구현하였다.

 

1) DefaultUserLevelUpgradePolicyTest.java

@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "/test-applicationContext.xml")
class DefaultUserLevelUpgradePolicyTest {

    @Autowired
    IUserDao userDao;

    DefaultUserLevelUpgradePolicy userLevelUpgradePolicy;

    List<User> users; // 테스트 픽스처

    public static final int MIN_LOGIN_COUNT_FOR_SILVER = 50;

    public static final int MIN_RECCOMEND_FOR_GOLD = 30;
    @BeforeEach
    void setUp(){

        userLevelUpgradePolicy = new DefaultUserLevelUpgradePolicy();
        userLevelUpgradePolicy.setUserDao(userDao);

        users = Arrays.asList(
                new User("test1","테스터1","pw1", Level.BASIC, MIN_LOGIN_COUNT_FOR_SILVER-1, 0),
                new User("test2","테스터2","pw2", Level.BASIC, MIN_LOGIN_COUNT_FOR_SILVER, 0),
                new User("test3","테스터3","pw3", Level.SILVER, 60, MIN_RECCOMEND_FOR_GOLD-1),
                new User("test4","테스터4","pw4", Level.SILVER, 60, MIN_RECCOMEND_FOR_GOLD),
                new User("test5","테스터5","pw5", Level.GOLD, 100, 100)
        );


    }
    @Test
    void canUpgradeLevel() {

        assertThat(userLevelUpgradePolicy.canUpgradeLevel(users.get(0))).isFalse();
        assertThat(userLevelUpgradePolicy.canUpgradeLevel(users.get(1))).isTrue();
        assertThat(userLevelUpgradePolicy.canUpgradeLevel(users.get(2))).isFalse();
        assertThat(userLevelUpgradePolicy.canUpgradeLevel(users.get(3))).isTrue();
        assertThat(userLevelUpgradePolicy.canUpgradeLevel(users.get(4))).isFalse();

    }

    @Test
    void upgradeLevel() {

        userLevelUpgradePolicy.upgradeLevel(users.get(1));
        assertThat(users.get(1).getLevel()).isEqualTo(Level.SILVER);

        userLevelUpgradePolicy.upgradeLevel(users.get(3));
        assertThat(users.get(3).getLevel()).isEqualTo(Level.GOLD);
    }
}

 

2) EventUserLevelUpgradePolicyTest.java

@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "/test-applicationContext.xml")
class EventUserLevelUpgradePolicyTest {

    @Autowired
    IUserDao userDao;

    EventUserLevelUpgradePolicy userLevelUpgradePolicy;

    List<User> users; // 테스트 픽스처

    private static final int MIN_LOGIN_COUNT_FOR_SILVER = 30;
    private static final int MIN_RECOMMEND_FOR_GOLD = 20;
    private static final int MIN_RECOMMEND_FOR_PLATINUM = 100;
    @BeforeEach
    void setUp(){

        userLevelUpgradePolicy = new EventUserLevelUpgradePolicy();
        userLevelUpgradePolicy.setUserDao(userDao);

        users = Arrays.asList(
                new User("test1","테스터1","pw1", Level.BASIC, MIN_LOGIN_COUNT_FOR_SILVER-1, 0),
                new User("test2","테스터2","pw2", Level.BASIC, MIN_LOGIN_COUNT_FOR_SILVER, 0),
                new User("test3","테스터3","pw3", Level.SILVER, 60, MIN_RECOMMEND_FOR_GOLD-1),
                new User("test4","테스터4","pw4", Level.SILVER, 60, MIN_RECOMMEND_FOR_GOLD),
                new User("test5","테스터5","pw5", Level.GOLD, 100, MIN_RECOMMEND_FOR_PLATINUM-1),
                new User("test6","테스터6","pw6", Level.GOLD, 100, MIN_RECOMMEND_FOR_PLATINUM),
                new User("test7","테스터7","pw7", Level.PLATINUM, 100, 120)
        );


    }
    @Test
    void canUpgradeLevel() {

        assertThat(userLevelUpgradePolicy.canUpgradeLevel(users.get(0))).isFalse();
        assertThat(userLevelUpgradePolicy.canUpgradeLevel(users.get(1))).isTrue();
        assertThat(userLevelUpgradePolicy.canUpgradeLevel(users.get(2))).isFalse();
        assertThat(userLevelUpgradePolicy.canUpgradeLevel(users.get(3))).isTrue();
        assertThat(userLevelUpgradePolicy.canUpgradeLevel(users.get(4))).isFalse();
        assertThat(userLevelUpgradePolicy.canUpgradeLevel(users.get(5))).isTrue();
        assertThat(userLevelUpgradePolicy.canUpgradeLevel(users.get(6))).isFalse();

    }

    @Test
    void upgradeLevel() {

        userLevelUpgradePolicy.upgradeLevel(users.get(1));
        assertThat(users.get(1).getLevel()).isEqualTo(Level.SILVER);

        userLevelUpgradePolicy.upgradeLevel(users.get(3));
        assertThat(users.get(3).getLevel()).isEqualTo(Level.GOLD);

        userLevelUpgradePolicy.upgradeLevel(users.get(5));
        assertThat(users.get(5).getLevel()).isEqualTo(Level.PLATINUM);
    }
}

 

3) UserServiceTest.java

@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "/test-applicationContext.xml")
class UserServiceTest {

    @Autowired
    UserService userService;

    @Autowired
    IUserDao userDao;

    @Autowired
    DefaultUserLevelUpgradePolicy defaultUserLevelUpgradePolicy;

    @Autowired
    EventUserLevelUpgradePolicy eventUserLevelUpgradePolicy;

    List<User> users; // 테스트 픽스처

    @BeforeEach
    void setUp(){
       users = Arrays.asList(
               new User("test1","테스터1","pw1", Level.BASIC, 49, 0),
               new User("test2","테스터2","pw2", Level.BASIC, 50, 0),
               new User("test3","테스터3","pw3", Level.SILVER, 60, 29),
               new User("test4","테스터4","pw4", Level.SILVER, 60, 30),
               new User("test5","테스터5","pw5", Level.GOLD, 100, 100),
               new User("test6","테스터6","pw6", Level.PLATINUM, 100, 100)
       );
    }

    @Test
    @DisplayName("업그레이드 레벨 테스트-DefaultUserLevelUpgradePolicy")
    void upgradeLevelWithDefaultUserLevelUpgradePolicy(){
        userService.setUserLevelUpgradePolicy(defaultUserLevelUpgradePolicy);
        userDao.deleteAll();
        users.forEach(user -> userDao.add(user));

        userService.upgradeLevels();
        checkLevelUpgraded(users.get(0),false);
        checkLevelUpgraded(users.get(1),true);
        checkLevelUpgraded(users.get(2),false);
        checkLevelUpgraded(users.get(3),true);
        checkLevelUpgraded(users.get(4),false);
        checkLevelUpgraded(users.get(5),false);
    }

    @Test
    @DisplayName("업그레이드 레벨 테스트-EventUserLevelUpgradePolicy")
    void upgradeLevelWithEventUserLevelUpgradePolicy(){
        userService.setUserLevelUpgradePolicy(eventUserLevelUpgradePolicy);
        userDao.deleteAll();
        users.forEach(user -> userDao.add(user));

        userService.upgradeLevels();
        checkLevelUpgraded(users.get(0),true);
        checkLevelUpgraded(users.get(1),true);
        checkLevelUpgraded(users.get(2),true);
        checkLevelUpgraded(users.get(3),true);
        checkLevelUpgraded(users.get(4),true);
        checkLevelUpgraded(users.get(5),false);

    }

    @Test
    @DisplayName("레벨이 할당되지 않은 User 등록")
    void addWithNotAssignLevel(){
        userDao.deleteAll();

        User user = users.get(0);
        user.setLevel(null);

        userService.add(user);

        checkLevelUpgraded(userDao.get(user.getId()), false);
    }

    @Test
    @DisplayName("레벨이 할당된 User 등록")
    void addWithAssignLevel(){
        userDao.deleteAll();

        User user = users.get(4);
        userService.add(user);

        checkLevelUpgraded(userDao.get(user.getId()), false);
    }

    private void checkLevelUpgraded(User user, boolean upgraded){
        User userUpdate = userDao.get(user.getId());

        if(upgraded){
            assertThat(userUpdate.getLevel()).isEqualTo(user.getLevel().getNexeLevel());
        }else{
            assertThat(userUpdate.getLevel()).isEqualTo(user.getLevel());
        }
    }
}

4. 회고

 상수는 enum으로 관리하고, 비지니스 로직은 Service, 데이터 조작은 DAO, 각 객체가 가진 내부정보(멤버필드)의 수정은 스스로 처리하도록 구현했다. 이론적으로는 숙지하고 있던 내용이었지만 실무에서는 객체 스스로 처리하도록 하는 작업을 많이 생략했던 것 같다. 비지니스 로직에만 집중했었기 때문이었다. 회사의 업무 롤도 분명 큰 영향이 있었지만, OOP 대해 깊히있게 이해하려 노력하지 않았던게 더 큰것 같다. 이번 기회를 통해 객체 스스로 처리하도록 구현하는 부분에 더 신경쓸 수 있게 된 것 같다.

 스프링에 대해 어느정도 안다고 생각했지만, 모르는 부분도 너무 많다고 생각한다. 이를 바로잡기 위해 토비의 스프링을 공부하고 있는데, 공부하면 할수록 기초적이지만 중요한 내용들을 놓치고 있었구나 라는게 느껴진다.

반응형

+ Recent posts