제로베이스 프론트엔드 스쿨 10기 2차 JS 과제 후기

조경석·2023년 2월 20일
0

제로베이스 프론트엔드 스쿨

지난 HTML/CSS 클론코딩 과제에 이어, 제로베이스 프론트엔드 스쿨의 JS 과제를 완료했다.
라이브러리 환경에 제약이 있던 환경에서 실무를 진행한 경험이 있어 바닐라 자바스크립트는 꽤나 자신이 있었는데, 요구사항의 제한사항 내에서 구현하는건 처음 해보는 경험이라 새로운 부분이 많았다.
이하는 학습 커리큘럼의 두번째 과제인 바닐라 JS 과제의 작업~제출까지의 기간동안 느낀 부분을 정리한 내용이다.

JavaScript를 공부하면서 느낀점

이번 과제를 진행하면서 개인적으로 세운 목표는 "다른 사람의 구현사항을 참고하지 않기"였다.
당연히 요구사항에서 요구하는 객체나 메서드에 대한 레퍼런스는 참조했지만, 특정 요구사항에서 일반적으로 사용되는 패턴이나 템플릿을 사용하지 않는걸 최우선 목표로 유지했다.

그러다보니 가장 나를 괴롭게 했고, 가장 만족스러운 아이디어를 유추해낸 문제가 "달력 만들기"의 페이지 첫 날짜 정하기였다.

당연히 달력의 현재 페이지의 년, 월 정보를 가지는 Date 객체를 별도로 저장해두고, 그때그때 필요로 하는 날짜의 년, 월을 지정한 Date 객체를 새로 만들어서 첫날(1일)의 요일을 구하는것이 일반적인 방법이다.
아래는 이 글을 작성하면서 찾아본 달력에서 이전 달, 다음 달 날짜를 표기하기 위한 함수 예제이다.
출처 : https://www.codingnepalweb.com/dynamic-calendar-html-css-javascript/

const renderCalendar = () => {
    let firstDayofMonth = new Date(currYear, currMonth, 1).getDay(), // 이번 달의 첫 날을 저장해둔다.
    lastDateofMonth = new Date(currYear, currMonth + 1, 0).getDate(), // 이번 달의 마지막 날도 저장해둔다.
    lastDayofMonth = new Date(currYear, currMonth, lastDateofMonth).getDay(), // 위에서 구한 마지막 날의 요일을 구해 저장해둔다.
    lastDateofLastMonth = new Date(currYear, currMonth, 0).getDate(); // 지난 달의 마지막 날도 저장해둔다.
    let liTag = "";

    for (let i = firstDayofMonth; i > 0; i--) { // 역순으로 첫 날의 요일만큼 반복하여 지난 달 날짜를 표기한다.
        liTag += `<li class="inactive">${lastDateofLastMonth - i + 1}</li>`;
    }

    for (let i = 1; i <= lastDateofMonth; i++) { // 이번 달 마지막 날까지 반복하여 이번 달 날짜를 표기한다.
        // 기존에 저장해둔 date와 오늘의 new Date()와 비교해 active 클래스를 추가한다.
        let isToday = i === date.getDate() && currMonth === new Date().getMonth() 
                     && currYear === new Date().getFullYear() ? "active" : "";
        liTag += `<li class="${isToday}">${i}</li>`;
    }

    for (let i = lastDayofMonth; i < 6; i++) { // 이번 달의 마지막 날의 다음 날부터 반복하여 최대 6일까지의 날짜를 표기한다.
        liTag += `<li class="inactive">${i - lastDayofMonth + 1}</li>`
    }
    currentDate.innerText = `${months[currMonth]} ${currYear}`;
    daysTag.innerHTML = liTag;
}

별도 조건의 반복문만 세개나 있고, 각 반복문이 변수 하나씩을 반복 조건으로 사용하며, 모든 변수가 불필요한 날짜 객체이다. 취향 문제긴 하다.
나의 경우 달력의 모든 날짜 버튼 요소를 Date 객체를 속성값으로 가지는 클래스 객체로 만들기로 결정해 여기서 또 계산만 수행하기 위한 Date 객체를 만드는것은 깔끔하지 않다는 생각이 들었다.

목표는 달력을 그릴 때 전달받은 기준일의 Date 객체 하나만으로 달력을 채우기 시작할 첫 날짜의 요일 구하기였다.
첫 날짜를 구하면, 지난 달 이번 달 다음 달 따로 반복문을 돌릴 필요 없이 달력의 한 페이지의 칸 수인 42개의 날짜를 연속적으로 표기하기만 하면 된다.


달력의 '첫번째 날'은 이번 달 1일부터 이번 달 1일의 요일 값(0 ~ 6)만큼의 전 날이다.
23년 2월의 경우, 2월 1일이 수요일(3)이므로 3일 이전인 1월 29일이 된다.

이를 위해 필요한 식은 아래와 같았다.
1 ~ 31 날짜 A,
0 ~ 6 요일 B가 있을때
그 달 1일의 요일 C(0 ~ 6)를 구하는 식

여기까지 정하고 식을 만들기 위해 일단 달력을 척 봤는데,
뭔가 패턴은 뻔한거 같은데 아무리 머리를 짜내도 깔끔한 식은 나오지 않고 반복문이나 조건식을 사용하는 지저분한 방법만 나오고 있었다.
인터넷을 찾아봐도 제라의 공식으로 년도와 월 값으로 첫날을 계산하는 예제만 나오고, 변수로 날짜 A와 요일 B만 사용하는 경우는 찾지 못했다.

머리를 싸매다 결국 친구에게 지원을 요청하니, 0 ~ 6 사이의 숫자에서 순환하는 해이므로 모듈로 연산 없이는 불가능한 계산식이라는 힌트를 받았다.
위 링크에 써있듯이 JS에서는 모듈로 연산자를 지원하지 않아 직접 구현하는 방법을 찾아야 했고, 결국 아래의 식을 찾아 과제에 적용했다.

// 오늘 날짜 A
let A = (new Date()).getDate()

// 오늘 요일 B
let B = (new Date()).getDay()

// 첫날의 요일을 계산하는 식은 아래와 같으나, JS는 mod 연산자가 없다.
// (B - (A - 1)) mod 7

// x mod y function
function mod(x, y) return (x % y + y) % y

// 이번 달 첫날의 요일 C
let C = mod((B - (A - 1)), 7)

// mod 함수 없이 표현한 이번 달 첫날의 요일 C
C = ((B - (A - 1)) % 7 + 7) % 7

인터넷에서 찾기 어려운 알고리즘을 유추해내는 과정은 확실히 재미있고, 생각해보지 못한 개념을 깨우치고, 나중에 유사한 처리를 적용할 때 불필요한 고민거리를 덜어주는 장점이 있다.
하지만 "일반적인 구현"이라는건 당연히 근거가 있기에, 긴급한 작업이거나 효율이 검증되어야 하는 경우에는 당연히 불필요한 작업이 맞다는 사실도 다시 한번 깨닫는 좋은 경험이기도 했다.

JavaScript 공부하면서 어려웠던 개념과 이유

과제를 처음 시작해 주의사항을 확인했을때부터 약점을 찔린 듯한 느낌을 받았는데, "ES Module(또는 Webpack)을 사용해 모듈화하라"는 항목이 있었기 때문이다.

지금까지 자바스크립트를 사용하는 경험은 항상 개인작업이었으므로 모듈화 개념은 차후 스스로 유지보수하기 편하기 위해 적용하는 수준이었지, 철저하게 기능 단위로 분리하고 추상화하는 수준으로는 한번도 적용해본적이 없었다.

역시 예상대로 과제 제출 후에도 가능하면 함수형이 아닌 클래스형 컴포넌트로도 구현해보라는 평가를 받았다.
물론 클래스형 컴포넌트가 특별히 복잡하다기보단, 항상 함수 단위로 기능을 작성하는 습관이 들어 객체 컨트롤이 능수능란하지 못하다는 생각을 하고 있었는데 과제 평가에서 정확히 그 부분을 지적받은 것 같아 다시금 공부가 필요하다고 느꼈다.

변명이 될 수 있지만 독학으로 공부한 입장에서 모듈화의 가장 큰 걸림돌은 라이브러리 환경이 당연해진 모던 자바스크립트 환경에서, 바닐라 자바스크립트의 컴포넌트와 모듈에 대한 정보의 접근성이 떨어지는 편이다.
바닐라 자바스크립트에 대한 철저한 이해가 있어야 라이브러리도 '알고' 사용할 수 있다는 생각이라, 공부를 하면서도 꽤 어려웠던 부분이었다.

제로베이스 온라인 강의 중 가장 도움이 되었던 강의와 이유

강의라기엔 애매하지만 모범답안을 제공하는 코딩테스트가 상당히 도움이 되었다.
날 잡고 코딩테스트를 하기엔 아무 문제나 풀면 시간만 소요되고 의미가 없고, 적절히 내가 모르는 알고리즘을 사용하는 문제를 선택하기에도 쉽지 않은데,
제로베이스의 코딩테스트 문제는 주차별로 주제별 문제를 선별해 제공한다는것이 느껴졌다.
개인적으로 문제에서 유도하는 알고리즘을 바로 깨닫지 못하고 이상한 아이디어를 떠올리고 시간을 낭비하는 버릇이 있는데,
절대적인 코딩테스트 경험이 부족한 것도 있지만, 모범' 답안은 코딩테스트를 백날 해봐도 타인의 답안을 제공할 뿐인 일반적인 코딩테스트로는 경험하기 어려웠다.
첫 문제에서 알고리즘을 유추한 뒤 다른 문제에서 그를 응용하는 구조의 문제 배치 자체도 코딩테스트 실력을 높이는 데 도움이 된다고 느껴졌다.

나만의 공부팁

자바스크립트와 같은 언어는 구현의 결과보다 과정이 중요하다고 생각한다.
코딩테스트 역시 아무데서나 긁어와서 집어넣어도 정답이야 맞출 수 있고, 더 과장하면 난수를 출력해도 운이 좋아서 정답을 맞추면 장땡이라고도 할 수 있다.
그렇기 때문에 공부를 하는 과정에서는 단순히 결과를 내기 위해서 참조하는것을 넘어서, 내 것으로 만들기 위해 억지로라도 응용하는 습관이 필요하다.
가져온 알고리즘 전반이 이해되지 않더라도, 반복문이나 조건식같이 내가 이해할 수 있는 일부의 패턴을 수정하거나 코딩 컨벤션이라도 바꿔보면서 나의 코드로 만들어보는 식으로 응용하는게 가장 쉬운 방법이라고 생각한다.

마무리

자바스크립트의 경우 내가 원해서 만드는 개인 프로젝트에서는 문제 없이 사용했지만,
요구사항이 명확한 과제를 수행하고 나니 지금까지 간단하게 구현하기 위해 필요한 레퍼런스들을 회피해왔다는 생각이 들었다.
실무 경험에서는 단순 요구사항 외에도 수많은 제약사항과 오류, 예외사항이 있으니 다양한 구현방법에 대한 지식은 필수적이라고 다시 한번 느끼게 되었다.
무엇보다 과제를 평가해주신 강사님께서 내가 스스로 아쉬웠던 부분을 정확하게 지적해주셔서, 벌써 1/3정도 지나간 부트캠프의 나머지 기간동안 무엇을 심화시켜 공부할지 생각해보는 기회가 되었다고 생각한다.

0개의 댓글