차곡차곡 성 쌓기
article thumbnail

코드를 짜면서 느낀 거는 지금 내 코드 스타일은 아주 옛날에나 썼을 방식이라는 것이다.(옛날에도 안 썼을 수도...) 

그래서 다른 사람들의 코드를 보면서 흥미로운 것들, 배우고 싶은 것들을 정리해 볼 것이다!! ++ 피드백 리뷰

 

1. 입력 메세지는 모두 상수

코드 도중에 문자열을 넣으니 깔끔하지 않다는 느낌이 있었다. 아래와 같이 모두 상수로 선언하고 코드에 작성하니 보기도 깔끔하고, 수정도 쉬워지는 장점이 있다.`final`:값이 변경될 수 없음. 상수, `static` : 메모리가 한 번 할당됨

 

   private static final String GAME_START_MESSAGE = "숫자 야구 게임을 시작합니다.";
   private static final String INPUT_NUMBERS_MESSAGE = "숫자를 입력해주세요 : ";
   private static final String GAME_END_MESSAGE = "3개의 숫자를 모두 맞히셨습니다! 게임 종료";
   private static final String RE_GAME_MESSAGE = "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.";

   private static final String NOTHING = "낫싱";
   private static final String STRIKE = "스트라이크";
   private static final String BALL = "볼";
   private static final String THREE_STRIKE = "3스트라이크";

단점

한 눈에 상수들이 어떤 것에 관련된 것인지 보기 힘들다. 또한 같은 이름으로 정의된 상수가 있다면 컴파일 단계에서 오류가 발생한다.

 

더 좋은 해결 방법 : enum을 이용한 상수 정의

enum은 상수의 집합을 표현할 때 사용한다.

1 방법은 자바에서 많은 사람이 쓰는 방법이고, 2가 enum을 사용한 상수 정의 방법이다. enum의 장점은 다음과 같다.

  • 코드가 단순해지며 가독성을 높인다.
  • 인스턴스 생성과 상속을 방지한다.
  • 키워드 enum을 사용하기 때문에 구현의 의도가 '열거'임을 분명히 나타낼 수 있다.
public class Constant {
    public enum UserRequestMessage{
        GUESS_NUMBER_REQUEST_MESSAGE("숫자를 입력해주세요 : "),// 추가 속성 정의
        REPEAT_MESSAGE("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.");

        private final String message;

        UserRequestMessage(String message){
            this.message = message;
        }

        @Override
        public String toString(){
            return message;
        }
    }
}

 

 

2. 입력 메시지는 하나의 클래스에

하지만 위의 사례와 같이 하나의 클래스에 저런 상수가 많아지면 뭔가 지저분하다. 그럴 때는 하나의 class를 만들어서 모아 놓는 방법도 생각해 보자.

    private static final String STRIKE = "스트라이크";
    private static final String BALL = "볼";

   public String strike() {
        return STRIKE;
    }
    public String ball() {
        return BALL;
    }

 

3. Stream

자바 스크립트 배울 배운적 있었지만, 자바에서 본 적이 없어서 적용 하는 줄 몰랐다. 오 근데 많이 이렇게 쓰는 것 같다! 스트림 쓰니깐 코드가 너무 간단해지고 예뻐진다.... 신기방기. 스트림의 고수가 되어야겠다.

 

3.1 chars()

이번에 처음 써본 스트림은 chars()이다. 알아서 `char` 배열로 만든 후 요소 하나하나 처리할 수 있다.

public void validateIsDigit(String input){
        // 1~9 인지 검증
        boolean result = input.chars()
                .allMatch(ch -> Character.isDigit(ch) && ch != '0');
        if(!result){
            throw new IllegalArgumentException("유효 숫자가 아닙니다.");
        }
    }

 

3.2 :: (메소드 레퍼런스)

또 신기했던 것은 `::`기호인데, 아직 잘 모르겠지만 람다 식의 매개변수를 생략할 수 있다. 이름은 '메소드 레퍼런스'라고 한다. 아래와 같이 사용할 수 있다.

// 수정 전
input.chars().allMatch(ch -> Chracter.isDisit(ch))

// 수정 후
input.chars().allMatch(Chracter::isDisit)

 

3.3 collect()

map이나 filter를 쓰고 난 후에 스트림을 결과로 받고 싶은데 어떻게 받는 줄 몰랐는데 그 방법이 바로 `collect()`이다. collect()에는 자료를 어떻게 수집할 것인가 방법이 정의되어 있는데 이를 구현하는 것이 `Collector`이다. Collector를 직접 구현하기도 하지만 잘 만들어진 static 함수가 있는데 바로 `Collections` 클래스에 선언되어 있다.

collect() 스트림의 최종 연산, 매개변수로 Collector를 필요로 한다.
Collector 인터페이스로 컬렉터는 이를 구현해야 한다.
Collections 클래스로 static 메서드로 미리 구현한 collector를 제공한다.

출처 : https://abcdefgh123123.tistory.com/424

 

Collections 클래스의 Collector

List로 변환 Collectors.toList()
Map으로 변환 Collectors.toMap()
그 외 Collections로 변환 Collectors.toCollection(람다식)

 

잘 모르겠지만 다음과 같이 사용하여 최종적으로 리스트를 반환 받을  수있다.

public List<Integer> toList(String inputNumber) {
        return Arrays.stream(inputNumber.split(""))
                .map(Integer::parseInt)
                .collect(Collectors.toList());
    }

 

더 쉬운 예시를 봐보자. 다음 코드는 현재 요소에 각 10을 더하여 새로운 배열을 만드는 코드이다. 

for문을 돌릴 필요 없이 간단히 코드를 작성할 수 있다.

List nums = new ArrayList<>();
List newNums = nums.stream().map(i -> i+10).collect(Collector.toList());

 

 

💊 공식 피드백 

1.  기능 명세 작성법

정말 단위 기능 중심으로 작성한다. 클래스를 나누는 작업은 행동의 주체가 아니라 기능 중심이다. 예를 들어 `Computer`, `Player`로 클래스를 나누는 것이 아니라 `NumberGenerator`, `Referee`, `Judgment`로 나눈다. 확실히 저렇게 나누면 더 직관적이면서 함수를 재사용하기 수월한 것같다. 만약 `Computer` 클래스에 랜덤 수 생성하는 함수가 있다면, 반드시 Computer 레퍼런스가 있어야 함수를 사용할 수 있기 때문에 불편한다. 

 

2. 커밋 메시지 참조

커밋은 기능 구현을 다 하고 한 번에 작성하는 것이 아니다. 게임의 중간 저장처럼, 워드 작업을 할 때 항상 저장을 하는 것처럼 상시로 하는 것이다. 예를 들어 '랜덤 수 만들기' 같은 작은 기능 하나를 구현할 때 커밋 메시지도 작성하는 것이다.

 

 

📑 커밋 메시지 컨벤션

태그 : 제목의 형태이며, :뒤에만 space가 있음에 유의한다.

  • `feat`: 새로운 기능 추가
  • `fix` : 버그 수정
  • `docs` : 문서 수정
  • `style` : 코드 포맷팅, 세미콜론 누락, 코드 변경이 없는 경우
  • `refactor` : 코드 리펙토링
  • `test` : 테스트 코드, 리펙토링 테스트 코드 추가
  • `chore` : 빌드 업무 수정, 패키지 매니저 수정

 

Gitmoji

이모지를 사용하여 커밋 메시지의 가독성을 확 높일 수 있다.

 

Gitmoji 사용하기

Gitmoji란? gitmoji란? Gitmoji = git + emoji 입니다. 글을 쓸 때 이모지를 이용하면, 나중에 글을 읽을때 명확합니다. 👍 커밋할 때도 이모지를 이용한다면, 내용을 한 눈에 알아보기 더 쉽겠죠. 그래서

treasurebear.tistory.com

 

3. 테스트 코드 작성법

한 번에 돌려볼 생각 말고 기능 중심으로 함수 구현이 완료되면 테스트 해본다. 테스트 코드를 작성하면 실제로 결과가 맞는지 수동으로 확인할 필요 없다. 확실히 테스트를 생각하고 코드를 나누는 방법도 참 좋은 것 같다. 복잡한 코드는 테스트 코드를 작성하려면 많은 객체들이 필요하다. 아래 예시처럼 함수는 최대한 작게 만들고, input, ouput과의 연관이 없도록 작성해야할 것 같다.

 

- 테스트 코드 더 간단하게

728x90
profile

차곡차곡 성 쌓기

@nagrang

포스팅이 좋았다면 "좋아요" 해주세요!