[클린코드] 3주차 회고 (7-9장)

Sheryl Yun·2023년 11월 2일
1

클린코드 회고

목록 보기
3/5
post-thumbnail

찰쓰 코치님, 병현님, 윤몬님, 한솔님, 나 5명 참여
1시간 5분 토론

주제 1: 테스트 코드도 실제 코드 못지 않게 중요할까?

책 157페이지
내 이야기가 전하는 교훈은 다음과 같다. 테스트 코드는 실제 코드 못지 않게 중요하다.

발제자 제안

  • 실무에서 테스트 코드를 실제 코드 못지 않게 구현하여 작성할 시간과 여유가 안 되는 것 같다.
  • 애초에 테스트 주도 개발(TDD)이 가능한가?

나눈 의견

  • 회사에서 테스트를 학습할 때 기존 백엔드의 유틸 함수를 바탕으로 다른 팀원들이 학습해서 작성할 수 있도록 함
  • 하지만 프론트엔드는 유틸 함수가 많아서 쉽지 않다.

프론트에 TDD를 적용하려는 노력

  • 한계: 테스트 커버리지를 어디까지 할 것인가?
  • 회사에서는 빨리 '구현'이 중요하다.
  • 그래도 테스트를 진행하기 위해 나름의 범위를 정함
    => util성 함수까지만 테스트
  • UI를 위한 E2E 테스트도 도입
    • 하지만 이건 관리할 시간이 부족
  • page of object pattern(?) 사용
    • 페이지 단위로 클래스를 넣어서 테스트를 작성했더니 assert문이 많았는데 줄어들었다.

TDD (테스트 주도 개발) 방식

  • 우선 실패하는 테스트 코드를 먼저 짠다.
  • 이후 이 테스트가 성공하는 코드를 짠다.
  • 테스트 코드를 바탕으로 실제 구현을 진행한다.
  • TDD 과정을 실무에서 과연 다 수행하는가? (시간이 모자람)
    • 테스트를 10개 하면 TDD는 1개 적용하는 것 같다는 하소연 (ㅠ.ㅠ)

TDD가 잘 되려면?

  • 탄탄한 기획이 뒷받침 되면 테스트가 수월해짐 (시간적 여유 확보, 테스트 단위 잡기 좋음 등)
  • mock 데이터가 많으면 테스트가 수월해짐
    => 결국 TDD가 지속되고 잘 되려면 개발팀 뿐만 아니라 전 조직 단위의 지원(예: 기획팀)이 필요하다. 다른 직무에도 TDD의 필요성을 공감하게 하고 성과를 공유하려는 노력 필요

주제 2: null 처리

책 139페이지
null을 반환하지 마라

발제자 제안

  • 책에 나온 예시 코드는 리스트여서 빈 리스트라는 대안을 제시했다.
    • 만약 다른 타입의 값들은 어떻게 해야할까? default 값을 주어야 할까?
  • 정말로 null을 인수로 전달하거나 반환하면 안될까?
  • 책에서는 '가능하다면' null을 반환하지 말자는 취지일 수도 있다.
  • 하지만 빈 리스트도 결국 빈 리스트(null)인지에 대한 확인 조건이 추가되어야 한다.

나눈 의견

  • 책에서는 null 대신 Exception을 던지라고 하고 있음 (자바 코드 기준)
    • 하지만 null이 필요할 때는 던져야
  • try/catch(throw Error~)로 되면 해결하고, 아니면 null도 괜찮음
  • 프론트엔드의 경우 DOM이 화면에 없을 때를 표현하기 위한 null 필요
  • 자바에서는 null을 싫어함 (NullPointerException)
  • 에러를 throw로 던지다보면 언젠가는 해결해야 함 (던진다고 끝나는 게 아님)

try/catch의 throw로 에러를 처리하면 좋은 점

  • 관심사를 모아서 처리
  • null보다는 더 전략적인 에러 처리

주제 3: 특수 사례 패턴 논의

책 138페이지
예제를 살펴보자. 다음은 비용 청구 애플리케이션에서 총계를 계산하는 허스한 코드다. (코드)

발제자 제안

책 코드 인용

try{
	MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
	m_total += expenses.getTotal();
} catch(MealExpensesNotFound e) {
	m_total += getMealPerDiem();
}

위의 코드를 더 간결하게 표현하면 아래와 같다.

MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
m_total += expenses.getTotal();

ExpenseReportDAO를 고쳐 언제나 MealExpense 객체를 반환하고, 청구한 식비가 없다면 일일 기본 식비를 반환하는 MealExpense 객체를 반환한다.

public class PerDiemMealExpenses implements MealExpenses{
	public int getTotal(){
		// 기본값으로 일일 기본 식비를 반환한다.
	}
}

그러나 expenseReportDAO는 MealExpenses를 상속 받는 것이지 PerDiemMealExpenses를 상속 받는 것이 아니기 때문에 기본 식비를 반환하지 못하는게 아닌지, 위 코드들에 대한 의논이 필요해보인다.

나눈 의견

  • 위 코드에 특수 사례 패턴이 있는가?
  • 아주 OOP스럽게 느껴짐
    • 기본 값을 따로 관리

(여기는 무슨 말인지 몰라서 오가는 얘기를 거의 이해하지 못함)

토론 중 노션에 추가된 코드

class expenseReportDAO {

  public getMeals(id) {
		res = repository.get(id)
		if res === null {
			// throw MealExpensesNotFound; 
			// return 1;
			return new PerDiemMealExpenses();  // 요거를 PerDiemMealExpenses 요거로 대체하고 싶었던 거 아닐까요?
		}

		return res; // MealExpense
	}
}

class PerDiemMealExpenses implements MealExpense {
		DEFAULT = 1;
		public int getTotal() {
			return DEFAULT;
		}
}

주제 4: 값을 내놓는 return보다 예외 처리를 먼저 하는 것이 더 좋은 코드인가?

책 141페이지
어떻게 고치면 좋을까? 다음과 같이 새로운 예외 유형을 만들어 던지는 방법이 있다. (코드)

발제자 의견

  • MetricsCalculator 메서드의 예외 처리 코드에서 예외 처리하는 조건 명시와 그에 따른 예외 처리를 먼저 실행하고 마지막에 return 을 하고 있다.
  • 코드를 위에서 아래로 읽어내려갈 때 이 메서드가 ‘언제 예외를 발생시킬지’ 보다 ‘어떤 기능을 하는지’를 먼저 명시하는 것이 읽기 좋지 않을까? 라는 생각을 했다.
  • 현업에서도 저는 기능 실행을 먼저 명시하는 코드 위주로 작성했지만 예외 처리(저의 경우에는 빠른 return)를 먼저 시도하는 것으로 변경하는 것이 좋다는 코드 리뷰를 받은 적이 있다.
  • 위 리뷰를 받고 나서 자세히 이유를 생각해보지는 못했었다보니 다른 분들의 의견이 궁금하다.

나눈 의견

  • 보통 throw(에러 처리)를 뒤로 빼는 게 가독성이 더 좋음
  • 조건문이 복잡하지 않다면 에러 처리를 뒤에서 하는 게..
  • 앞에 두면서 얼리 리턴(early return)을 할 수도 있고 뒤에서 처리할 수도 있고 (상황에 따라 달라질 수 있다)
  • 에러나 예외 처리는 아무래도 뒤에 두는 게 코드 가독성 측면에서 좋은 것 같다.
  • 얼리 리턴도 무조건 좋은 게 아니라 단점이 있음
    • 함수가 커지면 위에 리턴이 있으면서 아래에 또 있을 수 있음
    • 이렇게 에러 처리가 흩어져 있기보다 차라리 맨 아래에 두고 하나로 모아 두는 게 낫다.
  • (다른 의견) 앞에서 에러 처리를 하고 '이 함수가 하고자 하는 것'을 가장 마지막에 두는 방법?
    • 이 제안자의 경우 함수가 할 일을 맨 마지막에 두는 것이 오히려 더 가독성이 좋다고 봄

에러 처리 대신 기능 실행을 먼저 하는 코드 예시 (Java)

노션에 추가된 코드

public class MetricsCalculator
{
  public double xProjection(Point p1, Point p2) {
    if (p1 != null && p2 != null) {
      return (p2.x - p1.x) * 1.5;
    } else {
      throw InvalidArgumentException(
        "Invalid argument for MetricsCalculator.xProjection"
      );
    }
  }
}

노션에 공유된 자료

Early Return은 과연 좋은가?🔗

마지막 결론
Early Return은 들여쓰기를 줄여 코드를 간결하고 읽기 쉽게 만드는 좋은 방법입니다. 그러나 이 방법이 매번 적용될 수 있다는 의미는 아닙니다.
때때로 Early Return은 함수의 복잡도를 증가시키고 코드를 더 복잡하게 만들 수 있습니다. 그리고 리뷰어의 의견에서처럼, 간결한 코드에서는 오히려 if-else문이 더 명확할 수 있습니다.
따라서, 읽기 쉬운 코드를 작성하기 위해서는 상황에 맞게 적절한 패턴을 선택하는 것이 중요합니다. 무조건적인 Early Return보다는 맥락을 고려해야 합니다.

profile
데이터 분석가 준비 중입니다 (티스토리에 기록: https://cherylog.tistory.com/)

0개의 댓글