[워밍업 클럽 4기 - BE 클린 코드 & 테스트 코드] Day 4 미션
🎯 Day 4 미션 1⃣번 미션Step 0) 분석 및 이해하기 & 리팩토링 대상/범위 확인키워드 : 논리, 사고의 흐름 , 읽기 좋은 코드, 리팩토링코드와 설명을 통해, 해당 도메인에 대해서 이해합니다.⇒ 주문에 대한 비즈니스 측면의 유효성 검사가 아닌 사용자가 생성한 주문 객체에 대한 유효성 검사는 Order 객체에서 진행한다고 가정하겠습니다.// 사용자가 생성한 '주문'이 유효한지를 검증하는 메서드 public boolean validateOrder(Order order) { // a. 주문 항목이 있는지 확인 if (order.getItems().size() == 0) { // a-1. 주문 항목이 없음 log.info("주문 항목이 없습니다."); return false; } else { // a-2. 주문 항목이 있음 // b. 주문 총액이 올바른지 확인 (0원 초과) if (order.getTotalPrice() > 0) { // b-1. 주문 총액이 0원 초과 // c. 주문한 사용자 정보가 있는지 확인 if (!order.hasCustomerInfo()) { // c-1. 사용자 정보가 없음 log.info("사용자 정보가 없습니다."); return false; } else { // c-2. 사용자 정보가 있음 return true; } } else if (!(order.getTotalPrice() > 0)) { // b-2. 주문 총액이 0원 이하 log.info("올바르지 않은 총 가격입니다."); return false; } } // 모든 조건을 통과하여 유효한 주문인 경우 return true; } Step 1) 리팩토링 1. 주문 항목이 있는지 확인 (a)if (order.getItems().size() == 0)if 조건에서 주문 항목이 없으면 false를 반환하고, 주문 항목이 있다면 그 이후의 else로 자연스럽게 넘어가게 됩니다. 따라서, 주문 항목이 없는 경우에만 false를 반환하고, 그 외의 주문 항목이 존재하는 경우에는 계속해서 다음 조건을 검사하게 되므로 else를 제거해도 문제가 없습니다.⇒ 뇌 메모리 적게 쓰기 (인지적 경제성)public boolean validateOrder(Order order) { if (order.getItems().size() == 0) { log.info("주문 항목이 없습니다."); return false; } 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; } 2. 주문 총액이 올바른지 확인 (b)(b-2)의 !(order.getTotalPrice() > 0) 를 부정의 의미를 담지 않은 order.getTotalPrice() <= 0 로 표현할 수 있습니다.public boolean validateOrder(Order order) { if (order.getItems().size() == 0) { log.info("주문 항목이 없습니다."); return false; } 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; } 주문 총액이 0원 이하(b-2)인 경우를 먼저 확인하게 하면 이 조건을 만족하면 바로 false를 반환합니다. 이후, 주문 총액이 0원을 초과(b-1)하는 경우에만 사용자 정보를 확인하는 로직으로 넘어가게 됩니다. 이렇게 조건문의 순서 변경을 통해, 불필요한 else if를 제거할 수 있습니다.public boolean validateOrder(Order order) { if (order.getItems().size() == 0) { log.info("주문 항목이 없습니다."); return false; } if (order.getTotalPrice() <= 0) { log.info("올바르지 않은 총 가격입니다."); return false; } if (!order.hasCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } else { return true; } return true; } 3. 주문한 사용자 정보가 있는지 확인 (c)(c-2)의 경우는 모든 조건을 통과한 경우로, else를 제거해도 됩니다.공백 라인으로 모든 조건을 만족한 경우를 다른 조건과 분리해줍니다.public boolean validateOrder(Order order) { if (order.getItems().size() == 0) { log.info("주문 항목이 없습니다."); return false; } if (order.getTotalPrice() <= 0) { log.info("올바르지 않은 총 가격입니다."); return false; } if (!order.hasCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } return true; } 2⃣번 미션SRP (Single Responsibility Principle; 단일 책임의 원칙)하나의 클래스는 하나의 책임/관심사를 가진다.→ 변경하는 이유는 하나여야 한다. → 높은 응집도 & 낮은 결합도OCP (Open-Closed Principle; 개방-폐쇄의 원칙)확장에는 열려 있고, 수정에는 닫혀 있어야 한다. → 기존 코드 변경 없이 기능 확장 가능해야 한다.LSP (Liskov substitution Priciple; 리스코프 치환 원칙)부모 클래스의 인스턴스는 자식 클래스의 인스턴스로 치환할 수 있어야 한다. → 자식 클래스는 부모 클래스를 변경시키지 않아야 한다.ISP (Interface Segregation Principle; 인터페이스 분리 원칙)인터페이스에는 필요한 기능만 선언한다.DIP (Dependecy Inversion Principle; 의존성 역전의 법칙)구체화된 것보다 추상화된 스펙에 의존해야 한다. 👨🏻💻 강의 출처Readable Code: 읽기 좋은 코드를 작성하는 사고법