개발공부/Clean Code

[클린코드] 함수

개발자 찐빵이 2021. 12. 8. 23:56
728x90

함수를 만들 때 고민해야 하는 것

  • 의도를 분명히 표현하는가?
  • 어떤 속성을 부여해야 읽는 사람이 직관적으로 파악할 수 있을까?

1. 최대한 작게 만들자

함수가 작을수록 이해하기 쉽다.
그럼 얼마나 작아야 할까?

조건문이 들어가는 블록은 한 줄이어야 한다.
함수에서 중첩 구조를 지양하자.
들여 쓰기 수준은 1단이나 2단을 넘지 않는 게 좋다.

또한 함수를 구성할 때 추상화 수준이 높은 단계부터 낮은 단계로 내려가면서 배치해야 한다.

2. 한 가지만 하자

함수를 만드는 이유는 큰 개념을 추상화 수준에서 여러 단계로 작게 나눠서 수행하려는 것인데,
하나의 함수 안에서 여러 단계를 처리하면 복잡해진다.

함수가 한 가지 작업만 하는지 판단하는 방법

  • 함수 내 추상화 수준이 동일한 단계만 수행한다면 그 함수는 한 가지 작업만 한다.
  • 함수 내 작업을 섹션을 나눌 수 있으면 여러 작업을 하는 셈이다.

3. Switch 문을 팩토리로 변경하자

Switch 문의 단점

  • 작게 만들기 어렵다.
  • 한 가지 작업만 하기 어렵다.

N가지 작업을 하는 Switch문은 추상 팩토리로 변경할 수 있다.
switch문을 꽁꽁 숨겨서 적절한 Employee 파생 클래스의 인스턴스를 생성한다.

예시

public abstract class Employee
{
    public abstract boolean isPayday();
    public abstract Money calculatePay();
    public abstract void deliverPay(Money pay);
}

public interface EmployeeFactory
{
    public Employee makeEmployee(EmployeeRecored r) throws InvalidEmployeeType;
}

public class EmployeeFactoryImpl implements EmployeeFactory
{
//각 타입에 따른 Employee 객체를 만들어서 각각의 함수를 호출한다.
    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);
        }
    }
}

Employee 객체를 생성할 때만 switch 문을 사용하고, 그 뒤는 사용하지 않아도 된다.
각 객체에 맞는 함수가 호출되기 때문이다.

4. 함수 인수

함수에서 이상적인 인수는 0개(무항)이다.
많이 쓰는 형식은 1개(단항)이고, 3항은 가능하면 피하는 게 좋다.

아규먼트가 많은 함수는 이해하기 어렵다.
인수가 여러 개 필요하다면 일부를 독자적인 클래스 변수로 선언할 수 있는지 꼭 확인해봐야 한다.
또는 아규먼트들을 객체로 묶을 수 있는지 확인해야 한다.

5. Try/Catch 블록 뽑아내기

try/catch 블록은 코드 구조에 혼란을 일으키며, 정상 동작과 오류 처리 동작을 뒤섞는다.
따라서 try/catch 블록을 별도 함수로 뽑아내는 편이 좋다.

6. 중복을 제거하자

중복은 코드 길이를 늘리고 오류를 만들 확률이 높다.

결론

이름 변경, 중복 제거, 순서 변경 등 코드를 다듬자.
꼭 단위 테스트도 빼먹지 않기!

반응형