안녕하세요 프론트엔드 개발자 Garden, 오소현입니다:)
저는 요즘 항해 플러스 프론트엔드 3기 코스 과정에 참여하면서 공부하고 있는데요!
오늘은 그 4주차의 회고를 진행해보려고 합니다 !
(참고로 4개의 과제중에 제일 힘들었습니다 ㅠㅠ)
이번주차 부터는 테오 코치님의 클린코드 파트가 시작되었는데요!
게슈탈트 법칙으로 이해하는 클린코드: 가독성의 비밀 이 테오코치님의 블로그글과 함께 과제를 시작했는데요! 다들 읽어보시면 좋을 것 같습니다!
단일 책임의 원칙, 기능을 드러내는 함수명 짓는 방법, 더 나은 코드 구조 설계 등등 한 주동안 굉장히 많이 고민하면서 과제를 진행했고 정말 많이 고민 하기도 했습니다
기본 과제에서는 한 함수는 하나의 기능만을 하는 단일 책임의 원칙을 많이 따르고자 했고,
MVC 패턴에 맞추어 폴더명을 Controller / Model / View 로 분리하여 각각의 함수들을 역할에 따라 분리했습니다.
그러다 심화 과제에서는 View 의 컴포넌트들을 UI만 담당하는 컴포넌트와 이를 조합하여 사용하는 컴포넌트, 계산이 붙은 컴포넌트를 분리하기로 하여 아토믹디자인패턴을 기반으로 atoms와 organisms 폴더를 구분하여 분리하였습니다.
따라서 사용자들은 atoms을 통해 재사용성이 높은 컴포넌트를 편하게 이용할 수 있는 구조라고 생각했습니다.
기본 과제에서 모두 함수를 분리한 것을 Controller / Model로 분리하여 구현하였더니 너무 분리를 하였다는 생각이 들었고, 심화과제에서는 이를 필수적 계산로직을 같은 파일명으로 작성했습니다. 따라서 기본 과제의 Controller / Model 을 Services라는 이름으로 모두 구현하였습니다.
제가 심화 과제에서 더 개선된 구조로 구현했는지 궁금했습니다..!
멘토링 이전에는 다음과 같이 테스트 코드를 구현해보았었습니다.
이번주 과제 요구사항에 번개 세일 기능에 대한 추가 테스트 코드를 어떻게 작성할지 고민해보았습니다.
그러다가 랜덤에-대한-테스트는-어떻게-이루어-져야-하는가 이 글을 보면서 아와 같은 형식으로
const mockRandoms = (numbers) => {
MissionUtils.Random.pickUniqueNumbersInRange = jest.fn();
numbers.reduce((acc, number) => {
return acc.mockReturnValueOnce(number);
}, MissionUtils.Random.pickUniqueNumbersInRange);
};
테스트 코드에서도 위와 같이 랜덤 숫자를 생성해야한다고 생각했습니다.
하지만 dom을 기준으로 테스트 하기 때문에 이번에는 랜덤 값과, 결과값을 아예 고정해야한다고 판단을 했습니다
따라서 다음과 같이 우선 테스트 코드를 작성해보았습니다.
it('번개세일 기능이 정상적으로 동작하는지 확인', () => {
vi.useFakeTimers();
const mockAlert = vi.spyOn(window, 'alert').mockImplementation(() => {});
// Math.random()을 모의하는 것은 동일
// 랜덤 선택과 할인 조건을 다양하게 추가
// 첫 번째는 setTimeout, 두 번째는 setInterval 선택, 세 번째는 할인 조건
const randomValues = [0.01, 0.2, 0.1];
vi.spyOn(Math, 'random').mockImplementation(() => randomValues.shift());
const prodList = [
{ name: '상품1', val: 10000, q: 10 },
// 이 상품은 재고가 없어 할인되지 않는 경우도 추가하기
{ name: '상품2', val: 20000, q: 0 }
];
// 매우 아쉽지만 직접 로직 가져오기
setTimeout(function () {
setInterval(function () {
const index = Math.floor(Math.random() * prodList.length);
var luckyItem = prodList[index];
if (Math.random() < 0.3 && luckyItem.q > 0) {
luckyItem.val = Math.round(luckyItem.val * 0.8);
alert('번개세일! ' + luckyItem.name + '이(가) 20% 할인 중입니다!');
}
}, 30000);
}, Math.random() * 10000);
vi.advanceTimersByTime(10000);
vi.advanceTimersByTime(30000);
expect(mockAlert).toHaveBeenCalledWith('번개세일! 상품1이(가) 20% 할인 중입니다!');
mockAlert.mockRestore();
Math.random.mockRestore();
});
[개선 내용]
Math.random()
을 randomValues
배열의 값을 순차적으로 반환하도록 변경하여 다양한 케이스를 모의할 수 있도록 해보았습니다.setTimeout
의 최대 지연 시간인 10초와 setInterval
의 30초 간격을 모두 고려하도록 구현해 타이머를 실행시키고자 했습니다..!prodList
에서 랜덤하게 아이템을 선택하고, 이에 따라 할인이 적용될 아이템이 결정되어 재고가 없는 상품을 포함시키는 테스트 확장성을 생각해보았습니다.위와 같이 구현해서 오프코치님께 멘토링을 받았고 구현된 함수를 테스트 하기 위해서 심화과제의 테스트 코드를 한번 작성해보았습니다.
t('번개세일 기능이 정상적으로 동작하는지 확인', async () => {
vi.spyOn(global.Math, 'random').mockReturnValue(0.1);
global.prodList = [
{ id: 'p1', name: '상품1', price: 10000, quantity: 10 },
{ id: 'p2', name: '상품2', price: 20000, quantity: 5 }
];
const alertMock = vi.spyOn(window, 'alert').mockImplementation(() => {});
const luckySaleSpy = vi.spyOn('useLuckySale');
useLuckySale();
const randomInterval = 30000;
const randomDelay = randomInterval * 0.1;
vi.advanceTimersByTime(randomInterval + randomDelay);
expect(luckySaleSpy).toHaveBeenCalled();
expect(global.prodList[0].price).toBe(8000);
expect(alertMock).toHaveBeenCalledWith(expect.stringContaining('번개세일! 상품1이(가) 20% 할인 중입니다!'));
vi.restoreAllMocks();
});
이전 보다 더 나은 구조가 되긴했었는데 테스트 코드가 실패해서 ㅠㅠ 이전보다 어느 부분을 더 공부해보면 좋을지 궁금했습니다
이번주차 과제는 역대급 난이도였던 만큼 과제가 끝나질 않았습니다 뭐가 더 낫지.. 모든 체크 포인트를 다 챙기면서 계속 밤샜던 것 같았어요 ㅠㅠ 클린코드 첫주차부터 이렇게 어렵다니...
이번주 멘토링도 저는 오프 코치님께 :) 받았습니다.
위의 테스트 코드 위주로 멘토링을 받았고 vitest의 테스트 코드 작성법을 더 열심히 봤던것 같아요!!
두 과제 모두 PASS와 BestPractice를 받았네요 ㅎㅎㅎ
사실 이번주에는 너무 힘들어서 기대를 안했는데.. 패스만 하자 싶었습니다 감사합니다 ㅠㅠ
이번주가 클린코드 과제라서 다른 사람들 리뷰하면서 성장하는점이 많았습니다
따라서 주말에 다른 팀 분들 PR 리뷰해보면서 새로운 인사이트를 많이 얻었어요
재혁 단우님 감사합니다,, bb
이번주에 회사일중에 중요한 일이 있어서 zep에 많이 못들어가서 아쉬웠습니다 ㅠㅠ
팀원들과의 소통을 더 늘려봐야겠습니다!! 그리고 PR도 더 빨리 쓰자,,,
과제 끝나고 계속 검토를 하면서 정리하는 습관을 가지자!
저는 현재 4주차를 진행하고 있지만 3주동안 정말 열심히 몰입해서 공부하고 있는데요!
바로 다음 기수인 항해 플러스 프론트엔드 코스 4기를 모집하고 있다고 하여 공유드립니다!
현재는(24.10.19)에는 슈퍼 얼리버드 기간으로 약 46% 할인을 받을 수 있습니다!
저도 3기 입과할때 슈퍼 얼리버드 기간에 합류해 추천인 할인까지해서 제일 최대 할인된 가격에 합류할 수 있었습니다 ㅎㅎ
또한 추천인 제도로 [추천인] 코드에 “fWHY9o”를 입력하시면 20만 원 추가 할인 혜택이 있으니 결제하실때 꼭 추천인 할인 코드도 함께 입력해주세요!
제 항해 플러스 프론트엔드 후기 글을 보고 궁금한 사항이 있으시다면 댓글이나, 벨로그 프로필 이메일, 링크드인으로 문의주세요 :)