[클린 코드] TIL 함수 - 2022.04.26

컴클로딩·2022년 4월 26일
0

클린코드

목록 보기
4/5
post-thumbnail

DAY 5

오늘 공부한 범위 : 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")와 같은 코드는 추상화 수준이 아주 낮다. 라는 구절에서 추상화 수준 단계에 대해서도 궁금하다.
  • (p.47) SRP를 위반한다. OCP를 위반한다. 와 같이 객체지향프로그래밍의 5대 원칙 SOLID 중 Single Responsibility Principle과 Open Closed Principle에 관해 나오는데 SOLID에 대해 정확히 몰라 어떻게 위반했는지 잘 모르겠다.
  • (p.54) 부수 효과를 일으키지 마라! 에서 부수효과는 무엇인가?
profile
어떠한 가치를 창출할 수 있을까를 고민하는 개발자. 주로 Spring으로 개발해요. https://comclothing.tistory.com/ 👈🏻티스토리 블로그로 이전 완료

0개의 댓글