들어가면서
완벽하진 않지만 많이 성장할 수 있었던 그리고 객체지향과 조금 더 친해질 수 있었던 마지막 4주 차 회고 시작합니다..!(벌써 마지막이라니.. 아쉽아쉽.. 프리코스는 끝났지만 앞으로도 열심히 공부합시다!! 파이팅)
4주 차에 무엇을 공부했나?
1. 핵심 기능부터 구현하고자 노력하였습니다.
3주 차 코수타에서 준 코치님께서 기능을 구현할 때는 핵심부터 구현해 보라고 하시는 말씀이 기억에 남아서 4주 차 과제를 수행할 때는 핵심 기능부터 구현을 하기로 결심하였습니다. 기존에는 과제의 진행 흐름에 따라서 개발을 진행하였는데 4주 차 과제부터는 핵심 기능을 먼저 구현하게 되니 처음에는 어색하게 느껴졌지만 나중에 핵심 기능을 구현하고 나서 이전의 방식과 비교를 해보니 확실히 덜 중요한 클래스들보다 중요한 기능을 가진 클래스부터 개발을 하게 되어 조금 더 내가 처음에 의도했던 설계대로 구현이 되어간다는 것을 깨닫게 되었습니다. 그리고 핵심 기능부터 구현을 하게되니 개발 속도도 훨씬 빨라졌다는 것을 체감하게 되어서 앞으로도 개발을 할 때는 핵심 기능부터 구현을 해야겠다는 생각을 하게 되었습니다.
2. 명령 쿼리 분리 원칙에 대해서 알게 되었습니다.
오브젝트 서적을 열심히 읽으면서 중간에 명령 쿼리 분리 원칙에 대한 내용을 발견하였습니다. 기존에는 명령과 쿼리 분리에 대한 원칙을 모르고 구현을 하다 보니 명령과 쿼리를 한곳에 합쳐서 구현을 진행하였는데 명령과 쿼리를 한곳에서 뒤섞게 되면 내가 개발할 때는 괜찮을 수 있어도 협업을 하게 된다면 다른 개발자분들은 실행 결과를 예측하기 어려워지고 버그를 양산할 수 있다는 것을 알게 되었습니다. 이 내용을 읽고 나서는 구현을 할 때 나도 모르게 명령과 쿼리 법칙을 계속해서 떠올리면서 개발을 진행하게 되었고 공부를 할 때마다 새로운 관점을 배우고 성장하는 기분이 들어서 기뻤습니다.
3. 디미터의 법칙에 대해서 알게 되었습니다.
이전에 3주 차 과제를 진행하면서 전체 로직을 관리하는 Game이라는 객체가 다른 객체들에게 너무 많은 의존성을 지니고 있는 문제를 어떻게 해결을 해야 할지 고민을 하고 있었습니다. 그러던 찰나에 오브젝트 서적에서 결합도는 낮추고 응집도를 높일 수 있는 디미터의 법칙에 대해서 배울 수 있었고 4주 차 과제 설계에 적용을 할 수 있었습니다. 다만 디미터의 법칙에 너무 몰두해서 객체를 분리하려고 하다 보니 한 객체에서 다른 객체로 정보만 넘겨주는 싱크홀 패턴이 발생했다는 것을 알게 되었습니다. 그래서 다음부터는 조금 더 이런 부분을 보완할 수 있는 방법에 대해서 공부해서 조금 더 개선된 객체지향 설계를 하려고 노력할 것입니다.
4. 확장성을 고려하며 과제를 수행하였습니다.
4주 차 과제에서는 할인에 대한 내용이 나왔습니다. 처음에 과제를 수행할 때는 eventChecker라는 객체에서 메뉴와 날짜가 주어지면 정보들을 조합해서 이벤트를 체크해 주는 함수들을 만들었었습니다. 하지만 이것은 새로운 이벤트들이 추가되면 변동될 가능성이 너무 많았기 때문에 확장성을 갖추기 위해서 리팩토링을 해야 하는데 어떻게 해야 할지에 대한 감을 못 잡고 있었습니다. 그러던 와중 오브젝트 서적의 영화 할인 기능을 만드는 과정에서 DiscountPolicy라는 영화 할인 추상 클래스를 생성하고 그 추상 클래스를 상속받는 할인 정책들을 각각 만들어서 확장성과 유연성을 가진 객체지향적으로 구현하는 것을 보고 과제에 적용시켜야겠다는 생각을 하게 되었습니다. 기존의 로직들을 뒤엎는 큰 작업이 될 수 있었기 때문에 고민이 되었지만 프리코스 기간 중에 최대한 어려움을 피하지 말고 직면하여서 내가 적용할 수 있는 것들을 마음껏 실험해 보고 성장해 보고 싶다는 의지가 있었기 때문에 서적에 나온 내용을 공부하면서 기능을 완성할 수 있었습니다. 이 외에도 확장성을 고려하기 위해서 예를 들어 메뉴의 가격을 비교하는 로직이 있으면 메뉴의 가격이 변동되더라도 시스템이 정상 작동할 수 있도록 Menu Enum에 생성해놓은 값들을 가져와서 비교하는 등 섬세한 부분들을 신경 썼습니다. 이렇게 대규모 리팩토링을 피하지 않고 한번 해내고 나니 내가 해냈다는 뿌듯함을 많이 느낄 수 있었고 그 과정에서 많은 성장을 할 수 있었습니다.
참고한 깃허브 영화 예매 코드 : https://github.com/eternity-oop/object/blob/master/chapter09/src/main/java/org/eternity/movie/step03/DiscountPolicy.java
5. 정규식에 대해서 공부하였습니다.
4주 차 과제에는 메뉴 형식이 예시와 다른 경우 에러메세지가 나와야 하는 조건이 있었습니다. 처음에는 이 조건을 어떻게 구현을 해야 하는지에 대한 해답이 떠오르지 않았는데 그동안 리뷰를 진행하면서 다른 분들의 코드에서 보았던 정규식이 떠오르게 되었고 메뉴 형식을 검사하는 정규식을 도입해서 형식과 다를 경우 에러 메세지를 반환하는 함수를 만들게 되었습니다. 정규식을 직접 만들어보는 것은 처음이었기 때문에 인터넷에서 정규식을 참고해서
([\\\\w\\\\s]+-\\\\d+,)*[\\\\w\\\\s]+-\\\\d+";
”문자-숫자,” 의 형식을 검사할 수 있는 정규식을 만들 수 있었습니다. 하지만 문제는 이렇게 정규식을 도입하더라도 타파스&1, 과 같은 입력이 주어졌을 때 정규식이 이런 문자를 걸러주지 못하는 문제가 발생했습니다. 현재는 이 문제를 해결하지 못해서 정규식을 통하여 값을 한번 걸러주고 메소드 내에서 split을 진행할 때 에러가 나면 catch를 하도록 코드를 작성해 놓았는데 정규식에 대해서 더 깊이 공부해서 이런 문제를 해결할 수 있도록 할 예정입니다.
6. getter 사용을 지양하기 위해서 노력하였습니다.
4주 차 공통 피드백에서는 데이터를 꺼내지 말고 메세지를 던져라라는 항목이 있었습니다. 과제 수행 기간 중에 열심히 읽은 오브젝트에서도 이런 비슷한 내용이 있었지만 과제에 실제로 적용하기는 쉽지 않았습니다. 그래서 리팩토링을 진행할 때 많은 코드들이 메세지를 던질 수 있음에도 불구하고 getter를 통해서 데이터를 가져오고 있다는 것을 깨닫게 되었고 해결 방법에 대해서 고민한 끝에 getter를 사용하지 않고 메세지를 던지는 형식으로 리팩토링을 할 수 있었습니다. 예를 들어서 제 코드 중 총 주문금액에서 할인금액을 뺀 금액을 계산하는 로직이 있었는데 할인금액들 중 증정 메뉴의 금액은 빼고 나머지 할인금액들을 더해야 하는 로직이 있었습니다. 이 로직에서 기존에는 할인의 종류를 getter를 통해서 가져와서 비교를 하였는데 isGiveaway라는 Boolean을 반환하는 함수를 만들어서 객체 내부에서 메세지를 받으면 증정 메뉴인지 아닌지를 검사하여 true or false를 반환함으로써 조금 더 객체지향스럽게 리팩토링을 완료할 수 있었습니다.
변경 전 calculateExpectedPaymentAmount
public long calculateExpectedPaymentAmount(long totalOrderAmount) {
return totalOrderAmount + eventResult.stream().filter(result -> result.getName() !=EVENT_NAME_GIVEAWAY)
.mapToLong(DiscountInfo::getDiscount).sum();
}
변경 후 calculateExpectedPaymentAmount
public long calculateExpectedPaymentAmount(long totalOrderAmount) {
return totalOrderAmount + eventResult.stream().filter(result -> result.isGiveaway() == false)
.mapToLong(DiscountInfo::getDiscount).sum();
}
변경 후 isGiveaway 함수
public Boolean isGiveaway() {
if (name == EVENT_NAME_GIVEAWAY) {
return true;
}
return false;
}
7. 인텔리제이 단축키와 더 친해질 수 있었습니다.
점점 주차를 거듭하면 할수록 객체지향에 대한 이해도가 높아져서 많은 객체들을 생성하게 되었습니다. 그 과정에서 리팩토링을 할 때 하나의 메소드명을 바꾸면 다른 클래스에서도 수정을 해야 하는 경우가 많아지게 되었고 기존에는 단축키를 잘 몰라서 일일이 수정을 했었지만 한 번에 수정하는 IntelliJ 단축키를 통해서 손쉽게 해결할 수 있다는 것을 알게 되면서 개발 시간을 줄여줄 수 있는 단축키에 더욱 관심을 가지게 되었습니다. 그 이후부터는 TDD 테스트 코드를 짤 때 만들어둔 템플릿을 바로 생성해 주는 기능이라든지 메소드를 추출하여 분리해 주는 단축키라든지 많은 단축키에 대해서 더 공부하게 되었고 익숙해지고 배우려고 노력하게 되었습니다.
4주 차 아쉬웠던 점
1. 디미터의 법칙에 너무 집중하다 보니 다른 기능을 하지 않고 한 객체에서 다른 객체로 데이터를 넘겨주는 싱크홀 패턴이라는 안 좋은 패턴이 발생했다는 것을 알게 되었습니다. 다음번에는 조금 더 고민하여 이런 패턴을 없앨 수 있도록 노력할 것입니다.
2. Calulcator객체와 EventChecker라는 객체가 있었는데 두 객체를 분리하여서 Calculaotr에서는 계산만을 하고 EventChecker에서는 Check 기능만을 만들었어야 하는데 조금 더 기능이 분리된 클래스를 만들지 못하였습니다.
3. 3주 차에서는 controller의 비대함을 느껴 Service 계층을 도입해보고자 하였으나 4주 차에서는 객체를 많이 분리해서 그런지 controller에서 조합을 할 때 로직이 간단해서 service 계층을 도입할 이유가 없었습니다. service를 도입해서 짜보지 못해서 아쉽습니다.
4. 켄트 백의 테스트 주도 개발 방법 서적을 4주차에 다 읽게 되었지만 여유를 가지고 책에 나오는 원칙들을 적용해 보지 못해서 아쉽습니다. 그래서 프리코스가 끝난 이후에 다시 책을 천천히 읽으면서 TDD를 이용해서 개발을 진행해보고자합니다.
끝으로
매주 설레는 마음으로 과제를 수행하고 소감문을 제출한 게 엊그제 같은데 프리코스 과정이 마무리가 되다니 시간의 빠름을 느낍니다. 물론 즐겁기만 한건 아니고 공부를 하면서 힘든 순간들도 많았습니다. 하지만 힘듦은 내가 성장의 오르막길을 걷고 있다 라는 것을 알려주는 지표임을 알기에 그 힘듦마저 즐겁게 받아들이면서 공부했던 4주였습니다. 나중에 훌륭한 개발자로 잘 성장한 제가 과거를 돌아봤을 때 가장 많은 성장과 깨달음을 얻게 해준 시간이 언제였냐고 물으면 자신 있게 올해 프리코스를 꼽을 수 있을 것 같습니다. 그만큼 최선을 다해서 우테코 프리코스에 참여했기 때문에 떨어지더라도 마음은 아프겠지만 후회는 없을 것 같습니다. 워낙 잘하시는 분들이 많고 열심히 하신 분들이 많은 것을 직접 눈으로 보았기 때문에 최종 합격까지 할 수 있을 거라고 생각은 하지 않습니다. 하지만 우테코 1차 결과 발표 이후에 얼마 있지 않아 최종 시험이 있기에 그전까지 조금의 휴식을 취하고 최종 시험 준비 스터디에 들어가서 그동안의 과제들 리마인드와 더불어 최종 시험 대비를 진행하려고 합니다. 오늘은 그동안 최선을 다한 저에게 맛있는 치킨과 맥주를 선물해 주려고 합니다. 그동안 이런 좋은 학습의 기회를 제공해 주신 포비님과 코치님들 그리고 같이 열심히 공부한 프리코스 참가자분들도 모두 행복하고 보람찬 하루가 되셨으면 합니다. 그리고 또 꼭 합격해서 우테코에서 다시 만날 수 있었으면 좋겠습니다. 감사합니다.
+ 4주 차 크리스마스 레포지토리
https://github.com/junhyeongkim2/java-christmas-6-junhyeongkim2
'우아한테크코스 프리코스' 카테고리의 다른 글
우테코 6기 프리코스 3주 차 로또 회고 (0) | 2023.11.09 |
---|---|
우테코 6기 프리코스 2주 차 자동차 게임 회고 (1) | 2023.11.02 |
우테코 6기 프리코스 1주 차 숫자야구 회고 (1) | 2023.10.26 |