General FE
기본 개념
Q. CSR / SSR / SSG / ISR 에 대해 설명해주세요.
-
네 가지 모두 웹 페이지를 렌더링하는 방식인데, 어디서 HTML을 생성하느냐, 언제 생성하느냐에 따라 구분됩니다.
CSR은 클라이언트 사이드 렌더링으로, 브라우저가 빈 HTML을 받은 후 JavaScript를 실행해서 화면을 그리는 방식입니다. 초기 로딩은 느리지만 이후 페이지 전환이 빠르고, React 같은 SPA 프레임워크가 이 방식을 기본으로 사용합니다.
SSR은 서버 사이드 렌더링으로, 서버에서 완성된 HTML을 만들어 브라우저에 전달하는 방식입니다. 첫 화면을 빠르게 볼 수 있고 SEO에 유리하지만, 매 요청마다 서버에서 처리해야 해서 서버 부하가 증가합니다.
SSG는 정적 사이트 생성으로, 빌드 시점에 미리 모든 HTML을 생성해두는 방식입니다. CDN으로 바로 배포가 가능하고 응답 속도가 매우 빠르지만, 데이터가 자주 바뀌는 페이지에는 적합하지 않습니다.
ISR은 증분 정적 재생성으로, SSG의 변형입니다. 빌드 시점에 정적 HTML을 생성하되, 설정한 주기마다 백그라운드에서 페이지를 재생성합니다. SSG의 빠른 응답 속도를 유지하면서 콘텐츠를 주기적으로 최신화할 수 있어, 자주 바뀌지는 않지만 완전히 정적이지도 않은 페이지(블로그, 상품 목록 등)에 적합합니다. Next.js에서
revalidate옵션으로 사용할 수 있습니다.
Q. CSR과 SSR의 단점을 극복하는 방법에 대해 설명해주세요.
-
CSR의 가장 큰 단점은 초기 로딩이 느리고 SEO가 취약하다는 점입니다. 이를 극복하기 위해 코드 스플리팅을 통해 초기에 필요한 코드만 로드하거나, 프리렌더링을 사용해 HTML을 미리 생성해두는 방식을 쓸 수 있습니다. SSR이나 SSG를 부분적으로 적용하는 것도 방법입니다.
SSR의 단점은 매 요청마다 서버에서 렌더링이 필요해 서버 부하가 크고 응답 시간이 길어질 수 있다는 점입니다. 이를 극복하기 위해 서버 응답을 캐싱하거나, 자주 바뀌지 않는 콘텐츠는 SSG로 처리하고 동적인 부분만 SSR로 처리하는 방식을 혼용할 수 있습니다.
Q. PNG, JPG, WEBP, AVIF와 같은 이미지 포맷의 차이점에 대해서 설명해주세요.
-
각 포맷은 압축 방식과 특성이 달라서 용도에 맞게 선택하는 것이 중요합니다.
PNG는 무손실 압축 방식으로 투명도를 지원합니다. 화질 손실이 없어서 아이콘이나 로고처럼 선명한 엣지가 필요한 이미지에 적합하지만 파일 크기가 큽니다.
JPG는 손실 압축 방식으로 파일 크기를 많이 줄일 수 있어 사진에 주로 사용됩니다. 다만 압축할수록 품질이 저하되고 투명도를 지원하지 않습니다.
WebP는 Google이 개발한 포맷으로 손실·무손실 압축을 모두 지원하고, JPG나 PNG보다 파일 크기가 30~50% 더 작습니다. 대부분의 최신 브라우저에서 지원되어 현재 가장 많이 권장되는 포맷입니다.
AVIF는 AV1 코덱 기반의 포맷으로 WebP보다 압축률이 더 높습니다. 다만 구형 브라우저에서는 지원이 제한적이라 브라우저 호환성을 고려해야 합니다.
Q. 프론트엔드에서 피처 구현하면서 가장 고려해야 될 게 뭐라고 생각하나요?
-
프론트엔드에서 피처를 구현할 때 가장 중요하게 고려해야 할 점은 사용자 경험이라고 생각합니다. 최종적으로 프론트엔드가 개발하는 모든 기능은 사용자를 위한 것이기 때문입니다.
구체적으로는 성능, 접근성, 유지보수성 세 가지를 균형 있게 고려해야 합니다. 성능 측면에서는 불필요한 렌더링을 줄이고 코드 스플리팅, 이미지 최적화, 캐싱 전략 등을 통해 로딩 시간을 최소화해야 합니다. 접근성 측면에서는 모든 사용자가 장애 여부와 관계없이 기능을 사용할 수 있도록 시맨틱 HTML과 ARIA 속성, 키보드 네비게이션 지원이 필수적입니다. 마지막으로 유지보수성을 위해 컴포넌트의 재사용성과 명확한 관심사 분리를 고려해야 합니다.
Q. SPA에서 검색 엔진 최적화를 이루는 방법에 대해서 알려주세요.
-
SPA는 기본적으로 빈 HTML에 JavaScript로 내용을 채우는 방식이라 검색 엔진 크롤러가 콘텐츠를 제대로 인식하지 못할 수 있습니다.
해결 방법으로는 SSR 적용이 있습니다. 서버에서 페이지 HTML을 미리 만들어 검색 봇에게 전달하면 초기 콘텐츠를 바로 인식할 수 있습니다.
SSG는 빌드 시점에 모든 페이지의 HTML을 미리 생성해두어 SEO에 유리하며, Next.js나 Gatsby가 지원합니다.
동적 렌더링은 사용자에게는 SPA를, 검색 봇에게는 서버에서 미리 렌더링된 버전을 보여주는 방식입니다.
Q. SSR 방식으로 SPA를 구현하는 과정에 대해서 알려주세요.
-
SSR 방식의 SPA는 사용자가 첫 페이지를 요청하면 서버가 필요한 데이터를 포함한 완성된 HTML을 만들어 브라우저에 전달합니다.
브라우저는 받은 HTML을 화면에 표시한 후 JavaScript를 로드해서 정적인 HTML에 동적인 기능을 붙이는데, 이 과정을 하이드레이션이라고 합니다. 이후에는 일반적인 SPA처럼 클라이언트에서 페이지를 업데이트하며 동작합니다.
Q. CLS 말고 Core Web Vitals 측정항목에는 뭐가 있는지 아시나요?
-
Core Web Vitals는 Google이 사용자 경험을 측정하는 핵심 지표들입니다.
LCP는 페이지에서 가장 큰 콘텐츠 요소가 화면에 표시되는 시간을 측정하며, 2.5초 이내가 권장됩니다.
FID는 사용자가 페이지와 처음 상호작용했을 때의 응답 지연 시간을 측정하며 100ms 이하가 좋습니다.
INP는 FID를 대체하는 지표로 페이지의 모든 사용자 상호작용에 대한 응답성을 측정하며 200ms 이하가 좋은 경험으로 평가됩니다.
TTFB는 리소스 요청부터 첫 번째 바이트를 받는 데 걸리는 시간으로 서버 응답 속도를 나타냅니다.
Q. Lighthouse 성능 측정 기준에는 뭐가 있는지 설명해주세요.
-
Lighthouse는 Google이 개발한 웹페이지 품질 측정 도구로, 다섯 가지 영역을 평가합니다.
성능 영역에서는 FCP, LCP, TTI, TBT, CLS, Speed Index 같은 지표들을 측정하며 페이지 로딩과 상호작용 속도를 수치로 보여줍니다.
접근성 영역에서는 ARIA 속성 사용, 색상 대비, 키보드 접근성 등 장애가 있는 사용자도 웹사이트를 사용할 수 있는지 확인합니다.
권장사항 영역에서는 HTTPS 사용 여부, 안전하지 않은 API 사용, 올바른 이미지 비율 등 보안과 호환성 항목을 체크합니다.
SEO 영역에서는 meta 태그, 텍스트 가독성, 크롤링 가능 여부 등 검색 엔진이 페이지를 얼마나 잘 이해할 수 있는지 평가합니다.
PWA 영역에서는 오프라인 동작, 설치 가능성 등 프로그레시브 웹 앱 기준을 충족하는지 평가합니다.
Q. 웹 애플리케이션의 성능을 최적화할 수 있는 방법들에 대해서 설명해주세요.
-
웹 성능 최적화는 크게 로딩 성능과 렌더링 성능으로 나눠 생각할 수 있습니다.
로딩 성능 측면에서는 코드 스플리팅을 통해 초기에 필요한 코드만 로드하고, 이미지를 WebP나 AVIF로 변환하거나 lazy loading을 적용해서 불필요한 리소스 로딩을 줄일 수 있습니다. CDN을 활용해 사용자와 가까운 서버에서 리소스를 제공하는 것도 효과적입니다.
렌더링 성능 측면에서는 불필요한 리렌더링을 방지하는 것이 중요합니다. React 기준으로는
memo,useMemo,useCallback등을 적절히 활용하고, 대량의 리스트는 가상 스크롤을 사용해 효율적으로 처리할 수 있습니다.네트워크 측면에서는 API 응답을 캐싱하거나, 필요한 데이터만 요청하도록 쿼리를 최적화하는 것도 도움이 됩니다.
Q. 웹 접근성의 개념과 개선 방법에 대해 설명해주세요.
-
웹 접근성은 장애가 있는 사용자를 포함해 모든 사람이 웹을 동등하게 사용할 수 있도록 보장하는 개념입니다. 시각 장애인은 스크린 리더를 통해 웹을 탐색하고, 신체적 장애가 있는 사용자는 마우스 대신 키보드만으로 탐색할 수 있어야 합니다.
개선 방법으로는 먼저 시맨틱 HTML을 사용하는 것이 중요합니다.
div대신header,nav,main,article같은 태그를 사용하면 스크린 리더가 구조를 올바르게 해석할 수 있습니다. 이미지에는 alt 텍스트를 꼭 추가해야 하고, 버튼이나 링크에는 역할을 설명하는 ARIA 속성을 적절히 사용해야 합니다. 키보드 네비게이션도 중요해서 Tab 키로 모든 인터랙티브 요소에 접근할 수 있어야 하며, 색상 대비 비율도 WCAG 기준에 맞게 충분히 확보해야 합니다.
Q. 낙관적 업데이트에 관해서 설명해 주세요.
-
낙관적 업데이트는 서버 응답을 기다리지 않고 UI를 먼저 업데이트한 후, 서버 응답이 돌아오면 최종 상태로 조정하는 패턴입니다.
예를 들어 좋아요 버튼을 눌렀을 때, 서버 응답을 기다리지 않고 바로 눌린 상태로 보여주는 방식입니다. 사용자 입장에서는 앱이 훨씬 빠르게 느껴집니다. 다만 서버 요청이 실패했을 때 원래 상태로 되돌리는 롤백 로직을 반드시 구현해야 하고, 이로 인해 상태 관리가 복잡해질 수 있다는 단점이 있습니다.
Q. 이미지 최적화 방법들에 대해 설명해주세요.
-
이미지 최적화는 포맷 선택, 반응형 이미지, lazy loading 세 방향으로 접근할 수 있습니다.
적절한 이미지 포맷 선택이 기본으로, WebP를 사용하면 JPG나 PNG보다 30~50% 더 작은 파일 크기로 동일한 화질을 유지할 수 있습니다. 반응형 이미지는
picture태그를 활용해 디바이스나 화면 크기에 따라 다른 포맷이나 크기의 이미지를 제공하는 방식입니다. lazy loading을 적용하면 뷰포트에 들어올 때만 이미지를 로드하여 초기 페이지 로드 시간을 크게 단축할 수 있습니다.
Q. 애자일에 대해 설명해주세요.
-
애자일은 소프트웨어 개발 방법론 중 하나로, 짧은 개발 주기를 반복하면서 지속적으로 제품을 개선해나가는 방식입니다.
전통적인 워터폴 방식이 요구사항 정의부터 배포까지 순차적으로 진행되는 것과 달리, 애자일은 보통 1~2주 단위의 스프린트로 작업을 나눠서 빠르게 결과물을 만들고 피드백을 반영합니다. 핵심 가치는 문서보다 동작하는 소프트웨어, 계획을 따르기보다 변화에 대응하는 것입니다. 대표적인 애자일 프레임워크로는 스크럼과 칸반이 있습니다.
Q. 웹, 앱 브릿지에 대해서 알고계신가요? 알고 계시다면 설명해주세요.
-
웹 앱 브릿지는 하이브리드 앱에서 웹뷰와 네이티브 앱 간에 통신을 가능하게 해주는 방식입니다.
하이브리드 앱은 네이티브 앱 껍데기 안에 웹뷰를 올려서 웹 코드를 실행하는 구조인데, 이때 웹 코드에서 카메라, 위치 정보, 푸시 알림 같은 네이티브 기능을 사용하거나 반대로 네이티브에서 웹으로 데이터를 전달할 때 브릿지를 통해 통신합니다. iOS에서는 WKWebView의
postMessageAPI, Android에서는 JavascriptInterface를 사용해 구현합니다.
Q. 지원자님이 생각하시는 클린 코드에 대해 설명해주세요.
-
클린 코드는 읽기 쉽고 의도가 명확한 코드라고 생각합니다. 코드는 한 번 작성되지만 여러 번 읽히기 때문에, 다른 개발자가 읽었을 때 바로 이해할 수 있는 코드가 좋은 코드라고 봅니다.
구체적으로는 변수명과 함수명이 목적을 명확하게 나타내야 하고, 하나의 함수는 하나의 역할만 해야 합니다. 불필요한 중복을 없애고, 복잡한 로직에는 의도를 설명하는 주석을 적절히 달아주는 것도 포함됩니다. 또한 아무리 잘 짠 코드라도 팀 컨벤션과 다르면 오히려 유지보수가 어려워질 수 있기 때문에, 팀의 코딩 스타일을 따르는 것도 중요하다고 생각합니다.
Q. 지원자님이 생각하시는 클린 아키텍처에 대해 설명해주세요.
-
클린 아키텍처는 관심사를 분리해서 코드의 각 부분이 독립적으로 변경될 수 있도록 설계하는 방식이라고 생각합니다.
핵심은 비즈니스 로직이 UI나 외부 서비스 같은 세부 구현에 의존하지 않도록 하는 것입니다. 이렇게 하면 UI를 바꿔도 비즈니스 로직은 그대로이고, API가 바뀌어도 UI는 영향을 받지 않게 됩니다. 프론트엔드 관점에서는 화면 렌더링을 담당하는 컴포넌트 레이어, 상태와 비즈니스 로직을 담당하는 서비스 레이어, API 통신을 담당하는 데이터 레이어를 명확하게 분리하는 것이 클린 아키텍처를 적용하는 방법이라고 생각합니다.
Q. non-blocking과 async의 차이점에 대해 설명해주세요.
-
non-blocking과 async는 자주 함께 쓰이지만, 관점이 조금 다릅니다.
non-blocking은 함수를 호출했을 때 결과가 나올 때까지 기다리지 않고 즉시 제어권을 돌려주는 실행 방식이고, 예를 들어 A 함수가 B 함수를 호출했을 때 B가 끝나지 않아도 A가 계속 실행될 수 있는 흐름을 말합니다.
async는 작업이 완료됐을 때 어떻게 처리할지를 미리 지정해두는 코드 구조로, B가 끝난 후에 실행될 콜백이나 then 체이닝 같은 처리 방식을 말합니다.
Q. blocking / non-blocking / sync / async 에 대해 설명해주세요. 그리고 각각을 조합한 것에 대해 설명해주세요.
-
blocking은 함수가 호출되면 작업이 끝날 때까지 제어권을 넘기지 않는 방식이고, non-blocking은 작업이 끝나지 않아도 즉시 제어권을 돌려주는 방식입니다.
sync는 작업의 결과를 호출한 쪽에서 바로 받아 처리하는 방식이고, async는 결과를 나중에 콜백이나 이벤트로 받아 처리하는 방식입니다.
네 가지를 조합하면, blocking + sync는 작업이 완료될 때까지 기다리면서 순서대로 처리하는 가장 직관적인 방식입니다.
blocking + async는 제어권은 넘기지 않으면서 결과 처리는 나중에 하는 방식인데, 실질적인 이점이 없어서 잘 사용하지 않는 조합입니다.
non-blocking + sync는 제어권은 바로 돌려받지만 결과가 나올 때까지 계속 확인하는 방식으로, 폴링이 여기에 해당합니다.
non-blocking + async는 제어권도 바로 돌려받고 결과도 나중에 받아 처리하는 가장 효율적인 방식으로, Node.js의 I/O 처리가 대표적인 예입니다.
Infra, Build, Tools
Q. Nginx에 대해서 설명해주세요.
-
Nginx는 고성능 웹 서버이자 리버스 프록시로 많이 사용되는 도구입니다.
웹 서버로서는 정적 파일을 빠르게 제공하는 역할을 하며, React 같은 SPA를 빌드한 결과물을 Nginx로 서빙하는 것이 대표적인 사용 사례입니다. 리버스 프록시로는 클라이언트 요청을 받아서 뒤에 있는 실제 서버로 전달하고, 여러 서버로 트래픽을 분산하는 로드밸런싱도 가능합니다. 아파치와 비교했을 때 Nginx는 이벤트 기반 아키텍처를 사용해서 동시 접속 처리 성능이 뛰어나고 메모리 사용량이 적다는 장점이 있습니다.
Q. CI/CD에 대해서 설명해주세요.
-
CI/CD는 코드 변경사항을 자동으로 빌드, 테스트, 배포하는 파이프라인을 말합니다.
CI는 지속적 통합으로, 개발자가 코드를 푸시하면 자동으로 빌드와 테스트가 실행되며, 코드를 자주 통합하면서 충돌이나 버그를 빠르게 발견할 수 있다는 장점이 있습니다.
CD는 지속적 배포로, CI를 통과한 코드를 자동으로 스테이징이나 프로덕션 환경에 배포하는 과정입니다. 수동 배포 과정을 줄여서 배포 주기를 빠르게 가져갈 수 있습니다. 대표적인 도구로는 GitHub Actions, Jenkins, GitLab CI 등이 있습니다.
Q. 웹 서비스 배포 시스템 구축 경험이 있으신가요? 배포 프로세스에 대해 아는대로 설명해주세요.
-
AWS 환경에서 배포해본 경험이 있습니다. 배포 프로세스는 개발, 빌드, 테스트, 배포, 모니터링 순서로 이루어집니다.
웹 서버는 HTTP 요청에 대해 정적인 HTML 파일을 전달하는 역할을 하고, WAS는 클라이언트 요청에 따라 동적으로 콘텐츠를 생성해서 제공하는 역할을 합니다.
Q. Monorepo 사용 경험에 대해서 말씀해주세요.
-
모노레포는 여러 프로젝트나 패키지를 하나의 저장소에서 관리하는 방식입니다.
멀티레포와 비교했을 때, 프로젝트 간에 코드를 쉽게 공유할 수 있고 의존성 관리가 간편하다는 장점이 있습니다. 예를 들어 공통 UI 컴포넌트나 유틸리티 함수를 별도 패키지로 분리해서 여러 앱에서 공유할 수 있습니다. 대표적인 도구로는 Turborepo, Nx, pnpm workspace 등이 있으며, Turborepo는 빌드 캐싱을 통해 중복 작업을 줄여주고 병렬 빌드로 성능을 높여줍니다.
Q. 패키지 매니저(npm, pnpm, yarn, yarn2) 사용 경험에 대해 말씀해주세요.
-
npm은 Node.js에 기본으로 포함된 패키지 매니저로, 가장 범용적으로 사용됩니다.
yarn은 Facebook이 npm의 속도와 보안 문제를 개선하기 위해 만든 패키지 매니저로, 패키지 설치를 병렬로 처리해서 더 빠릅니다. pnpm은 디스크 공간 효율성이 뛰어난 패키지 매니저로, 패키지를 전역 저장소에 한 번만 저장하고 심볼릭 링크로 연결하는 방식을 사용해서 중복 저장 없이 디스크 사용량을 크게 줄일 수 있습니다. 모노레포 환경에서 특히 효과적입니다. yarn berry라고도 불리는 yarn2는 PnP 방식을 도입해 node_modules 폴더 자체를 없애고 패키지를 zip 파일로 관리하며, 설치 속도가 빠르고 의존성 문제를 더 엄격하게 관리할 수 있습니다.
Q. Git에 대해서 설명해주세요.
-
Git은 분산 버전 관리 시스템입니다. 코드의 변경 이력을 추적하고, 여러 개발자가 동시에 작업할 수 있도록 도와줍니다.
핵심 개념으로는 커밋, 브랜치, 머지가 있습니다. 커밋은 코드 변경사항의 스냅샷이고, 브랜치는 독립적인 작업 공간을 만드는 것이며, 머지는 브랜치를 합치는 작업입니다. 분산 버전 관리라는 특성 덕분에 각 개발자의 로컬에 전체 저장소 이력이 저장되므로, 서버가 없어도 로컬에서 커밋이나 브랜치 생성 등의 작업이 가능합니다.
Q. 사용하신 Git 브랜치 전략에 대해 설명해주세요.
-
저는 주로 Git Flow와 GitHub Flow를 사용해봤습니다.
Git Flow는 main, develop, feature, release, hotfix 브랜치를 구조적으로 나눠서 사용하는 전략으로, 배포 주기가 명확하고 안정성이 중요한 프로젝트에 적합합니다. 다만 브랜치가 많아서 관리가 복잡해질 수 있습니다.
GitHub Flow는 main 브랜치와 feature 브랜치만 사용하는 더 단순한 전략으로, 기능 개발이 끝나면 PR을 만들고 코드 리뷰 후 main에 바로 머지합니다. 빠른 배포가 필요한 서비스에 더 적합합니다.
팀 규모와 배포 주기에 따라 적합한 전략이 다르다고 생각합니다.
Q. Git Merge, Squash, Rebase의 차이에 대해서 설명해주세요.
-
세 가지 모두 브랜치를 통합하는 방법이지만 커밋 이력을 다루는 방식이 다릅니다.
Merge는 두 브랜치의 이력을 그대로 합치고 머지 커밋을 하나 생성합니다. 작업 흐름을 추적하기 쉽지만, 브랜치가 많아지면 이력이 복잡해 보일 수 있습니다. Squash는 feature 브랜치의 여러 커밋을 하나로 합쳐서 머지하여, 작업 중 남긴 불필요한 커밋들을 정리해서 깔끔한 이력을 만들 수 있습니다. Rebase는 feature 브랜치의 시작점을 main의 최신 커밋으로 옮겨서 이력을 선형으로 만드는 방식입니다. 커밋 이력이 깔끔해지지만, 이미 공유된 브랜치에 rebase를 하면 이력이 달라져서 문제가 생길 수 있습니다.
Q. dependencies 와 devDependencies 차이에 대해 설명해주세요.
-
dependencies는 프로덕션 환경에서 앱을 실행하는 데 필요한 패키지들로, React, Redux, Axios처럼 실제 서비스 동작에 필요한 것들이 여기에 들어갑니다.
devDependencies는 개발 과정에서만 필요한 패키지들입니다. 빌드 도구, 테스트 프레임워크, 린터 등이 여기에 해당하며 Webpack, Babel, ESLint, TypeScript 같은 것들이 포함됩니다. 실제 배포 시에는 devDependencies가 설치되지 않으므로 배포 용량을 줄일 수 있습니다.
Q. MSA 경험이 있으신가요? 알고 계시는 만큼 설명해주세요.
-
MSA는 마이크로서비스 아키텍처의 약자로, 하나의 큰 서비스를 독립적으로 배포 가능한 작은 서비스들로 나눠서 운영하는 방식입니다.
모놀리식 아키텍처와 비교하면, MSA는 각 서비스를 독립적으로 개발하고 배포할 수 있으며, 특정 서비스만 스케일아웃하거나 한 서비스에 장애가 생겨도 다른 서비스에 영향이 적다는 장점이 있습니다. 프론트엔드 관점에서는 마이크로 프론트엔드와 연결되는 개념으로, 각 팀이 독립적으로 UI 모듈을 개발하고 배포하는 방식으로 발전하기도 합니다. 다만 서비스 간 통신이 복잡해지고 운영 및 모니터링 부담이 늘어난다는 단점도 있습니다.
Q. BFF 아키텍처 구현 경험이 있나요? 혹은 알고 계시는 만큼 설명해주세요.
-
BFF는 Backend for Frontend의 약자로, 프론트엔드만을 위한 맞춤형 백엔드 서버입니다.
백엔드가 범용 API나 마이크로서비스로 구성될 때, 프론트엔드는 화면 하나를 그리기 위해 여러 API를 호출하거나 불필요한 데이터를 받아 직접 가공해야 하는 불편함이 생깁니다. BFF는 이 문제를 해결하기 위해 중간에서 백엔드의 여러 API를 대신 호출해 데이터를 조합하고 프론트엔드에 필요한 형태로 가공해서 전달합니다. 덕분에 프론트엔드는 복잡한 데이터 처리 없이 BFF가 제공하는 API만 호출하면 되어 개발이 편해지고 성능도 개선됩니다.
Q. Webpack과 Vite, 기타 번들링 도구에 대한 설명 해주세요.
-
Webpack은 가장 많이 쓰이는 번들러 중 하나로, 모든 자원을 JavaScript 모듈로 간주해서 의존성을 분석하고 하나 또는 여러 파일로 번들링해줍니다. 플러그인과 로더 기반으로 확장성이 높고 트리 쉐이킹, 코드 분할을 지원합니다.
Vite는 최근 많이 사용되는 빠른 빌드 도구입니다. 개발 환경에서는 번들링하지 않고 ESM 방식으로 바로 실행해서 매우 빠른 개발 서버를 제공하고, 빌드 시에는 Rollup 기반으로 번들링합니다. 설정이 간단하고 빠르다는 장점이 있지만, 복잡한 커스터마이징이 필요할 때는 Webpack보다 제약이 있을 수 있습니다.
Q. 디바운스와 쓰로틀에 대해 설명해주세요.
-
둘 다 이벤트 핸들러가 너무 자주 실행되지 않도록 제어하는 기법입니다.
디바운스는 이벤트가 연속으로 발생할 때 마지막 이벤트 이후 일정 시간이 지나야 핸들러가 실행되는 방식입니다. 검색창에 타이핑할 때 글자 하나하나마다 API를 호출하는 게 아니라, 입력을 멈춘 후 일정 시간이 지나면 호출하는 식으로 사용합니다. 쓰로틀은 일정 시간 간격 동안 이벤트가 아무리 많이 발생해도 한 번만 핸들러가 실행되는 방식으로, 스크롤 이벤트나 연속 클릭 처리에 적합합니다.
[ 디바운스 코드 ]
function debounce(fn, delay) {
let timer = 0;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
fn(...args);
}, delay);
};
}[ 쓰로틀 코드 ]
function throttle(fn, delay) {
let timer = null;
return (...args) => {
if (timer) return;
timer = setTimeout(() => {
fn(...args);
timer = null;
}, delay);
};
}
Q. 무한 스크롤 구현 시 디바운스와 쓰로틀링 중 어떤게 더 적합한가요?
-
쓰로틀이 더 적합하다고 생각합니다. 스크롤은 연속적인 동작이며, 사용자는 스크롤이 페이지 하단에 도달했을 때 즉각적인 반응을 기대합니다. 쓰로틀은 하단에 도달하는 순간 즉시 추가 데이터 요청을 수행하므로 자연스러운 스크롤 경험을 제공합니다.
반면 디바운스를 적용할 경우, 사용자가 계속 스크롤하면 마지막 스크롤이 멈춘 후에야 데이터를 불러오기 시작하므로 지연이 발생할 수 있습니다.
Q. 무한 스크롤 구현 방식에 대해 설명해주세요.
-
사용자가 페이지를 아래로 스크롤할 때 마지막 요소가 뷰포트에 닿는 순간을 감지해서 추가 데이터를 요청하는 방식으로, 주로 Intersection Observer API를 사용합니다.
저는 무한스크롤을 구현할 때 React Query의
useInfiniteQuery훅을 활용했습니다. API 요청, 데이터 병합, 로딩 상태 관리 등 전체 흐름을 처리해줘서 편리했습니다.
Q. 무한 스크롤의 장단점은 무엇이고, 개선은 어떻게 할 수 있나요?
-
무한 스크롤의 장점은 초기에 모든 데이터를 한 번에 불러오는 대신, 사용자의 스크롤에 따라 필요한 데이터만 점진적으로 요청하기 때문에 초기 로딩 속도를 개선하고 UX를 향상시킬 수 있다는 점입니다.
하지만 스크롤이 계속되면서 DOM에 컴포넌트가 누적되면 브라우저가 많은 요소를 렌더링하고 유지해야 하므로 성능 저하가 발생할 수 있습니다. 이러한 문제를 해결하기 위해 가상 스크롤 기법을 사용할 수 있습니다. 화면에 보이는 영역만 실제 DOM에 렌더링하고, 스크롤에 따라 보이지 않는 영역은 제거하거나 교체해서 전체 DOM 노드 수를 최소화하는 방식입니다.
Q. 가상스크롤 방식에 대해 좀 더 자세히 설명해주세요. 현재 보이는 부분만 데이터를 가져와 렌더링되고, 위아래로 스크롤할때마다 데이터 요청해서 가져오면 오히려 비효율적인거 아닌가요?
-
가상 스크롤은 데이터를 새로 요청하는 방식이 아니라, 이미 로딩된 데이터를 화면에 효율적으로 렌더링하기 위한 기술입니다.
수백 개의 데이터가 클라이언트에 존재하더라도 DOM에는 현재 화면에 보이는 일부만 렌더링하고, 스크롤 위치에 따라 렌더링 대상을 교체합니다. 구현 방식은 스크롤 위치와 아이템 높이를 기준으로 현재 화면에 보여줄 데이터의 인덱스를 계산해서 해당 항목만 렌더링하는 방식이며, 데이터가 많아도 성능을 효율적으로 유지할 수 있습니다.
Testing
Q. FE 개발에서 테스트 코드를 작성해서 얻는 이점이 무엇인가요?
-
Jest를 통해서 테스트 코드를 작성해본 경험이 있습니다. 테스트 코드를 작성하면 코드 수정이 발생할 때마다 동작의 성공 여부를 빠르게 판단할 수 있어서 생산성에 유리합니다.
특히 리팩토링을 할 때 기존 기능이 의도대로 동작하는지 바로 확인할 수 있어서 안전하게 코드를 수정할 수 있고, 요구사항이 변경됐을 때도 빠르게 대응이 가능합니다. 또한 테스트 코드 자체가 문서 역할을 해서, 코드가 어떤 동작을 해야 하는지 파악하는 데도 도움이 됩니다.
Q. 유닛 테스트, 통합 테스트, E2E 테스트에 대해 각각 설명해주세요.
-
유닛 테스트는 앱의 개별 구성 요소를 독립적으로 테스트합니다. Button 컴포넌트를 클릭했을 때 특정 함수가 호출되는지 확인하는 것이 예시입니다.
통합 테스트는 여러 구성 요소가 함께 동작할 때 올바른지 테스트하며, 폼을 제출했을 때 API 호출이 올바르게 발생하는지 확인하는 것이 예시입니다.
E2E 테스트는 사용자 관점에서 앱의 전체 흐름을 테스트합니다. 로그인하고 상품을 구매하는 과정처럼 실제 사용 시나리오를 처음부터 끝까지 검증합니다.
Q. 만약 간단한 입력 필드 컴포넌트를 만든다면, 어떤 부분을 테스트해봐야 할까요?
-
입력 필드 컴포넌트라면 렌더링, 사용자 인터랙션, 유효성 검사 세 가지를 테스트해야 한다고 생각합니다.
렌더링 테스트는 컴포넌트가 올바르게 화면에 표시되는지, placeholder나 초기값 같은 props가 제대로 반영되는지 확인합니다. 사용자 인터랙션 테스트는 텍스트를 입력했을 때
onChange핸들러가 올바르게 호출되는지, 입력된 값이 상태에 반영되는지 테스트합니다. 유효성 검사 테스트는 잘못된 값 입력 시 에러 메시지가 표시되는지, 올바른 값 입력 시 에러가 사라지는지 확인합니다.
Q. FE 테스트를 위해 주로 어떤 라이브러리나 프레임워크를 사용하나요?
-
프론트엔드 테스트에서 가장 많이 사용되는 조합은 Jest와 React Testing Library입니다.
Jest는 JavaScript 테스트 프레임워크로, 유닛 테스트와 통합 테스트를 작성할 때 사용하며 테스트 실행, 모킹, 코드 커버리지 측정 등 테스트에 필요한 기능을 대부분 제공합니다. React Testing Library는 React 컴포넌트를 사용자 관점에서 테스트하기 위한 라이브러리로, 구현 세부사항보다는 실제 사용자처럼 화면에서 요소를 찾고 인터랙션하는 방식으로 테스트를 작성하도록 유도합니다. E2E 테스트는 Cypress나 Playwright를 주로 사용하며, 실제 브라우저 환경에서 사용자 시나리오 전체를 테스트할 수 있습니다.
Q. 컴포넌트를 테스트할 때, API 호출을 실제 네트워크 요청 없이 테스트하려면 어떻게 해야 할까요?
-
API 호출을 모킹하는 방법을 사용합니다.
Jest에서는
jest.mock을 사용해서fetch나axios같은 HTTP 클라이언트를 가짜 함수로 대체할 수 있습니다. 특정 API 호출에 대해 원하는 응답값을 반환하도록 설정하면 실제 네트워크 요청 없이 테스트할 수 있습니다. 더 체계적으로 관리하고 싶다면 MSW를 사용하는 방법도 있습니다. MSW는 Service Worker를 기반으로 API 요청을 가로채서 모의 응답을 반환해주며, 실제 서버처럼 동작하기 때문에 테스트 코드가 구현 세부사항에 덜 의존하게 되고, 개발 환경에서도 동일한 핸들러를 재사용할 수 있어서 편리합니다.
Q. 프론트엔드 E2E 테스트에 대해 설명해주세요.
-
E2E 테스트는 애플리케이션의 사용자 경험을 처음부터 끝까지 시뮬레이션해서 테스트하는 방식입니다.
유닛 테스트나 통합 테스트와 달리 사용자 관점에서 전체 애플리케이션이 의도한 대로 동작하는지 검증합니다. 브라우저 환경에서 실제 사용자 동작을 흉내 내어 UI 상호작용, API 호출, 화면 전환 등 여러 구성 요소가 함께 동작하는 과정에서 발생하는 문제를 탐지할 수 있습니다. 보통 Cypress나 Playwright 같은 도구를 이용해 작성합니다.