[워밍업 클럽 스터디 2기] 1주차 발자국 🐾

 

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


  • 클래스는 단 하나의 책임을 가져야 한다.

    • 변경하는 이유는 단 하나여야 한다.

  • SRP 원칙을 잘 지키면, 유지보수가 필요한 상황이 생겼을 때 수정할 대상이 명확해진다.

  • 클래스를 분리할 때 주의점

    • 어떤 파라미터를 전달할지 객체 입장에서 고민하기

      • 예) 익셉션 핸들러에게 e를 줄까? e.getMessage를 줄까? ⇒ e ( ∵ e를 가지고 뭘 할지는 핸들러가 알아서 해 ~ )

    • 클래스에게서 get으로 필드를 가져오는 건 무례하다구! Rude! ⇒ 메서드로 필요한 정보만을 요청하자

  • 예) 지뢰찾기 게임

    • ‘게임의 진입점’과 ‘지뢰찾기 실행’ 부분 분리

    • 입출력 관련한 것 분리

    • 게임보드 분리

 

OCP(Open Closed Principle) : 개방 폐쇄 원칙


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

  • 새로운 요구사항이 생겼을 때, 기존 코드의 수정은 최소화 되고 새로운 기능 확장은 손쉽게 되도록 해야 한다.

  • 인터페이스를 활용하면 새로운 기능을 추가할 때

    • 기존 코드를 수정하지 않고

    • 새로운 구현체 클래스를 생성하면 된다.

  • 예) 지뢰찾기 게임 : 난이도에 따라 보드의 크기를 달리 하는 기능 추가

    • 상수로 박아둔 크기를 변수 처리

    • GameLevel 인터페이스 사용

      • 각 난이도는 각 구현체로

 

LSP(Listov Substitution Principle) : 리스코프 치환 원칙


  • 부모 클래스의 인스턴스를 자식 클래스의 인스턴스로 치환할 수 있어야 한다.

     

  • 상속 구조로 리팩토링할 때, 타입 체크를 하는 방향은 좋은 설계가 아니다.

    • 기존 패턴을 유지하면서 통합하는 방식으로 인터페이스를 만들면 타입 체크가 생기게 돼 ⇒ 더 추상화된 관점에서 새로운 설계를 떠올릴 수 있어야 해

  • 예) 지뢰찾기 게임 : 지뢰 Cell, 숫자 Cell, 빈 Cell을 Cell을 상속 받는 구조로 리팩토링

    • 지뢰 Cell을 구현체로 만들었으므로 플래그를 세우는 turnOn 메서드 삭제

    • 숫자 Cell을 구현체로 만들었으므로 주변부 지뢰 개수를 세서 update하는 메서드 삭제 ⇒ 생성자로 넣기

 

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


  • 클라이언트는 자신이 사용하지 않는 인터페이스에 의존해서는 안 된다.

     

    image

  • 예) 지뢰찾기 말고 다른 게임이 추가되는 상황

    • 새로운 게임은 initialize 메서드 사용하지 않아 ⇒ Game 인터페이스를 GameInitial과 GameRunnable로 분리

 

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


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

  • 의존성의 순방향 : 고수준 모듈이 저수준 모듈을 참조하는 것

    • 의존을 역전시킨다 = 고수준, 저수준 모듈 모두 추상화에 의존한다.

  • 저수준은 구체 쪽에 가깝기 때문에 수정이 잦으므로 고수준이 추상화 된 스펙만 참조하도록 한다.

    • 저수준 모듈이 자유롭게 변경되어도 고수준 모듈에는 영향이 가지 않게 설계해야 한다.

       

image

  • 예) 콘솔 외의 다른 I/O가 추가되는 상황

    • 현재 코드에서 수정하려 한다면, 마인스위퍼의 수정 불가피 해 (저수준 모듈의 변경이 고수준 모듈에 영향을 미치는 것)

    • 콘솔 핸들러를 구현체로 가지는 인풋,아웃풋 핸들러 인터페이스 생성해서 마인스위퍼에서 사용

    • 기존 메서드명이 어색해진다면 이것도 더 추상화 된 메서드 명으로 수정 : printXXX → showXXX

 



 

  • 회고

    • 칭찬하고 싶은 점 : 워밍업 클럽의 미션을 성실히 수행했다.

    • 아쉬웠던 점 : 진도를 따라잡기 위해 리팩토링을 직접 고민해보는 과정은 생략했다.

    • 보완하고 싶은 점 : 강의에서 질문거리가 나오면 잠시 멈춰두고 혼자 고민하는 시간을 가지면 좋을 것 같다.

 

  • 미션

    • As Is

        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;
        }
    • To Be

      • if - else 문은 else 대신 return을 사용해서 Early return

      • 중첩 조건문은 메서드로 추출해서 사고의 depth 줄이기

      • 의미 단위로 공백 주기

      • 부정어 줄이기

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

        if (order.getTotalPrice() > 0) {
            return checkCustomerInfo(order);
        }

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

    public boolean checkCustomerInfo(Order order) {
        if (order.hasCustomerInfo()) return true;

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

 

 

 

댓글을 작성해보세요.

채널톡 아이콘