발자국 1주 차
본 내용은 인프런 워밍업 클럽 스터디를 진행하면서 작성한 회고 글 입니다.
배운 것
절차형 프로그래밍 방식으로 구현된 '지뢰찾기'게임을 여러 추상화 기법과 객체지향 원칙을 적용해서 리팩토링하는 과정을 진행했다.
섹션 1에서 간단한 강의 구성과 프로젝트 설명을 듣고 섹션 2부터 코드를 가지고 리팩토링을 하게된다. 섹션 2에서 소개한 추상화 기법은 다음과 같다.
이름 짓기
메서드 선언부
추상화 레벨
매직 넘버, 매직 스트링
여기서 이름 짓기, 메서드 선언부, 매직 넘버/스트링에 대한 내용은 이미 어느정도 알고 있었던 내용이기도 하고 실제 프로젝트를 진행할 때도 고민을 했었던 부분이었다. 그래서 내가 알고 있는 내용 중에서 틀린 부분이 있는지에 집중하면서 들었던 것 같다.
반면, 추상화 레벨 파트에서 소개해주신 내용은 내가 무의식적으로 수행했었던 내용이었다. 프로젝트를 진행하면서 구현 내용이 길게 작성이 되면, 코드를 읽기 불편하다는 기분이 들어서 별도의 메서드로 분리하곤 했는데, 이게 강의에서 소개한 추상화 레벨을 맞추는 행위였다. 확실히 추상화 레벨을 맞춘 메서드가 더 읽기 편하게 느껴졌고, 앞으로 프로젝트를 진행할 때 이 내용은 완벽하게 적용을 해야겠다고 생각했다.
섹션 3에서는, 뇌가 저장해야 하는 인지적 부하를 줄여서 읽기 쉬운 코드를 만드는 방법을 배운다.
Early return
사고의 depth 줄이기
공백 라인을 대하는 자세
부정어를 대하는 자세
해피 케이스와 예외 처리
이 중 예외 처리 파트에서, 복구할 수 있는 예외와 없는 예외를 구분해서 처리하는 것이 인상깊었다. 나머지 Early return 같은 내용은 아래에 적을 Day4미션에 적용하면서 실전 감각을 길렀다.
섹션 4와 5는 강의에서 가장 긴 섹션이면서, 실제 코드의 변경이 매우 많이 일어나는 파트였다. 섹션 4에서 소개된 SOLID 원칙을 적용하면서 변경이 용이한 코드로 구조가 개선되었으며, 섹션 5의 VO, Enum, 일급 컬렉션 등을 적용해서 하나의 의미있는 객체로 승급시키고, 외부에 산재되어 있던 로직을 객체가 책임지게 하는 방법을 알게 되었다.
보완할 점
1주 차에 진행되었던 섹션 5까지의 강의 분량이 10시간 정도여서, 1주일이면 여유있게 듣고 적용할 수 있을거라고 생각했었다. 그런데 강의에서 들었던 내용을 요약 정리하고, 리팩토링도 직접 따라하면서 들으니까 실제로 걸리는 시간이 정말 많이 들었다. 그래서 강의에서 진행된 리팩토링을 그대로 따라 치는 방식으로 듣게 되었는데, 원래 코드로 돌아가서 내가 혼자 진행한다면 이런 구조의 코드를 만들어낼 수 있을지에 대한 의문이 들었다. 많은 연습이 필요하다고 느껴져서 다음 주에는 조금 더 많은 시간을 투자해야겠다는 생각이 들었다. 그리고 이번에 배운 내용은 자바 프로그램 뿐만 아니라 모든 프로젝트에 적용이 가능하고 정말 기본이 되는 내용이기 때문에, 매 프로젝트를 할 때마다 이번에 배운 내용을 의식적으로 적용하는 연습을 해야겠다.
Day2, Day4 미션
1주 차에는 Day2와 Day4 2개의 미션이 주어졌다. Day2 미션은 추상과 구체에 대한 예시를 작성해보는 간단한 미션이었다. 나는 섹션 2의 추상과 구체 강의를 참고하여 사물을 보는 과정을 추상과 구체 레벨로 표현하여 미션을 제출했다.
Day4 미션은 아래의 코드를 섹션 3에서 배운 인지적 부하를 줄이는 방법을 사용해서 리팩토링 하는 것이었다.
public boolean validateOrder(Order order) {
if (order.getItems().size() == 0) {
log.info("주문 항목이 없습니다.");
return false;
} else {
if (order.getTotalPrice() > 0) {
if (!order.hasCustomerInfo()) {
log.info("사용자 정보가 없습니다.");
return false;
} else {
return true;
}
} else if (!(order.getTotalPrice() > 0)) {
log.info("올바르지 않은 총 가격입니다.");
return false;
}
}
return true;
}
주문 객체의 유효성을 검증하는 로직인데, 중첩된 if-else로 로직을 한 번에 알아보기 힘들다.
이를 개선하고자 Early return을 사용하여 depth를 줄이고 코드를 읽는 사람이 기억해야 하는 정보를 최소화했다.
public boolean validateOrder(Order order) {
if (order.getItems().size() == 0) {
log.info("주문 항목이 없습니다.");
return false;
}
if (!(order.getTotalPrice() > 0)) {
log.info("올바르지 않은 총 가격입니다.");
return false;
}
if (!order.hasCustomerInfo()) {
log.info("사용자 정보가 없습니다.");
return false;
}
return true;
}
이전 코드에 비해서 확실히 읽기 수월하지만, 두 번째 if문을 읽을 때 "주문의 총 금액이 0보다 큰 게 아니면~" 이런 식으로 읽힌다. 부정어 때문에 앞에서 읽은 내용을 반대로 생각해야 하는 불필요한 부하가 생긴다.
부정어를 없애고, 추가로 order의 총 금액이나 주문 항목을 get으로 꺼내지 않고 주문 객체에게 묻는 방식으로 코드를 개선했다.
public boolean validateOrder(Order order) {
if (order.isEmpty()) {
log.info("주문 항목이 없습니다.");
return false;
}
if (order.isInvalidTotalPrice()) {
log.info("올바르지 않은 총 가격입니다.");
return false;
}
if (order.isCustomerInfoMissing()) {
log.info("사용자 정보가 없습니다.");
return false;
}
return true;
}
개선된 코드는 부정어를 제거하여 자연스럽게 읽힌다. 그리고 주문 항목이나 총 금액을 꺼내지 않고 적절한 메서드를 만들었기 때문에 재사용성과 응집도가 향상되었고, 결합도는 낮추는 효과를 얻을 수 있었다.
SOLID에 대하여 자기만의 언어로 정리하는 것도 미션 내용에 있었는데, 강의를 들으면서 정리했던 걸 간략하게 요약해서 제출했다.
간단 회고
강의에 대한 내용으로 미션이 주어졌기 때문에, 학습한 것을 실제로 적용해볼 수 있어서 재미있었고, 앞으로 개발을 할 때 이 내용은 확실하게 적용을 할 수 있겠다는 자신감을 얻었다. 생각보다 더 빡빡한 일정이지만 남은 3주도 열심히 해서 많은 내용을 내 것으로 만드는 시간이 되도록 할 것이다.
댓글을 작성해보세요.