나의 독학은

[프리코스 4주차] 크리스마스 프로모션 회고 본문

회고/우아한테크코스 6기 프리코스 회고

[프리코스 4주차] 크리스마스 프로모션 회고

안종혁 2023. 11. 17. 21:34

😊4주차 목표

  • 1, 2, 3주차에 학습한 모든 것들을 코드에 녹여내서 아쉬움이 남지 않도록 최선을 다하기!

😊4주차 목표

☆ 코드의 전문입니다.

 

✅ 어려울 수록 빛났던 테스트 코드

이번 주차도 <구현 → 테스트코드 → 커밋> 을 지키면서 테스트 코드의 장점인 코드에 대한 피드백을 빨리 받고자 했다.

그렇게 다음과 같은 것들을 누리게 되었다.

 

  1. 람다식으로 예외를 터뜨리거나 map 을 순회하는 람다식을 올바르게 사용할 수 있었던 이면에는 초록불이 들어올 때까지 테스트 코드를 돌려봤기 때문이었다.
  2. 테스트 코드를 처음 학습했던 2주차에서 알게된 "코드를 작성하면서 '어떻게 테스트를 할 것인가?' 를 자문하기" 를 지키게 되었다. 구현 전에 어떻게 테스트를 작성할지 미리 생각하게 되었고, 이는 테스트 코드를 작성하기 어려운 기능을 더 작은 단위의 기능으로 세분화할 수 있었고, 이는 살아있는 README로도 이어졌다.
  3. 잘못된 케이스를 검사하는 테스트코드를 발견해서 올바르게 수정할 수 있었다.
  4. 함수분리와 테스트코드의 코드가 많아질수록 하나의 테스트가 어떤 기능을 테스트했는지 구분하기가 어려워졌다. 이러한 문제를 해결할 수 있게 리팩토링전에도 구현 로직과 테스트 코드에게 적절한 이름을 부여할 수 있도록 충분한 시간을 갖게 되었다.
  5. 요구사항을 잘못 이해해서 총 메뉴의 개수를 구하는 기능에서 디저트 메뉴만 구하는 기능으로 변경해야했다. 이 때, 미리 작성했던 테스트 코드들 덕분에 재사용할 수 있는 함수를 구별해낼 수 있었습니다.
  6. 요구사항을 잘못 이해하는 바람에 미션을 진행하며 필요없는 필드를 구현했었다. 예를 들면 Order객체에는 Map<String, Integer> 의 자료구조 뿐만 아니라 Map<MenuBoard, Integer> 도 있었던 만큼 스스로 구현 난이도를 올려버렸었다..ㅎ 그래도, 테스트 코드를 작성한 덕분에 구현한 코드를 신뢰하며 미션을 원활하게 진행할 수 있었다.

✅ 객체 분리 : 테스트 코드에도 영향을 끼치다

이번 4주차를 통해 객체 분리는 명확한 테스트 코드를 작성하는데에도 매우 유용하단 사실을 알게 되었다.

 

사용자 입력 (ex.초코케이크-3,제로콜라-4) 를 이용해 주문을 생성하는 Order 객체의 생성자에는 - 와 , 를 이용해 메뉴와 개수를 나누고, 나눈 값들이 오류는 일으키지 않는지 검증하고, 타입도 변환하는 등 별의별 기능이 다 있었다.

 

이 기능들을 테스트 하는 코드에서는 @DisplayName을 이용해서 어떤 기능을 테스트 하는지만 나타낼 뿐,

@DisplayName이 없다면 어떤 기능을 테스트 하는지 알 수가 없었다.

음료만 주문하면 예외 발생하는 기능은 new Order 만을 호출해서 테스트 하기에는 직관적이지 않다.

 

그러나, Order(메뉴와 개수를 필드로 갖고있음)를 객체분리하자 OrderValidator(사용자 입력을 검증), OrderGenerator( Order 객체를 생성), OrderCalculator(String타입에서 Map으로 변환) 로 기능에 따라 분리되었다.

그러자 private 메서드가 public 으로 바뀌게 되었고, 이는 테스트 코드에서 호출할 수가 있었다.

빨간줄의 @DisplayName 의 테스트 설명과 호출하는 함수의 이름이 맞아 떨어진다.

 

이러한 깨달음은 마지막 날에 여러 개의 테스트도 추가하고, 테스트 하지 않는 기능들을 찾는 쏠쏠한 재미를 주었다.

 

✅ 중복제거를 위한 추상클래스 사용

크리스마스 디데이, 평일, 주말, 특별 할인들은 주문 금액이 10000원 이상일 때만 할인되는 조건을 갖고 있었다.

공통된 조건을 가지고 있었기 때문에 코드의 중복이 생겼고, 나는 이 중복을 없애고 싶었다.

뿐만 아니라 혜택내역을 담당하는 한 메서드에게 전달되는 매개변수가 6개였는데, 이를 줄이고 싶었다.

 

그래서, 오브젝트 책을 읽으며 답을 찾고자 했고, 추상클래스와 인터페이스를 이용하는 방법이 있다는 것을 알게 되었다.

이 2가지 방법을 이용하면 유연하고, 쉽게 재사용 하고, 추가 요구사항이 있을 때, 확장이 가능한 객체 지향 설계를 할 수 있다는 것이었다. 나는 설계할 때, 할인혜택들이 이벤트 기간중에 변동될 가능성이 있다고 생각했다.

 

그 이유는 12월의 이벤트 목표는 5년이란 기간에서 최고 주문 금액을 달성하고, 12월의 참여 고객의 5%가 1월에도 참여하도록 하는것이었다.

이 목표를 달성하기 위해서 이벤트 기간 중에 할인혜택들을 변동 시킬 가능성이 있다고 생각했고, 할인 혜택들을 변동시켜야 하는지에 대해 기준을 세울 수 있도록 아래와 같은 필드를 추가했었다.

 

즉, 나는 확장이 가능한 설계를 했었다.

 

나는 인터페이스와 추상클래스 중 추상클래스를 다음과 같은 이유로 선택했고, 이 글(추상클래스 vs 인터페이스)에 많은 도움을 받았다.

1. 중복멤버통합

  - 할인조건들은 할인혜택이라는 내역(금액)을 출력하기 위해 포함하고 있어야 한다.

2. 의미적인 관계

  - 클래스와 의미있는 연관관계를 구축할 때, 즉 단어 그 자체에 논리성과 의미성이 있는 연관관계이면 추상클래스를 사용한다. 특별할인, 평일할인,주말할인, 보통할인은 "날짜에 대한 할인"이라는 공통된 논리성과 의미성이 연관있다고 생각했다.

 

✅ 3주차 피드백 적용

[@ParameterizedTest 학습]

4주차에서는 3주차 피드백에서 테스트 코드도 코드이니 파라미터만 반복되는 경우는 아래 코드 처럼 테스트 할 수 있다고 한다.

그래서 나는 Parameterized, ValueSource, CsvSource를 사용하기 위해 이 글을 계속 보며 사용법을 익혀서 적용시켰다.

 

[그 외]

  • 필드의 수를 줄이고자 노력했다.
  • 객체는 객체스럽게 사용하기 위해 View 에서 도메인의 값을 가져올 때 빼고는 get 을 사용하지 않고, 객체에게 메시지를 보냈다!
  • get 에 의해 값이 꺼내지는 변수들은 final 키워드를 이용해 값의 변을 막았고, 2주차에 미리 알게 되었던 불변컬렉션도 이용해서 값의 변경을 막아보았다!

😊한달 간의 프리코스를 마치며 : 주간의 노력들이 모여 만들어낸 성장

미션을 진행했던 날들을 복기하며 지난 한달을 되돌아 보았다.

 

프로젝트 경험도 없고, 백준이나 프로그래머스에서만 문제를 접했던 내게 프리코스 미션 중 쉬운 미션은 단 하나도 없었다.

객체지향? MVC? 테스트 코드? 깃? README? 모든 것이 처음이었다. 뿐만 아니라 매주의 목표와 피드백도 처음이었다.

그렇지만, 프리코스에서 배운 모든 것을 체화하고 싶었다. 코드에 다 적용하고 싶었다.

 

1,2,3주차마다 배운 것은 엄청 많았지만 모든 것을 체화하지 못해 항상 아쉬움이 남았었다.

매 주마다 최선을 다했음에도 아쉬움이 남자 프리코스도 체화하지 못하는데 본 코스 가더라도 잘 할 수 있을까란 생각도 하게 되었다. 

그래서, 4주차 목표를 어떤 아쉬움도 남기지 않는 것으로 설정했었다.

 

그렇게 4주차도 최선을 다 했고, 미션을 제출하면서 느낀 것은 그 동안의 노력들이 전혀 헛되지 않았음을 느꼈다.

정말 그 동안 했던 노력에 대해 보상받는 기분이 들어 너무너무 뿌듯했다.

 

[첫 번째 보상]

1주차의 나의 코드는 객체에는 상태가 없고, 모든 메서드는 static이었다. 원인을 찾고자 4일을 투자했고, 이 덕에 객체라는 존재와 친해질 수 있었다. 객체는 메시지를 통해 협력하고, 메시지에 응답하기 위해 스스로 일을 하는 존재임이란 것을 기억 하게 되었다.

 

이 기억은 3주차에 일급컬렉션을 이해하고, 객체안에 또 다른 객체가 포함되어있는 객체를 이해하는데 큰 힘이 되었다.

또한, 이것을 깨달을 때까지 구현했던 코드들을 3번이나 뒤엎었던 경험은 객체를 다룰 수 있다는(수정 할 수 있다는) 자신감이 되었다.

 

이 자신감은 4주차에서 객체를 분리하는데 도움이되었다.

1주차에는 static 메서드를 지우다가 에러를 만나서 미션에 실패할 것같은 두려움 때문에 기존 코드는 보존하고 다른 곳에 처음부터 다시 구현했지만 4주차는 기존 코드를 바로 수정할 수 있었고, 성공적으로 객체 분리를 할 수 있었다.

 

[두 번째 보상]

2주차에서 캡슐화에 위반되는 로직인 값을 꺼내오는 코드를 발견했었고, 이를 해결하고자 했다.

이 과정에서 불변컬렉션을 알게 되어 불변의 역할을 미리 알수 있었고, 값을 전달한다는 의미를 명확하게 파악하게 되었다.이는 3주차의 도메인 로직과 UI 로직의 분리를 위해 읽었던 글과 MVC패턴을 이해하는 데에도 큰 도움이 되었다.

결국 값들을 불변으로 만들라는 3주차 피드백을 큰 어려움 없이 수용했고, 4주차에 적용시켰다.

 

[세 번째 보상]

1주차에 테스트 코드의 장점을 알게 되었고, 이 장점을 누리고자 구현과 테스트 코드를 함께 작성하는 것을 2주간(2, 3주차) 노력했다.

이 덕에 4주차 미션의 구현과 테스트 코드를 함께 작성하는데 어려움이 없었고, 미션을 원활하게 진행할 수 있었다고 생각한다.

뿐만 아니라 2주차에는 @Test 만을 활용한 테스트 코드 작성에도 버거웠지만, 4주차에는 JUnit의 다양한 어노테이션을 점진적으로 사용해서 테스트 코드를 작성할 수 있었다고 생각한다.

 

[네 번째 보상]

2주차와 3주차에 함수분리를 하려고 노력했던 덕분에 함수를 쪼개고, 어떤 것을 기능으로 봐야할지를 알게 되는 눈이 생겼다.

이는 다양한 요구사항이 많은 4주차 README 를 작성 할 때, 구현해야 할 기능들을 이전과 다르게 작성할 수 있게 되었고, 바뀐 README 덕분에 어려운 구현 속에서도 길을 잃지 않고 미션을 완주할 수 있었다고 생각한다.

 

이렇게 매 주마다 노력했던 행동들이 하나 둘 모여 4주차 미션을 완성시키는 데 도움을 줬다.

 

지금 이 글을 쓰면서 미션에 대해 아쉬움이 전혀 없다. 정말 이토록 후련할 수 있을까 싶다. 너무 후련하다.

이 글을 볼 때마다 내가 느끼고 있는 이 감정을 기억하고 싶기에 오글거릴 수 있겠지만 남겨본다.

 

어떤 마음으로 독학 해왔고, 프리코스에 참여했는지 스스로가 알기에 나는 지금의 내가 자랑스럽다.

후련하며 벅차다.

😊앞으로의 계획

3주차 코수타에서 코치님이 말씀하신 핵심 기능을 파악해서 핵심 기능부터 구현하기를 4주차에 적용하고자 2일 동안 노력했으나, 실력 부족으로 인해 기존에 했던 방식인 입력부터 구현해 나갔다.

 

그래서, 1~4주의 미션들을 핵심 기능부터 다시 구현해 보려고 한다.

프리코스의 요구사항을 지킬때 마다 성장과 배움을 얻었었기에 이 가르침에도 분명히 성장할 수 있는 발판이 있다고 확신한다.

 

성장하고 후기를 남겨보도록 하겠다😊 -> 클릭