현업 프론트엔드 기술을 Araboja.

김정훈·2023년 9월 5일
0

Web

목록 보기
2/2

저는 현재 4학년 1학기를 마친 프론트엔드 개발자가 되고 싶은 졸업예정자입니다. 취업준비에 힘을 쏟는 시기이죠. 그래서 기업들의 채용공고를 많이 보는 편입니다. 특히, 자격요건/우대사항을 자세히 살펴보면서 이 회사의 개발팀이 사용하는 기술을 유추해볼 수 있었습니다.

다양한 공고를 분석하니 기본적인 HTML, CSS, JS 외에 공통적으로 자주 등장하는 프론트엔드 기술들이 있었습니다. 크게 네 가지로, React.js, Next.js, 상태관리 도구, TypeScript가 그 기술들인데요. 문득 이런생각이 들었습니다.

이 기술들이 많이 사용되는 이유가 뭐지? 얘네들은 왜 만들어진 걸까?

궁금증을 해소하고자 이 기술들이 만들어진 배경과 사용되는 이유에 대하서 조사하고 나름대로 분석해 보려고 합니다.

해당 기술들의 공식문서들을 기반으로 작성된 포스트입니다.

ReactJS

탄생배경

제가 Vanilla Javascript로 프로젝트를 진행할 때, DOM요소를 document객체로 직접 접근하여 조작하는 경우가 많았습니다. 작은 프로젝트라면 DOM요소에 직접 접근하여 조작하는 것은 큰 문제가 없을 수 있습니다. 하지만 instagram, facebook과 같은 매우 큰 규모의 웹 애플리케이션이라면 어떨까요?

앱의 규모가 커질수록 사용자와의 상호작용 성능의 중요도가 높아집니다. 요즘 웹에선 사용자와의 상호작용으로 DOM요소 조작이 빈번하게 일어납니다. 이때, DOM요소에 직접 접근하여 조작하게 되면 브라우저에 추가적인 연산을 발생시키기 때문에 웹 애플리케이션의 성능 저하의 위험이 있습니다.

이런 문제를 해결하기 위해 Virtual DOM이라는 개념이 생겨나게 됩니다. Javascript나 jQuery와 같이 DOM에 직접 접근하여 조작하는 추가적인 연산을 발생시키는 대신, Virtual DOM을 통해 간접적으로 DOM을 조작하는 것입니다. 이러한 Virtual DOM의 조작을 쉽게 만들어주는 라이브러리가 React입니다.

React, 왜 쓰는가?

웹 서비스를 이용할 때, 페이지 전환이 일어날때 마다 새로고침이 된다면 아무래도 사용자입장에서 불편할 수 밖에 없습니다. 따라서 화면 깜빡임(새로고침) 없이 부드럽게 페이지 전환이 일어나는 것이 사용자 경험과 비즈니스적 측면에서 중요합니다. 이런식의 애플리케이션을 기본적인 JS로도 만들수야 있지만 코드의 양이 방대해지고 어렵기 때문에 React를 사용해야 보다 쉽게 만들 수 있습니다.

그렇다면 이런 장점을 발휘할 수 있도록 해준 React의 특징은 무엇이 있을까요?

1. 선언형

React는 상호작용이 많은 UI를 만들 때 생기는 어려움을 줄여줍니다. 애플리케이션의 각 상태에 대한 간단한 뷰만 설계하세요. 그럼 React는 데이터가 변경됨에 따라 적절한 컴포넌트만 효율적으로 갱신하고 렌더링합니다. - 리액트 공식문서 설명

선언형 프로그래밍은 코드의 동작이 어떻게(How) 동작하는지 보다 무엇을(What)을 이끌어내는지에 집중하는 방식입니다. 그 과정에 대해서는 추상화를 통해 유추만 할 뿐입니다. 이런 특성은 코드의 가독성을 높여주고, 사람이 코드를 쉽게 이해할 수 있도록 도움을 줍니다.

const App = () => {
  <Header />
  <Main />
  <Footer />
}
  /* 렌더링 되는 과정은 잘 모르지만 App 컴포넌트는 Header, Main, Footer 
  세 개의 컴포넌트로 이루어져 있는 것은 쉽게 파악이 가능하다. */

공식문서의 설명을 나름대로 해석하자면,

순수 자바스크립트만으로 상호작용이 많은 UI를 만드는 어려움을 줄여줍니다. 애플리케이션이 각 상태마다 어떻게 보여져야 하는지만 설계하세요. 그럼 React가 당신의 설계대로 브라우저에 렌더링 할 것입니다. 어떻게 렌더링하는지 그 과정은 신경쓰지 않아도 괜찮습니다.

2. 컴포넌트 기반

개발자는 중복을 매우 싫어하는 사람들이죠. HTML/CSS로만 웹 애플리케이션을 만들다 보면 HTML안에 내용만 다르고 같은 구조를 가지고 있는 요소들을 하나의 파일안에 여러번 작성해야 하는 경우가 생기기 마련입니다. React는 컴포넌트 기반 프레임워크로 재사용성을 높여 중복을 제거했습니다.

velog 같은 애플리케이션을 순수 HTML/CSS로만 작성한다고 상상하면 머리가 지끈거립니다.

3. 확장성

React Native는 모바일 앱을 쉽게 만들수 있는 프레임워크로 React를 기반으로 만들어졌습니다. React를 아는 개발자라면 쉽고 빠르게 모바일 애플리케이션을 만들 수 있습니다. 하나의 서비스만 잘 만들어두면 모바일에서도 같은 서비스를 출시할 수 있습니다.

전체적으로 정리하자면

React는 컴포넌트 단위로 개발할 수 있기 때문에 UI개발이 쉬우며, 재사용성이 뛰어나다. 또한, 페이지 전환이 부드러운 SPA를 만들기 쉽고 모바일 앱으로도 확장할 수 있다. 이와 같은 장점덕분에 UX적으로 뛰어난 애플리키에션을 만들기 쉽고, 기업의 비즈니스를 실현하기 적합하다.

NextJS

탄생배경

과거 웹 애플리케이션은 대부분 다수의 웹 페이지를 SSR(Server Side Rendering)로 렌더링하는 방식을 사용했다고 합니다. 이러한 방식은 우수한 초기 로딩속도와 SEO를 자랑했지만 페이지 전환시 브라우저 화면 전체가 깜빡이는 현상이 발생했습니다.

이러한 문제 때문에 사용자 경험 측면에서 좋지 못했고, 스마트폰이 대중화 되면서 부드러운 화면전환의 중요성이 더욱 커졌습니다. AJAX를 통해 클라이언트에서 필요한 데이터만을 비동기적으로 불러와 보여주는 형태로 발전하였지만 인간의 욕심은 끝이 없는 법.

클라이언트에서 데이터를 받아오는 것 뿐만아니라 렌더링(Client Side Rendering)까지 해버리고 싶은 욕심이 생겨 태어난 기술들이 React, Vue, Angular입니다. CSR을 바탕으로 사용성 좋은 SPA들이 많이 많이 개발되어 전성기를 누렸지만 이 방식에도 문제점이 존재했습니다.

SSR방식과 달리 다소 느린 초기 로딩속도와 SEO가 그리 좋지 못하다는 점이었습니다. CSR의 장점을 유지하면서 SSR의 장점까지 갖춘 애플리케이션을 만들기 위해 탄생한 기술이 NextJS입니다.

Next, 왜 쓰는가?

CSR방식의 문제점은 왜 생겨나게 되는 걸까요? React의 경우 웹 사이트를 요청했을 때, 빈 HTML파일을 가져와 script를 로딩하기 때문입니다.

반면, next.js는 pre-rendering을 통해 미리 데이터가 렌더링된 상태로 브라우저로 가져올수 있게 해줍니다. 따라서 빠른 초기로딩속도와 SEO에서도 장점을 드러내게 됩니다.

이미지 출처, next 공식문서

이러한 특징으로 아주 강력한 웹 애플리케이션을 만들 수 있습니다. NextJS 역시 기업의 비즈니스를 사용자들이 쉽고 편하게 이용할 수 있도록 만들어 줄 수 있는 효자 기술이라고 할 수 있겠습니다.

Next.js는 또 어떤 좋은 기능들을 가지고 있을까요?

1. 라우팅 시스템

next.js는 페이지 기반 라우팅 시스템도 제공합니다. next.js로 프로젝트를 생성하면 /pages라는 폴더가 생성되는데, 이 폴더에서 컴포넌트를 export하면 페이지 route가 됩니다. 예를 들어 index.js를 export하면 /pages/index.js라는 라우터가 하나 만들어지며, 해당 파일에 정의된 UI가 브라우저에 렌더링 됩니다.
매우 직관적인 시스템이라 개발자가 이해하기 쉽습니다.

2. Client-Side Navigation

next.js Link컴포넌트는 동일한 Next.js 애플리케이션의 페이지간 클라이언트 측 탐색을 가능하게 합니다. <a href="...">와 달리 전체 페이지를 로드하지 부드럽게 페이지를 전환할 수 있습니다.

3. 코드 분할과 prefetching

Next.js는 자동으로 코드 분할을 수행하므로 각 페이지는 해당 페이지에 필요한 항목만 로드합니다. 즉, 홈 페이지가 렌더링 될 때 다른 페이지에 대한 코드는 가져오지 않습니다. 이런식으로 코드를 분할하면 수백 페이지가 잇는 웹 애플리케이션의 경우에도 페이지가 빠르게 로딩됩니다. 페이지마다 코드가 분할되어있기 때문에 하나의 페이지에서 문제가 발생해도 다른 페이지는 정상적으로 동작할 수 있습니다.

Link 컴포넌트가 브라우저의 뷰포트에서 나타날 때마다 Next.js는 백그라운드에서 링크된 페이지에 대한 코드를 자동으로 prefetching합니다. 링크를 클릭하면 대상 페이지의 코드가 이미 백그라운드에 로드되고 페이지 전환이 거의 즉시 완료됩니다.

prefetching 부분의 설명이 조금 아리송해서 좀 더 찾아봤습니다.
Next.js로 만들어진 웹 페이지에서 링크에 마우스를 올리는 순간, 해당 페이지의 대한 데이터를 받아오는 모습을 확인할 수 있었습니다. 페이지에 접근 전에 데이터를 미리 백그라운드에 fetch한다라고 생각하면 될 것 같습니다.

상태관리도구

탄생배경

JS 기반의 SPA가 갖춰야할 요건이 점점 더 복잡해지고 있는 만큼, 많은 상태를 자바스크립트 코드로 관리할 필요가 생겨났습니다. 그러나 React만으로 상태를 관리하기에는 다음과 같은 한계점이 있습니다.

컴포넌트의 상태는 공통된 상위 컴포넌트까지 끌어올려야만 공유될 수 있으며, 이 과정에서 매우 큰 트리가 다시 렌더링 되는 문제가 발생할 수 있습니다. 상태관리 도구 없이 React로만 개발을 해보신 분들은 충분히 공감할 불편함입니다. 또한, 이러한 특성은 Props drilling이슈를 발생시킬 수 있습니다.

예를 들어, 상위 컴포넌트의 상태를 하위 컴포넌트가 사용한다고 가정합시다. 두 컴포넌트 사이에 존재하는 다른 컴포넌트들은 상위 컴포넌트의 상태가 필요하지 않음에도 props로 하위 컴포넌트까지 상태를 내려꽂아야(drilling)하는 불편함이 생깁니다. 이러한 번거로움을 Props drilling이라고 합니다.

그리고 자주 변하는 상태를 관리하는 것은 어렵습니다. 애플리케이션이 커지고 복잡해진다면 모델이 모델을, 뷰가 모델을, 이 뷰가 다시 모델을, 이에 따라 다시 다른 뷰가 업데이트 매우 머리아픈 동작이 발생할 수 있습니다. 어느 시점에서는 개발자조차 자신이 만든 애플리케이션에서 무슨 일이 일어나는지 파악할 수 없는 지경까지 이를 수 있습니다.

이런 문제를 해결하기 위해 등장한 기술들이 상태관리도구입니다.

상태관리도구, 왜 쓰는가?

애플리케이션의 상태를 한 곳에서 관리하고 변경사항을 보다 쉽게 예측 가능하고 추적 가능한 상태로 유지할 수 있습니다.

상태변화로인해 다시 렌더링해야 하는 컴포넌트만을 렌더링 하기 때문에 애플리케이션의 성능을 향상 시킬 수 있습니다.

애플리케이션의 구조를 쉽게 이해할 수 있어 유지보수를 쉽게 만들어주며, 쉬운 디버깅을 지원할 수 있습니다.

상태관리도구들의 이러한 장점은 개발자가 보다 편리하게 개발을 진행할 수 있도록 도움을 줍니다. 기업 입장에서는 개발자들이 자신들의 비즈니스를 보다 편하게 실현시켜주는 것이기에 사용하지 않을 이유가 없겠습니다.

TypeScript

탄생배경

Javascript는 Dynamic Typing언어입니다. 변수의 타입(type)지정 없이 값이 할당되는 과정에서 리터럴에 의해 자동으로 type이 결정됩니다. 따라서 같은 이름의 변수에 다양한 유형의 리터럴을 대입하거나 선언하여도 문제가 없습니다.

let name = 'Tom';
name = 1;

// ...

하지만 이러한 유연성 때문에 오히려 문제가 발생할 수 있습니다. 아래 작성된 함수 코드를 보면 함수 실행 과정에서 전달해야 할 각 인자의 타입을 알지 못할 경우 의도치 않은 문제가 발생할 수 있습니다.

function ellipsisText(text, limit, symbol='...') {
  return `${text.slice(0, limit - 1)}${symbol}`
}

ellipsisText(100304040202, 30, 101)

이 예시코드는 첫 번째 인자에 숫자를 넣어, 문제가 발생했음에도 오류를 표시하지 않고 프로그램이 실행됩니다.

대부분의 프로그래밍언어는 이러한 종류의 오류가 발생할 때, 오류를 발생시켜 프로그램을 종료 시키거나 컴파일하는 동안에 오류를 발생시키기도 합니다. 작은 프로그램을 개발할 때 이러한 단점은 번거롭지만 관리할 수 있는 수준입니다. 하지만 코드가 길어지고 애플리케이션의 복잡성이 증가한다면 심각한 수준의 문제로 이어질 가능성이 높습니다.

오류를 알리지 않는 함수는 선언시 각 매개변수로 전달 받을 값의 타입을 검사해 문제를 해결할 수는 있습니다. 하지만 이와 같은 검사 과정을 직접 작성하는 것은 매우 번거롭고 불편합니다.

function ellipsisText(text, limit, sybol='...') {
  if (typeof text !== 'string') 
    throw new Error('1번째 전달인자 유형은 문자여야 함')
  
  if (typeof limit !== 'number') 
    throw new Error('2번째 전달인자 유형은 숫자여야 함')
  
  if (typeof symbol !== 'string') 
    throw new Error('3번째 전달인자 유형은 문자여야 함')
  
  return `${text.slice(0, limit - 1)}${symbol}`
}

이러한 문제를 해결하기 위해 TypeScript가 등장하게 됩니다.

TypeScript, 왜 쓰는가?

단순 코드량만 보면 굳이 TypeScript를 써야 할까 싶지만, TypeScript는 JavaScript와 달리 코드 작성 과정에서 코드를 실시간으로 디버깅 할 수 있어 매우 편리합니다. 또한, TypeScript는 정적 유형 검사기라서 코드를 실행하지 않고 오류를 감지 할 수 있습니다.

function ellipsisText(text:string, limit:number, symbol:string = '...'):string {
  return `${text.slice(0, limit - 1)}${symbol}`
}

ellipsisText(10203010201, 30);

이 코드는 TypeScript에서 이런 오류를 내놓습니다.

Argument of type 'number' is not assignable to parameter of type 'string'.

이러한 엄격한 Type 검사는 코드 품질과 이해도를 높일 수 있습니다. 게다가 런타임에 오류를 포착하는 것이아니라 컴파일러가 오류를 찾아내기 때문에 더 빠르게 코드를 개선할 수 있겠습니다.

개발 시간 대부분은 코딩하는 시간보다 디버깅 시간으로 이루어져 있다고 생각해도 과언이 아닙니다. 런타임에서 오류를 찾아내야 하는 JavaScript의 디버깅 시간을 획기적으로 TypeScript가 줄여줄 수 있을 것입니다.

0개의 댓글