관리 메뉴

너와 나의 스토리

TDD, 클린 코드 with Java 16기 수강 후기 & 피드백 정리 본문

개발

TDD, 클린 코드 with Java 16기 수강 후기 & 피드백 정리

노는게제일좋아! 2023. 4. 8. 01:14
반응형

현재 TDD, 클린 코드 with Java 16기를 수강 중이며, 피드백 내용은 계속해서 추가 중입니다.

 

 

수업 형식

  • 격주에 한 번씩 라이브 강의
    • 수업 종료 후에도 녹화된 영상을 볼 수 있습니다.
  • 일주일에 두 번 조끼리 토론하는 시간 있음. 
    • 고민 포인트나 과제를 하면서 토론하고 싶은 부분이 있으면 이 시간을 이용하시면 됩니다.
  • 매주 과제가 있고, PR을 올리면 리뷰어 분들이 24시간 내에 comment를 달아주십니다. 
  • PR에 질문을 올리거나, Slack의 DM을 통해 질문할 수 있습니다.

 

 

 

코드 개선

  • assertj를 사용하여 검증하라
    • 존 코드의 경우 단순히 결과와 기대값이 동일한지만 비교하고 있다. 즉, 어떤 연산이 이루어졌는지와 결과값이 어떤 건지에 대한 정보가 없다.
    • 반면, assertj를 사용하면 검증 대상과 기댓값을 더 명시적으로 작성할 수 있다. 
    • 예외 발생 검증도 assertj에서 제공해주는 메서드를 사용하면 메시지도 함께 검증할 수 있다.
<Ex 1: assertj에서 제공하는 컬렉션의 사이즈를 검증하는 메서드 사용>

// 기존 코드
assertEquals(3, numbers.size());

// 수정한 코드
assertThat(numbers).hasSize(3);


<Ex 2: assertj에서 제공하는 특정 원소를 포함하고 있는지 검증하는 메서드를 사용>
// 기존 코드
@ValueSource(ints = {1, 2, 3})
void testFindValueInSet(int input) {
    assertTrue(numbers.contains(input));
}

// 수정한 코드
@ValueSource(ints = {1, 2, 3})
void testFindValueInSet(int input) {
    assertThat(numbers).contains(input);
}

<Ex 3: assertj에서 제공하는 예외 발생 검증 메서드 사용>
// 기존 코드
assertThrows(StringIndexOutOfBoundsException.class, ()-> input.charAt(-1));

// 수정한 코드
assertThatThrownBy(() -> input.charAt(-1))
                .isInstanceOf(IndexOutOfBoundsException.class)
                .hasMessageContaining("String index out of range: -1");
  • 들여쓰기 간격 등 잘 확인하기 (Reformat Code 까먹지 않기)
  • 파일 마지막 newline 꼭 넣어주기
    • 이유 1: Java 컴파일러 및 인터프리터는 코드를 처리할 때, 파일의 마지막이 개행 문자(newline)으로 끝나는 것을 요구
      • 만약 파일의 마지막에 개행 문자가 없다면 컴파일러나 인터프리터는 파일의 끝을 처리하지 못하고 오류를 발생시킬 수 있습니다.
    • 이유 1: 코드 스타일의 일관성을 유지하기 위해
      • 마지막 줄에 개행 문자를 포함하는 것은 Java 코드 스타일 가이드에서도 권장되는 사항 중 하나
    • intellij에서 파일 끝에 자동으로 개행 문자 추가하는 방법:
      • 쉬프트 키 두번 눌러 검색 창 열고 "Ensure every saved file ends with a line break" 검색 -> 체크 박스 
  • static method만 가지는 utility class는 private 생성자를 가지도록 구현한다.
  • null / empty에 대한 테스트를 할 때에는 다음의 어노테이션을 쓸 수 있다.
    • @NullSource: 매개변수에 null 값 전달
    • @EmptySource: 매개변수에 빈 문자열 전달
    • @NullAndEmptySource: 매개변수에 null과 빈 문자열 둘 다 전달
@ParameterizedTest
@DisplayName("계산식이 공백이면 예외를 리턴한다.")
@NullAndEmptySource
void testThrowExceptionWhenExpressionIsBlank(String expression) {
    assertThatIllegalArgumentException().isThrownBy(() -> new Expression(expression));
}
  •  

 

자주 실수하는 부분

  • 클래스 내에서만 사용하는 필드는 private 접근 제어자 사용
  • if문 쓸 때는 중괄호를 사용해서 코드 블록으로 관리하기
  • 메서드 순서 (배치 기준)
  • 기능을 더 나눌 수 있는지 생각하기 -> 클래스 또는 메서드 분리

 

 

디미터 법칙 (The Law of Demeter)

  • 객체 지향 프로그래밍에서 클래스 간의 결합도를 낮추기 위한 원칙 중 하나.
  • 객체는 다른 객체에 대해 제한된 지식만 가져야 한다.
  • 예:
public class RacingCars {
    private final List<Car> cars;

    //...
    
    public List<Car> getWinner() {
        int largestPosition = cars.stream()
                .mapToInt(Car::getPositionValue)
                .max()
                .orElse(0);
        return cars.stream()
                .filter(car -> car.getPositionValue() == largestPosition)
                .collect(Collectors.toList());
    }
}
  • 위 예제는 RacingCars 객체에서 우승자를 반환하는 코드이다. 이를 위해 Car 객체로부터 position 값을 가져와 비교하고 있다.
  • 이는 RacingCars 객체가 Car 객체의 내부 정보에 접근하는 것이므로 디미터 법칙에 어긋난다. 
  • 수정
    • Car 객체에게 해당 위치에 있는지 물어보는 형태로 수정.
    • 이렇게 수정하면 Car 내부의 구현이 변해서 RacingCars의 코드를 수정하지 않아도 된다.
public List<Car> getWinner() {
    CarPosition largestPosition = getLargestCarPosition();
    return cars.stream()
            .filter(car -> car.isAt(largestPosition))
            .collect(Collectors.toList());
}

private CarPosition getLargestCarPosition() {
    int largestPosition = cars.stream()
            .mapToInt(Car::getPositionValue)
            .max()
            .orElse(0);
    return new CarPosition(largestPosition);
}

 

반응형
Comments