현재 3회차 로또 게임이 끝난 시점에서 2회차에 진행했던 레이싱게임의 코드를 보면서 2회차의 회고록에 대해서 작성해보고자한다.
난이도 측면에서는 1회차 2회차 둘 다 그렇게 어렵진 않았다고 생각한다. 거의 난이도의 차이가 없을정도 였던거 같다. 물론 1회차보다 더 많은 기능 구현 사항과 그에 따른 클래스의 볼륨이 커져서 이를 나누기 위해 클래스가 많아졌다는거 말곤 딱히 없었다.
그래서 하루이틀 만에 기능 구현 사항을 모두 구현해놓고 리팩토링에 들어갔었다.
1회차에서의 단점들을 2회차에서는 어떻게 풀어냈는지 보면서 거기서 생겼던 문제들을 살펴보겠다.
기능 구현 사항

수도 코드 작성하기 (SRP 원칙 지키기)
// TODO: 프로그램 구현
/*
Printer.print(SystemMessage.START_MESSAGE);
String carNames = Console.readLine();
Printer.print(SystemMessage.ATTEMPT_COUNT_MESSAGE);
String count = Console.readLine();
List<Car> list = Car.createCars(carNames);
GameDirector.run(list, count);
*/
먼저 애플리케이션의 Main 메서드에서 애플리케이션의 실행 순서를 먼저 정함으로써 어디서 데이터를 입력받고 해당 데이터를 어떻게 누가 처리할 것인지에 대해서 탑다운 방식적용 시키기 위해 수도 코드를 먼저 작성하고 이를 바탕으로 코드를 작성했다.
1회차를 진행하면서 해당 방식으로 진행하지 않았을 때의 문제점이 SRP 원칙을 지키지 않았던 문제점 때문에, 먼저 클래스의 역할과 기능을 정의하기 위해 수도 코드를 작성하고 탑다운 방식으로 설계를 하게 되었다.
먼저 이렇게 하고나니 클래스를 생성할 때 받는 데이터와 해당 데이터를 가지고 해야할 일이 명확하니 1회차를 진행했던 것보다는 코드들이 캡슐화가 더 잘되어있단 느낌(?)이 들었다.
수도 코드로 먼저 작성해놓으면서 SRP 원칙에 대해서 깊게 생각하면서 코드를 작성했었다.
정책 정하기 (가독성을 올리고, 유지보수성과 확장성 높이기)
public enum Condition {
RANDOM(//...);
//.... 움직이는 조건 및 기능 구현
자동차가 움직이는 조건을 해당 enum클래스에서 조정할 수 있고, 자동차가 움직이는 새로운 정책이라던가, 정책이 변경 될 경우 -> 확장성을 높이기 위해서
그리고 enum 클래스로 생성함으로써 가독성 적인 측면에서 어떤 정책이 현재 적용되는지 눈에 쉽게 띄고 어떻게 움직이는지에 대해서의 로직은 enum 클래스가 내부에서 가질 수 있도록 구현하였다.
이 역시 1회차에서의 느꼈던 문제점을 인지하고 바로 적용한 부분이였다. 근데 이게 정확히 어떤 시점에 정책이 결정되고, 어느 클래스에 있어야 맞는가? 에대한 감이 확 오지 않아서, 해당 부분을 만들어 놓고 어느 시점에 적용해야 하는지 한참 고민했었다.
결국 움직이는 것은 Car 객체이니, Car 클래스의 생성자에서 초기화 해주는 방식으로 코드를 작성했는데, 썩 눈에 띄지도 않고 맘에들지는 않는다... 하지만 더 나은 방법도 모르겠다. 해당 정책을 Application의 Main 메서드의 두자니 해당 정책 부분을 몰라도 되는 클래스들도 전파되다보니, 그냥 Car 클래스가 가지기로 하여서 넣어두었다.
기본기가 부족함....
public abstract class Printer {
public static void print(SystemMessage message) {
printMessage(message.getMessage());
}
public static void print(Car car) {
printMessage(car.toString());
}
public static void breakLine() {
printMessage("");
}
public static void print(SystemMessage message, String winner) {
printMessage(message.getMessage() + winner);
}
private static void printMessage(String message) {
System.out.println(message);
}
나의 Application의 진행상황을 콘솔로 보여줄 Printer 클래스이다.
코드를 보면 파라미터로 SystemMessage와 String 타입의 데이터를 받아서 처리하는데, 보통
private static void printMessage(String message) {
System.out.println(message);
}
해당 기능을 하나 만들어 놓고 해당 메서드를 오버로딩 하는 개념으로 만들어서 계속 사용하고있다.(현재 코드의 문제점이다)
내가 해당 유틸클래스를 정의하고 사용한 이유는 단순히 System.out.println() 함수를 사용하기 보다는 뭔가 그 출력되는 부분에 대해서 어떤 데이터를 담고 있으며 어떻게 출력할 것인지에 대해서 이름을 정해주기 위해 해당 유틸클래스를 만들어서 사용중이였는데...
인자로 들어오는 데이터의 타입이 String 뿐만이 아니기 때문에, 해당 타입이 바뀌거나 추가될 때마다 메서드를 오버로딩하고있다....
그래서 해당 부분을 어떻게 하지 어떻게 하지... 하고 생각하다가 나온게
public static void printMessage(Object...messages) {
for (Object message : messages) {
System.out.print(message);
}
System.out.println();
}
인자를 Object 배열로 받아서 메시지를 처리하는 로직을 작성하는 것이였다.
이렇게 하면 해당 함수를 사용하는 개발자 입장에서는 어떠한 타입이라도 받아서 처리할 수 있으니까, String, enum... 등등 다른 타입을 받아서 메시지를 출력할 수 있게끔 할 수없을까? 라는 취지에서 나온 코드이다.
물론 enum 타입같은 경우 enum.toString() or enunm.getMessage()와 같은 getter를 만들어서 넘겨버리면
private static void printMessage(String message) {
System.out.println(message);
}
해당 타입의 메서드 하나로 해결이 가능하지만 해당 코드를 호출해서 사용하는 쪽인 클라이언트 코드쪽에서 .toString(), .getMessage()여기서 이 .이 맘에들지 않았다.
이뻐보이지 않아서(?) 그런 이유로 Object 배열로 받아서 처리할 수 있도록 리팩토링을 진행하게 되었었다.
근데 Object... 부분을 사용하게 되니 뭔가 모든 타입을 다받아서 처리할 것 같고 컴파일에러가 없다는 점에서 좀..불안해가지고
@SafeVarargs
public static <T> void printMessage(T... messages) {
//... 출력 로직
}
제네릭 방식으로 리팩토링하였다. 제네릭 방식으로 처리할 때가 타입 안정성이 있으니... Object 만큼의 유연성은 없지만 현재 내 코드에서는 String + Integer 타입을 출력한다거나 그런 부분은 없으니까 제네릭 방식을 택하게 되었다.
그래서 최종 형태는 기존에는 한가지 메서드를 계속해서 오버로딩해서 사용했다면 Printer 클래스에는 해당 메서드 하나만 딱 남게되었다.나름 만족하는 리팩토링중 하나였다.
느낀점
이번 2회차는 1회차와 비슷한 흐름으로 코드가 진행되고 기능 구현사항도 그렇게 어렵지 않아서 1회차에 느꼈던 단점들을 보완해보고자 하는 마음으로 2회차를 진행했다. 나름 코드를 어떻게 작성해야 하는지에 대한 감도 어느정도 생기고 1회차와 비슷한 난이도여서 우테코 측에서 어디한번 1회차의 어떤 단점을 느꼈는지, 2회차에서는 어떻게 보완하는지 볼까?? 하는 마음으로 낸거같은 느낌이 들정도로 1회차와 2회차가 비슷한 느낌이 많았다.
현재 3회차가 끝난 시점에서... 엄청난 벽을 느꼈지만... 3회차가 끝난 시점에서야 또 보이는게 있어서 4회차가 끝나자마자 3회차에 대한 회고록 또한 빨리 작성해보고싶다.
내가 우테코에 지원하면서 느끼고 싶었던 부분은 내가 뭐가 부족한지, 어느 부분을 더 공부해야하는지, 어떻게 공부를 해야하는지에 대한 방식들이였는데 해당 부분들을 이런 단기간에 알게되어서 기쁘기도 하고... 갈길이 멀구나.. 하는 생각도 들지만 이런 경험치가 쌓여서 1~2년 뒤에는 더 나은 모습의 내가 있을 테니 힘도 많이나는 건 사실이다!! . 4회차도 열심히 준비해보자!!
'회고록' 카테고리의 다른 글
| [인프런 워밍업 클럽 스터디 - 테스트 코드를 대하는 자세 2주차 회고] 어떤 것이 더 적절한 단위 테스트인가? (0) | 2025.03.17 |
|---|---|
| [우테코 7기 백엔드 회고] 4주차 편의점 (1) | 2024.11.18 |
| [우테코 7기 백엔드 회고]3주차 로또 (0) | 2024.11.12 |
| [우테코 7기 백엔드 회고] 1주차 미션 문자열 계산기 (0) | 2024.10.28 |