[워밍업 클럽 4기 백엔드] Day 4 미션

1. 읽기 좋은 코드로 리팩토링 해봅시다.

😫 Before

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;
}

😄 After

public boolean validateOrder(Order order) {
    if(order.isEmptyItems()) {
        log.info("주문 항목이 없습니다.");
        return false;
    }

    if(order.isInvalidTotalPrice()) {
        log.info("올바르지 않은 총 가격입니다.");
        return false;
    }

    if (order.hasNotCustomerInfo()) {
        log.info("사용자 정보가 없습니다.");
        return false;
    }
    
    return true;
}

불필요한 중첩 분기문 제거 & early return

  • 사고의 흐름을 복잡하게 하는 중첩 분기문을 제거하여 사고의 depth를 줄임

  • early return을 활용하여 각 분기문에 대한 맥락만 파악할 수 있도록 함

부정 연산자보단 부정어구 사용

  • !order.hasCustomerInfo() 같이 가독성이 떨어지는 부정 연산자 보단, order.hasNotCustomerInfo() 처럼 문장 자체에 부정의 의미를 담는 방식을 채택하여 이해를 도움

getter를 통한 검증보단 해당 객체에 검증 위임

  • order 객체가 가진 값을 직접 꺼내와서 검증하는 것보다, 객체에게 메시지를 보내어 검증을 요구

  • 기존 getter를 통해 값을 가져와서 하는 검증보다, 메서드명에서 무엇을 검증하려고 하는지 보여줄 수 있어 기능에 대한 이해를 빠르게 할 수 있음

     


2. SOLID에 대하여 자신만의 언어로 정리해 봅시다.

📌Single Responsibility Principle(단일 책임 원칙)

하나의 클래스하나의 책임만 가지도록 설계하자!

  • 객체간의 책임을 명확하게 나누어 설계해야 한다.

  • 객체의 관심사를 분리하여 하나의 관심사만 가지도록 하여 명확한 책임을 부여한다.

  • 우리가 설계한 객체가 하나의 책임만을 가지고 있는지 점검하며 개발한다.

     

  • 책임을 제대로 나누지 못하면 리팩토링 과정에서 엉뚱한 클래스를 수정 해야하는 상황이 발생한다.

 

📌Open-Closed Principle(개방-폐쇄 원칙)

확장에는 열려 있고, 수정에는 닫혀 있어야 한다!

  • 요구 사항이 생겨도 기존 코드를 과도하게 변경하지 않고 확장할 수 있어야 한다.

  • 인터페이스를 활용하여 확장 가능성이 있는 기능은 추상화를 잘해야 한다.

 

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

자식 클래스는 부모 클래스의 책임을 준수하며, 부모 클래스의 행동을 변경하지 않아야 한다.

  • 상속 구조로 객체를 설계할 때, 자식은 @Override 를 통해 부모의 기능을 훼손해서는 안된다.

  • 항상 부모의 자리에 자식이 위치했을 때도 생각하며 자식을 설계해야 한다.

  • 만약 자식 클래스의 기능을 사용할 때 타입 체크를 해야 하는 상황이라면 설계를 다시 하자.

 

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

클라이언트는 자신이 사용하지 않는 인터페이스에 의존하면 안 된다!

  • 인테페이스를 잘게 쪼개어 꼭 필요한 기능만 구현할 수 있도록 설계한다.

  • 모든 기능을 추상화한 인터페이스로 인해, 구현 클래스에서 구현을 하기 힘들거나 예외 던지기 같은 상황을 유발하면 안된다.

 

📌Dependency Inversion Principle(의존성 역전 원칙)

상위 수준의 모듈은 하위 수준의 모듈에의존해서는 안 된다. 둘 모두 추상화에 의존해야 한다!

  • 저수준 모듈 : 구체에 가까운 모듈

  • 고수준 모듈 : 추상화 레벨이 높은 모듈

  • 추상화에만 의존하여 런타임 시점에 어떤 구현체가 들어와도 추상화된 기능에만 의존할 수 있도록 한다.

출처: Readable Code: 읽기 좋은 코드를 작성하는 사고법

댓글을 작성해보세요.

채널톡 아이콘