대범하게

[클린코드] 6일차 - 좋은 함수를 위한 n가지 주의사항 본문

알아두면쓸데있는신기한잡학사전/독서일지

[클린코드] 6일차 - 좋은 함수를 위한 n가지 주의사항

대범하게 2023. 10. 30. 21:24
반응형

[클린코드] 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);
	}
}

위 함수의 문제는 다음과 같다.

  1. 함수가 길다. (직원 유형 추가 시 더 길어진다)
  2. 한 가지 작업만 수행하지 않는다.
  3. SRP(Single Responsibility Principle)을 위반한다. (코드를 변경할 이유가 여럿이다)
  4. 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"); // 명령
}
Comments