인프런 워밍업 클럽(백엔드 클린코드, 테스트 코드)-Day4 미션
출처: 인프런 워밍업 클럽 스터디 2기 - 백엔드 클린 코드, 테스트 코드 (Java, Spring Boot)
Readable Code: 읽기 좋은 코드를 작성하는 사고법
워밍업 클럽 스터디 백엔드 클린코드, 테스트 코드 day4 미션 내용 입니다.
미션 1. 코드 리팩토링
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
}
해당 코드를 리팩토링 해야 한다.
먼저 이 메서드가 동작하는 과정을 보면
order에Items가 있는지 체크를 한다.- 있으면 다음으로 없으면
false를 리턴한다.
- 있으면 다음으로 없으면
order에totalPrice가 0 이상인지 체크한다.- 0 이상이라면 다음으로 넘어간다.
- 0 이하라면 또(?) 검사하고,
false를 리턴한다.
hasCustomerInfo로 사용자 정보를 체크한다.- 있으면
true를 리턴하고, 없으면false를 리턴한다.
- 있으면
다음과 같이 검증을 하는 로직이다.
이를 리팩토링 해보자.
먼저 나는 if-else 가 필요하지 않을 것 같아서 다 분리하겠다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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;
}
이제 return false보다는 오류 메시지를 넘겨서 확실하게 표현 해주자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public boolean validateOrder(Order order) {
if (order.getItems().size() == 0) {
throw new IllegalArgumentException("주문 항목이 없습니다.");
}
if (!(order.getTotalPrice() > 0)) {
throw new IllegalArgumentException("올바르지 않은 총 가격입니다.");
}
if (!order.hasCustomerInfo()) {
throw new IllegalArgumentException("사용자 정보가 없습니다.");
}
return true;
}
마지막으로 if문 안에 조건을 하나의 로직 보다는 추상화를 하여, 다른 사람들이 읽어도 이해가 될 수 있게 바꾸자.
order.getItems().size() == 0->orderHasNoItems()- 오더가 아이템이 없는가?
!(order.getTotalPrice() > 0)->isTheTotalPriceZero()- 전체 가격이 0인가? (의미가 좀 다른거 같은데.. 0 이하인가)
!order.hasCustomerInfo()->orderHasNoCustomerInfo()- 오더가 사용자정보를 가지고 있는가?
(영어가 ㅎㅎ..)
그럼 전체 코드를 보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class OrderService {
public boolean validateOrder(Order order) {
if (orderHasNoItems(order)) {
throw new IllegalArgumentException("주문 항목이 없습니다.");
}
if (isTheTotalPriceZero(order)) {
throw new IllegalArgumentException("올바르지 않은 총 가격입니다.");
}
if (orderHasNoCustomerInfo(order)) {
throw new IllegalArgumentException("사용자 정보가 없습니다.");
}
return true;
}
private static boolean orderHasNoCustomerInfo(Order order) {
return !order.hasCustomerInfo();
}
private static boolean isTheTotalPriceZero(Order order) {
return order.getTotalPrice() <= 0;
}
private static boolean orderHasNoItems(Order order) {
return order.getItems().isEmpty();
}
}
사실 아래 private 메서드는 Order 객체 내에 선언하면 더 좋을것 같지만, 오늘은 여기다 만들었다.
미션 2. SOLID 정리
내가 생각하는 SOLID를 정리해 본다.
Single Responsibility Principle (SRP) - 단일 책임 원칙
- 하나의 클래스는 하나의 책임만 가져야 한다.
- 클래스를 작은 단위로 나누어 책임을 명확하게 해서 코드를 더 이해하기 쉽고, 변경에 유연하게 만들 수 있다.
- 내가 생각하기에 하나에 집중하기도 어려운데 두가지 일을 하려하면 분명 문제가 발생한다..
Open/Closed Principle (OCP) - 개방-폐쇄 원칙
- 소프트웨어 요소(클래스, 모듈 등)은 확장에는 열려있고, 변경에는 닫혀있어야 한다는 원칙
- 기존 코드를 수정하지 않고, 새로운 기능을 추가할 수 있도록 설계해야 한다.
- 기존걸 건들면 어떤 일이 벌어질 지 모른다. 달리는 마차에서 바퀴를 바꿔 끼워야 한다.
Liskov Substitution Principle (LSP) - 리스코프 치환 원칙
- 자식 타입은 언제나 부모 타입으로 교체할 수 있어야 한다.
- 자식 클래스를 사용중인 자리에 부모 클래스를 꼽아도 이상이 없어야 한다.
- 즉 자식은 부모의 행동을 따를 수 있어야 한다.
- 내가 생각하는 이 원칙은 약속이라고 생각한다.
Interface Segregation Principle (ISP) - 인터페이스 분리 원칙
- 인터페이스는 클라이언트가 자신이 사용하지 않는 메서드에 의존하지 않도록 작게 분리되어야 한다.
- 클라이언트가 그 안이 어떻게 돌아가는지 이해할 필요가 없다. 클라이언트한테 원하는 결과만 잘 전달하면 된다.
Dependency Inversion Principle (DIP) - 의존 역전 원칙
- 고수준 모듈은 저수준 모듈에 의존하면 안되고, 둘 다 추상화에 의존해야 한다. 즉, 구체적인 클래스에 의존하는 것이 아니라 인터페이스나 추상 클래스에 의존해야 한다.
- 개발을 하면서 구체적인 클래스를 다 의존해놓으면 만약에 다른 구현체로 바꿀려면 진짜 다바꿔야 한다.
- 인터페이스로 의존해놨으면 그냥 생성자 주입 같은걸로 바꿔주기만 하면 된다.
댓글남기기