메타인지를 위한 최고의 도구 중 하나는 회고입니다. 회고를 통해 우리는 학습과 경험을 그냥 지나치지 않고 반성하고 개선할 수 있습니다. - 프리코스 2주 차 공통 피드백 中
벌써 프리코스의 절반이 지나갔습니다. 미션이 마감되고 제출된 많은 PR을 구경하다 보면 새로운 방법이 떠오르기도 하고, 걱정이 많아지기도 합니다.
그래도 주도적으로 부족한 부분을 학습하는 시간이 늘었고, 다양한 지원자분들과 관점을 공유하거나 제가 작성한 코드를 어떻게 이해했는지 리뷰를 남겨주셔서 많은 부분을 돌아보게 된 것 같습니다.
저는 다양한 의견을 듣고 배울 기회를 소중히 여기며, 함께 성장하고 싶습니다.
프리코스 2주 차에는 공감되는 피드백을 학습하고 생각해 보는 것을 가장 중요하게 생각했습니다. 1주 차 미션의 목표가 함께 성장할 준비
였고, 피드백을 주고받으며 이를 제 것으로 흡수하는 과정에서 많은 성장을 할 것으로 기대했기 때문입니다.
코드 리뷰를 정리해 보고 공감되는 부분을 찾아 학습하고 이를 적용하려고 했습니다.
1주 차 미션에서 구분자를 객체로 다루고 기본 구분자와 사용할 수 없는 구분자를 enum으로 관리하도록 구현했습니다. 덕분에 구분자 규칙을 명확하게 확인할 수 있었고, 큰 변경 없이 새로운 구분자를 추가할 수 있게 되었습니다.
많은 분이 제 의도를 알아주어서 많이 좋았습니다. 앞으로도 더 명확하게 코드의 의도를 전달해야겠다고 생각했습니다.
그래서 2주 차 미션에서 자동차의 움직임 여부를 결정하는 로직을 하나의 패턴으로 분리했습니다. 움직임 전략 인터페이스에는 움직일 수 있는지 확인하는 하나의 메서드만 존재하고 만들려는 규칙에 맞게 움직임 전략 구현체를 만들어 사용하도록 설계했습니다. 덕분에 기본 규칙에 따라 무작위 값을 기준으로 자동차가 움직이는가?
를 테스트하는 것이 아니라 특정 전략에 맞춰서 자동차가 움직이는가?
를 테스트할 수 있게 되어 더 깊은 부분까지 테스트 코드를 작성해볼 수 있었습니다.
다른 사람이 보더라도 의도를 쉽게 파악할 수 있게 작성하려고 하고, 그 부분이 전달되는 것을 기대하고 있습니다. (네이밍과 코드 컨벤션 등)
지금까지 저는 해당 객체가 스스로 검증하고 생성되도록 설계하는 것을 좋아했습니다. 런타임 시점에 생성된 모든 객체가 모두 검증된 상태임을 보장하고, 코드가 안정적으로 동작할 수 있다고 생각했습니다.
저와 같은 의견을 가지신 분도 있지만, 약간의 우려를 말씀해 주신 분도 계셨습니다. 특히, 검증 로직이 많아질수록 객체의 역할이 묻히는 느낌을 받게 되고, 검증 로직이 여러 곳에 흩어져서 한눈에 파악하기 어렵다는 것이 문제가 될 수 있다는 것을 인지하게 되었습니다.
여러 방법을 직접 경험하고 더 좋다고 판단되는 것을 고를 수 있는 개발자가 되고 싶었습니다. 그래서 2주 차 미션에서는 검증 로직을 한 곳으로 모아서 책임지는 객체를 만들어보기로 했습니다.
2주 차 미션에서 자동차 경주를 위해 신청서를 작성하는 것처럼 신청폼이라는 개념을 코드에 도입하려고 했습니다. 덕분에 한번에 검증 로직을 파악할 수 있었고, 검증 로직이 한 곳으로 모여있으니 테스트 코드에서도 각 객체의 역할과 책임을 잘 표현할 수 있었습니다.
다만, 검증되지 않은 객체가 런타임 동안에 생성되는 것을 물리적으로 막을 수는 없기 때문에 이 부분에 대해서 고민이 필요한 것 같습니다. (검증 로직 중복을 막기 위해 입력값 검증 이후 각 객체는 별도의 검증 없이 검증된 입력값을 사용하는 방식으로 구현했습니다.)
위 질문에 대한 답변입니다.
서비스를 왜 만들게되었는지는 설명할 수 있었으나, 피드백 이후 다시 읽어보니 관리하는 책임이 많다고 생각했습니다.
그래서 이번에는 단일 책임 원칙을 의식하며 지키려고 노력했습니다. 이 과정에서 테스트 코드를 작성하는 것이 가장 많은 도움이 되었습니다. 테스트 케이스를 고민하다가 필드에 따라 너무 많은 경우의 수가 필요하거나, 중간 과정이 아닌 큰 메서드 하나의 결과만 확인할 수 있는 경우에 여러 개의 책임을 가진 것은 아닌지 생각할 수 있는 중요한 지표였습니다.
초기 자동차 경주는 라운드 진행(시도한 횟수만큼), 움직임 전략에 따라 이동 명령(라운드마다), 경주 기록 반환 등 다양한 역할을 모두 수행하고 있었습니다. 그래서 객체의 필드(상태)가 많아지게 되었고, 메서드 분리만으로는 복잡성을 줄이기 쉽지 않았습니다.
필드(상태)가 많을 때 발생하는 문제 (학습 내용 요약)
- 필드가 많으면 코드의 복잡도가 증가하고 이해하기 어려워집니다.
- 필드 값 조합을 모두 고려해야 하므로 테스트가 어려워집니다.
- 여러 필드가 얽혀 있어 단일 책임을 구현하기 어렵고, 특정 필드와 관련된 기능만 수정하려 해도 다른 필드와의 연관성 때문에 쉽게 수정하기 힘듭니다.
이 문제를 해결하고자, 라운드 관리와 경주 기록 반환의 책임을 가진 객체로 분리했습니다. 이렇게 구조를 나누면서 필요한 부분만 수정하거나 테스트하기가 한층 수월해졌습니다. 예를 들어, 경주 기록에 시간 정보를 추가해야 할 경우, 경주 기록을 담당하는 객체와 기록 객체(DTO)만 수정하면 구현할 수 있습니다.
이 문제를 해결하기 위해 라운드 관리
와 경주 기록 반환
의 책임을 각각 독립된 객체로 분리했습니다. 이렇게 구조를 나누면서 특정 부분만 수정하거나 테스트하기가 훨씬 편해졌습니다. 예를 들어, 라운드 관리 객체에서는 라운드를 정해진 횟수만큼 정확히 진행할 수 있는지에 집중하여 테스트할 수 있었습니다. (이전 구조에서는 자동차와 경주 전체를 생성하고, 라운드 진행과 경주 기록 반환을 한 번에 테스트해야 했던 번거로움이 있었습니다.)
마지막으로 생각하지 못했거나 놓쳤던 부분에 대한 피드백입니다. 다른 지원자분의 꼼꼼한 리뷰로 알 수 있게 되었습니다. 문제가 될 수 있는 부분을 보완하고, 제출 전 요구 사항을 다시 한번 검토하는 과정으로 실수를 줄이려고 했습니다.
저는 그동안 구현할
기능 목록을 작성할 때 미리 모든 상황을 꼼꼼히 고려해 설계한 후 그대로 따르는 방식을 선호했습니다. 그러나 예상보다 시간이 많이 소요되었고, 정해둔 틀에 갇혀 자유롭게 수정하기가 어렵다는 느낌을 받았습니다.
2주 차 공통 피드백에서 구현할 기능 목록을 죽은 문서가 아닌 살아있는 문서로 유지하도록 지속적인 업데이트가 필요하다는 피드백에 큰 공감을 했습니다.
더 나은 프로그램을 만들기 위해 주기적으로 기능 목록 문서를 확인하고 필요한 경우 변경하려고 합니다.
2주 차 미션에서는 1주 차 미션에서 받은 피드백을 분석하고 이를 학습하거나 적용하려고 했습니다.
프리코스 커뮤니티를 활용해 상호 코드 리뷰를 진행했습니다. 미션을 수행하면서 놓쳤던 부분을 알게 되면서 부끄럽다는 생각도 했지만, 한편으로는 먼저 알게되고 다음 미션을 수행하기 전에 미리 생각해 볼 수 있게 되어 다행이라고 생각했습니다.
다양한 의견을 접하는 것은 장점이지만, 리뷰 요청이 제한 없이 쌓일 때는 리뷰의 질이 떨어진다는 점도 알게 되었습니다. 제한된 시간 내에 성장에 집중하려면 피드백하는 시간을 더 체계적으로 관리하는 것이 필요하다고 생각했습니다. 그래서 코드 리뷰 인원의 제한을 두거나 중점적으로 봐주면 좋을 부분을 어필한다면 더욱 도움 되는 의견을 많이 받을 수 있을 것 같습니다.
추가적으로 단순히 해결 방법을 제시하기보다 문제의 원인을 꼼꼼하게 설명해 주는 것이 서로에게 더욱 의미 있는 학습 기회를 제공한다는 사실을 다시 한번 느꼈습니다.
1주 차 미션에서는 단순히 "이런 입력이 들어오면 이러한 결과가 나온다.", "특정 입력이 주어졌을 때 예외가 발생한다."와 같이 프로그램의 실행과 결과만을 테스트했습니다.
이후 프리코스 1주 차 공통 피드백을 참고하여 테스트 방법을 학습했고, 각 객체가 역할을 잘 수행하고 있는지를 확인하는 테스트를 작성해 봤습니다. 만약 테스트하기가 너무 어렵다거나 디테일한 테스트를 작성할 수 없는 경우 분리를 고민했던 것 같습니다.
이를 통해 느낀 테스트 코드 작성의 큰 장점은, 객체가 너무 많은 책임을 가지고 있는지 아닌지를 파악할 수 있는 좋은 기준이 되었다는 점입니다.
앞으로도 다양한 사람과 피드백을 주고받으며 더 나은 선택을 할 수 있도록 학습하고 적용할 예정입니다.
감사합니다.