프로그래머스 데브코스 - 9월 3주차 WIL

지인혁·2023년 10월 8일
2
post-thumbnail
post-custom-banner

😒들어가며

3주차를 들어가면서 처음으로 5일 모두 교육을 받은 날이다. 그래서 많이 힘들거라 생각했는데 정신차려보니 금요일에 이제 과제도 생기면서 점차 적응하는 내 모습을 본 3주차 같았다.

그리고 팀원들과 자바스크립트, 알고리즘 스터디도 시작했고 처음으로 Pull Request(PR)이란 짜릿한 경험을 통해 내 코드를 팀원, 멘토님에게 보여주며 서로 리뷰를 해봤다.

3주차에는 알고리즘 과정이 끝나는 무렵 본격적인 Javasciprt로 Dom을 제어하며 개발 교육이 시작됐다. 나는 이때까지 유튜브나 책을 통해서 독학을 했지만 전문적으로 누군가에게 배워보기는 처음이라 매우 기대되고 재밌는 3주차였다.

그래서 그런지 3주차에는 신기하고 정말 처음보는 지식을 마주한 주차여서 꼼꼼히 정리해서 기록해야겠다..


✅ JavaScript 주요 문법(7) 10.02

백트래킹

백트래킹이란?

  • 모든 경우의 수를 탐색하는 알고리즘
  • DFS나 BFS를 이용할 수 있다.
  • 효율을 위해 탐색하지 않아도 되는 곳을 미리 막는 것을 가지치기(Pruning)라고 한다.
  • 자바스크립트는 재귀 효율이 나쁘기 때문에 DFS를 구현할 경우 스택을 이용하는 것이 좋다.
  • 코딩 테스트에선 이를 고려하여 재귀로 작성해도 풀 수 있도록 문제를 제출하는 경우도 있다.
  • 탐색에서 순환(Cycle)이 발생할 수 있따면 BFS를 이용하는 것이 편하다.

어떻게 작성할 것인가?

  • 우선 모든 경우의 수를 찾을 수 있도록 코딩
  • 이후 문제에서 특정한 조건을 만족하는 것만 탐색하고 나머지는 탐색하지 않도록 조건문을 작성한다.
  • 즉 절대로 답이 될 수 없는 것은 탐색을 종료한다.

🤔 백트래킹의 개념은 이전에 N-Queen 문제를 풀면서 가지치기라는 개념은 알고 있었다. 근데 백트래킹 실습 과제로 N-Queen문제가 나와서 당연히 풀 수 있을거라 생각했는데 문제를 어떻게 해결할지 잘 떠오르지도 않음... 그래서 이전에 java로 풀었던 코드를 보고 경우의 수가 어떻게 만들어지는지 트리 구조로 그림을 그려 겨우 다시 이해하고 풀었다.

동적 계획법

동적 계획법이란?

  • 해결한 작은 문제로 큰 문제를 해결하는 문제 풀이 방식
  • 그리디나 백트래킹처럼 특정 알고리즘이 아닌 문제 해결 방식을 의미한다.
  • Dynamic Programming(DP)이라고도 부른다. (프로그래밍과 관련이 없다.)
  • 메모리를 많이 사용하는 대신 빠른 성능을 자랑한다.
  • 두 가지 방법론이 있다.
    메모이제이션(Memoization)
    타뷸레이션(Tabulation)

메모이제이션

  • 하향식 접근법
  • 동적 계획법에서 작은 문제들의 결과는 항상 같다.
  • 따라서 이 결과들을 메모리에 저장해 필요할 때 꺼내 쓰는 것이 메모이제이션이다.

타뷸레이션

  • 상향식 접근법
  • 필요한 값들을 미리 계산해두는 것
  • 메모이제이션은 필요할 때 계산한다면(Lazy evaluation) 타뷸레이션은 미리 계산해둔다(Eager evaluation)
  • 보통 코딩 테스트에선 메모이제이션을 쓰는 경우가 대부분이다.

어떻게 접근할까?

  • 동적 계획법 유형은 키워드만으로 동적 계획법 문제임을 알기 어렵다.
  • 그렇기 때문에 문제 유형을 알수 없다면 다음을 확인해보자.
    가장 작은 문제를 정의할 수 있는지?
    작은 문제를 통해 큰 문제를 해결할 수 있는 규칙이 있는지?
  • 위 두 가지가 가능하다면 동적 계획법 문제다.
  • 간혹 메모리를 너무 사용하여 통과 못하는 경우도 있다.
  • 이런 경우엔 백트래킹을 이용할 수 있지만 보통 코딩 테스트에서 자주 나오진 않는다.

🤔 내가 제일 어려워 하는 알고리즘 유형 동적 계획법 알고리즘... 싸피 면접 볼때 동적 계획법이 뭐냐고 설명하라고 했을때 벙쪗던 경험이 있어 그 후로 관련 문제들을 풀었지만 와... 정말 문제 해결 상상력에 의존하는 알고리즘인 것 같다.

다른 알고리즘은 어떻게 활용해야하는지 정의 되어있지만 DP는 개념만 존재하고 정답이 없는 알고리즘이라 정말 어렵다. 실습 문제로 단어 퍼즐 문제가 나왔지만 강사님 코드를 봐도 이해를 아직도 못했다.

그래서 아직 기초가 부족한 것 같아. 같은 팀원과 알고리즘 스터디를 통해 DP의 기본 문제 부터 차근차근 경험을 쌓아 나갈 계획이다.


✅ JavaScript 주요 문법(8) 10.03

문제를 읽기전에 무조건 입출력 제한을 보자!

🤔 사실 이때까지 알고리즘 문제를 풀때 유형별로 풀어서 해당 유형의 알고리즘으로 바로 접근했다. 실제 코딩 테스트에서는 어떠한 유형의 문제가 나올지 모르는데 잘못된 알고리즘을 선택했을때 시간이 부족한 경험도 많았고 입력 값 범위도 제대로 보지 않아 변수 범위도 고려하지 않은 적도 있다.

구현만 하고 공개된 테스트 케이스만 맞추며 히든 테스트 케이스는 진짜 운에 맡긴거 같다. 근데 강사님께서 이렇게 친절하게 정리까지 해주시고 중요성을 깨닫게 해주는데 공부를 안할 수가 없는... 앞으로 알고리즘 문제를 풀면서 입력 값을 보는 습관을 들여 어떻게 접근할지도 같이 고려하도록 노력할 예정이다.

자바스크립트의 9가지 코드 트릭

DOM

렌더링 과정

  • 브라우저가 HTML 파일을 받아 해석(Parsing)하여 DOM Tree를 구성, CSS가 포함되어 있다면 CSSOM Tree도 구성

  • Style 단계에서 생성된 DOM Tree와 CSSOM Tree를 매칭시켜 Render Tree를 구성, Render Tree는 실제 화면에 그려질 Tree

  • Layout 단계에서 Render Tree로 정확한 위치와 크기 스타일을 계산한다. Render Tree에서 위치, 크기 등을 알 수 없어 위치 크기 등을 정해주는 과정으로, 모든 css의 선택자를 토대로 스타일을 분석해 태그에 스타일 규칙이 적용된다.

  • Paint 단계에서는 Layout 단계에서 계산된 값을 이용해 Render Tree의 각 노드를 화면상의 실제 픽셀로 변환한다, 즉 실제 화면에 그리는 작업을 하게 된다.

  • Composite 단계에서 Paint 단계에서 생성된 레이어를 합성하여 실제 화면에 나타내고 우리는 화면으로 웹 페이지를 볼 수 있다.

리플로우 : 레이아웃 계산을 다시 함
리페인트 : 재결합된 Render Tree를 기반으로 다시 Paint

🤔 교육 내용에서는 정말 가볍게 설명하고 넘어간 내용이지만 웹 프론트엔드 개발자를 목표로하는 내가 렌더링이 어떻게 이루어지는지 물었을때 대답을 못하는건 말이 안된다고 생각해서 개인적으로 좀 더 찾아보고 공부한 내용이다.

또한 알게된 내용은 자바스크립트로 DOM, CSSOM을 변경하는 순간 리렌더링이 발생하는 것이다. 내가 개발했던 것을 생각하면 당연한 내용이지만 DOM, CSSOM의 존재를 알게된 뒤로 뭔가 렌더링 과정이 머리속에 그려지는 기분ㅎ

documnet.createDocumnetFragment

여러 개의 요소 노드를 생성하여 DOM에 추가할 때 DOM에 여러번 추가하므로 DOM이 반복되서 변경된다. DOM을 변경하는 것은 높은 처리 비용이므로 횟수를 줄이는 편이 성능에 유리하다.

그럼 어떻게 횟수를 줄일까? DOM에 추가할 여러요소를 컨테이너 요소에 자식 노드로 추가하고 컨테이너 요소를 실제 DOM 요소 자식으로 추가한다면 DOM은 한 번만 변경된다.

이때 컨테이너는 div태그가 될 수도 있지마 이렇게 된다면 쓸모없이 빈 div 태그를 차지에 바람직하지 않다.

DoucumentFragment를 통해 모든 것을 해결할 수 있다. DoucumentFragment는 부모 노드가 없어서 기존 DOM과 별도로 존재하는 특징이 있다. DoucumentFragment 노드를 DOM에 추가하면 자신은 제거되고 자신의 자식 노드만 DOM에 추가된다.

<body>
    <ul id="fruits"></ul>
    <script>
        const $fruits = document.querySelector("#fruits");
        const $fragment = document.createDocumentFragment(); // fragment 노드 생성

        ["Apple", "Banana", "Orange"].forEach(text => {
            const $li = document.createElement("li");
            
            $li.textContent = text;
            $fragment.append($li); // fragment에 자식 li 추가
        })

        // fragment에 담은 li 태그들을 실제 DOM 부모 노드에 한 번만 추가
        $fruits.appendChild($fragment);
    </script>
</body>

🤔 fragment는 강의를 듣기전에 자바스크립트 스터디 DOM 파트를 공부하면서 처음 알게 되었다. 렌더링 비용이 많이 들고 이를 최적하는 것이 프론트엔드 개발자로써 정말 중요한 능력이고 fragment라는 개념을 알게된 이후는 이전까지 렌더링 최적화에 신경도 쓰지 않던 모습을 다 버려야겠다!


✅ VanillaJS를 통한 자바스크립트 기본 역량 강화 I(1) 10.04

this

🤔 오늘은 자바스크립트에 대한 지식 퀴즈를 풀고 해설하는 교육을 받았다. 퀴즈는 주로 this, 클로저, 호이스팅, var과 let의 차이 등 자바스크립트의 정말 중요한 부분의 퀴즈였다.

퀴즈 난이도는 개인적으로 조끔? 어려웠으며 그 중에서도 this 관련 문제를 맞추기 힘들었다. this는 예전에 꼼꼼히 정리했다고 했었는데 막상 문제로 나오니 기억도 잘 나지 않고 헷갈렸다. 그래서 이 참에 this에 대해 공부했다.

또한 클로저와 var이 섞어서 문제가 나오지 진짜 혼동이였다.

/* undefined가 다섯번 출력된다 */
const numbers = [0, 1, 2, 3, 4];

for(var i=0; i<numbers.length; i++) {
    setTimeout(function(){
        console.log(`[${i} number] ${numbers[i]} turn!`);
    }, i * 1000)
}

var는 블록스코프에서 선언되도 전역 스코프를 가지며 setTimeout함수는 반복이 다 끝난후에 하나씩 실행된다 i값이 증가하는 것은 각 블록 렉시컬 환경 내의 i값이 증가하는 것이 아니라 전역 렉시컬의 1개 i의 값을 증가하는 것이라 i가 5가되고 numbers[i]는 undefined를 출력한다.

/* 해결 방법 */
for(let i=0; i<numbers.length; i++) {
    setTimeout(function(){
        console.log(`[${i} number] ${numbers[i]} turn!`);
    }, i * 1000)
}

let은 블록스코프에서 선언되면 자기 자신만의 i를 생성한다. 외부 렉시컬 블록 스코프의 자신만의 i를 참조해서 에러를 발생하지 않는다.

함수 즉시 실행 방법과 사용 이유

즉시 실행 함수 구현 방법

IIFE : 즉시 실행 함수 정의되자마자 즉시 실행되는 Javascript Function

(function() {
    // 함수 내부의 코드 작성
})();

(() => {
    // 함수 내부의 코드 작성
})();

함수를 괄호로 둘러싸고 그 뒤에 추가적인 괄호 ()를 붙여 호출한다. 이렇게 하면 함수가 정의되자마자 바로 실행된다.

사용 이유
한 번의 실행만 필요로 하는 초기화 코드 부분에 많이 사용된다.

아니 그냥 전역 공간에 변수를 선언하고 로직을 작성하면 실행하자 마자 바로 원하는 로직이 실행되는데 왜 굳이 즉시 실행함수를 사용할까? 의문이 들었다.

그 이유는 변수를 전역으로 선언하는 것을 피하기 위해서다, 전역에 변수를 추가하지 않아도 되기 때문에 코드 충돌 없이 구현할 수 있어서 즉시 실행 함수를 이용한다.

🤔 다른 사람의 자바스크립트 코드를 보면서 즉시 실행 함수 형태는 얼추 본 기억이 있다. 하지만 왜 저렇게 사용하는지 이해를 못했고 나는 내 방식대로 즉시 실행 함수를 사용하지 않고 코드를 작성했다. 이제는 그 이유를 알겠다😁


✅ VanillaJS를 통한 자바스크립트 기본 역량 강화 I(2) 10.05

생성자 함수로 추상화

🤔 나는 이때까지 javascript로 개발할때 하나의 js 파일에서 로직을로 쭉 작성했다. 하지만 생성자 함수로 추상화하여 기능을 작성하여 재사용성을 높이고 유지보수에도 훨씬 좋은 모습의 코드를 강의에서 봤다.

핵심은 기능별로 추상화하여 구별하고 구별된 각 기능은 어떻게 구현할지의 로직만 담겨있다. 그리고 그 기능을 호출할때 필요한 데이터만 넘겨주면 되는 개념이였다. 데이터를 어떻게 넘겨주는지 데이터의 기반으로 기능이 구현되었고 나는 재사용성이 뛰어나겠다고 그냥 온 몸으로 느꼇다.


✅ VanillaJS를 통한 자바스크립트 기본 역량 강화 I(3) 10.06

컴포넌트 방식으로 생각하기

TodoList라는 기능을 App이라는 컴포넌트로 지정하고 App에서 Header, TodoForm, TodoList 3개의 컴포넌트로 분리하여 TodoList 앱을 만드는 실습을 했다.

컴포넌트로 구별하여 생각할때 각 컴포넌트는 다른 컴포넌트와 의존성 높으면 안된다. 다른 컴포넌트에 직접 접근하게 되면 의존성이 강해지고 재사용성이 떨어진다. 만약 다른 컴포넌트에 접근해야 한다면 직접 접근하는 것이 아니라 Container의 App에서 콜백 함수의 로직을 담아 처리해야하게 함으로 독립성을 강하게 해야한다.

전달받은 콜백함수는 해당 컴포넌트에서 콜백 함수가 있으면 실행해줄게 안에 내용은 난 상관없다는 생각으로 다른 컴포넌트에 의존하면 안된다.

main 역할 : App 컴포넌트 내 컴포넌트들이 어디에 배치될지 넣는것, App컴포넌트 초기 데이터 정의
App 역할 : App 전체에서 어떠한 컴포넌트들이 들어가는가, 생성 및 관리

🤔 컴포넌트로 분리하여 분리된 컴포넌트는 각 파일로 나뉘게 되어 관리를 했다. 정말 내가 궁금했던 부분 중 하나다. 어떻게 파일을 분리하고 어떻게 로직을 분리해야할지

각 컴포넌트 클래스가 자기 자신만을 담당해서 정말 각각 파일의 역할이 명확해서 이해하기도 쉽고 수정하기도 쉬웠다. 또한 변경되는 데이터는 state로 관리하고 state가 변경되면 리렌더링을 수행하면서 정말 state 상태 값만 잘 관리하면 로직이 정말 깔끔했다.

컴포넌트를 분리하여 코드를 작성해보니 React와 정말 비슷하다고 생각했는데 자세히 살펴보니 그냥 React를 바닐라 자바스크립트로 구현한거다. React는 컴포넌트를 분리하고 각 컴포넌트에 state를 또 관리하고 렌더링이 발생하면 자동으로 렌더링이 일어났지만 바닐라 자바스크립트에서는 setState()함수를 구현하여 state를 변경시키고 render()함수 안에서 state 값으로 DOM을 생성하여 그린다. setState() 함수가 호출되면 그냥 render() 함수를 호출하여 리렌더링이 발생하게 해주면서 그냥 React를 구현한 느낌이였다.

React가 이러한 까다로운 리렌더링 과정을 편하게 도와주는 라이브러리였구나 다시 생각하게 되었고 바닐라 자바스크립트로 구현할 수 있는지도 처음 알게 되었다.

로컬 스토리지

  • 도메인만 같다면 여러탭 내에서 로컬스토리지가 공유된다. www.naver.com과 www.naver.com/search 페이지는 같은 도메인이기에 로컬스토리지가 공유된다.

  • 브라우저가 닫혀도 삭제하거나 스토리지를 날리지 않는 한 삭제되지 않는다.

  • 객체를 JSON 문자열로 변경하고 값을 넣어야한다. JSON.stringify(Object)
    파싱할때도 JSON.parse(localStorage.getItem("key")) JSON문자열을 다시 객체로 변경


🥱마치며

이번주차는 DOM을 제어하기 시작하면서 재미가 솔솔 붙는 느낌이였다. 그리고 특히 PR을 통해 리뷰를 주고받는 경험이 정말 신기했다.

제일 충격인건 이때까지 javascript로 개발하면 그냥 생각나는대로 한 파일에 무작정 코드를 작성하기 바빳다. 근데 강의에서 컴포넌트 방식으로 분리하여 생성자 객체를 통해 딱!딱! 역할에 맞게 분리 해서 코드를 작성하는 것에 충격이였지만 아 내가 이 부분은 정말 빠삭하게 들고가서 차후 프로젝트나 React 파트때 활용할 수 있겠구나 느꼇다.

그리고 React를 사용하면서 컴포넌트 분리한 적은 있지만 다른 컴포넌트의 접근 해야하면 그냥 직접 접근해서 필요한 데이터를 가져오곤 했다. 그래서 재사용성이 떨어지고 중복되는 코드도 많아지고 개인적으로 답답했지만 진짜 해결방법을 몰랐다. 근데 의존성과 독립성 콜백 함수의 활용을 배우고 아 그때 이렇게 했으면 더 깔끔한 코드가 되었을텐데 하면서 후회도 하고 다음 프로젝트에서는 절대 실수 안해야지라고 생각하며 3주차 만에 생각하는 방식이 달라졌다고 느꼇다.

3주차만에 정말 성장한 느낌이 팍팍들면서 지치고 않고 다음 주차에 이제 뭘 배울까 기대가 되기도 한다. 데브코스에 합격하면서 좋았지만 그래도 사소한 걱정들은 했는데 이제는 성장을 목표로 열심히 쭉 나아겠다는 생각뿐인거 같다.

3주차 종료 이상.

profile
대구 사나이
post-custom-banner

0개의 댓글