[클린코드] 6일차 - 좋은 함수를 위한 n가지 주의사항
클린코드 6일차 (p. 46~56(3장) )
3 함수
3. 함수 당 추상화 수준은 하나로!
- 함수가 확실히 '한 가지' 작업만 하려면 함수 내 모든 문장의 추상화 수준이 동일해야한다.
- 한 함수 내에 추상화 수준을 섞으면 코드 읽는 사람이 헷갈린다.
위에서 아래로 코드 읽기: 내려가기 규칙
4. Switch 문
- switch 문은 작게 만들기 어렵다.
- 본질적으로 switch문은 N가지를 처리한다.
- 하지만 각 switch 문을 저차원 클래스에 숨기고 절대로 반복하지 않는 방법이 있는데, '다형성'을 이용하는 것이다.
public Money calculatePay(Employee e)
throws InvalidEmployeeType {
switch (e.type) {
case COMMISSIONED :
return calculateCommissionedPay(e);
case HOURLY :
return calculateHourlyPay(e);
case SALARIED :
return calculateSalariedPay(e);
default :
throw new InvalidEmployeeType(e.type);
}
}
위 함수의 문제는 다음과 같다.
- 함수가 길다. (직원 유형 추가 시 더 길어진다)
- 한 가지 작업만 수행하지 않는다.
- SRP(Single Responsibility Principle)을 위반한다. (코드를 변경할 이유가 여럿이다)
- OCP(Open Closed Principle)을 위반한다.
이 문제를 해결한 코드는 다음과 같다. 이렇게 상속 관계로 숨긴 후 절대 다른 코드에 노출시키지 않는다.
public abstract class Employee {
public abstract boolean isPayday();
public abstract Money calcuatePay();
public abstract void deliverPay(Money pay);
}
public interface EmployeeFactory{
public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;
}
public class EmployeeFactoryImpl implements EmployeeFactory {
public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType {
switch (r.type) {
case COMMISSIONED :
return new CommissionedEmployee(r);
case HOURLY :
return new HourlyEmployee(r);
case SALARIED :
return new SalariedEmployee(r);
default:
throw new InvalidEmployeeType(r.type);
}
}
}
5. 서술적인 이름을 사용하라!
- 이름을 붙일 때는 일관성이 있게.
- 모듈 내에서 함수 이름은 같은 문구, 명사, 동사를 사용하자.
boolean isTestable
void includesetupAndTeardownPages
6. 함수 인수
- 다음은 1개고, 다음은 2개다. 3개는 가능한 피하는 편이 좋다.
- 최선은 입력 인수가 없는 경우이며, 차선은 입력 인수가 1개 뿐인 경우다.
- SetupTeardownIncluder.render(pageData)는 아주 이해하기 좋은 케이스다.
7. 부수 효과를 일으키지 마라!
- 함수에서 한 가지를 하겠다고 약속해놓고선 다른 일을 하면 안 된다.
8. 명령과 조회를 분리하라!
- 함수는 무언가를 수행하거나, 무언가를 답하거나 둘 중 하나만 해야한다.
- ex) 객체 상태 변경 / 객체 정보 반환
public boolean set(String attribute, String value);
위 함수는 이름이 attribute인 속성을 찾아, 값을 value로 설정한 후 성공하면 true를 반환하고 실패하면 false를 반환한다.
이렇게 함수를 구성했을 때, if(set("username, "unclebob"))와 같은 요상한 코드가 발생할 수 있다.
set이 동사인지 형용사인지에 따라 의미가 달라지기 때문이다.
if(attributeExists("username")){ // 조회
setAttribute("username", "unclebob"); // 명령
}
'알아두면쓸데있는신기한잡학사전 > 독서일지' 카테고리의 다른 글
[클린코드] 8일차 - 나쁜 코드에 주석을 달지 마라. 새로 짜라. 하지만 좋은 주석은 분명히 있다. (2) | 2023.11.01 |
---|---|
[클린코드] 7일차 - 오류 보단 예외처리, 그리고 클린코드로 인한 중복 알레르기 (1) | 2023.10.31 |
[클린코드] 5일차 - 분명한 이름을 위한 의미있는 맥락(Context) 부여, 함수는 한 가지 일만. (1) | 2023.10.29 |
[클린코드] 4일차 - 의미 있는 이름 짓는 시간은 유의미하다. (2) | 2023.10.27 |
[클린코드] 3일차 - 의미 있는 이름은 어떻게 지을까? (2) | 2023.10.25 |