개요

계산기 미션 다음에는 레이싱카 미션이다.
총 2단계로 구성되어 있으며, 1단계에서는 페어 프로그래밍을 2단계에서 MVC로 구조 전환을 수행하는것이다. 
프로그램은 다음 플로우로 흘러간다. 
1. 자동차, 횟수 입력한다.
2. 랜덤 넘버를 받아와서 4이상이면 전진할 수 있다. 단, 전진하는 경우 상태값을 콘솔에 출력한다. 
3. 가장 많이 전진한 자동차를 우승자로 선정한다. 우승자는 복수가 될 수 있다. 

프로젝트 구조 

프로젝트 구조에서도 조금 아쉬운것은 domain package에 많은 객체가 포함되어 있다.
굳이 쪼갠다면 entity pacakge 정도 하나 더 둘 수 있을것 같다. Helper 클래스는 Racing 클래스 쪽으로 합칠 수 있을것 같다. 
관련 비즈니스 로직이 명확하게 domain package에 포함되어있다 는 확신하지 못하겠다. 

| - racingcar
|     ` -- common
|             ` -- exception
|                     ` -- InputValidationException.java
|             ` -- info
|                     ` -- RacingGameErrorInfo.java
|                     ` -- RacingGameInfo.java  
|             ` -- UserInput.java
|     ` -- domain
|             ` -- Car.java
|             ` -- Helper.java
|             ` -- Judgement.java
|             ` -- Racing.java
|     ` -- Application.java 
| --

객체 

Application.java
코드에서 객체 생성을 보면 일관성이 부족해 보인다.
흐름상 Racing 클래스의 호출이 UserInput 보다 먼저 올 수 없는데 가독성이 떨어진다. (정상 동작 하겠지만.) 
Judgement도 보면 비즈니스 로직 실행과 결과 출력 두가지를 담당하는것 같은데, 역할이 너무 많이 부여 되어 있다고 생각한다. 

 

InputValidationException.java
메시지를 받아서 Custom 하게 예외 설정을 잡아주었다.
이렇게 해주면 이점은 무엇인가?  > 이점이 없어 보인다. 오히려 모르고 쓰면 애플리케이션의 결함만 야기시킬 수 있을 것 같다. 

RuntimeException은 Unchecked Exception의 일종이다. 명시적으로 예외 처리를 하지 않는다. 오히려 이점 보다는 tradeoff 가 발생할 수 있다고 생각했다. 왜냐하면, 예외를 변경시킨다면 호출하고 있는 클래스의 메소드 예외도 변경시켜야 하는데 명시적이지 않을 경우 확인되지 않은 예외를 사용하게 되서 호출하고 있는 클래스의 업데이트를 잊어버릴 수 있기 때문에 결함이 발생할 수 있다고 접근했다. 

 

RacingGameErrorInfo.java
불필요한 생성자 방지 목적으로 잘 작성해줬다고 생각한다.


RacingGameInfo.java
위 클래스와 마찬가지로 매직리터럴 의도로 작성하였다. 
불필요한 생성자 방지 목적을 잘 지켰다고 생각한다. 


UserInput.java

유저 인풋 외에도 분리, 파싱, 검증 까지 책임을 갖고 있다. 분리해줘야 한다.
그리고, UserInput 클래스가 갖고 있는 상태가 너무 많다. 
상태가 많아지게 되면 이 객체를 의존하게 되는 다른 객체가 생기게 되기 때문에 결집도가 높아지게 될것이다. 
그래서 응집력을 키우기 위해서라도 최대한 객체에 역할을 알맞게 할당해야 한다고 생각한다. 


Car.java

maxCheck, toString 클래스는 Car클래스가 가지는 역할에 적합하지 않다.
maxCheck는 Racing 클래스에 포함되어야 한다. 
마찬가지로 toString은 OutputView 클래스를 따로 생성하여 구현해줘야 한다고 생각한다. 


Helper.java

Wrapper 역할을 수행하는 일급 컬렉션으로 racing 클래스 안에 List<Car> cars 가 존재하게 된다.
오히려 이런 경우는 Cars 객체를 구현하고 여기에 Car 클래스를 넣는것이 맞다고 생각한다.
Racing 안에 Car 객체를 담아주게 되면 Racing 클래스 역할이 어디까지 인지 다시 한번 고려해봐야 한다. 


Judgement.java

가장 먼저 눈에 띄이는것은 Winner, OutputView 클래스를 각각 둬야 하는 것이다.  
이후 참고해야할것은 DTO 개념이다.
OutputView 클래스에 전달할 객체 개념으로 DTO를 사용하면 좀 더 클래스의 역할과 책임을 분리할 수 있다고 생각한다. 


Racing.java

registerCar를 Racing에 두는것이 맞는지에 대해 약간의 관점 차이가 발생할 수 있다고 생각한다. 
내 생각은 Cars 클래스에서 Car를 Wrapping 해줘야 하는것이 더 적합하다고 생각이 든다. 


ApplicationTest.java
domain package에 대한 테스트 코드가 충분하지 않다.
그리고, 객체의 책임과 역할이 적절하게 분리되지 못한것은 TDD에 집중하지 않았기 때문이라고 볼 수 있다. 
Parameterized를 써서 여러 테스트를 수행할 수 있어야 한다. 

코드 리뷰

상태를 가지지 않는 객체일 경우 static 하게 정적 처리한다. 

 

클라이언트가 구현에 의존하지 말아야 한다. 

 

결과

계산기 과제보다 조금 나아졌지만, 아직도 객체 설계하는데 책임과 역할을 분리하지 못했다. 
Java 8버전에 맞춰서 Stream을 사용하였지만 활용을 크게 하지 못했다. 
객체 설계 관점에서는 TDD를 도입하면 불필요한 객체 생성을 막을 수 있을것 같다. 
테스트 코드 작성도 마찬가지로  @Parameterized를 도입해 적용하지 못했다. 
domain package에 public 하게 열려있는 객체를 테스트코드 작성을 완료하지 못했다. 

'IT' 카테고리의 다른 글

카프카 스터디를 시작하며  (0) 2022.12.03
넥스트스텝 - 레이싱 카 2단계  (0) 2022.01.30
넥스트스텝 - 계산기 리뷰  (2) 2022.01.29
git cherry-pick으로 rebase 완성하기  (0) 2022.01.28
centOS mirror  (0) 2021.12.16