벌써 2주차 끝..? 최근에 정신없이 하루를 보내고 있다보니 시간이 정말 빠르게 흘러가네요🥲
1주차 회고에서 의지를 불태웠던 것과는 다르게, 2주차 기간 동안에는 중간고사 시험과 더불어 건강 악화와 개인 사정까지 마구마구 덮치는 바람에 개발에 대한 몰입과 프리코스 진행에 있어 매우 아쉬운 기간을 보냈던 것 같습니다..
육체적으로나 정신적으로나 많이 힘든 일주일이었지만, 최대한 마인드 컨트롤 하며 다음 주차에 대한 의지를 다잡는 것 또한 스스로의 소프트 스킬 디벨롭으로 생각하려 합니다..!
아직 도전은 끝나지 않았고, 제 사전에 포기란 없습니다🔥🔥
2주차 회고 시작!
두 번째 회고록 주제는 '코드 리뷰' 입니다.
Keyword : 코드 리뷰
1주차 회고록에서 아쉬웠던 점이자 하나의 목표로, 활발한 커뮤니티 참여를 꼽았었습니다. 특히, 프리코스 커뮤니티의 꽃이자 얻어갈 것이 가장 많다고 생각되는 코드리뷰를 통해 저의 2주차 코드를 살펴보며 배운 점을 회고하려고 합니다!

사실, 프리코스 정식 참여 전에 받았던 메일을 통해, 코드 리뷰라는 것이 있다는 것은 알고 있었습니다.
근데 막상 1주차 때는 디스코드(커뮤니티)나 문제 풀이, 제출 방식 등에 적응하느라 정신이 없어서 크게 신경쓰지 못하고 있다가, 이번 2주차 부터 참여하게 되었습니다.
확실히, 코드 리뷰를 받거나 직접 해드리는 경험을 통해 미처 생각하지 못했거나 놓친 부분에 대해 알 수 있더라구요?
특히, 다른 스타일의 여러 코드들을 보면서 스스로 더 좋은 방식에 대해 생각할 수 있는 견해가 생긴다는 점에서 정말 좋은 배움이 된 것 같아요!
이 좋은걸 왜 2주차부터 알았을까...
코드 리뷰.. 재밌다..!
Q .
'적어도 하나의 자동차를 입력해야 한다'는 부분이나,'시도 횟수는 최소 1 이상이어야 한다'는 검증 로직은 도메인과 밀접하게 관련된 부분이라 생각한다. View가 아니라 Model에서 처리하는 것은 어떤가?
'적어도 하나의 자동차를 입력해야 한다'
검증 로직 자체는 도메인과 밀접한 관련이 있다고 생각하지는 않습니다. 다만, 표현 상의 문제는 있다고 생각합니다.
해당 기능은 '입력값이 비어있거나, 공백은 허용하지 않는다'는 점을 명시하는 것이기 때문에, 예외 표현을 바꾸는 것이 옳다고 생각합니다.
private void validateNotBlank(String input) {
if (input == null || input.trim().isEmpty()) {
throw new IllegalArgumentException("입력값은 비어 있거나 공백일 수 없습니다.");
}
}
'시도 횟수는 최소 1 이상이어야 한다'
이 부분의 경우, 검증 책임은 View에서 입력를 받아 중간 도메인을 거치지 않고 바로 Controller에서 사용하기 때문에 View에 두었습니다.
특히, MVC 패턴에서 Controller는 Model과 View 사이의 흐름이나 예외 처리를 조율할 뿐이고, 도메인이나 입출력의 검증에 대한 부분은 각 계층에게 위임한다고 알고 있었습니다. 그래서 해당 검증에 대한 책임을 View에 둔 것도 있습니다.
해당 로직이 '도메인과 밀접하게 관련되어 있는가'에 대해서는 저 또한 맞는 것 같다는 생각이 들었습니다.
하지만, 검증을 위해 시도 횟수에 관련된 클래스를 만들어 위임하기에는 오버 엔지니어링이라는 생각이 들기도 하고, 과연 '이러한 방식이 객체지향적으로 옳은가?'에 대한 물음에도 아직 의문을 가지고 있습니다.
Q . 사용자에게 입력을 받는 동시에 문자열을 쉼표(
,)로 분리하고 있다. 입력값 파싱(parsing)은 View의 책임인가?
이때까지만 해도, View의 책임은 입출력을 관장하며 사용자에게 보여줄 형식과 입력 파싱에 대한 것이라고 알고 있었습니다.
하지만 해당 피드백을 접하고 나서, View의 역할과 책임에 대해 다시 생각해 보게 되었습니다.
View의 근본적인 역할이 사용자 인터페이스와 데이터 표현인 만큼, 파싱 책임은 Model이나 Controller에서 수행하는 것이 좀 더 객체지향적인 방법인 것 같다고 느꼈습니다.
Q . 각 기능을 의미있는 이름의 메서드로 분리하면 가독성이 더 좋아질 것 같다.
확실히 제어문을 기준으로 메서드를 분리하면, 메서드 명에 따라 해당 기능의 역할을 좀 더 명확하게 알 수 있고, 또 코드 들여쓰기(indent depth)를 줄이거나 메서드를 짧게 유지하는데에 큰 도움이 될 것 같다고 느꼈습니다.
Q .
racingGame.judge(carList)의 반환값이 우승자라고 추측하는 것은, 프로그램 작동 방식에 대해 정확히 알지 못하면 생각하기 힘든 것 같다.
저는 여태껏, 코드의 가독성은 들여 쓰기(indent depth)나 메서드 길이, 개행과 같은 부분만 생각했었습니다.
그런데 해당 피드백을 통해, 이러한 경우에는 코드 작성자 외의 리뷰어나 제 3자가 보았을 때 한 번에 이해하기는 힘들 것 같다는 생각을 처음으로 해보았습니다.
racingGame에서, 메서드명을 judge()가 아니라 좀 더 명확한 메서드명으로 바꾸거나, 아예 GameManager에서 우승자 출력을 위한 메서드를 따로 뺐어도 지금보다는 가독성이 좀 더 나아지지 않았을까 싶습니다.
Q . '자동차의 움직임'과 '자동차'를 분리한 이유는 무엇인가.
추후에 레이싱 게임의 규칙이 '무작위 난수가 5 이상일 때 자동차는 후진한다' 등 과같이 바뀔 수도 있겠다는 확장성의 측면을 고려하여 두 역할을 분리하였습니다.
만약 서비스가 변경될 가능성이 현저히 적을 때에는, 자동차 움직임에 대한 책임을 자동차 스스로 갖도록 하는 것이 객체의 응집도를 높이고 비용 절감 면에서도 더욱 좋을 것이라고 생각합니다.
Q .
InputView,OutputView같은 유틸 클래스들은 꼭 인스턴스를 생성해서 사용할 필요가 있는가.
해당 부분에 대해서는 옳은 방식이었다고 생각합니다.
입출력 메서드를 모두 public static으로 둬버리면, 해당 메서드들을 어느 클래스에서나 호출할 수 있기 때문에 객체 간의 책임이 모호해질 수도 있을 것입니다.
다만, 이번 피드백을 통해 유틸 클래스(유틸리티 클래스)에 대해 처음 듣게 되었고, 해당 부분에 대해 추후에 공부하기 위해 포스팅 내용으로 넣어보았습니다.
Q . 생성자가 아니라
from (of)메서드를 통해 생성자를 호출하는 이유는 무엇인가?
RacingCar 클래스에서, 객체 생성을 위한 디자인 패턴 중 하나인 '정적 팩토리 메서드'를 적용하려 했습니다.
정적 팩토리 메서드를 통해 객체가 스스로 검증하는 책임을 지녀, 객체 생성 전에 예외 발생하면 객체의 생성 자체를 하지 않도록 하려함 이었습니다.
이때, 정적 팩토리 메서드를 사용하기 위해서는 예외 처리 로직을 private static 으로 호출해야 했습니다.
프리코스 기간 동안 계속해서 좋은 코드에 대해 생각 하며 개발을 하다보니, '매 검증 로직을 정적으로 생성하다 보면 문제가 생기진 않을까?' 라는 의문이 생겼습니다.
또, 객체 안에 정적 팩토리 메서드가 여러 개일 때 생성자 내에서 검증 로직을 호출하면 각 정적 팩토리 메서드마다 '검증을 중복적으로 호출하지 않아도 되지 않을까?' 라는 의문이 생겼습니다.
2주차에는 검증 로직을 생성자에 넣는 방식을 선택했지만, 지금이었다면 맨 처음 생각대로 생성 전에 검증을 거쳐 사전에 차단하는 방식을 선택했을 것 같습니다.
무분별한 static에 대해서는 아직 고민해야될 부분이지만,
현재 프리코스 과제의 요구사항 자체는 크게 복잡하지 않은 수준이며 사전 검증 및 차단이라는 부분의 메리트가 더 크다고 느꼈습니다.
Q . 단순히 List에 객체를 추가하고 반환하는 RegisteredCarList 클래스를 정의하고 사용하는 이유는 무엇인가?
해당 클래스는 RacingCar를 담은 리스트를 객체화 한 '일급 컬렉션'으로 사용하여, 컬렉션의 불변성을 보장하고 상태와 행위를 한 곳에서 관리하기 위해 정의하였습니다.
다만, 아직 행위라고 볼 수 있는것은 add 메서드 밖에 없어 반쪽짜리 일급 컬렉션이라고 생각합니다.
추후에 리팩터링을 한다면, 현재 자동차 이름 중복 검증 책임만을 지니고 있는 CarRegistration 클래스를 없애고 해당 클래스가 가지고 있던 책임을 일급 컬렉션에 할당하여 응집도를 높이는 것이 좋을 것 같습니다.
이전에는 미처 생각하지 못한 부분들이 많이있었지만, 확실히 이번 코드 리뷰를 계기로 더 넓은 생각과 시야로 코드를 바라볼 수 있을 것 같습니다.
특히, 여러 사람들의 코드를 보다보니 어느 부분에서는 '나보다 많이 아는 것 같은데?', '이 사람 엄청 잘하는데?'와 같은 부분이 있다가도,
'이 부분은 내가 더 잘하는 것 같은데?' 와 같이 사람마다 깊이 아는 범위와 분야가 다르다는 것을 깨달았습니다.
이러한 부분이, "서로 경쟁자임을 떠나서 함께 성장해 나아가야 하는 이유"라고 생각합니다.
내가 남들에 비해 무엇을 알고, 무엇을 모르는지에 대한 부분은 스스로에 대한 메타 인지를 하게 해주며, 이것이 함께하는 성장의 1단계라 한다면
같은 '교육생'의 눈높이에서, 여러 사람들이 여러 방식과 경험을 통해 체득한 방식을 함께 공유하며 자신이 부족한 부분을 채워 나가는 것이 함께하는 성장의 2단계라고 생각합니다.
프리코스를 통해 이러한 단계들을 계속해서 돌다보면, 언젠가 성장해 있는 스스로를 볼 수 있을 것이라 믿습니다.
마지막 날, 시간에 쫓겨 급급하게 제출하느라 새로운 시도를 많이 해보지 못한것에 대한 아쉬움이 많이 남습니다..
특히, 우아한테크코스의 철학 중 하나가 '완벽하게 해내는 것'보다 '새로운 시도를 멈추지 않는 것'이라는 점에서 이를 지키지 못해 아쉬웠던 것 같네요.
2주차가 마무리되고 공통 피드백 사항으로 클래스와 함수에 대한 단위 테스트를 통해 의도한 대로 정확하게 작동하는 영역을 확보한다.가 있는 만큼, 이번 주차에는 TDD를 열심히 수행해 보겠습니다..!!