[스터디] 프레임워크 없는 프론트엔드 개발 1주차

park·2024년 12월 19일
0
post-thumbnail

들어가면서

한날님의 푸딩캠프에서 여는 '프레임워크 없는 프론트엔드 개발' 책 읽기 스터디에 참여하게 되었다. 스터디를 진행하면서 정리한 내용을 블로그에 연재할 계획이다.

1장 프레임워크에 대한 이야기

'때로는 프레임워크만으로 작업을 수행하기가 충분하지 않다'

키워드

프레임워크가 무엇이냐?
라이브러리 vs 프레임워크
프레임워크 방식(제약 사항)
그러면 리액트는?
프레임워크 연혁
기술 부채와 기술 투자


프레임워크가 무엇이냐?

프레임워크란 무언가를 만들 수 있는 지지구조다.

라이브러리와 프레임워크의 차이는? 프레임워크는 코드를 호출한다. 코드는 라이브러리를 호출한다.

즉, A라는 어떤 코드 조각이 있다면, 프레임워크는 개발자가 A라는 코드 조각을 내가 사용하고 있다는 인지 조차 하지 못한 채 A를 사용할 수 있게 한다. 이에 비해 라이브러리는 개발자가 A를 직접 사용하게 한다. (내가 이해한바로는 그렇다.)

프레임워크 vs 라이브러리

프레임워크는 코드를 어떻게 구성해야 하는지 특별한 형식을 요구. 이에 비해 라이브러리는 요구하지 않음.

앵귤러(프레임워크)와 moment.js(라이브러리)를 떠올려보라.

그렇다면 리액트는 프레임워크인가, 라이브러리인가?

프레임워크 방식

그전에 먼저, 프레임워크 방식에 대해 알아보자.

(프레임워크 방식이라고 책에 나와있기는 한데 나는 이것을 '프레임워크가 가지는 특유의 제약사항'에 가깝게 이해했다.)

프레임워크들이 제약을 거는 몇몇의 사항들이 있다. 즉, 프레임워크에는 제약 사항들이 있다. (즉, 이 프레임워크를 사용할 때 이것을 반드시 따라주세요...)

  • 언어
  • 의존성 주입
  • 옵저버블

이러한 공식적인 속성의 제약조건 외에도 커뮤니티가 만든 '사실상의 표준'도 있다.

사용하려는 각각의 프레임워크가 어떤 제약조건을 가지고 있느냐를 따져서 프로젝트에 적합한 도구를 선택하도록 해야한다.

그러면 리액트는?

공식 홈페이지에서 리액트는 '라이브러리'라고 소개되어있다. 이에 따르면 리액트는 라이브러리다. 그런데 이렇게 간결하게 판단하고 넘어가기에는 조금 복잡한 부분이 있다.

리액트에는 제약 사항이 있다. 저자가 집중한 제약 사항은 '선언적 패러다임'이다. 리액트 커뮤니티는 명령형으로 로직을 전개하기 보다는 선언적 패턴을 쓰라고 권장하고 있으며, 리액트 기반 라이브러리나 프레임워크가 따르고 있는 사실상의 표준이다.

따라서 저자는 리액트가 '라이브러리'가 아니라 '프레임워크'라고 '믿는다'.

이에 대한 나의 생각

'ooo은 ooo이다.' 라고 결론 내릴 수 있을만큼 단순한 문제는 아닌 것 같다. 리액트의 어떤 부분에 집중하냐에 따라 라이브러리가 될 수도 있고 프레임워크가 될 수도 있다고 생각한다. 훅을 만들거나 사용할 때 지켜야하는 것과 같은 제약 사항들이 여럿있고, 내부적 흐름을 알아서 처리하는 것을 보면 리액트는 프레임워크다. 그러나 리액트를 여전히 개발자가 직접 '호출'해야한다는 것과 완전히 틀에 얽매이지 않고 어느정도 자유롭게 개발자가 구현을 할 수 있는 부분이 있는 것을 보면 리액트는 라이브러리다.

그러나 나는 프레임워크에 가깝다고 생각한다.

사실상 프레임워크

프레임워크 연혁

  1. 제이쿼리: 현재 많은 사람들이 무시하고 있지만, 브라우저 간 공통어를 만들어 내었고 프론트엔드 개발의 만능 도구라는 점에서 의의가 있다.

  2. 앵귤러JS: SPA 앱을 주류로 만드는 데 큰 역할. 양방향 데이터 바인딩. 그러나 양방향 데이터 바인딩은 대규모 앱에는 적합하지 않았음

  3. 리액트: 단방향 데이터 바인딩. 선언적 패러다임.

  4. 앵귤러: 엔터프라이즈 세계를 타겟팅. 타입스크립트를 사용하는 것이 사실상의 표준

기술 부채와 기술 투자

당장의 문제를 해결할 때, 빠르지만 지저분한 솔루션을 선택할수도 있고 느리지만 깔끔한 솔루션을 선택할수도 있다.

'지저분한 솔루션을 선택할수록 부채는 기술부채는 늘어난다'.

기술부채란? 기존 기능의 변경이나 새로운 기능의 추가에 따르는 비용.

모든 프레임워크는 기술 부채를 가지고 있다. 그리고 최적이 아닌 방법을 택할 때 부채가 발생한다. -> 내 문제를 해결하는 데 있어 다른 사람의 코드가 최적이 될 수는 없다. -> 프레임워크가 최적의 해결책이 될 수는 없다.

그래서 프레임워크가 제공하는 기능을 직접 만들어보는 것이 중요하다.

그러나 세상은 녹록치 않고, 우리는 모든 문제를 직접 손수 해결할만큼 시간과 돈이 많지 않다.

다만 명심해야할 것은 프레임워크는 무료가 아니라는 것이다. 프레임워크를 사용하게 되면 미래에 코드 변경이 어렵다. 즉, 아키텍쳐 자체에 이미 비용을 포함하고 있다. 프레임워크는 변경이 필요한 상황에서 장애물이 된다.

그러면 어쩌란 말이냐?

기술 부채가 항상 나쁜 것만은 아니라는 사실을 명심하자. 경제에서 부채는 일종의 자산으로 취급된다. 합리적인 이유로 부채를 만들었다면 그것은 '투자'이다.

개발에서도 마찬가지다. 합리적인 이유로 빠른 솔루션을 사용한다면 기술 부채가 아니라 기술 투자가 된다. 따라서 이 합리적인 이유에 대해 잘 따져보는 것이 중요하겠구나.....

2장 렌더링

여기서부터는 본격적으로 프로그래밍이 시작된다. 따라서 요약할 내용은 그리 많지 않으며, 큰 흐름과 내가 개인적으로 인상 깊었던 것에 대해서 주로 작성할 것이다.

데이터를 표시하는 것이 앱의 가장 중요한 기능 중 하나다. 데이터를 표시한다는 것은 출력 장치에 '렌더링'하는 것을 의미한다. 이러한 렌더링을 프로그래밍 방식으로 관리하는 것이 DOM이다. 이 렌더링을 프레임워크 없이 해보자는 것이 이 장의 요지이다.

키워드

DOM이 뭐냐
렌더링 성능 모니터링법
렌더링 함수 작성 1차 - 개선
2차 - 선언적 프로그래밍을 위한 레지스트리
동적 데이터 렌더링(interval) - 성능을 위한 가상 돔 구현(diff 알고리즘)


DOM이 뭐냐?

렌더링을 프로그래밍 방식으로 관리하는 것. 웹 구성 요소를 조작하는 API.

구체적인 형태: HTML 요소로 정의된 트리.

이 트리 그 자체이자, 트리를 관리하는 방법이 DOM

렌더링 성능 모니터링법

웹용 렌더링 엔진을 설계할 때는 가독성, 유지보수성 뿐만아니라, 성능도 중요하다.

이 성능을 모니터링하는 도구에는 개발자 도구, state.js, 수제 성능 측정기(...) 등이 있다.

렌더링 함수 작성 1차 - 개선

애플리케이션의 상태에만 의존하도록 순수 함수를 사용해 렌더링을 구현할 것이다.

view = f(state)

TodoMVC 라는 투두 애플리케이션 템플릿을 사용하여 구현한다.

여기서 구현하는 것은 3가지이다.

  • 투두 아이템을 가져와 ul 태그 안에 보여주기
  • 완료되지 않은 투두 수를 span 안에 보여주기
  • 선택한 필터 유형 강조해서 보여주기

html로 앱의 뼈대를 구성하고, 위 목적을 각각 달성하는 세 가지 함수를 파일 하나에다 작성한다. 그리고 default로 export할 함수에 이 함수들을 호출하여 만들고 싶은 ui를 만든다.

여기서 인상 깊었던 것은 default로 export 하는 함수는 데이터를 표시하고픈 타겟 요소를 인자로 받게 되는데, 바로 해당 타겟 요소에 수정 사항을 반영하는 게 아니라, cloneNode를 통해 복제를 하고 복제한 노드에 수정 사항을 반영하는 것이다. 복제한 노드는 다큐먼트와 별개이며, 이 단계에서는 실제 수정사항이 커밋되지 않기 때문에 성능이 향상된다. 실제 연결하는 것은 나중이다.

즉, 가상(virtual)이라는 개념을 사용하는 것이다.

실제로 연결할때는 window.requestAnimationFrame(callback)을 사용하게 된다. 이것은 렌더링 엔진의 기반이 되게 되는데, 이 콜백 내에서 DOM 작업을 수행하면 더 효율적이게 된다고 한다.

이유를 조사해본 결과, 대표적인 비교군으로는 setTimeout이 있는데, 얘는 메인스레드에서 바로 실행되게 된다. 따라서 메인 스레드를 차단하게 된다. 그러나 requestAnimationFrame은 메인 스레드에서 바로 실행되지 않아 메인 스레드를 차단하지 않으며, repaint 타이밍에 맞춰서 실행하게 된다. 즉, 브라우저는 어차피 언젠가 repaint를 하게 되는데, '그 타이밍에 할 거 있으면 하는 김에 같이 할게'라는 식으로 작동하게 되어서 더 효율적이게 된다는 것이다.

다만 저자는 여기서 만족하지 않고 코드를 개선하게 된다. 거대한 함수를 여러 파일에 나눠 분리시키고, 그 각 함수들이 동일한 인터페이스를 가져서 일관성을 가지도록 한다.

2차 - 선언적 프로그래밍을 위한 레지스트리

선언적 프로그래밍을 하기 위해, 레지스트리를 사용하게 된다.

올바른 함수를 수동적으로 호출해야하는 불편함을 없앨 수 있다.

사용할 view 함수들을 적절한 data-component 속성값과 매치한다. 이것은 컴포넌트 기반 렌더링 엔진의 핵심 메커니즘이다.

이 과정에서 좀 더 범용성 있게 로직을 구현하려면 상속 로직이 필요한데, 순수 함수를 사용하므로 고차함수를 사용하여 이를 해결한다.

동적 데이터 렌더링(interval) - 성능을 위한 가상 돔 구현(diff 알고리즘)

setInterval을 통해 5초보다 상태가 무작위로 변경되게끔 조작하여, 해당 변경된 상태가 동적으로 렌더링 되도록 한다.

간단한 가상돔(diff 알고리즘) 구현을 통해 변경되어야할 부분만 변경되도록 한다.

profile
프론트엔드 개발자. 엔지니어가 되고 싶습니다. 개발자의 관점에서 문제를 이해하고 해결하는 것을 연습하고 있습니다.

0개의 댓글

관련 채용 정보