본문 바로가기

우아한테크코스/코드 리뷰

체스 게임 2

한 주 방학을 통해 휴식을 취한 후 Level2를 시작했다.

더 나아가기 위해, 방학때 푹 쉬면서 충전을 하는게 목표였지만 체스 미션이 끝나지 않았고, 불안한 마음이 들어서 조금씩 공부를 했다. Map interface에 모르는 메소드들을 정리해서 글로 올리기도 했다.

그렇게 방학이 끝나고 Level 2가 시작되었다.


Level 2의 첫 미션은 Level 1때 구현한 체스를 Spring으로 다시 구현하는 것이다. 총 5단계로 나뉘어져 있는데 이번 주는 1단계를 구현한다. 1단계는 새로 배정받은 페어와 Level 1때 각자 구현한 체스를 합치는 미션이다.

새로 구현하는 것이 이번 미션의 의도가 아니기 때문에 나의 Level1 체스 코드를 베이스로 사용하고 페어와 코드리뷰를 하면서 수정하기로 합의를 봤다.


페어와 내 코드를 리뷰하는 과정에서 배운 것

1단계는 Spark Java로 구현한 체스를 합치는 과정이기 때문에, Spring을 사용하며 배울 순 없었지만 Spark Java를 사용함으로써 DI, DB관련 작업의 간소화 등 Spring의 편리함을 직접 느낄 수 있었다.

또한 Spring이였다면 예제를 따라하며 무심코 넘어갔을 부분도 Spark Java를 사용하며 Level 1에서 이해가 부족했던 부분들을 지적받고 학습할 수 있었다.

public class SparkController {
    private final ChessService chessService;

    public SparkController() {
        chessService = new ChessService();
    }
}
public static void main(String[] args) {
    final SparkController controller = new SparkController();
}

SparkController의 생성자에서 ChessService를 직접 생성해서 인스턴스 변수로 가지고있는 구조로 코드를 작성했었다.

하지만 이 코드에는 문제가 있었다.

public SparkController() {
    chessService = new ChessService();
}

위 SparkController의 생성자를 통해 SparkController와 ChessService가 강하게 결합되어 있다는 점이다.

체스 미션에서는 ChessService가 인터페이스가 아니지만, 여러 개의 Service Layer를 인터페이스로 추상화했을 때를 생각해보자.

Controller에서 쓰는 Service를 갈아끼우고 싶을 때 Controller를 생성하는 부분의 인자도 수정해야 하고 Controller에서 생성자도 수정해줘야 한다.

그렇기 때문에 Controller는 Service와 강하게 결합되어 있는 것이다.

변화할 수 있는 부분은 분리해야한다.

public SparkController(ChessService chessService) {
    chessService = chessService;
}

이와 같이 Controller의 생성자를 작성했다면 Service를 갈아끼울 때도 Controller를 생성하는 부분의 인자만 다른 구현체로 수정해주고 Controller의 생성자는 건들지 않아도 된다. 결합도가 낮아진 것이다.


스프링에 대해 새롭게 배운 사실을 정리해보자.

Bean 객체는 상태를 가지면 안된다.

빈 객체는 디폴트로 싱글톤으로 관리되기 때문에 읽기 전용 값이 아니라면, 많은 사용자의 요청을 처리할 때 상태가 공유되기 때문에 의도하지 않은 결과가 응답될 수 있다.

즉, thread-safe하지 않기 때문이다.

Dependency Injection은 Constructor를 이용하자.

의존성을 주입할 때의 방법은 세가지가 있다.

  1. Constructor
  2. Setter
  3. Field

가장 많이 사용하는 방법이 Field를 사용하는 방법이다.

Field Injection은 사용하기도 간편하고, 코드도 깔끔하다는 장점이 있다. 하지만, Constructor를 사용하는 방법이 더 좋은 DI 방법이라고 내가 설득된 이유는 두가지이다.

  1. Constructor Injection을 사용하면 필드에 final 키워드를 선언할 수 있다.
  2. Constructor Injection은 순환 의존성을 가질 경우 BeanCurrentlyCreationExeption을 발생시켜서 순환 의존성을 알 수 있다.

스프링이 객체들을 관리줌으로써 얻는 장점

  1. 객체의 생명주기를 고려하지 않게 하여 비즈니스 로직에만 집중할 수 있게 해줌
  2. 작업 실행을 구현에서 분리
  3. 서로 다른 구현을 쉽게 전환 할 수 있다.
  4. 프로그램의 더 큰 모듈성
  5. 컴포넌트를 격리하거나 의존성을 mocking하기 편하여 테스트가 훨씬 쉬워짐

그 외 Spring 용어에 대한 개념을 정리하는 글을 쓰기 시작했다.
알게되는 개념을 계속해서 업데이트 할 예정이다.


이번 주는 드디어 웹을 시작하는 단계인 만큼 새로 배우는 내용이 매우 많았다.

아직도 알아야 할 내용이 산더미처럼 많은 것 같다. 작은 것부터 천천히 학습해서 전부 내 지식으로 만들고 싶은 욕심이 생긴다.

자세히 공부해보고 그 지식에 대해 나의 주관을 가지는 것이 목표이다.

'우아한테크코스 > 코드 리뷰' 카테고리의 다른 글

지하철 1  (0) 2020.05.10
체스 게임 3  (0) 2020.05.05
체스 게임 1  (2) 2020.04.17
블랙잭 2  (0) 2020.03.30
블랙잭 1  (0) 2020.03.18