인프런 워밍업클럽 4기 BE- 클린코드&테스트 DAY4 과제 (SOLID 원칙과 리팩토링)

<변환 전 코드>

public boolean validateOrder(Order order) {
    if (order.getItems().size() == 0) {
        log.info("주문 항목이 없습니다.");
        return false;
    } else {
        if (order.getTotalPrice() > 0) {
            if (!order.hasCustomerInfo()) {
                log.info("사용자 정보가 없습니다.");
                return false;
            } else {
                return true;
            }
        } else if (!(order.getTotalPrice() > 0)) {
            log.info("올바르지 않은 총 가격입니다.");
            return false;
        }

    }
    return true;
}

<변환된 코드>

import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


record Item(int price) {}
record Customer(String name) {}

class Order {
    private final List<Item> items;
    private final Customer   customer;

    Order(List<Item> items, Customer customer) {
        this.items    = items;
        this.customer = customer;
    }


    void validate() {
        if (items.isEmpty())            throw ex("주문 항목이 없습니다.");
        if (totalPrice() <= 0)          throw ex("올바르지 않은 총 가격입니다.");
        if (customer == null)           throw ex("사용자 정보가 없습니다.");
    }


    private int totalPrice() { return items.stream().mapToInt(Item::price).sum(); }
    private IllegalStateException ex(String msg) { return new IllegalStateException(msg); }
}


class OrderValidator {
    private static final Logger log = LoggerFactory.getLogger(OrderValidator.class);

    boolean validateOrder(Order order) {
        if (order == null) { log.info("주문 정보가 없습니다."); return false; }

        try { order.validate(); return true; }
        catch (IllegalStateException e) { log.info(e.getMessage()); return false; }
    }
}
  • 부정 연산자 제거

  • Early Return (예외를 던져 첫 실패시 즉시 반환함)

  • 불필요한 클래스 제거 (OrderItems, ValidationResult 없애기)

  • 레코드 사용 (Item, Customer를 Record로 사용해, 불변 데이터 정의를 간결화 함)

 

SOLID 원칙

단일 책임 원칙 (Single Responsibility Principle, SRP)

  • 책임이 명확히 분리된 코드는 읽기 쉽고, 유지보수와 테스트가 쉬워진다.

  • 여러 기능이 한 클래스에 섞이면 변경이 자주 발생하고, 코드의 복잡도가 증가한다.

     

개방-폐쇄 원칙 (Open/Closed Principle, OCP)

  • 인터페이스나 추상 클래스를 활용해 유연하게 설계하면, 변화에 강한 구조를 만들 수 있다.

  • 새로운 기능 추가 시 기존 코드를 수정하지 않고, 확장만으로 요구사항을 반영할 수 있어야 한다.

     

리스코프 치환 원칙 (Liskov Substitution Principle, LSP)

  • 상속 구조에서 자식 클래스가 부모 클래스의 규약을 깨지 않도록 설계해야 한다.

     

인터페이스 분리 원칙 (Interface Segregation Principle, ISP)

  • 하나의 큰 인터페이스보다는 여러 개의 구체적인 인터페이스로 분리하는 것이 좋다.

  • 불필요한 의존성을 줄이고, 각 구현체가 꼭 필요한 기능만 구현하도록 유도할 수 있다.

의존 역전 원칙 (Dependency Inversion Principle, DIP)

  • 구체적인 구현이 아니라, 인터페이스나 추상 클래스에 의존하도록 설계한다.

  • 코드의 결합도가 낮아지고, 테스트와 확장이 쉬워진다.

 

 

 

 

 

 

 

댓글을 작성해보세요.

채널톡 아이콘