8주차 과제 체크포인트
기본 과제
필수
- 반복 유형 선택
- 일정 생성 또는 수정 시 반복 유형을 선택할 수 있다.
- 반복 유형은 다음과 같다: 매일, 매주, 매월, 매년
- 31일에 매월을 선택한다면 -> 매월 마지막이 아닌, 31일에만 생성하세요.
- 윤년 29일에 매년을 선택한다면 -> 29일에만 생성하세요!
- 반복 일정 표시
- 캘린더 뷰에서 반복 일정을 시각적으로 구분하여 표시한다.
- 아이콘을 넣든 태그를 넣든 자유롭게 해보세요!
- 캘린더 뷰에서 반복 일정을 시각적으로 구분하여 표시한다.
- 반복 종료
- 반복 종료 조건을 지정할 수 있다.
- 옵션: 특정 날짜까지, 특정 횟수만큼, 또는 종료 없음 (예제 특성상, 2025-06-30까지)
- 반복 일정 단일 수정
- 반복일정을 수정하면 단일 일정으로 변경됩니다.
- 반복일정 아이콘도 사라집니다.
- 반복 일정 단일 삭제
- 반복일정을 삭제하면 해당 일정만 삭제합니다.
선택
- 반복 간격 설정
- 각 반복 유형에 대해 간격을 설정할 수 있다.
- 예: 2일마다, 3주마다, 2개월마다 등
- 예외 날짜 처리:
- 반복 일정 중 특정 날짜를 제외할 수 있다.
- 반복 일정 중 특정 날짜의 일정을 수정할 수 있다.
- 요일 지정 (주간 반복의 경우):
- 주간 반복 시 특정 요일을 선택할 수 있다.
- 월간 반복 옵션:
- 매월 특정 날짜에 반복되도록 설정할 수 있다.
- 매월 특정 순서의 요일에 반복되도록 설정할 수 있다.
- 반복 일정 전체 수정 및 삭제
- 반복 일정의 모든 일정을 수정할 수 있다.
- 반복 일정의 모든 일정을 삭제할 수 있다.
심화 과제
각 팀원들의 테스트 전략은?
저희팀은 팀원별로 테스트 전략에 대한 의견을 주고 받기 보다는 피그잼을 통해 함께 브레인스토밍하며 전략을 좁혀 나갔습니다.
- [9팀 테스트 전략 키노트](https://www.figma.com/board/dYGP9N0xBufQX0NiHFq0Rg/9%ED%8C%80?node-id=0-1&p=f&t=2jT1n4jmI1VUH04 Q-0)
따라서, 하나의 PR에 테스트 전략을 수립하여 모두 페어코딩을 진행했습니다. 결론적으로 9팀은 심화과제 PR부분과 코드 전략을 함께 작성하여 그 내용이 같습니다.
- 테스트 전략을 적용한 최종 코드 PR 바로가기
합의된 테스트 전략과 그 이유는 무엇인가요?
저희 9팀은 TDD 기반으로 반복 일정 기능을 구현하면서 윤년, 월말 날짜 등 다양한 엣지 케이스를 마주할 수 있다고 판단했습니다. 따라서 테스트 전략의 목표를 엣지 케이스를 최소화하는 것으로 잡고, 이를 검증하기 위한 방향을 고민했습니다.
이 과정에서 단순히 “어떻게 테스트할까” 라는 관점에 머무르지 않고, “어떻게 하면 코드를 테스트하기 좋은 구조로 만들까” 라는 질문에 집중했습니다. 코치님께서도 이 점을 강조해주셨고, 그 조언을 바탕으로 레이어를 먼저 추상화한 뒤, 테스트할 부분과 그렇지 않은 부분을 의도적으로 구분하여 선택적으로 검증하는 전략을 수립했습니다.
아키텍처 정의하기
[기존 구조]
- 역할 기반 디렉토리 구조
- 유닛 테스트 비중이 높음 (피라미드 구성)
뿐만 아니라 utils 디렉토리는 아래와 같은 서로 다른 역할과 관심사가 혼재하고 있었습니다.
- repeatEventUtils : 반복 일정의 다음 날짜를 계산하는 순수 계산 로직
- notificationUtils : 사용자에게 알림을 띄우는 UI 관련 사이드 이펙트
- eventUpdateUtils: 이벤트 관련 도메인 레이어
이처럼 역할이 다른 코드들이 한 폴더에 섞여있어 반복 일정 계산 로직을 구별하기 어려웠습니다.
[레이어 도출]
- 반복 일정의 엣지 케이스를 판단하는 핵심 로직은 대부분 repeatEventUtils 같은 순수 함수 안에 있다고 판단했습니다.
- 이 함수들을 사이드 이펙트가 있는 함수로부터 분리하여 레이어를 나눈다면 테스트가 쉬워질 것이라고 의견을 모았습니다. 이 부분을 도메인 유틸 레이어(repeat) 로 정의하고 기존에 작성한 유닛 테스트를 활용하기로 했습니다.
- 전략적 선택과 집중
- 집중: "도메인 레이어" 에 유닛 테스트를 집중하기로 했습니다.
- 선택: 도메인 로직 테스트에 집중하는 대신, 변경이 잦고 테스트 비용이 비싼 UI 관련 테스트의 비중은 낮추기로 결정했습니다.
- 가정: msw 핸들러와 같은 라이브러리나 Date 객체, Javascript 내장 함수 관련 로직은 자체의 동작을 신뢰하기로 가정했습니다. 대신 API 요청/응답에 따라 앱이 어떻게 반응하는지를 검증하는 통합 테스트를 추가하기로 했습니다.
[새로운 레이어 구조] 관심사의 분리와 테스트 용이성이라는 두 가지 키워드로 다음과 같이 레이어를 세분화하고자 했습니다.
1. utils
repeat이라는 기능(feature)단위로 디렉토리를 묶고, 그 안에서 역할을 세분화 했습니다.
📦repeat
┣ 📜actions.ts # 상태를 변경하는 로직 (도메인)
┣ 📜constants.ts # 기능 관련 상수
┣ 📜formats.ts # 문자열 포맷팅 등 (도메인/UI 보조)
┗ 📜helpers.ts # 핵심 계산 로직 (순수 함수, 도메인)
2. test
📦repeat
┣ 📂e2e
┣ 📂integration
┗ 📂unit
┃ ┣ 📜actions.spec.ts
┃ ┗ 📜helpers.spec.ts
레이어 별 테스트 전략 수립
아키텍처가 명확하게 정의되니 코치님 말씀대로 각 디렉토리의 역할에 맞는 테스트 전략을 구체화 할 수 있었습니다.
반복 일정 생성에서는 기준에 맞는 일정 생성 및 엣지 케이스 판단이 중요합니다. 반면 UI 구현의 비중은 적습니다. 이를 테스트 전략에도 반영했습니다. 일정 생성과 기준에 맞는 일정일지 판단하는 함수의 유닛 테스트의 비중을 높였습니다. UI 구현을 검증하는 통합 테스트와 e2e테스트는 최소한의 사용성을 보장하는 정도로 최소화했습니다.
저희는 '전략적 선택과 집중' 원칙에 따라 테스트의 종류와 범위를 다음과 같이 결정했습니다.
[Unit Test] - 도메인 로직 (Domain Logic)
- 대상: utils/repeat/helpers.ts, utils/repeat/actions.ts
- 전략: 테스트의 절반 이상을 집중합니다. helpers의 순수 계산 함수들을 테스트하며 엣지 케이스를 검증하고, actions의 상태 변경 로직이 의도대로 동작하는지 확인합니다.
- 이유: 반복 일정을 생성함에 있어서 윤년, 월별 일수와 같은 예외적 케이스를 고려하는 것은 큰 비중을 차지합니다. 그에 따라 테스트의 비중도 가장 높습니다.
[Integration Test] - 계층 간 통합 (Layer Integration)
- 대상: UI 컴포넌트, API 레이어, 도메인 로직의 통합 동작
- 전략: MSW를 활용하여 API의 성공, 실패, 비정상 응답 등 다양한 시나리오에 따라 UI 상태와 도메인 로직이 올바르게 연동되어 동작하는지 검증합니다.
- 이유: "API 요청/응답에 따라 앱이 어떻게 반응하는가" 를 확인하는 것이 목적입니다. 실제 서버나 fetch 라이브러리를 테스트 하는 것이 아니라, 각 레이어들이 올바르게 통합되어 데이터의 흐름을 잘 처리하는지 확인하는 목적입니다.
[E2E Test] - 사용자 시나리오 (User Scenario)
- 대상: 반복 일정 폼 등록, 삭제
- 전략: "사용자가 반복 일정을 생성하고 저장할 수 있다" 와 같은 중요한 시나리오 위주로 검증합니다.
- 이유: UI는 변경이 잦고 테스트 유지보수 비용이 아이콘 및 이벤트 리스트를 추가하는 UI구현의 중요도가 적습니다. 따라서 사용자에게 최종적으로 전달되는 핵심 기능이 문제없이 동작하는지만을 보장하기로 "선택" 했습니다.
과제 셀프회고
안녕하세요! 이번 과제는 기본과제는 util함수만 작성하여 미완으로 제출하게 되었습니다(😱). 기능을 완성하지 못했다는 점에서 부족함을 크게 느꼈지만, 대신 심화 과제를 조금이나마 참여하면서 많은 또다른 배움을 얻을 수 있었습니다.
팀원들과 함께 브레인스토밍을 하며 어떤 전략이 더 효과적인지, 테스트 코드를 어떤 기준으로 분리하고 추상화할지 깊이 논의할 수 있었던 점이 인상 깊었습니다. 단순 구현에 그치지 않고 전략적 선택과 집중의 중요성을 공유하면서, 유닛 테스트·통합 테스트·E2E 테스트 각각의 목적과 범위를 어떻게 설정할지 함께 고민할 수 있었습니다. 같은 의견으로 쉽게 합의된 부분도 있었지만, 생각이 엇갈려서 더 깊이 토론했던 부분도 있어 흥미로웠습니다. 무엇보다 작은 항목이라도 가볍게 넘어가지 않고 끝까지 딥다이브하는 팀원들의 모습이 큰 자극이 되었습니다.
특히 레이어 추상화는 저에게 어렵고 헤매게 된 주제였는데, 이해되지 않는 부분을 계속 질문하고 설명을 주고받으며 점차 생각이 맞춰져 가는 과정이 인상적이었고, 어느 순간 서로가 합을 맞춰가는 경험이 뿌듯하게 다가왔습니다.
결과적으로 이번 과제는 구현의 완성도에서는 아쉬움이 있었지만, 테스트 전략을 설계하고 합의하는 과정 자체가 매우 유익한 경험이었다고 생각합니다. 특히 TDD로 접근하면서, 구현되지 않은 함수를 테스트 코드에서 먼저 정의하고 “어떤 함수로 만들어야 할까”를 고민하는 과정이 저에게는 다소 어색했지만, 오히려 요구사항을 놓치지 않고 함수 구현에 집중할 수 있게 해주는 방식이라는 점을 깨달았습니다. util 함수만 작성했을지라도, 그 안에서 충분히 배운 점을 많이 느꼈습니다 :)
과제 피드백
undefined