프리코스 1주차 - 숫자야구 게임 구현이 끝났다.
https://github.com/Anyeon00/java-baseball-precourse
프리코스를 진행해보며 느낀 점이 몇 가지 있었다.
첫 번째로 프로그래밍 요구사항인 "함수(또는 메소드)가 한 가지 일만 하도록 최대한 작게 만들어라"를 따르며 느낀 점이다.
나는 원래 메서드를 상당히 기능단위로 분리하는 편이었다. 왜냐하면 나는 프로그램을 사람이 생각하는 것과 동일하게 짜는 걸 좋아했기 때문에, 일일이 이 코드는 뭘 하는 부분이라고 메서드로 쪼개서 작성하고는 했었다. 그렇다해도 어디까지나 단순 내 취향에 따랐던 것이므로 결국 그냥 내 편의대로 비교적 자유롭게 만들어 사용했었다.
그런데 이번 프로그래밍 요구사항에 따라서 메서드를 이렇게까지 쪼개려고 하다보니, 처음에는 조금 어색하기도 하고 이래도 되나 라는 생각까지 들었다. 그런데 막상 쪼개놓고 보니 쪼갠 메서드를 사용하는 쪽도 예상과 다르게 훨씬 보기 좋았고, 쪼개진 메서드 쪽도 무슨 일을 하는 메서드인지 코드만 봐도 한 눈에 알 수 있음을 느꼈다. 그 대표적인 예가 다음 사진의 코드였다.
InputInspector 클래스
사용자의 입력 형식을 검증하여, IllegalArgumentException을 발생시키는 메서드를 제공하는 클래스
- inputUserAnswerInput() : 사용자가 제출한 답의 입력형식을 검증하는 메서드
원래는 6,7,8 라인의 checkContainsZero(), checkEqualsDigits(), CheckIsNum() 이 세 개의 기능이 메서드로 분리되지 않고, 통째로 포함되어 있었다. 쪼개기 전에는, 이를 쪼갤 생각도 안해봤고 쪼개려고 하니 앞서 말한 것 처럼 이래도 되나 싶은 생각이 들었는데, 쪼개고나니 코드가 너무 깔끔해져서 보이는 것 처럼 주석도 그냥 지워버렸다.
그리고 이런 식으로 쪼개진 메서드들도 정확하게 하나의 기능만을 수행하게 되어, 업무를 분할하여 협업을 하거나, 또는 각 기능에 대하여 리팩토링 할 때 훨씬 수월해질 것이 보였다. 한마디로 정처기에서 배운 결합도가 낮아지고 응집도가 높아지며 생기는 이점들을 체감할 수 있었다.
또 이런 경험이 처음이다보니, 기능 단위로 분리하고자 하여도 뭔가 깔끔하고 예쁘게 분리하기 어려움을 느낀 부분도 있었다. 다음 사진의 코드가 그 부분이었다.
AnswerProcessor 클래스
사용자가 제출한 답을 처리해주는 클래스
- Score : 사용자가 제출한 답의 점수를 저장하는 Inner클래스 (strike갯수, ball갯수, nothing여부)
- judge() : 사용자가 제출한 답으로 Score를 생성하고, 출력하고, 정답여부를 리턴하는 메서드
- generateNowScore() : 사용자가 제출한 답으로 Score를 생성하는 메서드
(34~41 라인의 코드를 checkNowDigits()으로 쪼개고, 이를 checkStrike()와 checkBall()로 한 번 더 쪼갠 상황이다)
34~41 라인을 보면 원래 리팩토링 전에도 isStrike(), isBall()등의 메서드로 쪼개어 사용하고 있었다. 그런데 이렇게 사용하니 isStrike()면 strike를 ++해주는 코드가 그 밑에 따라 붙는데 여기까지가 strike를 처리하는 로직이 된다. 따라서 바로 밑의 ball을 처리하는 로직과 분리를 위해, 메서드로 한 번 더 쪼개야 하나 고민하였다. 요구사항을 따르자니 그렇게 쪼개야 하는데, 당연하게도 강한 위화감을 느꼈고 이걸 어떻게 해야 하지 하고 한참 고민하게 되었다.
그러다 생각 끝에, isStrike()와 strike++하는 코드를 하나의 메서드로 합쳐서 checkStrike()로 만들어 해결하였다. checkStrike()를 만들고 보니, 굳이 if문 내용을 isStrike()로 한 번 더 분리하지 않아도 될 것 같았다. (하고나서 보니 이걸 왜 고민했지 싶다) checkBall도 마찬가지였다.
또한 checkStrike로 boolean을 리턴받아, isStrike면 볼 검사를 건너뛴다고 코드상으로 작성할 수 있어, 사용하는 쪽의 가독성도 훨씬 개선할 수 있었다.
이렇게 직접 프로그래밍해보니 자연스럽게 이런 점들을 느꼈다. 그래서 드는 생각이 백날 결합도가 이렇니 응집도가 저렇니 말로 할 필요없이, 그냥 이렇게 한 번 해봐. 그러면 자연스럽게 깨닫겠지. 하는게 이 프로그래밍 요구사항을 내준 의도가 아닐까 싶었다.
그리고 단순히 내가 직접 프로그래밍한다는 것 뿐만 아니라, 요구사항 등을 지키며 구현하는 과정에서 배우고 깨닫는게 생기니 더욱 재미있었다.
사실 느낀점의 대부분은 위의 내용들이었고, 두번째로 느껴진 점은 commit에 대한 부분이었다.
지금까지는 그냥 단순히 현재까지 작업내용을 저장한다는 개념으로 commit을 사용하였다. 당연히 커밋 메시지도 크게 신경쓰지 않았다. 하지만 기능단위로 커밋함에 따라, 커밋 로그를 확인하기가 굉장히 용이해졌음을 느꼈다. 또한 커밋 메시지의 컨벤션을 지킴으로써 지금까지의 작업과정과 내용을 확인하기가 굉장히 좋아졌다. 만약 협업을 하는 상황이라면 정말 필수적인 행동양식이구나 라는걸 느꼈고, 코드리뷰를 주고받음에 있어서도 마찬가지로 꼭 필요하겠다고 느꼈다.