1. 아래 코드와 설명을 보고, [섹션 3. 논리, 사고의 흐름]에서 이야기하는 내용을 중심으로 읽기 좋은 코드로 리팩토링해 봅시다.
- 사용자가 생성한 '주문'이 유효한지를 검증하는 메서드.
- Order는 주문 객체이고, 필요하다면 Order에 추가적인 메서드를 만들어도 된다. (Order 내부의 구현을 구체적으로 할 필요는 없다.)
- 필요하다면 메서드를 추출할 수 있다.
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;
}
리팩토링
- 각각의 메소드를 Early-Return 구조로 변경
- 부정어 연산제거
- validate 연산 Order객체 내부로 캡슐화
public boolean validateOrder(Order order) {
try {
order.validate();
} catch (OrderException e) {
log.info(e.getMessage());
return false;
}
return true;
}
public class Order {
private List<OrderItem> items;
private int totalPrice;
private Customer customer;
public void validate() {
if (emptyItems()) {
throw new OrderException("주문 항목이 없습니다.");
}
if (validatePrice()) {
throw new OrderException("올바르지 않은 총 가격입니다.");
}
if (hasNoCustomerInfo()) {
throw new OrderException("사용자 정보가 없습니다.");
}
}
private boolean validatePrice() {
return totalPriceNegativeOrZero();
}
private boolean emptyItems() {
return items.isEmpty();
}
private boolean totalPriceNegativeOrZero() {
return totalPrice <= 0;
}
private boolean hasNoCustomerInfo() {
return customer == null || customer.isEmpty();
}
}
2. SOLID에 대하여 자기만의 언어로 정리해 봅시다.
그럼 자동차 정비소를 예로 들어 SOLID 원칙을 설명해보자
1. 단일 책임 원칙 (Single Responsibility Principle, SRP)
설명: 하나의 클래스 또는 모듈이 하나의 책임만을 가져야 한다는 원칙
- 엔진 정비사, 타이어 정비사, 전기 시스템 정비사가 각각의 역할만 맡는 경우를 생각해보자.
- 엔진 정비사: 엔진 수리 및 정비에만 집중.
- 타이어 정비사: 타이어 교체와 수리에만 집중.
- 전기 시스템 정비사: 전자 장비와 전기 시스템에만 집중.
장점:
각 정비사가 자신의 전문 분야에만 집중할 수 있어, 정비 효율성이 높아지고 문제가 발생했을 때 수정하기도 쉽다.
2. 개방-폐쇄 원칙 (Open/Closed Principle, OCP)
설명: 시스템은 확장에 열려 있고, 기존 코드는 변경하지 않도록 설계해야 한다는 원칙.
- 처음에는 정비소에서 엔진과 타이어 수리만 제공하다가, 나중에 전기 시스템 수리를 추가하고 싶다고 가정.
기존 엔진과 타이어 정비 담당자들의 업무를 변경하지 않고, 전기 시스템 담당자를 새로 추가하면 됩니다. - 즉, 정비소 시스템은 기존의 작업 흐름에 영향을 주지 않고도 새로운 서비스를 추가할 수 있도록 설계되어야 한다
- 수리라는 부분을 추상화시키고 수리 담당자들에게 수리의 구체 역할을 부여함으로써 확장에는 열려 있을 수 있게된다.
장점:
기존 정비 작업을 변경하지 않고 새로운 서비스(기능)를 추가할 수 있어 정비소 운영에 지장을 주지 않고 확장이 가능.
3. 리스코프 치환 원칙 (Liskov Substitution Principle, LSP)
설명: 하위 클래스가 상위 클래스를 대체할 수 있어야 한다는 원칙.
- 정비사 A가 휴가를 가도, 정비사 B가 그 역할을 대신할 수 있어야 한다.
- 만약 A가 타이어 정비를 담당했다면, B도 타이어 관련 수리를 정상적으로 수행해야 한다..
B가 대체할 수 없다면 정비소 운영에 문제가 생깁니다.
이는 프로그래밍에서 하위 클래스가 상위 클래스를 치환할 수 있어야 하는 것과 같다.
장점:
상위 역할을 맡고 있던 정비사가 자리를 비워도, 다른 정비사가 그 역할을 원활히 수행할 수 있어 시스템(정비소)이 계속 정상적으로 운영 될 수 있다..
4. 인터페이스 분리 원칙 (Interface Segregation Principle, ISP)
설명: 클라이언트가 자신이 사용하지 않는 메서드에 의존하지 않도록 인터페이스를 분리해야 한다는 원칙.
- 정비소에서 엔진 정비사에게는 엔진 수리 기능만 제공하고, 타이어 정비사에게는 타이어 수리 기능만 제공해야 한다.
- 각 정비사는 자신이 맡은 부분에 필요한 장비와 정보만 제공받아야 한다.
장점:
각 정비사가 필요한 정보와 도구만 제공받으면 불필요한 작업을 하지 않게 되어 효율성이 증가
각자 필요한 기능에만 집중하므로 작업 흐름이 간단하고 명확해진다.
5. 의존성 역전 원칙 (Dependency Inversion Principle, DIP)
설명: 상위 모듈이 하위 모듈에 의존하지 않고, 추상화된 인터페이스에 의존해야 한다는 원칙.
- 정비소의 매니저는 각 정비사의 구체적인 작업 방법에 의존하지 않고, 표준 절차와 매뉴얼(추상화된 지침, 수리라는 작업) 에 의존.
- 예를 들어, 엔진 정비사나 타이어 정비사가 어떤 방식으로 수리하는지에 대해 매니저는 세부적으로 알 필요가 없다.
매니저는 정비사가 해당 매뉴얼에 맞춰 작업을 진행하는지 확인하기만 하면 된다.
장점:
매니저는 구체적인 작업 방식에 상관없이 표준 절차를 통해 정비소를 관리할 수 있고.
새로운 정비사가 들어와도 같은 매뉴얼에 따라 일할 수 있으므로, 새로운 사람을 고용하더라도 시스템이 쉽게 유지될 수 있다.
댓글