[우아한테크코스 프리코스] 코드리뷰 피드백 정리

이상현·2023년 11월 26일
0

Java

목록 보기
19/21

우아한테크코스 프리코스

우아한테크코스 백엔드 6기 프리코스가 끝났다.

진행중에 매주 과제를 코드리뷰 받으며 개선해나갔다.

그 때 피드백 받은 점들을 정리해보자.

클린코드

  • 클린코드 원칙을 억지로라도 지켜보자. 가독성이 높아지는것을 느낄 수 있다.

  • 문자열 같은거 다국어 지원까지 생각하면 별도로 관리하는게 맞다. 다만 간단할 경우 그냥 View에서 관리.

  • 원시값 포장 했는데 막장 getter 밖에 안쓰면 그냥 원시값으로 두는게 나을수도 있다.

  • 변수 이름 작성의 모든 기준은 보는 사람이 헷갈리지 않게.

  • 연결된 코드끼리 근처에 두기

  • 로직 잘 생각해서 쓸모없는 변수 줄이기

객체지향

  • 객체를 객체답게
    필요없는 상태 저장 X, 상태보다는 메세지 전달

  • getter는 View에서 사용할 데이터를 전달할 때 말고는 최대한 사용을 지양하는게 좋다. 객체끼리 메세지를 주고 받아야지 상태를 주고받으면 안된다. 참고

  • 추상화 되어있거나 가능성 있는 클래스만 의존성 주입 하기

  • 컬렉션은 안전성(불변성 보장)과 역할 분리를 위해 일급 컬렉션으로 사용하는게 좋다.
    게터에서는 Collections.unmodifiableList() 사용

메소드

  • 성능이 조금 떨어지더라도 메소드의 역할을 명확히 구분하는게 더 좋다.

  • 한 메소드가 진짜 한가지 일만 하고 있는지 다시 생각해보기.

  • boolean 메소드와 validate 메소드는 구분하라. 여러 비교를 하는 로직을 따로 분리해서 그것을 validate 메소드의 if 문에서 호출해라.

객체 (클래스)

  • 사용자 입력에 대한 기본적인 검증과 정제는 View 에서 수행해도 된다.
    ex) view/InputUtil.class

  • 객체 생성 과정에서 유효성 검사를 하고, 변환은 dto를 이용하면 된다.

  • 필드(=인스턴스 변수) 가 많으면 복잡도가 높아 버그 발생 가능성이 높아지므로 줄이기 위해 노력하기.

  • final 이면 굳이 private으로 접근 막을필요 없다.
    (하지만, 기술적으로는 문제 없다고 해도 코드 일관성도 중요하다. 유지보수 가능성까지 생각하면 그냥 private 필드와 public 게터를 사용하는것도 괜찮다.)

  • 인터페이스 추상화, 상속 등 클래스 구조 합리적으로 잘 짜기
    (쓸데없이 많아도 알아보기 힘들다)

  • 추상클래스 접근지정자 잘 알고 쓰기

  • static 메소드만 있으면 생성자 private로 인스턴스 생성 막기

  • 디폴트 생성자 사용하기. 같은 패키지에서만 쓸꺼면!

패키지

  • 돌아가는 쓰레기를 일단 구현하라고 하지만 그래도 처음부터 domain, controller, view 정도는 분리하고 시작하기.

  • 예외 메세지 문자열을 만든다면 View에서 만들어야지 domain등 다른곳에서 만들 필요가 없다.

  • 게임 진행에 대한 책임은 컨트롤러가 아닌 모델이다. 컨트롤러는 입력값 전달과 메세지 전송, 결과값 수신만 하면 된다.

  • domain 에서 view로 데이터를 보낼 때 복잡하다면 DTO (ex 자바 record) 적극 고려하기

예외처리

  • 원래 존재하는 예외를 상속받은 임의 예외 클래스를 만들어서 사용하면 관리가 편하다.

    public class ChristmasEventException extends IllegalArgumentException {
        private static final String PREFIX = "[ERROR]";
        private static final String FRONT_MESSAGE = "유효하지 않은";
        private static final String LAST_MESSAGE = "입니다. 다시 입력해 주세요.";
    
        public ChristmasEventException(String element) {
            super(String.format("%s %s %s%s", PREFIX, FRONT_MESSAGE, element, LAST_MESSAGE));
        }
    }
    public class OrderedMenuException extends ChristmasEventException{
        private static final String ORDER = "주문";
    
        public OrderedMenuException() {
            super(ORDER);
        }
    }
  • 에러메세지는 enum타입을 사용하면 좋다.

    public enum ErrorMessage {
      INPUT_IS_EMPTY("입력값은 비어있을 수 없습니다."),
      INPUT_NOT_A_NUMBER("입력값은 숫자여야 합니다."),
      INPUT_NOT_POSITIVE_NUMBER("입력값은 자연수여야 합니다.");
    
      private final String message;
    
      ErrorMessage(String message) {
          this.message = message;
      }
    
      public String getMessage() {
          return message;
      }
    }

테스트

  • 테스트는 개념당 하나의 메소드.

  • 테스트 코드도 읽는 사람 생각해서 가독성 좋게 작성하기

  • 랜덤값 같은 테스트 어려운 것은 인터페이스를 만들어서 구현체를 전달하는 방식(의존성 주입)으로 구현하면 테스트가 편하다.

  • Junit의 @Nested 어노테이션으로 테스트 클래스에 계층 구도를 만들면 가독성이 올라간다.

  • 테스트 코드에서만 사용되는 코드는 main 말고 tests/ 내부에 작성

  • ParameterizedTestCsvSorce, ValueSource, ArgumentsSource 등 활용 잘 하기

  • 작은 단위부터 작성하고 빠른 피드백을 받는것이 중요하다.

  • 테스트로 예외 확인할때, 메세지까지 확인하자. (hasMessage())

  • 예외 상황 잘 파악해서 테스트 하기

  • 테스트 분리는 가독성 상승에 좋다. 성능은 떨어져도 된다.

리팩토링

리팩토링 하다가 객체의 역할이 엇나가고 있지 않은지 잘 체크하기

Java

  • static 메소드는 프로그램 시작부터 종료까지 메모리가 해제되지 않아서 비효율적이고, 전역에서 접근 가능하니 객체지향에도 방해된다. 꼭 필요한 경우 (ex 여러 곳에서 사용 되는 경우)에만 사용하기

  • 문자열 포장은 전역에서 사용되는 값 아니면 진짜 필요한 클래스에서만 privte static final으로 선언해주는게 좋은것 같다. 또한 너무 enum 했다가 상수 묶었다가 하지 말고 코드베이스 일관성 유지하는것도 좋다

  • stream 은 컬렉션이 매우 클 때 아니면 for문보다 성능이 떨어진다. 하지만 가독성 측면에서 장점이 있기 때문에 마음껏 써도 된다.

  • Map의 본질은 Key로 Value를 찾는것 (Value에 아이디를 붙혀줄 때)

  • 출력문자 포맷 (":" 등)은 "%s:%s" 이런 식으로 포매팅 하는것이 좋다. 출력문자 문자열에는 \n, : 같은 문자 지양하자.

  • 문자열.isEmpty 는 빈 것만 잡지만 .isBlank는 공백도 같이 잡는다.

  • 클래스 내부에는 상수(또는 클래스 변수), 멤버(인스턴스) 변수, 생성자, 메소드 순으로 작성

  • 생성자로 컬렉션 받을때 얕은복사 주의. new List<>(inputList) 이렇게 다시 생성해주는게 좋다.

  • Map 전체를 순회하는건 나쁜 방식은 아니다. 단, 매우 큰 Map을 자주 순회할때나 순회 도중 요소를 변경하게 될 경우에는 다른 구조 고려

  • Java는 날짜 관련 API를 제공한다. 기본 제공 API 잘 활용하기.

  • 형식이 쓸데 없이 복잡할 때 var 사용 고려 ex) for문 안에서 임시 변수

  • Map.of 로 맵 만들면 진짜 상수라서 상수 네이밍 가능하다. (List.of 등 포함)

  • Collector.joining 하면 출력 형식 만들 때 좋다.

정규 표현식

  • 정규 표현식은 유지보수가 힘들 수 있으니 웬만하면 로직 활용해서 하기

  • 정규식을 간단하게 사용할 때 (일치하는지)는 String.matches, 복잡하게 사용할 때(일치한 부분 모두 찾기 등)는 Pattern.matcher를 사용하자.

개발 이외

  • README 는 소스코드 이전에 어떤 프로젝트인지 소개하는 문서이다.

  • README에 요구사항이나 적용할 법칙같은 것 정리하고 시작해도 좋다. 하지만 기능 목록을 너무 상세하기 적지 말고 차라리 예외상황을 잘 파악해라. (계속 업데이트 하는것이 좋다.)

  • 단어 일관성 유지 하기. ex) increase라고 한번 썼으면 rise 같은 유의어 대신 쭉 increase 사용

  • 놓치는 부분이 무조건 있을 수 밖에 없으니 꼼꼼히 살피기 (접근지정자. 객체역할, 필요없는 로직 or 메소드 등)

0개의 댓글