본문 바로가기
대외활동/[미션] 우아한테크코스 프리코스 | Java

[우아한테크코스] 프리코스 2주차 : 숫자 야구(baseball)

by HelloJudy 2022. 11. 7.
이 글은 '프리코스' 과정에 작성한 글이며 현재 레포지토리에 있는 코드와 다를 수 있습니다. (리팩토링함)

 

 

🚩 2 주차 목표

1. 함수 분리 

2. 각 함수 별로 테스트를 작성하는 것

이 두 가지에 익숙해지는 것을 목표로 하고 있다.


 

[2주 차] 미션 - 숫자 야구 ⚾

 

🏃 리팩토링 전 프리코스 제출 코드 시점

👉 미션 저장소

📎 Source Code (PR)

📆 기간: 2022.11.02(수) 15:00 ~ 2022.11.08(화) 23:59

 

+ 프리코스 이후 리팩토링 포스팅

[우아한테크코스] 숫자 야구(baseball) 리팩토링


1. 구현 과정

 

1주 차 과제에서는 한 클래스 내에 필요한 메서드와 클래스를 구현해서 사용했다.

이때 메서드를 수정 및 테스트 하기가 불편했고 비슷한 역할을 하는 메서드끼리, 클래스끼리 묶어주는 작업의 필요성을 느꼈다.

 

이때 패키지를 생성하여 클래스를 묶어주기로 결심했다.

패키지(Package): 서로 관련된 클래스의 묶음 

 

하지만 아직 자바 프로그래밍에 익숙하지 않고 이런 구조를 설계하는 것에 익숙하지 않은 상태에서 폴더구조와 클린 코드, 클린 아키텍처, 디자인 패턴은 나에게 무리라는 생각을 했다.

그래서 일단 한 클래스에 구현과 테스팅을 한 뒤 아키텍처를 생각하기로 했다.

 

 

⚙️ 기능 구현 목록 작성

 

 

 

1️⃣ 처음부터 완벽하고 깔끔한 구조로 구현하려고 하지 말자.

 

  • 일단 필요한 코드를 Application에 작성하자.
    • 숫자 야구 게임 로직 구현
  • 단, 예외처리는 따로 validator package로 분리
    • NumbersValidator : 여러 개의 숫자에 대한 예외 처리 (ex. 123)
    • NumberValidator : 한 개의 숫자에 대한 예외 처리 (ex. 1)

  • test 코드 작성
    • ApplicationTest : 전체 코드 동작 테스트 
    • BaseBallGameTest : BaseBall Game 구현과 관련된 메서드 테스트 코드
    • InputTest : 예외처리 관련 메서드 테스트 코드

 

💡TDD에 대한 내 생각

 

  • TDD를 생각하면 우선 비즈니스 로직을 구현하기에 앞서 테스트 코드를 작성하면서 내가 어떤 메서드를 구현할지 생각해봐야 한다.
  • 하지만 TDD를 바로 시작하기엔 아직 실력이 부족하다. 일단 구현해보고 테스트 코드 작성해보자.
  • 설계에 대한 개념이 명확하지 않은 상태에서 TDD는 어렵다. 코드 작성에 익숙해져 보자.
  • 그리고 다음에는 테스트 코드 작성 다음 비즈니스 로직을 구현한다.

 

 

💡 Validator 패키지를 분리하면서 내가 고민했던 점

 

기능 요구 사항 중

Java에서 제공하는 RunTime Exception 중 현재 IllegalArgumentException을 사용한다.

이때 IllegalArgumentException만 사용할지 해당 exception을 상속받은 Custom Exception을 만들지 고민했다.

 

 

 

✔️ 결론: 주어진 예외를 잘 활용하자.

 

현재 validator는 유효하지 않은 입력(인자) 값에 대한 예외만 사용하고 있으므로 자바에서 정의해놓은 IllegalArgumentException을 사용하고 메시지만 예외사항에 맞게 재정의해준다면 충분히 그 의미를 파악할 수 있다고 생각했다.

 

그리고 메세지는 상수 처리하여 클래스 최 상단에 모아서 정의해두었다. 그렇게 하여 메서드만 많아지더라도 메세지를 빠르게 수정할 수 있도록 했다.

 

👉 참고한 블로그 'custom exception을 언제 써야 할까?'

 

 

/* 휴.. 메서드 하나.. 예외처리 하나 하는데 고민이 참 많다.

머리가 지끈지끈 아파오고 재밌다.

정말 설계하는 개발자의 첫걸음을 걷고 있는 것 같다. */

 

 

일단 구현은 완료했다. 괜히 게임 한 번 해주고~~ 자자.. 이제 구조 설계해볼까~~!!!

 

 

 

2️⃣ MVC 패턴으로 분리해보자.

 

자 기본적인 구현은 끝나고 코드 구현에 쓰던 신경을 아키텍처에 써보자!

 

패키지를 생성하여 클래스를 묶어주자.

패키지(Package): 서로 관련된 클래스의 묶음 

 

그런데 이 패키지를 묶는 기준은 어떻게 설정해야 할까? 비슷한 성격의 클래스. 좀 더 명확한 구조를 세우기 위해 디자인 패턴을 적용하기로 결정했다.

 

그중 사용한 경험이 있는 MVC 패턴으로 결정했다.

기존 node 프로젝트에서 mvc에서 service layer가 추가하여 구현을 했지만 디자인 패턴을 제대로 사용하고 있는지 의문이 생겨 다시 학습했다.

 

 

✔️ View

 

일단 이번 미션은 Console을 통한 입출력이 있다.

그래서 입출력을 담당하는 부분을 View 패키지로 분리해보자. (로직에 함께 있으니 코드를 디버깅할 때 깔끔하지 않다.)

 

분리 전에는 이렇게 한 클래스에 입력받는 메서드가 같이 있다.

 

분리 전 코드

이런 식으로 출력하는 코드도 게임 로직과 함께 있다.

분리전 코드

 

  • View Package 생성, InputView와 OutputView로 사용자에게 보이는 부분을 구현하자.
    • InputView : Console에서 Player의 input을 받기
    • OutputView : Console에서 Player에게 output 보여주기

출력될 메세지는 상수로 따로 관리한다.

분리한 메서드
실제 로직에서 메서드 호출

 

✔️ Domain

 

게임 로직에 필요한 클래스들을 정의했다.

 

  • Domain Package
    • GameLogic : Computer와 Player의 값을 비교하여 결과를 반환한다.
    • RandomNumbers : 랜덤 한 3자리 숫자를 생성한다.

 

✔️ Controller

 

순서에 알맞은 실행을 위해 domain-view를 연결하는 역할을 Controller에서 수행했다.

 

Controller에서 실제 게임이 실행된다.

 

 

💡 클래스를 분리하면서 내가 고민했던 점

 

클래스를 구현하면서 static에 대해서 여러 글을 찾아보며 다시 생각해보았다.

 

👉 참고 포스팅, 정적 메소드, 너 써도 될까?

 

현재 내 폴더 구조를 기준으로 View 부분은 static 하게, Domain 부분은 필요에 따라 인스턴스를 생성하도록 구현했다.

View 부분은 모든 사용자가 같은 input과 output을 보기 때문에 static으로 구현하는 게 속도가 빠르다고 판단했다.

 

 

 

🗂️ 최종 폴더 구조

 

(리팩토링 포함)

├─main
│  └─java
│      └─baseball
│          │  Application.java
│          │
│          ├─controller
│          │      BaseBallGame.java
│          │
│          ├─domain
│          │      GameLogic.java
│          │      RandomNumbers.java
│          │
│          ├─validator
│          │      NumbersValidator.java
│          │      NumberValidator.java
│          │
│          └─view
│                  InputView.java
│                  OutputView.java
│
└─test
    └─java
        ├─baseball
        │      ApplicationTest.java
        │      BaseBallGameTest.java
        │      InputTest.java
        │
        └─study
                StringTest.java

 

/* 구현을 먼저 하고 구조를 나누면서 오직 구조만 생각할 수 있어

좋았지만... 분리시킨다고 너무 힘들었다.. 이게 머선일이고~ */

 

 

3️⃣ 클린코드 체크리스트를 만들어서 리팩터링 하자.

 

💡 상수를 Constant로 분리할까?

 

상수들을 Constant로 따로 분리하지 않았다. 

  • 지금은 작은 서비스 구현이라서 내가 수정할 때 상수가 쓰이는 메서드 바로 위에서 확인하는 게 가독성이 높고 생산성이 높다고 판단했다.
  • 좀 더 코드가 많아지고 복잡해지면 분리할 생각을 가지고 있었다.
  • 중간에 분리를 시도해보았지만 코드 수정을 확인하기가 어려웠다.

 

추후에 중복되게 필요한 상수가 생긴다면 상수들을 클래스에 모아두면 수정이 필요할 때 쉽게 찾을 수 있다.

그때엔 Constant Package를 만들어서 class를 만들 수 있다.

 

 

💡 Random한 3자리 숫자를 가져오는 방식

 

  • 처음
    • 처음에는 랜덤 한 숫자를 반환하는 메서드를 호출해서 바로 사용했다. 하지만 Class를 분리하고 메서드를 분리하면서 RandomNumbers Class는 랜덤 숫자를 만들 때만 호출되었다.
  • 리팩토링
    • 그래서 클래스 생성자를 통해서 변수를 초기화하는 방식으로 구현했다.
    • 이렇게 하면서 캡슐화를 할 수 있었다.
    • RandomNumbers Class 내부에 있는 변수와 메서드는 private으로 선언하여 클래스 내부에서만 접근할 수 있다.

 

 


2. 구현 완료

 


3. TIL 

1) MVC 패턴

  • Model - 데이터와 관련된 부분
  • View - 사용자에게 보이는 부분
  • Controller - Model과 View를 이어주는 부분

 

 

2) 테스트 코드 작성

 

추가로 처음에 클래스를 분리하지 않고 메서드를 생성했을 때는 테스트 코드 작성이 수월했는데 나누는 순간....

난리가 났다..ㅎ..

 

메서드를 private으로 접근제어자를 설정했더니 테스트 코드가 안된다... 떼힝

 

 

막아...코드 여며...

 

private 메서드는 어떻게 테스트 코드를 작성할지 천천히 다시 공부해보자!! 파이팅

 


마무리

 

📎 [kakao x goorm] 구름톤(9oormthon) 후기

내가 작성했던 후기 글

 

위의 글은 내가 지난 8월에 해커톤에 참여한 후기를 작성한 포스팅의 일부이다.

 

프로젝트를 여러 번 하면서 코드를 짜는데 익숙해져 있다고 생각했다. 그런데 해커톤에서 내가 구현할 막연한 기능은 나를 두렵고 멈춰 서게 했다.

 

해커톤 이전 프로젝트에서는 오직 개발자만 이루어진 팀에서 협업했다.

개발자들과의 기획 회의에서는 이것을 어떻게 구현할까, 구현할 수 있을까에 더 초점 맞춰 이야기를 나눴던 거 같다.

그래서 구현 가능성이 있어 보이는 것, 어떻게 구현해야 할지 그려지는 기능들을 좀 더 우선시했다.

 

하지만 해커톤에서는 디자이너, 기획자, 개발자가 함께 협업을 했다.

처음으로 기획 회의에서 "우리가 이 기능을 구현할 수 있을까?"를 생각하지 않고, 개발 용어를 섞지 않고 회의했다.

(기술적으로 구현 가능한지 여부 정도만 확인했다.)

 

그렇게 탄생한 서비스 기획은 막연하고 추상적이고 두리뭉실했다.

 

이것 개발하기 위해 필요한 기능은 추상적이었고 이것을 구체적으로 설계하는 것이 어려웠다.

그래서 이런 기능을 개발할 때 어디서부터 시작해야 할지도 어려웠던 거 같다.

 

평소에 하던 방식으로 사고하고, 하던 문제만 풀어서는 실력이 향상되지 않는다는 것을 깨달았다.

이때 지금까지 나는 코드를 짜는 사람이었고, 설계를 하고 문제를 해결하는 사람으로 나아가기 위해서는 막연하고 추상적인 기능을 구현하고 설계하는 경험이 필요했다.

 

그리고..!

시작한 우테코 프리코스.

 

정말 내가 필요로 했던 교육을 제공하고 있고

내가 개발 역량에서 부족하다고 여기었던 진짜 설계를 배우는 과정이라는 확신이 생겼다.

 

하나씩 구조를 고민하고 코딩한 경험은 오랜만에 머리가 지끈지끈했다.

변수, 메서드, 클래스 하나하나 다 고민하고 생각했다.

 

어떻게 보면 미션에 던져진 나는 너무 막막하고 힘들지만

나는 이 힘든 과정이 나의 성장에 꼭 필요하다는 것을 알고 있다.

 

학교와 여러 스터디를 병행하면서 진행하여 너무너무 힘들지만!! 파이팅!

 

그리고 이번에 코드를 분리하면서 느낀 점은 

자바가 어려운 게 아니라 자바를 자바답게 사용하는 게 어렵다.

 

반응형

댓글