본문 바로가기
개발 관련됨/개발 관련 유용한 정보함

안전하게 코드 리팩토링하기 - 1

by simplify-len 2022. 7. 24.

안전하게 리팩토링하기

SOLID 원칙 중 DIP가 있다.

어떻게 하면 쉽게 리팩토링 할 수 있는지 간단하면서도 강력한 방법을 이야기해볼까 한다.

이것을 아래와 같이 변경한다고 해보자.

img.png

public class LotteriesFactory {

    private final RandomNumberGenerator randomNumberGenerator;

    public LotteriesFactory(RandomNumberGenerator randomNumberGenerator) {
        this.randomNumberGenerator = randomNumberGenerator;
    }

    // 만약 많은 곳에서 해당 코드를 사용하고 있다면 어찌하겠는가 ????????

    public String createNumber(){
        return randomNumberGenerator.create();
    }
}

이것을 아래와 같이 변경한다면 어떻게 안전하게 변경할 수 있을까?


public class LotteriesFactory {

    private NumberGenerator randomNumberGenerator;

    public LotteriesFactory(NumberGenerator randomNumberGenerator) {
        this.randomNumberGenerator = randomNumberGenerator;
    }

    // 만약 많은 곳에서 해당 코드를 사용하고 있다면 어찌하겠는가 ????????

    public String createNumber() {
        return randomNumberGenerator.create();
    }
}

public class RandomNumberGenerator implements NumberGenerator {
    @Override
    public String create() {
        return "123456";
    }
}

혹시 여러분은 IDE 에서 어떻게 이것을 안전하게 변경할 수 있나요?

저는 이것을 안전하게 변경하기 위해서 IntelliJ 의 Refactor 기능을 적극적으로 활용할 것입니다.

.
.
.
.
.
.
.
.
.
.
.
.
어떻게 하고 계신가요? 혹시 Rename 으로 하고 있나요? 아니면 이미 한땀한땀 고치고 계신건 아닌가요?

RandomNumberGenerator randomNumberGenerator 에서 어떻게 NumberGenerator numberGenerator 로 변경했나요?

저라면 RandomNumberGenerator 여기에서부터 시작합니다.

implements NumberGenerator@Override 를 활용해 아무런 비즈니스의 문제없이 NumberGenerator 를 만들어 냅니다.

public class RandomNumberGenerator implements NumberGenerator {
    @Override
    public String create() {
        return "123456";
    }
}

이후에는 어떻게 할까요?

아마도 LotteriesFactory 를 고치려 할 것 입니다.


public class LotteriesFactory {

    private final RandomNumberGenerator randomNumberGenerator;

    public LotteriesFactory(RandomNumberGenerator randomNumberGenerator) {
        this.randomNumberGenerator = randomNumberGenerator;
    }

    public String createNumber(){
        return randomNumberGenerator.create();
    }
}

어떻게 하면 기존 로직에 영향없이 코드를 변경할 수 있을까요?


public class LotteriesFactory {

    private NumberGenerator randomNumberGenerator;

    public LotteriesFactory(RandomNumberGenerator randomNumberGenerator) {
        this((NumberGenerator) randomNumberGenerator); // Look at this
    }

    public LotteriesFactory(NumberGenerator randomNumberGenerator) {
        this.randomNumberGenerator = randomNumberGenerator;
    }

    public String createNumber(){
        return randomNumberGenerator.create();
    }
}
img_1.png

Refactor > Inline method 를 하게 되면 아래와 같이 변경됩니다.

public class LotteriesFactory {

    private NumberGenerator randomNumberGenerator;

    public LotteriesFactory(NumberGenerator randomNumberGenerator) {
        this.randomNumberGenerator = randomNumberGenerator;
    }

    public String createNumber(){
        return randomNumberGenerator.create();
    }
}


class LotteriesFactoryTest {


    @Test
    void testA() {
        LotteriesFactory factory = new LotteriesFactory((NumberGenerator) new RandomNumberGenerator());
        String number = factory.createNumber();
        System.out.println(number);
    }

    @Test
    void testB() {
        LotteriesFactory factory = new LotteriesFactory((NumberGenerator) new RandomNumberGenerator());
        String number = factory.createNumber();
        System.out.println(number);
    }
}

이렇게 함으로써 안전하게 코드를 리팩토링하게 됩니다.


[추가 피드백]

이렇게 리팩토링을 하다보니 한가지 문제점을 발견했습니다. refactor > inline method 는 강력합니다. 강력한 만큼 조심해야 될 부분이 있었습니다.

바로 위 테스트 코드처럼 목적에 따라 변경이 필요하지 않는 부분이 변경될 수 있다는 사실을 말이죠.

사실은 하나하나 사용되는 보고 리팩토링을 하는게 맞다는 생각이 듭니다.

댓글