새소식

ETC

[클린 코드] 3장 함수

  • -
반응형

오늘 공부한 범위 : 3장. 함수

📘 책에서 기억하고 싶은 내용


  • (p.42) 함수를 만드는 첫째 규칙은 '작게!'다. 함수를 만드는 둘째 규칙은 '더 작게!'다.
    • 함수는 100줄을 넘어서는 안 된다. 아니 20줄도 길다.
    • 블록과 들여쓰기
      • 다시 말해, if 문/els e문/while 문 등에 들어가는 블록은 한 줄이어야 한다는 의미다. 대게 거기서 함수를 호출한다. 그러면 바깥을 감싸는 함수(enclosing function)가 작아질 뿐 아니라, 블록 안에서 호출하는 함수 이름을 적절히 짓는다면, 코드를 이해하기도 쉬워진다.
  • (p.44) 함수는 한 가지를 해야 한다. 그 한 가지를 잘 해야 한다. 그 한 가지만을 해야 한다.
    • 여기서 말하는 한 가지는 추상화 수준이 하나인 단계만 수행하는 것을 의미한다.
    • 위에서 아래로 코드 읽기 : 내려가기 규칙
      • 한 함수 다음에는 추상화 수준이 한 단계 낮은 함수가 온다.
      • 즉, 위에서 아래로 프로그램을 읽으면 함수 추상화 수준이 한 번에 한 단계씩 낮아진다.
  • (p.47) switch 문은 작게 만들기 어렵다. 본질적으로 switch 문은 N가지를 처리한다.
    • 각 switch 문을 저차원 클래스에 숨기고 절대로 반복하지 않는 방법이 있다. 물론 다형성(polymorphism)을 이용한다.

나쁜 코드
목록 3-4 Payroll.java

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);
    }
}

  • (p.47) 목록 3-4 위 함수에는 몇가지 문제가 있다.
    1. 함수가 길다.
    2. '한 가지' 작업만 수행하지 않는다.
    3. SRP(Single Responsibility Principle) 단일 책임 원칙을 위반한다.
    4. OCP(Open Closed Principle) 개방-폐쇠 원칙을 위반한다.
    5. 가장 큰 문제는 isPayday(Employee e, Date date); 혹은 deliverPay(Employee e, Money pay); 같이 구조가 _동일한 함수가 반복_하는 것이다.

변경된 코드
목록 3-5 Employee and Factory

public abstract class Employee {
    public abstract boolean isPayday();
    public abstract Money calculatePay();
    public abstract void deliverPay(Money pay);
}
----------------
pubic 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);
        }
    }
}

  • (p.48) 이 문제를 해결한 코드가 목록 3-5다.
    • switch 문을 추상 팩토리(ABSTRACT FACTORY)에 꽁꽁 숨긴다. 아무에게도 보여주지 않는다.
    • 팩토리는 switch 문을 사용해 적절한 Employee 파생 클래스의 인스턴스를 생성한다.
    • calculatePay, isPayday, deliverPay 등과 같은 함수는 Employee 인터페이스를 거쳐 호출된다. 그러면 다형성으로 인해 실제 파생 클래스의 함수가 실행된다.
  • (p.49) 일반적으로 나는 switch 문을 단 한 번만 참아준다. 다형적 객체를 생성하는 코드 안에서다. 이렇게 상속 관계를 숨긴 후에는 절대로 다른 코드에 노출하지 않는다.
  • (p.49) 서술적인 이름을 사용하면 개발자 머릿속에서도 설계가 뚜렷해지므로 코드를 개선하기 쉬워진다.
    • 모듈 내에서 함수 이름은 같은 문구, 명사, 동사를 사용한다.
    • 좋은 예. includeSetupAndTeardownPages, includeSetupPages, includeSuiteSetupPage, includeSetupPage 등
  • (p.50) 함수 인수
    • 0개(무항) : 이상적인 인수 개수
    • 1개(단항) : 그 다음으로 이상적인 인수 개수
    • 2개(이항) : 그 다음으로 이상적인 인수 개수
    • 3개(삼항) : 가능한 피하는 편이 좋다.
    • 4개(다항) : 특별한 이유가 필요하다. 특별한 이유가 있어도 사용하면 안 된다.
  • (p.51) 이벤트 함수는 조심해서 사용한다. 이벤트라는 사실이 코드에 명확히 드러나야 한다. 그러므로 이름과 문백을 주의해서 선택한다.
  • (p.54) 부수 효과를 일으키지 마라!
  • (p.56) 명령과 조회를 분리하라!
  • (p.57) 오류 코드보다 예외를 사용하라.
  • (p.60) 반복하지 마라!
  • (p.61) 그러므로 함수를 작게 만든다면 간혹 return, break, continue를 여러 차례 사용해도 괜찮다. 오히려 때로는 단일 입/출구 규칙보다 의도를 표현하기 쉬워진다.
  • (p.61) 내가 함수를 짤 때도 마찬가지다. 처음에는 길고 복잡하다. 들여쓰기 단계도 많고 중복된 루프도 많다. 인수 목록도 아주 길다. 이름은 즉흥적이고 코드는 중복된다. 하지만 나는 그 서투른 코드를 빠짐없이 테스트하는 단위 테스트 케이스도 만든다.
    그런 다음 나는 코드를 다듬고, 함수를 만들고, 이름을 바꾸고, 중복을 제거한다. 때로는 전체 클래스를 쪼개기도 한다. 이 와중에도 코드는 항상 단위 테스트를 통과한다.
  • (p.62) 함수는 그 언어에서 동사며, 클래스는 명사다. 프로그래밍 언어라는 수단을 사용해 좀 더 풍부하고 좀 더 표현력이 강한 언어를 만들어 이야기를 풀어간다.
  • (p.62) 여기서 설명한 규칙을 따른다면 길이가 짧고, 이름이 좋고, 체계가 잡힌 함수가 나오리라. 하지만 진짜 목표시스템이라는 이야기를 풀어가는 데 있다는 사실을 명심하기 바란다.

📗 오늘 읽은 소감


  • 3장 함수 부분을 보면서 이해가지 않는 부분도 있고 이해가는 부분에서는 이때까지 내가 짰던 코드가 클린하지 않다는 사실을 새삼 깨닫게되었다. 한 가지 함수에 여러 기능들을 넣었던 기억이 너무 많다. 특히 최근 진행했던 [Cafe24toSmartstore] 프로젝트에서 함수의 첫째 규칙 "작게!"를 너무 많이 어겼다. 그래서 한 번씩 내가 짰던 코드를 한 번씩 볼 때마다 이해가 잘 가지 않거나 헷갈리는 부분들이 있다. 이번에 클린 코드 책을 읽으면서 배웠던 점들을 차근차근 적용해보면서 최대한 프로젝트의 코드들을 클린하게 만들어봐야겠다.
  • 그나마 위안이 되었던 점은 이 책의 저자도 처음에는 길고 복잡한 코드를 쓰고 그 다음에 코드를 다듬는 작업을 한다고 한다. 조금 다르다면 처음부터 단위 테스트 케이스를 만든다는 점이다. 나도 이 책의 저자처럼 단위 테스트에 대해 따로 공부를 해서 TDD(Test Driven Development)를 적극 적용하도록 노력 해봐야겠다.

📙 궁금한 점, 잘 이해되지 않는 점


  • (p.45) 추상화 수준이란 말이 나오는데 추상화 수준은 무엇일까? 또한, (p.46) getHtml()은 추상화 수준이 아주 높다. String pagePathName = PathParser.render(pagepath); 는 추상화 수준이 중간이다. .append("\n")와 같은 코드는 추상화 수준이 아주 낮다. 라는 구절에서 추상화 수준 단계에 대해서도 궁금하다.
 

[CleanCode] 함수의 추상화 수준이란?

오랜만에 CleanCode를 다시 읽어보고 있는데 함수의 추상화 수준에서 책 읽기를 멈추고 3번 다시 읽었다. 아무래도 책의 추상화 수준이 높은 단계 였던 것 같다. "메서드는 한 가지만 해라!"라는 말

onestone-dev.tistory.com

  • (p.47) SRP를 위반한다. OCP를 위반한다. 와 같이 객체지향프로그래밍의 5대 원칙 SOLID 중 Single Responsibility Principle과 Open Closed Principle에 관해 나오는데 SOLID에 대해 정확히 몰라 어떻게 위반했는지 잘 모르겠다.
    • 아래 블로그리에 코드와 같이 잘 나와있음.
 

[OOP] 객체지향 프로그래밍의 5가지 설계 원칙, 실무 코드로 살펴보는 SOLID

이번에는 객체 지향 프로그래밍의 5가지 핵심 원칙인 SOLID에 대해 알아보고자 합니다. 실제로 애플리케이션을 개발할 때 어떻게 적용할 수 있을지 구체적인 예시를 들어 살펴보고자 합니다. 아

mangkyu.tistory.com

  • (p.54) 부수 효과를 일으키지 마라! 에서 부수효과는 무엇인가?
    • 부수효과 : 원래의 목적과 다르게 다른 효과 또는 부작용이 나는 상태를 지칭한다.
 

부수효과

용어정리이 카테고리는 비전공자로서 개발자로써 공부하며, 평소 이해하지 못한 단어를 제방식대로 정리하는 카테고리입니다.제방식대로 풀어 쓴것이므로 오류가 있을 수 있습니다.오류가 있

tuhbm.github.io

 

작성일자 : 2022년 4월 26일

반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.