Book/Clean Code

Clean Code - 함수를 안전하고 간결하게 작성하기

블로그 주인장 2024. 3. 25.

Chapter 03. 함수

 

1. Solid

객체 지향 설계의 5가지 원칙

S.O.L.I.D 원칙

 

  1. SRP : 단일 책임 원칙(한 클래스는 하나의 책임만 가져야한다)
    1. 클래스는 하나의 기능만 가지며, 어떤 변화에 의해 클래스를 변경해야하는 이유는 오직 하나뿐이어야한다.
    2. SRP 책임이 분명해지기 때문에, 변경에 의한 연쇄 작용에 자유로워질 수 있다.
    3. 가독성 향상과 유지보수가 용이해진다.
  2. OCP : 개방-폐쇄 원칙(소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀있어야한다)
    1. 변경을 위한 비용은 가능한 줄이고, 확장을 위한 비용은 가능한 극대화해야한다.
    2. 요구사항의 변경이나 추가 사항이 발생하더라도, 기존 구성요소에는 수정이 일어나지 않고,
      기존 구성 요소를 쉽게 확장해서 재사용한다.
    3. 객체 지향의 추상화와 다형성을 활용한다.
  3. LSP : 리스크프 치환 원칙(서브 타입은 언제나 기반 타입으로 교체할 수 있어야한다)
    1. 서브 타입은 기반 타입이 약속한 규약(접근제한자, 예외 포함)을 지켜야한다.
    2. 클래스 상속, 인터페이스 상속을 이용해 확장성을 획득한다.
    3. 다형성과 확장성을 극대화하기 위해 인터페이스를 사용하는 것이 좋다.
    4. 합성(composition)을 이용할 수도 있다. 
  4. ISP : 인터페이스 분리 원칙(자신이 사용하지 않는 인터페이스는 구현하지 말아야한다)
    1. 가능한 최소한의 인터페이스만 구현한다.
    2. 만약 어떤 클래스를 이용하는 클라이언트가 여러 개이고, 이들이 클래스의 특정 부분만 이용한다면,
      여러 인터페이스로 분류하여 클라이언트가 필요한 기능만 전달한다.
    3. SRP가 클래스 단일 책임이라면, ISP는 인터페이스의 단일 책임이다. 
  5. DIP : 의존성 역전 원칙(상위 모델은 하위 모델에 의존하면 안된다. 둘 다 추상화에 의존해야한다.
                                               추상화는 세부사항에 의존해서는 안된다. 세부 사항은 추상화에 따라 달라진다)
    1.  하위 모델의 변경이 상위 모듈의 변경을 요구하는 위계 관계를 끊는다.
    2. 실제 사용 관계는 그대로지만, 추상화를 매개로 메시지를 주고 받으면서 관계를 느슨하게 만든다.
class PaymentController {
    @RequestMapping(value = "/payment", method = RequestMethod.POST)
    public void pay (@RequestBody CardPaymentDto.PaymentRequest req) {
        final CardPaymentService cardPaymentService = 
            cardPaymentFactory.getType(req.getType());
            
        cardPaymentService.pay(req);
    }
}

public interface CardPaymentService {
    void pay(CardPaymentDto.PaymentRequest req);
}

public class ShinhanCardPaymentService implements CardPaymentService { 
    @Override
    public void pay(CardPaymentDto.PaymentRequest req) {
        shinhanCardApt.pay(req);
    }
}

추상화된 인터페이스에 의존하도록 만든다(예시)

 

 

2. 간결한 함수 작성하기

public static String renderPageWithSetupsAndTeardowns(PageData pageData, boolean isSuite)
    throws Exception { 
    if (isTestPage(pageData)) {
        includeSetupAndTeardownPages (pageData, isSuite);
    }
    
    return pageData.getHtml();
}
  1. 함수를 작게 쪼갠다
  2. 함수 내 추상화 수준을 동일하게 맞춘다.
    • private 메서드로 분리화 해서 추상화 수준이 비슷한 메서드끼리 묶어서 분류해준다.

 

public abstract class Employee {
    public abstract boolean isPayday();
    public abstract Money calculatePay();
    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 SalariedEmploye(r); 
        default:
            throw new InvalidEmployeeType(r.type);
        }
    }
}
  1. 계산의 타입 관리를 분리한다.
  2. 타입에 대한 처리는 최대한 Factory 내에서만 진행한다.

 

함수 인수

  • 인수의 갯수는 0 ~ 2개가 적당하다.
// 객체를 인자로 넘기기 👍
Circle makeCircle(double x, double y, double radius); //👎
Circle makeCircle(point center, double radius); //👍

// 가변 인자를 넘기기 -> 특별한 경우가 아니면
String.format(String format, Object... args);

 

 

3. 안전한 함수 작성하기

부수효과(Side Effect) 없는 함수

  • 부수효과 : 값을 반환하는 함수가 외부 상태를 변경하는 경우이다.
  • 함수 기능과 상관없는 다른 외부 상태를 변경시키는 동작을 하는 경우가 있어서는 안 된다.

 

4. 함수 리팩터링

 

 

 

 

본 포스트는 작성자가 공부한 내용을 바탕으로 작성한 글입니다.
잘못된 내용이 있을 시 언제든 댓글로 피드백 부탁드리겠습니다.
항상 정확한 내용을 포스팅하도록 노력하겠습니다.

반응형

'Book > Clean Code' 카테고리의 다른 글

Clean Code - 깨끗한 코드와 의미 있는 이름  (0) 2024.03.21

댓글