우아한테크코스

[우아한테크코스] 레벨2 - 웹 자동차 경주 미션 회고

hectick 2023. 4. 27. 12:50

 

레벨1의 첫 주에서는 콘솔에서 동작하는 자동차 경주 미션을 구현했었다. 이번 미션은 레벨1에서 구현했던 자동차 경주 미션 코드를 가져와서 웹 기반에서도 동작하도록 기능을 추가 및 수정하도록 하는 미션이었다. 그래서 결과적으로는 콘솔과 웹 모두에서 자동차 경주 게임을 할 수 있도록 만들어야 했으며, 콘솔 어플리케이션과 웹 어플리케이션에서 겹치는 중복 코드는 최대한 없애야 했다.

 

👇레벨1 자동차 경주 미션때 작성했던 코드👇

 

GitHub - hectick/java-racingcar: 자동차 경주 게임 미션 저장소

자동차 경주 게임 미션 저장소. Contribute to hectick/java-racingcar development by creating an account on GitHub.

github.com

 

 

이번 미션의 페어는 폴로였다. 페어 프로그래밍을 시작하기 전 다른 크루로부터 폴로가 속도감이 있다는 말을 들었는데, 덕분에 미션을 끝내고보니 진짜 PR을 1빠로 내게 되는 결과가 나와서 신기했다.

 

 


 

🐣 스프링에서 의존성을 주입하는 방법들

 

스프링에서 @Autowired 어노테이션을 이용해 의존성을 주입하는 방법에는 세가지가 있다.

1. 생성자(Constructor) 주입

2. 수정자(Setter) 주입

3. 필드(Field) 주입

 

나는 여기서 생성자 주입을 사용한다. 왜냐하면 수정자 주입은 필드를 final로 선언할 수 없게되고, 필드 주입은 테스트하기 불편한 구조가 되기 때문이다.

 

 

🐣 어떤 객체를 스프링 빈으로 등록해야 할까

 

빈은 일반적으로 싱글톤으로 존재한다. 싱글톤으로 관리되면 애플리케이션 전역에서 하나의 인스턴스만 공유되게 된다.

 

그래서 나는 컨트롤러, 서비스, DAO는 싱글톤으로 관리해도 지장이 없기 때문에 빈으로 등록해주었다. 다만 비즈니스 로직은 따로 빈으로 등록해주지 않았다. 여기에는 싱글톤으로 존재하면 안되는 것들이 있기 때문이다. 예를 들어 자동차는 싱글톤이면 안된다. 여러개의 자동차를 만들어야 하기 때문이다. 

 

그리고 또 문제가 있다.

 

 

저렇게 String, int 타입이 생성자의 파라미터로 들어가게 되면 해당 객체를 빈으로 등록할 수 없다. String, int는 빈으로 등록되어 있지 않기 때문에 자동으로 주입해줄 수 없기 때문이다.

 

나는 뭔가 섞이면 심기가 불편하고, 딱딱 나누어 떨어지는 것을 좋아하기 때문에 비즈니스 로직은 아예 순수하게 자바로만 관리하기로 정했다.

 

 

🐣 서비스 레이어의 역할

 

처음에는 컨트롤러에서 서비스로부터 다음처럼 게임 흐름에 관련된 메서드를 호출하도록 만들었다.

하지만 이러한 리뷰를 받게 되고, 서비스 레이어가 대체 어떤 역할을 하는 것인지 생각을 해보게 되었다.

 

컨트롤러는 서비스가 어떤 세세한 로직을 수행하는지 알고 싶어하지 않는다. 그렇다면 세세한 로직을 수행하는 것은 서비스 단에서 끊어야 한다.

 

서비스의 역할은 비즈니스 로직의 흐름을 관리하는 것이다. 컨트롤러에서 요청이 들어오면, 순서에 맞게 필요한 도메인을 차례대로 호출한다. DAO 같은 Persistence 레이어와 상호작용하며 데이터를 저장하거나 조회하기도 한다. 마지막으로 컨트롤러에게 적절한 응답을 반환해준다.

 

 

🐣 DTO 변환로직의 위치

 

레벨1 미션에서는 변환로직을 DTO안에 넣어놨었는데, 딱 한가지, DTO가 도메인을 알고 있다는 것이 걸렸었다. 그래서 이번 미션에서는 한번 DTO에 getter만 남겨보았다. 그리고 Mapper 클래스를 만들어서, DTO를 변환해주는 로직을 몽땅 넣어보았더니 역시나 리뷰가 달렸다.

 

도메인을 받아 단순 변환해주는 로직은 DTO 안에 정적 팩토리 메서드로 넣어둬도 괜찮다.

 

 

🐣 DTO에 대한 명시적인 네이밍

 

이번에 레이어들이 불어나면서, 레이어간에 데이터가 이동할 때 DTO를 많이 쓰게 되었다. 여러개의 DTO가 만들어지면서 네이밍을 어떻게 해야할지 감을 잘 못잡았는데, 이번에 네이밍과 관련한 피드백을 많이 듣게 되었다.

 

Information -> 광범위하다.

RequestDto -> 여러개의 Request가 생길 수 있기 때문에 어떤 Request인지 명시적으로 나타내는 것이 좋다.

ResponseDto -> 마찬가지로 여러개의 Response가 생길 수 있기 때문에 명시적으로 나타내는 것이 좋다.

ExceptionResponseDto -> 광범위하다.

 

광범위한 네이밍을 지양하고, 명시적으로 짓도록 해야한다. 또, Request, Response는 클라이언트와 컨트롤러 사이의 요청과 응답을 의미하는 일반적인 네이밍이기 때문에 뒤에 Dto를 따로 붙여주지 않아도 된다.

 

 

🐣 batchUpdate

 

자동차 경주 결과를 저장할 때, 여러개의 자동차들에 대한 정보가 데이터베이스에 저장되어야 한다. 하지만 이 데이터들을 저장하다가 문제가 생기게 된다면, 그때까지 저장된 데이터들이 남아있는게 싫었다. 그래서 데이터를 한번에 저장하는 법을 구글링을 하다가 batchUpdate를 찾았고 이를 적용해보았다. 하지만 리뷰를 통해 내가 batchUpdate를 사용한 의도와, batchUpdate의 원래의 의도는 다르다는 것을 알게 되었다.

 

저장 시 하나가 문제가 생기면 모든 것을 저장하지 않는 것은 트랜잭션(Transaction)과 관련있는 것이고, batchUpdate는 connection을 줄이기 위함이다.

 

 

🐣 읽기 전용 트랜잭션 (보류)

 

데이터베이스에 데이터를 저장하거나 조회할 때 @Transactional 어노테이션을 사용했다. 그런데 리뷰어분께서 조회만 할 때는 readOnly를 사용해보라고 하셨다.

 

@Transactional(readOnly = true)

이렇게 달아주면 이 트랜잭션이 읽기 전용으로만 수행될 것임을 선언하는 것이다.

좀 더 공부해보려고 했지만, JPA라는 용어도 같이 나와서 머리가 아파 일단 보류한다.

 

조회만 하는 트랜잭션은 @Transactional(readOnly = true)를 달아주는 것이 좋다.

 

 

🐣 Repository vs DAO (보류)

 

이번 미션을 하면서 DAO 클래스가 세개 만들어졌고, Repository 라는 것을 도입했다. 자세한 도입 배경은 사진으로 대체한다.

 

하지만 리뷰어님께 내가 만든 레포지토리는 서비스의 역할에 가깝다는 소리를 들어서 일단 없애버렸고 Repository가 무엇인지에 대한 고민에 빠지게 되었다.

 

브리의 피드백 강의를 듣다가 한 크루가 레포지토리와 DAO를 다음과 같이 정리해주었다.

DAO: 데이터를 저장한다.

Repository: 객체를 저장한다.

 

결국 DAO보다는 Repository가 좀 더 도메인에 가까운 것이다라는 느낌만 머릿속에 저장했다. 그리고, 아직 이 둘을 구분하는 것은 이르다는 리뷰어님의 말씀을 듣고 나중에 필요할 때 다시 정리해보기로 했다.

 

 

 

[1단계 - 웹 자동차 경주] 이리내(성채연) 미션 제출합니다. by hectick · Pull Request #1 · woowacourse/jwp-r

안녕하세요 배럴! 리뷰이 이리내입니다~ 따끔한 리뷰 부탁드립니다. 페어와 코드를 작성하다가 궁금한 점이 몇개 생겼는데, 그것은 코멘트로 달아두겠습니다!

github.com

 

[2단계 - 웹 자동차 경주] 이리내(성채연) 미션 제출합니다. by hectick · Pull Request #144 · woowacourse/jwp

안녕하세요 배럴! 2단계 제출합니다. 1단계에서 주신 리뷰들 적용해봤고, 남겨주신 코멘트에 대한 답변들은 아래 두개 달아봤습니다! #1 (comment) #1 (comment) 이번 단계에서 크게 바뀐 부분은 다음과

github.com


 

🐣 스프링을 어떻게 공부해야할까?

 

깃짱, 오잉과 스프링을 어떻게 공부하는게 좋을지 이야기를 나누어보다가, 우리는 브리가 제시해준 키워드를 잘 따라가기로 결정했다. 우리는 스프링 응애이기 때문에 이것 외의 것을 공부하기 보단, 이 키워드를 잘 공부하기로 정한 것이다. 

 

'셋이 알아서 키워드를 공부하고, 모르는게 생길 때 질문하면 셋중 누군가는 공부하고 있겠지'라고 생각하고 각자 모여서 스프링 공부를 시작했다. 그런데 깃짱 생일을 미리 축하할 겸 점심을 온보딩 조원들과 같이 먹다가 에코와 콩하나도 여기에 끼게 되어서, 서울단후회가 결성되었다.

 

서울단후회(徐菀單後會)는 '서울에 위치한 단순한 백엔드 모임'이다. 도쿄 리벤저스라는 애니메이션을 보면 도쿄만지회가 나오는데, 서울단후회는 이 도쿄만지회를 산하로 둔 조직이다. 아무튼 서울단후회는 코치님이 제시하는 키워드 외의 마이너한 길로 빠지는 것을 경계하며, 키워드에 집중해서 각자 공부하는 모임이다.

 

나는 코치님이 제시해준 키워드들 위주로 공부하고 블로그에 글을 써보면서 스프링을 공부하기로 했다. 왜냐하면 글을 쓰면 글을 쓰는 과정에서 내가 알고 있는 것이 한번 정리가 되기도 하고, 글을 쓰다가 개념적으로 부족하다고 판단되는 부분을 발견하면 책이나 다른 자료를 찾아가며 보충할 수 있으며, 내가 지금 알고 있는 것이 틀리더라도 이를 기록해두면 타인이나 미래의 내가 찾아서 정정할 수 있기 때문이다. 단순히 머릿속으로만 담고 있으면 언젠가 휘발되기 마련임을 나는 대학교 공부를 하면서 매번 느껴왔기 때문에, 올해만큼은 같은 실수를 반복하지 않으려고 하는 것이기도 하고, 내 블로그 명은 휘발방지용이니까 블로그가 닉값을 좀 해야하기도 한다. 절대 쉬발방지용이 아니다.

 

 

🐣 이번 미션을 진행하면서 작성한 글들

 

[consumes와 produces의 차이]

[@Component, @Repository, @Service, @Controller 는 뭐가 다를까]

[JDBC, JDBC 드라이버, JDBCTemplate]

[JdbcTemplate 써보기]

[Spring MVC - Annotated Controllers(@Controller와 @RestController)]

[Spring MVC - ControllerAdvice(@ControllerAdvice와 @ExceptionHandler를 이용한 예외처리)]

[POJO란?]

[Layered Architecture]

[Spring Core - IoC(Inversion of Control), DI(Dependency Injection)]

[Spring Core - Bean과 Configuration]

 

 

🐣 다음에 공부할 것들

 

테스트 코드 작성

 

 


 

넘치는 스프링 키워드들에 허우적거린 2주였다. 

방대한 양을 받아들이느라 무엇인가 하나에 대해 오래 생각을 못하고 얕게만 하고 넘어간 것도 많고, 보류하고 넘어간 것도 대부분이다.

그냥 얕게 여러번 겹겹이 공부해야겠다~