CastleJo의 개발일지

리팩터링과 패턴

|

리팩터링

리팩터링이란?

겉으로 보이는 동작을 바꾸지 않고, 이해하거나 수정하기 쉽게 소프트웨어의 내부 구조를 바꾸는 것 이다.

중복을 제거하고, 복잡한 로직을 단순화하며 불명확한 코드를 명확하게 만드는 작업이 포함된다.

리팩터링을 하는 이유

  • 새로운 코드를 더 쉽게 추가할 수 있도록 하기 위해
  • 기존 코드의 설계를 개선하기 위해
  • 기존 코드를 더 잘 이해하기 위해
  • 덜 짜증나는 코드를 만들기 위해
  • 기분좋아서…

사람이 읽기 쉬운 코드

하나의 예제가 있다.

public Date november(int date, int year){
    java.util.Calendar c = jave.util.Calendar.getInstance();
    c.set(year, java.util.Calendar.NOVEMBER,date);
    return c.getTime()
}

november(20, 2025);
java.util.Calendar c = jave.util.Calendar.getInstance();
c.set(2025, java.util.Calendar.NOVEMBER,25);
c.getTime()

무엇이 더 깔끔한가?

컴퓨터가 이해하는 코드는 어느 바보나 다 짤 수 있다.
훌륭한 프로그래머는 사람이 이해할 수 있는 코드를 짠다.

깔끔하게 설계하기

코드를 깔끔하게 유지하는 것은 방을 깔끔하게 유지하는 것과 비슷하다.
지속적으로 중복을 제거하고 코드를 단순화하고 더 명확하게 고쳐야 한다.

작은 단계

TDD를 하면서, 큰 단계부터 풀어가려고 하면 결국 실패할 수도 있다.
작은 단계씩 차근차근, 빨간색 상태가 오랫동안 남아있다면 충분히 작은 단계를 취하지 않고 있음을 기억하라.

설계 부채

설계 부채는 다음과 같은 사항을 꾸준히 수행하지 않을 때 발생한다.

  1. 중복 제거
  2. 코드 단순화
  3. 코드의 의도 명료화

빚을 오랫동안 쌓이게 두면, 나중에 더 갚기 힘들어지고 어려워진다. 명심하자.

복합 리팩터링과 테스트 주도 리팩터링

복합 리팩터링은 여러개의 저수준 리팩터링으로 이루어진 고수준 리팩터링이다.
Extract Method로 코드를 새로운 메소드로 이동시키고, Pull Up Method로 메소드를 서브클래스에서 수퍼클래스로 이동시키고 Extract Class 로 코드를 새로운 클래스로 이동시키고 Move Method로 메소드를 한 클래스에서 다른 클래스로 이동시킨다.

테스트 주도 리팩토링은 TDD를 통해 대체 코드를 작성한 다음 기존 코드를 새 코드로 대체(기존 코드에 대한 테스트는 그대로 유지하면서)하는 방법이다.

테스트 주도 리팩터링의 가장 전형적인 예는 Substitute Algorithm 이다. 본질적으로 기존의 알고리즘을 더 단순하고 명확한 알고리즘으로 완전히 대체하는 것이다.

복합 리팩터링의 장점

  • 리팩터링 절차에 대한 전반적인 계획을 설명한다.
  • 설계에 대한 명확한 방향을 제시한다.
  • 패턴 구현에 대한 통찰력을 제공한다.

패턴

패턴이란

패턴은 세상에 발생하는 사물인 동시에 그것을 어떻게 창조할 수 있는지, 그리고 언제 창조해야 하는지를 알려주는 규칙이다.

패턴 중독

패턴을 공부하는 사람들은 패턴에 중독될 수도 있다. 간단한 일을 하는데도 온갖 패턴을 사용하는 것.

단순히 hello, world! 를 출력하는 예제이다.

public interface MessageStrategy {
    public void sendMessage();
}

public abstract class AbstractStrategyFactory {
    public abstract MessageStrategy createStrategy(MessageBody mb);
}

public class MessageBody {
    Object payload;
    public Object getPayload() {
        return payload;
    }

    public void configure(Object obj) {
        payload = obj;
    }
    
    public void send(MessageStrategy ms) {
        ms.sendMessage();
    }
}

public class DefaultFactory extends AbstractStrategyFactory {
    private DefaultFactory() {;}
    static DefaultFactory instance;
    public static AbstractStrategyFactory getInstance() {
    if (instance==null) instance = new DefaultFactory();
    return instance;
    }

    public MessageStrategy createStrategy(final MessageBody mb) {
        return new MessageStrategy() {
            MessageBody body = mb;
            public void sendMessage() {
                Object obj = body.getPayload(); 
                System.out.println((String)obj);
            }
        };
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        MessageBody mb = new MessageBody();
        mb.configure("Hello World!");
        AbstractStrategyFactory asf = DefaultFactory.getInstance();
        MessageStrategy strategy = asf.createStrategy(mb);
        mb.send(strategy);
    }
}

// output: Hello World!

패턴의 진가는 패턴을 현명하게 사용할 때 나타난다.

패턴을 통한 리팩터링

패턴에 관련된 리팩터링은 세가지가 있다.

  1. 패턴을 목표로 하는 리팩터링
  2. 패턴을 지향하는 리팩터링
  3. 패턴을 제거하는 리팩터링

리팩터링의 목표는, 더 좋은 설계를 얻는것이다.

패턴 목표 지향 제거
Adapter Extract Adapter
Unify interfaces with Adapter
Unify interfaces with Adapter  
Builder Encapsulate Composite with Builder    
Collecting Parameter Move Accumulation to Collecting Parameter    
Command Replace Conditional Dispatcher with Command Replace Conditional Dispatcher with Command  
Composed Method Compose Method    
Composite Replace One/Many Distinctions with Composite,
Extract Composite,
Replace Implicit Tree with Composite
  Encapsulate Composite with Builder
Creation Method Replace Constructors with Creation Methods    
Decorator Move Embellishment with Creation Methods Move Embellishment with Creation Methods  
Factory Move Creation Knowledge to Factory,
Encapsulate Classes with Factory
   
Factory Method Introduce Polymorphic Creation with Factory Method    
Interpreter Replace Implicit Language with Interpreter    
Iterator     Move Accumulation to Visitor
Null Object Introduce Null Object    
Observer Replace Hard-Coded Notifications with Observer Replace Hard-Coded Notifications with Observer  
Singletone Limit Instantiation with Singleton   Inline Singletone
State Replace State-Altering Conditionals with State Replace State-Altering Conditionals with State  
Strategy Replace Conditional Logic with Strategy Replace Conditional Logic with Strategy  
Template Method Form Template Method    
Visitor Move Accumulation to Visitor Move Accumulation to Visitor  

뒤의 숫자는 페이지의 쪽수이다. 나중에 이걸 하이퍼링크로 대체할 예정이다.

사전설계 단계에서의 패턴 사용

사전설계를 할 때부터 무슨 패턴을 정할 지 고르는 것은, 시간 낭비가 될 수도 있다는 것이다.
리팩토링을 하면서 3가지 단계를 적용하는 것이 추천된다.(단 Command 패턴만은 써도 좋다고 한다)
만약 패턴을 이용해서 사전 설계를 할 때는 매우 주의해서 사용해야 한다.