레거시 코드 개선기

헨도·2025년 9월 9일

SpringBoot

목록 보기
36/41
post-thumbnail

인턴 생활을 하며 레거시 코드를 리팩토링한 경험을 쓰려고 한다.

문제 상황

복잡한 if-else 문

프로젝트 부분 중 특정 브랜드에 따라 해당 브랜드 로직을 수행하는 기능을 포함하고 있었다.
기존 코드는 아래와 같이 if-else 문으로 브랜드별 로직을 분기하고 있었다.

// 본 코드는 실제 프로젝트 코드와 무관합니다.

public void process(Product product) {
	if (product.getBrand().equals("NIKE")) {
    	// NIKE 브랜드 로직
    } else if (product.getBrand().euqals("ADIDAS")) {
    	// ADIDAS 브랜드 로직
	} else if (product.getBrand().equals("PUMA") {
		// PUMA 로직
    }
}

코드의 문제점

1. 높은 결합도

  • 새로운 브랜드가 추가될 때마다 기존 코드를 수정해야 한다.
    이는 OCP(개방-폐쇄 원칙, Open-Closed Principle)를 위반하는 것이다.

2. 낮은 가독성

  • if-else 문이 길어질수록 코드를 읽고 이해하기 어려워진다.

3. 유지보수의 어려움

  • 특정 브랜드 로직을 수정하기 위해선 if 문을 찾아야하며, 다른 브랜드의 로직까지 피해를 입힐 수 있다.

해결책

전략 패턴(Strategy Pattern) 도입

이 문제를 해결하기 위해 전략 패턴을 도입했습니다.
전략 패턴은 관련성 있는 알고리즘들을 캡슐화하고 교환 가능하게 만드는 디자인 패턴이다.
이를 통해 런타임에 필요한 알고리즘을 선택하여 수행할 수 있다.

구현 순서

1. 전략 인터페이스

모든 브랜드별 로직이 따라야 하는 공통된 인터페이스를 정의

// BrandStrategy.java
// 모든 브랜드 전략이 따라야 하는 인터페이스

public interface BrandStrategy {
	void execute(Product product);
}

2. 각 브랜드의 전략 구현체 생성

이제 각 브랜드에 맞는 구체적인 로직을 담는 클래스를 만든다.

// NikeStrategy.java
public class NikeStrategy implements BrandStrategy {
	@Override
    public void execute(Product product) {
    	System.out.println("NIKE 브랜드 로직 실행 : " + product.getName());
    }
}

// AdidasStrategy.java
public class AdidasStrategy implements BrandStrategy {
	@Override
    public void execute(Product product) {
    	System.out.println("ADIDAS 브랜드 로직 실행 : " + product.getName());
    }
}

// PumaStrategy.java
public class PumaStrategy implements BrandStrategy {
	@Override
    public void execute(Product product) {
    	System.out.println("Puma 브랜드 로직 실행 : " + product.getName());
    }
}

3. 전략을 사용하는 컨텍스트 클래스

컨텍스트 클래스는 BrandStrategy 인터페이스를 사용하여 로직을 실행한다.
Map을 이용해 브랜드 이름에 해당하는 전략 객체를 찾아 실행한다.

public class BrandProcessor {
	private static final Map<String, BrandStrategy> strateMap = new HashMap<>();
    
    static {
        // 모든 전략을 미리 초기화하여 맵에 저장합니다.
        strategyMap.put("NIKE", new NikeStrategy());
        strategyMap.put("ADIDAS", new AdidasStrategy());
        strategyMap.put("PUMA", new PumaStrategy());
    }

    public void process(Product product) {
        // 제품의 브랜드에 맞는 전략을 맵에서 가져옵니다.
        BrandStrategy strategy = strategyMap.get(product.getBrand().toUpperCase());
        
        if (strategy != null) {
            // 해당 브랜드의 전략을 실행합니다.
            strategy.execute(product);
        } else {
            System.out.println("지원하지 않는 브랜드입니다.");
        }
    }
}

결과

코드 개선

1. 유연성 향상

  • 새로운 브랜드가 추가될 경우 BrandStrategy 인터페이스를 구현하는 새로운 클래스만 추가하면 된다.
    BrandProcessor 의 기존 코드를 수정할 필요가 없다.
    이것으로 개방-폐쇄 원칙을 지킬 수 있다.

2. 쉬운 유지보수

  • 각 브랜드의 로직이 별도의 클래스에 캡슐화되어 있어, 특정 로직을 수정하거나 삭제하기 매우 쉽다.

3. 향상된 가독성

  • 길었던 if-else 문을 대체하여 핵심 로직에만 집중할 수 있게 코드가 깔끔해진다.
profile
Junior Backend Developer

0개의 댓글