-
Notifications
You must be signed in to change notification settings - Fork 1
기술 스택
- 동적 타입 언어인 Javascript는 유연하지만 프로젝트의 규모가 커질수록 예측할 수 없는 에러를 발생시킨다.
- 따라서 타입 체킹을 통해 정적 타입 언어의 장점인 컴파일 시 오류 검사를 위해 Typescript를 사용한다.
- 또한 매개변수에 타입이 지정되므로 IDE에서 자동 완성 지원이 편리하고 생산성에 이점을 가져다 준다.
- Interface, Decorator 등 편리한 문법을 지원하여 객체 지향의 장점을 가져갈 수 있다.
- 개발하려는 서비스의 핵심 비즈니스 로직이 사용자 정보제공이기 때문에 검색엔진 최적화(SEO)를 위해 SSR 프레임워크인 Next.js를 사용하기로 하였다.
- 빌드 타임 시 HTML을 생성하여(SSG) 제공할 수 있으므로 사용자 입장에서 느껴지는 초기 페이지 로딩 속도를 크게 줄일 수 있다.
- 라우팅이 react를 사용했을 때 보다 편리하다.
react-router-dom
같은 라이브러리를 사용하지 않고 폴더 구조로 라우팅을 편하게 할 수 있다.
-
클라이언트에서 전역으로 관리해야할 상태가 많지 않다.
-
Redux, Mobx, Recoil과 같은 상태관리 도구는 클라이언트 쪽 상태를 관리하기에는 적합하나 서버의 데이터들을 관리하기에는 적합하지 않다. 클라이언트 상태관리 도구에서 서버의 상태를 fetch해서 함께 관리하면 클라이언트 상태와 서버 상태가 섞여 구조가 복잡해진다.
두 개의 상태가 묶이면서 서버 데이터를 위한 로직이 과도하게 커지고, 클라이언트 상태를 관리하는 것이 아닌 서버상태를 관리하는 것과 같은 모습이 된다.
서버상태관리 도구를 사용한다면 서버와 클라이언트 데이터를 분리할 수 있다.
-
제공해야할 대부분의 정보는 서버에서 가져와야하고 순위 시스템의 경우 최신화가 중요하기 때문에 서버 데이터를 효율적으로 캐싱하고 데이터를 지속적으로 동기화하고 업데이트하는 작업을 도와주는 서버상태관리 도구를 도입하기로 하였다.
-
서버상태관리 도구를 사용하지 않았을 때 비동기 처리를 할 경우 loading, error state들이 비대하게 늘어나 코드의 관심사 분리가 힘들고 지저분해지는 경우가 있는데 직관적이고 짧은 코드로 대체할 수 있게 된다.
아래는 Redux로 서버의 데이터를 비동기적으로 받아오는 로직을 작성했을 때이다.
import React, { useEffect } from "react"; import { useSelector, useDispatch } from "react-redux"; import axios from 'axios'; const SET_TODOS = "SET_TODOS"; export const rootReducer = (state = { todos: [] }, action) => { switch (action.type) { case SET_TODOS: return { ...state, todos: action.payload }; default: return state; } }; export const App = () => { const todos = useSelector((state) => state.todos); const dispatch = useDispatch(); useEffect(() => { const fetchPosts = async () => { const { data } = await axios.get("/api/todos"); dispatch({ type: SET_TODOS, payload: data} ); }; fetchPosts(); }, []); return ( <ul>{todos.length > 0 && todos.map((todo) => <li>{todo.text}</li>)}</ul> ); };
아래는 React-query로 작성한 코드이다. 두 코드의 길이를 비교한다면 확연한 차이를 볼 수 있다.
import React from "react"; import { useQuery } from "react-query"; import axios from "axios"; // 캐싱 설정을 어느곳에서든 정의할 수 있습니다 const fetchTodos = () => { const { data } = axios.get("/api/todos"); // 필요하다면 데이터 유효성 검사를 여기서 수행하여, 실제로 값을 사용하는 곳에서는 검증된 값을 사용할 수 있습니다 return data; }; const App = () => { // 데이터가 필요한 곳에서 호출하면 됩니다 const { data } = useQuery("todos", fetchTodos); return data ? ( <ul>{data.length > 0 && data.map((todo) => <li>{todo.text}</li>)}</ul> ) : null; };
-
서버상태 관리 도구에 서버 데이터 페칭과 캐싱 역할을 위임하고 다른 기능 구현에 집중할 수 있다.
-
별도의 설정 없이 즉시 사용할 수 있고 react-hook과 같은 구조로 사용할 수 있어 사용방법이 쉽다.
-
이외에도 같은 데이터에 대한 요청이 여러번 있을 경우 중복을 제거한다.
-
백그라운드 상에서 데이터를 최신화 시켜준다.
-
공식문서가 잘돼있다.
- 디자인 시스템의 도입을 통해 일관성있는 디자인을 유지할 수 있다.
- 미리 개발된 UI들을 재활용하여 생산성이 올라간다.
- 협업하는데 있어 프론트엔드 UI를 문서화하여 유지보수와 관리의 용이성이 생긴다고 판단했다. 개발자끼리 서로의 코드를 컴포넌트 단위로 명확하게 이해할 수 있게 도와줌으로써 생산성의 향상을 이끌어 낼 수 있다.
- 스토리북을 통해 개발을 하게 되면 컴포넌트의 재사용성을 더욱 고려하면서 설계하게 된다.
- 페이지가 완성되기 전에도 결과물을 컴포넌트 단위로 불 수 있고 이러한 장점으로 인해 컴포넌트단위로 피드백을 하면서 개선해 나갈 수 있다
- 각 컴포넌트에 대해 상태에 따른 변화를 스토리북에서 쉽게 파악하고 관리할 수 있다.
- 그룹프로젝트를 하는 데 있어 협업 도구로 사용해볼 기회가 된다고 생각했다.
- Styled-components를 사용했을 때 CSS-in-JS이므로 리액트에서 컴포넌트 기반 개발을 할 때 각 컴포넌트의 스타일을 명시적으로 파악하기 쉽다.
- Style을 각 컴포넌트에서 작성하기 때문에 네이밍 중복을 고려하지 않아도 된다.
- 클래스명을 사용할 필요가 없기 때문에 클래스명을 짓는데 소요되는 코스트가 적다.
- css파일을 사용할 경우 파일의 수가 비대하게 늘어나고 파일구조가 복잡해진다. styled-component를 사용하면 따로 유지보수해야 할 스타일 시트 파일을 제거할 수 있다.
- props를 활용한 조건부 스타일링이 가능하다.
- styled-components를 사용하면 js파일이 너무 커질 수 있다하는데 이건 컴포넌트를 잘 분리한다면 해결되는 문제라 생각한다.
- 하나의 style을 가진 component를 작성해 재사용성을 높일 수 있다.
- Scss 라이브러리 설치 없이 Scss 문법을 사용할 수 있습니다.
- Styled-component로 만든 컴포넌트에 style을 오버라이드 해서 사용할 수 있다. 재사용성 증가.
- 관련한 미들웨어를 모두 구현해야하는 Express에 비해 프레임워크가 내장하고 있는 자체 기능들이 편의성을 많이 제공해준다. 따라서 비지니스 로직에 집중이 가능하다.
- 프레임워크가 제한해주는 구조가 협업 시 코드 파악을 용이하게 해준다.
- 타입스크립트만 지원하기 때문에 객체지향이 제공하는 장점을 최대한 활용할 수 있다.
- 인메모리 DB로 디스크I/O에 비해 병목이 적다.
- API 캐싱 및 refresh token 저장을 위해 사용한다.
- 필요한 데이터 사이의 관계가 복잡하지 않다. 따라서 관계에 대한 무결성 검사의 필요성 보다는 성능적인 측면에 초점을 맞춰도 된다고 판단했다.
- 트랜잭션을 통해 ACID 보장이 RDBMS와 동일하게 보장이 가능하다.
- 차후에 replication을 통한 수평 확장의 가능성이 RDBMS보다 열려있다.
- MongoDB와 가장 호환이 잘 되는 ORM 프레임워크라 판단했다.
- TypeORM은 MongoDB 버전에 따라 호환성 이슈가 존재한다.
- Prisma는 GraphQL과의 호환성을 강조해서, 굳이 안전성이 입증된 Mongoose의 대안으로 선택할 필요성을 느끼지 못했다.
- 어플리케이션의 컨텐츠들을 수정할 수 있는 Admin UI를 제공한다.
- NestJS와 Mongoose와 쉽게 통합이 가능하다.
- 개발자가 아닌 운영자도 이를 통해 컨텐츠들을 수정할 수 있으므로, 서비스 유지보수 측면에서 이점이 크다.
- 팀원 모두가 테스트 프레임워크로 Jest를 사용했던 경험이 있다.
- 평소 쓰던 도구에 대한 익숙함에서 오는 생산성, 다른 프레임워크를 학습하는 데 드는 비용을 감수하면서 굳이 다른 테스트 프레임워크를 선택할 필요성을 느낄 수 없었다.
- 부스트캠프 자체 크레딧 지원을 통해 비용을 절감할 수 있고 클라우드 서비스 별로 큰 차이가 있는 게 아니여서 사용하기로 결정했다.
- 요청 당 스레드 방식인 Apache는 요청 당 스레드를 할당하는 방식이므로 10K 문제를 해결하기 힘들다.
- 그에 비해 이벤트 루프 방식의 Nginx는 자원의 효율성, 더 많은 트래픽 처리에 이점이 있다.
- reverse proxy, 로드밸런싱, 캐싱 등 다양한 기능을 지원한다.
- 독립된 환경을 보장 할 수 있어 개발 환경과 배포 환경을 통합 할 수 있다.
- 저장소로 Github를 사용하면서 PR, Project, Issue와 같은 기능을 적극적으로 활용하면서 CI에서도 이를 활용 할 수 있다.
- Jenkins보다 쉽게 설정이 가능하다.